diff --git a/client/config/webpack.config.js b/client/config/webpack.config.js index 96d83038f9d9..61670a3174a2 100644 --- a/client/config/webpack.config.js +++ b/client/config/webpack.config.js @@ -40,12 +40,13 @@ function config(webpackEnv) { const env = getClientEnvironment(); // common function to get style loaders - const getStyleLoaders = (cssOptions, preProcessor) => { + const getStyleLoaders = (cssOptions, preProcessor, extract = true) => { const loaders = [ - isEnvDevelopment && resolve.sync("style-loader"), - isEnvProduction && { - loader: MiniCssExtractPlugin.loader, - }, + extract && isEnvDevelopment && resolve.sync("style-loader"), + extract && + isEnvProduction && { + loader: MiniCssExtractPlugin.loader, + }, { loader: resolve.sync("css-loader"), options: cssOptions, @@ -243,10 +244,6 @@ function config(webpackEnv) { resourceQuery: /raw/, type: "asset/source", }, - { - resourceQuery: /url/, - type: "asset/resource", - }, { test: [/\.avif$/, /\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/], type: "asset/resource", @@ -362,6 +359,22 @@ function config(webpackEnv) { sideEffects: true, }, // Opt-in support for SASS (using .scss or .sass extensions). + { + test: /\.(scss|sass)$/, + with: { type: "css" }, + use: getStyleLoaders( + { + importLoaders: 3, + sourceMap: isEnvProduction + ? shouldUseSourceMap + : isEnvDevelopment, + exportType: "css-style-sheet", + }, + "sass-loader", + false + ), + sideEffects: true, + }, { test: /\.(scss|sass)$/, use: getStyleLoaders( diff --git a/client/package.json b/client/package.json index f1ad9b7ab58a..58acd2b44593 100644 --- a/client/package.json +++ b/client/package.json @@ -4,6 +4,9 @@ "license": "MPL-2.0", "type": "module", "babel": { + "generatorOpts": { + "importAttributesKeyword": "with" + }, "presets": [ "react-app" ] diff --git a/client/src/assets/curriculum/landing-scrim.png b/client/src/assets/curriculum/landing-scrim.png new file mode 100644 index 000000000000..26929f273315 Binary files /dev/null and b/client/src/assets/curriculum/landing-scrim.png differ diff --git a/client/src/assets/curriculum/scrim-bg.png b/client/src/assets/curriculum/scrim-bg.png index 26929f273315..a88a6fab20f4 100644 Binary files a/client/src/assets/curriculum/scrim-bg.png and b/client/src/assets/curriculum/scrim-bg.png differ diff --git a/client/src/assets/curriculum/scrim-hexagons.svg b/client/src/assets/curriculum/scrim-hexagons.svg new file mode 100644 index 000000000000..3e9a2a7edccc --- /dev/null +++ b/client/src/assets/curriculum/scrim-hexagons.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/src/assets/curriculum/scrim-play.svg b/client/src/assets/curriculum/scrim-play.svg index 1c58caf801bb..6e9f3095da1c 100644 --- a/client/src/assets/curriculum/scrim-play.svg +++ b/client/src/assets/curriculum/scrim-play.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/client/src/assets/curriculum/scrimba-logo.svg b/client/src/assets/curriculum/scrimba-logo.svg new file mode 100644 index 000000000000..8d33b4f84f3f --- /dev/null +++ b/client/src/assets/curriculum/scrimba-logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/src/assets/fonts/BarlowCondensed-SemiBold.woff2 b/client/src/assets/fonts/BarlowCondensed-SemiBold.woff2 new file mode 100644 index 000000000000..82dc38e001cf Binary files /dev/null and b/client/src/assets/fonts/BarlowCondensed-SemiBold.woff2 differ diff --git a/client/src/curriculum/index.scss b/client/src/curriculum/index.scss index 6f1eedda36d3..5c6d2df369b6 100644 --- a/client/src/curriculum/index.scss +++ b/client/src/curriculum/index.scss @@ -289,9 +289,15 @@ } scrim-inline { + aspect-ratio: 1.5; display: block; - height: 14.25rem; - width: 22rem; + margin: 0.5rem auto; + max-width: 36rem; + width: 100%; + } + + p:has(> scrim-inline:only-child) { + margin: 1rem 0; } } } diff --git a/client/src/curriculum/landing.tsx b/client/src/curriculum/landing.tsx index f621777d6e06..b6d36e9808c5 100644 --- a/client/src/curriculum/landing.tsx +++ b/client/src/curriculum/landing.tsx @@ -16,6 +16,7 @@ import "./landing.scss"; import { ProseSection } from "../../../libs/types/document"; import { PartnerBanner } from "./partner-banner"; import { useIsServer } from "../hooks"; +import scrimBg from "../assets/curriculum/landing-scrim.png"; const ScrimInline = lazy(() => import("./scrim-inline")); @@ -141,7 +142,15 @@ function About({ section }) {
Learn our curriculum with Scrimba's interactive{" "}
diff --git a/client/src/curriculum/scrim-inline.global.css b/client/src/curriculum/scrim-inline.global.css
new file mode 100644
index 000000000000..ac55e7fa316a
--- /dev/null
+++ b/client/src/curriculum/scrim-inline.global.css
@@ -0,0 +1,8 @@
+@font-face {
+ font-family: "BarlowCondensed-SemiBold";
+ font-weight: 600;
+ font-display: block;
+ src:
+ local("BarlowCondensed-SemiBold"),
+ url("../assets/fonts/BarlowCondensed-SemiBold.woff2") format("woff2");
+}
diff --git a/client/src/curriculum/scrim-inline.scss b/client/src/curriculum/scrim-inline.scss
new file mode 100644
index 000000000000..6618fb42ac2f
--- /dev/null
+++ b/client/src/curriculum/scrim-inline.scss
@@ -0,0 +1,184 @@
+:host {
+ display: block;
+ overflow: hidden;
+}
+
+* {
+ box-sizing: border-box;
+}
+
+.visually-hidden {
+ border: 0 !important;
+ clip: rect(1px, 1px, 1px, 1px) !important;
+ -webkit-clip-path: inset(50%) !important;
+ clip-path: inset(50%) !important;
+ height: 1px !important;
+ margin: -1px !important;
+ overflow: hidden !important;
+ padding: 0 !important;
+ position: absolute !important;
+ white-space: nowrap !important;
+ width: 1px !important;
+}
+
+button {
+ appearance: none;
+ background: none;
+ border: none;
+ padding: 0;
+}
+
+dialog {
+ display: contents;
+
+ &[open] {
+ background-color: #0009;
+ height: 90vh;
+ width: 90vw;
+ }
+}
+
+.inner {
+ background-color: #000;
+ border: 1px solid #000;
+ container-type: size;
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ width: 100%;
+}
+
+.header {
+ align-items: center;
+ background: #000;
+ display: flex;
+ gap: 0.25rem;
+ margin: 0;
+ min-height: 1.75rem;
+ padding: 0 0.5rem;
+ width: 100%;
+
+ span {
+ color: #fff;
+ font-size: var(--type-tiny-font-size);
+ margin-right: auto;
+ }
+}
+
+.toggle,
+.external {
+ background-color: #fff;
+ cursor: pointer;
+ height: 1rem;
+ mask-position: center;
+ mask-repeat: no-repeat;
+ mask-size: contain;
+ width: 1rem;
+
+ &:hover {
+ background-color: var(--curriculum-color);
+ }
+
+ &:focus-visible {
+ outline-color: var(--accent-primary);
+ outline-offset: 1px;
+ outline-style: auto;
+ }
+}
+
+.toggle {
+ &.enter {
+ mask-image: url("../assets/icons/fullscreen-enter.svg");
+ }
+
+ &.exit {
+ mask-image: url("../assets/icons/cancel.svg");
+ }
+}
+
+.external {
+ mask-image: url("../assets/icons/external.svg");
+ mask-size: 75%;
+}
+
+.body {
+ flex: 1;
+ font-size: 4cqmin;
+ position: relative;
+}
+
+.background {
+ background-color: #453c78;
+ background-image: url("../assets/curriculum/scrimba-logo.svg"),
+ url("../assets/curriculum/scrim-hexagons.svg"),
+ url("../assets/curriculum/scrim-bg.png");
+ background-position:
+ 1.5em 1.5em,
+ right,
+ center;
+ background-repeat: no-repeat;
+ background-size:
+ auto 0.6em,
+ contain,
+ cover;
+ inset: 0;
+ position: absolute;
+
+ h1 {
+ bottom: 0;
+ color: #fff;
+ font-family: "BarlowCondensed-SemiBold", "Inter", sans-serif;
+ font-size: 3em;
+ font-weight: 600;
+ left: 0;
+ line-height: 1;
+ margin: 0.5em;
+ position: absolute;
+ text-transform: uppercase;
+ text-wrap: balance;
+ width: 60%;
+ }
+}
+
+.background-noise {
+ filter: url("#noise");
+ inset: 0;
+ mix-blend-mode: soft-light;
+ position: absolute;
+}
+
+.open,
+iframe {
+ border: none;
+ height: 100%;
+ position: absolute;
+ width: 100%;
+}
+
+.open {
+ --color: #8cb4ffcc;
+ background-image: var(--scrim-img);
+ background-position: center;
+ background-repeat: no-repeat;
+ background-size: cover;
+ cursor: pointer;
+ font-size: inherit;
+
+ &:hover {
+ --color: #8cb4ffe5;
+ }
+
+ svg {
+ height: 9em;
+ stroke-width: 2px;
+ width: auto;
+
+ circle {
+ fill: var(--color);
+ }
+
+ path {
+ fill: #fff;
+ }
+ }
+}
diff --git a/client/src/curriculum/scrim-inline.ts b/client/src/curriculum/scrim-inline.ts
index 8696a977d476..196a88ee6204 100644
--- a/client/src/curriculum/scrim-inline.ts
+++ b/client/src/curriculum/scrim-inline.ts
@@ -1,15 +1,14 @@
-import { css, html, LitElement, PropertyValues, unsafeCSS } from "lit";
+import { html, LitElement, PropertyValues } from "lit";
import { customElement } from "lit/decorators.js";
import { unsafeHTML } from "lit/directives/unsafe-html.js";
import { StyleInfo, styleMap } from "lit/directives/style-map.js";
+import { ifDefined } from "lit/directives/if-defined.js";
import { createComponent } from "@lit/react";
import React from "react";
import { CURRICULUM } from "../telemetry/constants";
-import externalIcon from "../assets/icons/external.svg?url";
-import fullscreenIcon from "../assets/icons/fullscreen-enter.svg?url";
-import cancelIcon from "../assets/icons/cancel.svg?url";
-import backgroundImg from "../assets/curriculum/scrim-bg.png";
+import "./scrim-inline.global.css";
+import styles from "./scrim-inline.scss?css" with { type: "css" };
import playSvg from "../assets/curriculum/scrim-play.svg?raw";
@customElement("scrim-inline")
@@ -21,146 +20,20 @@ class ScrimInline extends LitElement {
img?: string;
_imgStyle: StyleInfo = {};
+ scrimTitle?: string;
+
_fullscreen = false;
_scrimLoaded = false;
static properties = {
url: { type: String },
img: { type: String },
+ scrimTitle: { type: String },
_fullscreen: { state: true },
_scrimLoaded: { state: true },
};
- static styles = css`
- * {
- box-sizing: border-box;
- }
-
- .visually-hidden {
- border: 0 !important;
- clip: rect(1px, 1px, 1px, 1px) !important;
- -webkit-clip-path: inset(50%) !important;
- clip-path: inset(50%) !important;
- height: 1px !important;
- margin: -1px !important;
- overflow: hidden !important;
- padding: 0 !important;
- position: absolute !important;
- white-space: nowrap !important;
- width: 1px !important;
- }
-
- button {
- appearance: none;
- background: none;
- border: none;
- padding: 0;
- }
-
- dialog {
- display: contents;
-
- &[open] {
- background-color: #0009;
- height: 90vh;
- width: 90vw;
- }
- }
-
- .inner {
- background-color: #000;
- display: flex;
- flex-direction: column;
- width: 100%;
- height: 100%;
- }
-
- .header {
- align-items: center;
- display: flex;
- gap: 0.25rem;
- margin: 0;
- padding: 0 0.5rem;
- width: 100%;
- min-height: 1.75rem;
-
- span {
- color: #fff;
- font-size: var(--type-tiny-font-size);
- margin-right: auto;
- }
- }
-
- .toggle,
- .external {
- background-color: #fff;
- cursor: pointer;
- height: 1rem;
- width: 1rem;
- mask-size: contain;
- mask-position: center;
- mask-repeat: no-repeat;
-
- &:hover {
- background-color: var(--curriculum-color);
- }
-
- &:focus-visible {
- outline-color: var(--accent-primary);
- outline-offset: 1px;
- outline-style: auto;
- }
- }
-
- .toggle {
- &.enter {
- mask-image: url(${unsafeCSS(fullscreenIcon)});
- }
-
- &.exit {
- mask-image: url(${unsafeCSS(cancelIcon)});
- }
- }
-
- .external {
- mask-image: url(${unsafeCSS(externalIcon)});
- mask-size: 75%;
- }
-
- .open,
- iframe {
- border: 1px solid #000;
- width: 100%;
- height: 100%;
- }
-
- .open {
- --color: #8cb4ffcc;
- cursor: pointer;
- background-image: var(--img, url(${unsafeCSS(backgroundImg)}));
- background-repeat: no-repeat;
- background-position: center;
- background-size: cover;
-
- &:hover {
- --color: #8cb4ffe5;
- }
-
- svg {
- height: 7rem;
- width: 7rem;
- stroke-width: 2px;
-
- circle {
- fill: var(--color);
- }
-
- path {
- fill: #fff;
- }
- }
- }
- `;
+ static styles = styles;
willUpdate(changedProperties: PropertyValues${this.scrimTitle}
+