diff --git a/e2e/decoder.spec.ts b/e2e/decoder.spec.ts index dc6e72315..c9b367bf2 100644 --- a/e2e/decoder.spec.ts +++ b/e2e/decoder.spec.ts @@ -27,6 +27,7 @@ import { import { MessageStatusValue, MessageTypeValue } from "./e2e.values"; import { JwtDictionaryModel, JwtSignedWithDigitalModel } from "./e2e.models"; import jwts from "./jwt.json" with { type: "json" }; +import { EncodingValues } from "@/features/common/values/encoding.values"; const TestJwts = (jwts as JwtDictionaryModel).byAlgorithm; @@ -39,7 +40,7 @@ test.describe("Can interact with JWT Decoder JWT editor", () => { const jwtEditorInput = getDecoderJwtEditorInput(page); await expect(jwtEditorInput).toHaveValue( - "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.KMUFsIDTnFmyG3nMiGM6H9FNFUROf3wh7SmqJp-QV30", + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.KMUFsIDTnFmyG3nMiGM6H9FNFUROf3wh7SmqJp-QV30" ); }); @@ -53,8 +54,13 @@ test.describe("Can interact with JWT Decoder JWT editor", () => { await expect(jwtEditorInput).toHaveValue(inputValue); }); - test("can copy value in JWT editor", async ({ page, context, browserName }) => { - const permissions = browserName === 'firefox' ? [] : ["clipboard-read", "clipboard-write"] + test("can copy value in JWT editor", async ({ + page, + context, + browserName, + }) => { + const permissions = + browserName === "firefox" ? [] : ["clipboard-read", "clipboard-write"]; const inputValue = (TestJwts.RS512 as JwtSignedWithDigitalModel).withPemKey .jwt; await context.grantPermissions(permissions); @@ -76,7 +82,7 @@ test.describe("Can interact with JWT Decoder JWT editor", () => { await copyButton.click(); const clipboardContent = await page.evaluate(() => - navigator.clipboard.readText(), + navigator.clipboard.readText() ); expect(clipboardContent).toBe(inputValue); @@ -105,51 +111,14 @@ test.describe("Can generate JWT examples", () => { await page.goto(E2E_BASE_URL); }); - test("Can open and close JWT Decoder example widget", async ({ page }) => { - const lang = await getLang(page); - expectToBeNonNull(lang); - - const pickersUiDictionary = getPickersUiDictionary(lang); - - const decoderWidget = page.getByTestId(dataTestidDictionary.decoder.id); - - const exampleButton = decoderWidget.getByRole("button", { - name: pickersUiDictionary.exampleAlgPicker.label, - }); - - await exampleButton.click(); - - await expect(exampleButton).not.toBeVisible(); - - const closeButton = page.getByRole("button", { - name: pickersUiDictionary.exampleAlgPicker.closeButton.label, - }); - - await closeButton.click(); - - await expect(exampleButton).toBeVisible(); - await expect(closeButton).not.toBeVisible(); - }); - test.describe("Can generate a JWT decoder example", () => { test.beforeEach(async ({ page }) => { const lang = await getLang(page); expectToBeNonNull(lang); const pickersUiDictionary = getPickersUiDictionary(lang); - - const decoderWidget = page.getByTestId(dataTestidDictionary.decoder.id); - - const exampleButton = decoderWidget.getByRole("button", { - name: pickersUiDictionary.exampleAlgPicker.label, - }); - - await exampleButton.click(); - - await expect(exampleButton).not.toBeVisible(); - - const pickerIndicator = decoderWidget.getByText( - pickersUiDictionary.exampleAlgPicker.defaultValue, + const pickerIndicator = page.getByText( + pickersUiDictionary.exampleAlgPicker.defaultValue ); await pickerIndicator.click(); @@ -174,7 +143,7 @@ test.describe("Can generate JWT examples", () => { const targetToken = DefaultTokensValues[option]; const jwtEditor = decoderWidget.getByTestId( - dataTestidDictionary.decoder.jwtEditor.id, + dataTestidDictionary.decoder.jwtEditor.id ); const jwtEditorInput = jwtEditor.getByRole("textbox"); @@ -203,7 +172,7 @@ test.describe("Can generate JWT examples", () => { }); const secretKeyEditor = decoderWidget.getByTestId( - dataTestidDictionary.decoder.secretKeyEditor.id, + dataTestidDictionary.decoder.secretKeyEditor.id ); const secretKeyInput = secretKeyEditor.getByRole("textbox"); @@ -217,9 +186,13 @@ test.describe("Can generate JWT examples", () => { status: MessageStatusValue.VISIBLE, }); - const encodingValue = await secretKeyEditor - .locator(".react-select__single-value") - .innerText(); + const isEncodingSwitchChecked = await page + .getByRole("switch") + .isChecked(); + + const encodingValue = isEncodingSwitchChecked + ? EncodingValues.BASE64URL + : EncodingValues.UTF8; expect(encodingValue).toBe(symmetricToken.secretEncoding); @@ -236,8 +209,9 @@ test.describe("Can generate JWT examples", () => { status: MessageStatusValue.VISIBLE, }); - const formatValue = await secretKeyEditor + const formatValue = await page .locator(".react-select__single-value") + .nth(1) .innerText(); expect(formatValue).toBe(asymmetricToken.publicKeyFormat); @@ -270,7 +244,7 @@ test.describe("decode JWTs", () => { const decoderWidget = page.getByTestId(dataTestidDictionary.decoder.id); const jwtEditor = decoderWidget.getByTestId( - dataTestidDictionary.decoder.jwtEditor.id, + dataTestidDictionary.decoder.jwtEditor.id ); const jwtEditorInput = jwtEditor.getByRole("textbox"); @@ -327,14 +301,14 @@ test.describe("decode JWTs", () => { }); const secretKeyEditor = decoderWidget.getByTestId( - dataTestidDictionary.decoder.secretKeyEditor.id, + dataTestidDictionary.decoder.secretKeyEditor.id ); const secretKeyEditorInput = secretKeyEditor.getByRole("textbox"); await secretKeyEditorInput.fill(entryWithUtf8Secret.secret); await expect(secretKeyEditorInput).toHaveValue( - entryWithUtf8Secret.secret, + entryWithUtf8Secret.secret ); await checkSecretKeyDecoderEditorStatusBarMessage({ @@ -343,9 +317,13 @@ test.describe("decode JWTs", () => { status: MessageStatusValue.VISIBLE, }); - const encodingValue = await secretKeyEditor - .locator(".react-select__single-value") - .innerText(); + const isEncodingSwitchChecked = await page + .getByRole("switch") + .isChecked(); + + const encodingValue = isEncodingSwitchChecked + ? EncodingValues.BASE64URL + : EncodingValues.UTF8; expect(encodingValue).toBe(entryWithUtf8Secret.secretEncoding); @@ -388,17 +366,13 @@ test.describe("decode JWTs", () => { status: MessageStatusValue.VISIBLE, }); - const formatPicker = secretKeyEditor.locator( - ".react-select__single-value", - ); - - await formatPicker.click(); + const encodingSwitch = await page.getByTestId(dataTestidDictionary.encoder.switch) + expect(encodingSwitch).toBeVisible() - await page - .getByRole("option", { - name: entryWithBase64urlSecret.secretEncoding, - }) - .click(); + if ( + entryWithBase64urlSecret.secretEncoding === EncodingValues.BASE64URL + ) + await encodingSwitch.click(); await secretKeyEditorInput.fill(entryWithBase64urlSecret.secret); @@ -451,7 +425,7 @@ test.describe("decode JWTs", () => { }); const secretKeyEditor = decoderWidget.getByTestId( - dataTestidDictionary.decoder.secretKeyEditor.id, + dataTestidDictionary.decoder.secretKeyEditor.id ); const secretKeyEditorInput = secretKeyEditor.getByRole("textbox"); @@ -465,7 +439,7 @@ test.describe("decode JWTs", () => { status: MessageStatusValue.VISIBLE, }); - const formatValue = await secretKeyEditor + const formatValue = await page .locator(".react-select__single-value") .innerText(); @@ -511,8 +485,8 @@ test.describe("decode JWTs", () => { status: MessageStatusValue.VISIBLE, }); - const formatPicker = secretKeyEditor.locator( - ".react-select__single-value", + const formatPicker = page.locator( + ".react-select__single-value" ); await formatPicker.click(); @@ -530,7 +504,7 @@ test.describe("decode JWTs", () => { }); await secretKeyEditorInput.fill( - JSON.stringify(entrywithJwkKey.publicKey, null, 2), + JSON.stringify(entrywithJwkKey.publicKey, null, 2) ); await checkJwtEditorStatusBarMessage({ @@ -581,8 +555,8 @@ test.describe("decode JWTs", () => { status: MessageStatusValue.VISIBLE, }); - const formatPicker = secretKeyEditor.locator( - ".react-select__single-value", + const formatPicker = page.locator( + ".react-select__single-value" ); await formatPicker.click(); @@ -594,7 +568,7 @@ test.describe("decode JWTs", () => { .click(); await secretKeyEditorInput.fill( - JSON.stringify(entrywithJwkKey.publicKey, null, 2), + JSON.stringify(entrywithJwkKey.publicKey, null, 2) ); await checkJwtEditorStatusBarMessage({ @@ -642,10 +616,10 @@ test("Can decode JWTs signed with a non-supported algorithm", async ({ kid: "sig", }; const expectedDecodedPayload = { - "sub": "1234567890", - "name": "John Doe", - "admin": true, - "iat": 1516239022 + sub: "1234567890", + name: "John Doe", + admin: true, + iat: 1516239022, }; await page.goto(E2E_BASE_URL); @@ -656,7 +630,7 @@ test("Can decode JWTs signed with a non-supported algorithm", async ({ const decoderWidget = page.getByTestId(dataTestidDictionary.decoder.id); const jwtEditor = decoderWidget.getByTestId( - dataTestidDictionary.decoder.jwtEditor.id, + dataTestidDictionary.decoder.jwtEditor.id ); const jwtEditorInput = jwtEditor.getByRole("textbox"); @@ -678,22 +652,22 @@ test("Can decode JWTs signed with a non-supported algorithm", async ({ await expect( decoderWidget.getByTestId( - dataTestidDictionary.decoder.decodedHeader.json.id, - ), + dataTestidDictionary.decoder.decodedHeader.json.id + ) ).toHaveText(JSON.stringify(expectedDecodedHeader, null, 2), { useInnerText: true, }); await expect( decoderWidget.getByTestId( - dataTestidDictionary.decoder.decodedPayload.json.id, - ), + dataTestidDictionary.decoder.decodedPayload.json.id + ) ).toHaveText(JSON.stringify(expectedDecodedPayload, null, 2), { useInnerText: true, }); const secretKeyEditor = decoderWidget.getByTestId( - dataTestidDictionary.decoder.secretKeyEditor.id, + dataTestidDictionary.decoder.secretKeyEditor.id ); await expect(secretKeyEditor).not.toBeVisible(); @@ -711,10 +685,10 @@ test.describe("Decode pieces of JWTs in Base64Url", () => { jwtPiece: "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0", expectedDecodedOutput: { - "sub": "1234567890", - "name": "John Doe", - "admin": true, - "iat": 1516239022 + sub: "1234567890", + name: "John Doe", + admin: true, + iat: 1516239022, }, }, { @@ -737,7 +711,7 @@ test.describe("Decode pieces of JWTs in Base64Url", () => { const decoderWidget = page.getByTestId(dataTestidDictionary.decoder.id); const jwtEditor = decoderWidget.getByTestId( - dataTestidDictionary.decoder.jwtEditor.id, + dataTestidDictionary.decoder.jwtEditor.id ); const jwtEditorInput = jwtEditor.getByRole("textbox"); @@ -759,20 +733,20 @@ test.describe("Decode pieces of JWTs in Base64Url", () => { await expect( decoderWidget.getByTestId( - dataTestidDictionary.decoder.decodedHeader.json.id, - ), + dataTestidDictionary.decoder.decodedHeader.json.id + ) ).toHaveText(JSON.stringify(expectedDecodedOutput, null, 2), { useInnerText: true, }); await expect( decoderWidget.getByTestId( - dataTestidDictionary.decoder.decodedPayload.json.id, - ), + dataTestidDictionary.decoder.decodedPayload.json.id + ) ).toBeEmpty(); const secretKeyEditor = decoderWidget.getByTestId( - dataTestidDictionary.decoder.secretKeyEditor.id, + dataTestidDictionary.decoder.secretKeyEditor.id ); await expect(secretKeyEditor).not.toBeVisible(); diff --git a/e2e/encoder.spec.ts b/e2e/encoder.spec.ts index 1bf35f1c4..777ddad10 100644 --- a/e2e/encoder.spec.ts +++ b/e2e/encoder.spec.ts @@ -27,6 +27,7 @@ import { isNoneAlg, } from "@/features/common/services/jwt.service"; import { MessageStatusValue, MessageTypeValue } from "./e2e.values"; +import { EncodingValues } from "@/features/common/values/encoding.values"; const TestJwts = (jwts as JwtDictionaryModel).byAlgorithm; @@ -41,7 +42,7 @@ test.describe("Can interact with header editor in JWT Encoder", () => { const encoderWidget = page.getByTestId(dataTestidDictionary.encoder.id); const headerEditor = encoderWidget.getByTestId( - dataTestidDictionary.encoder.headerEditor.id, + dataTestidDictionary.encoder.headerEditor.id ); const headerEditorInput = headerEditor.getByRole("textbox"); @@ -65,7 +66,7 @@ test.describe("Can interact with header editor in JWT Encoder", () => { const encoderWidget = page.getByTestId(dataTestidDictionary.encoder.id); const headerEditor = encoderWidget.getByTestId( - dataTestidDictionary.encoder.headerEditor.id, + dataTestidDictionary.encoder.headerEditor.id ); const headerEditorInput = headerEditor.getByRole("textbox"); @@ -83,7 +84,7 @@ test.describe("Can interact with header editor in JWT Encoder", () => { const encoder = page.getByTestId(dataTestidDictionary.encoder.id); const headerEditor = encoder.getByTestId( - dataTestidDictionary.encoder.headerEditor.id, + dataTestidDictionary.encoder.headerEditor.id ); const headerEditorInput = headerEditor.getByRole("textbox"); @@ -107,7 +108,7 @@ test.describe("can interact with payload editor in JWT encoder", () => { const encoderWidget = page.getByTestId(dataTestidDictionary.encoder.id); const payloadEditor = encoderWidget.getByTestId( - dataTestidDictionary.encoder.payloadEditor.id, + dataTestidDictionary.encoder.payloadEditor.id ); const payloadEditorInput = payloadEditor.getByRole("textbox"); @@ -131,7 +132,7 @@ test.describe("can interact with payload editor in JWT encoder", () => { const encoderWidget = page.getByTestId(dataTestidDictionary.encoder.id); const payloadEditor = encoderWidget.getByTestId( - dataTestidDictionary.encoder.payloadEditor.id, + dataTestidDictionary.encoder.payloadEditor.id ); const payloadEditorInput = payloadEditor.getByRole("textbox"); @@ -149,7 +150,7 @@ test.describe("can interact with payload editor in JWT encoder", () => { const encoder = page.getByTestId(dataTestidDictionary.encoder.id); const payloadEditor = encoder.getByTestId( - dataTestidDictionary.encoder.payloadEditor.id, + dataTestidDictionary.encoder.payloadEditor.id ); const payloadEditorInput = payloadEditor.getByRole("textbox"); @@ -173,7 +174,7 @@ test.describe("can interact with secret editor in JWT encoder", () => { const encoderWidget = page.getByTestId(dataTestidDictionary.encoder.id); const secretKeyEditor = encoderWidget.getByTestId( - dataTestidDictionary.encoder.secretKeyEditor.id, + dataTestidDictionary.encoder.secretKeyEditor.id ); const secretKeyEditorInput = secretKeyEditor.getByRole("textbox"); @@ -191,7 +192,7 @@ test.describe("can interact with secret editor in JWT encoder", () => { const encoderWidget = page.getByTestId(dataTestidDictionary.encoder.id); const secretKeyEditor = encoderWidget.getByTestId( - dataTestidDictionary.encoder.secretKeyEditor.id, + dataTestidDictionary.encoder.secretKeyEditor.id ); const secretKeyEditorInput = secretKeyEditor.getByRole("textbox"); @@ -209,7 +210,7 @@ test.describe("can interact with secret editor in JWT encoder", () => { const encoder = page.getByTestId(dataTestidDictionary.encoder.id); const secretKeyEditor = encoder.getByTestId( - dataTestidDictionary.encoder.secretKeyEditor.id, + dataTestidDictionary.encoder.secretKeyEditor.id ); const secretKeyEditorInput = secretKeyEditor.getByRole("textbox"); @@ -229,32 +230,6 @@ test.describe("Generate JWT encoding examples", () => { await switchToEncoderTab(page); }); - test("Can open and close encoder example widget", async ({ page }) => { - const lang = await getLang(page); - expectToBeNonNull(lang); - - const pickersUiDictionary = getPickersUiDictionary(lang); - - const encoder = page.getByTestId(dataTestidDictionary.encoder.id); - - const exampleButton = encoder.getByRole("button", { - name: pickersUiDictionary.exampleAlgPicker.label, - }); - - await exampleButton.click(); - - await expect(exampleButton).not.toBeVisible(); - - const closeButton = page.getByRole("button", { - name: pickersUiDictionary.exampleAlgPicker.closeButton.label, - }); - - await closeButton.click(); - - await expect(exampleButton).toBeVisible(); - await expect(closeButton).not.toBeVisible(); - }); - test.describe("Can generate a JWT example", () => { test.beforeEach(async ({ page }) => { const lang = await getLang(page); @@ -262,18 +237,8 @@ test.describe("Generate JWT encoding examples", () => { const pickersUiDictionary = getPickersUiDictionary(lang); - const encoder = page.getByTestId(dataTestidDictionary.encoder.id); - - const exampleButton = encoder.getByRole("button", { - name: pickersUiDictionary.exampleAlgPicker.label, - }); - - await exampleButton.click(); - - await expect(exampleButton).not.toBeVisible(); - - const pickerIndicator = encoder.getByText( - pickersUiDictionary.exampleAlgPicker.defaultValue, + const pickerIndicator = page.getByText( + pickersUiDictionary.exampleAlgPicker.defaultValue ); await pickerIndicator.click(); @@ -311,7 +276,7 @@ test.describe("Generate JWT encoding examples", () => { } await expect(jwtOutput).toHaveValue( - /^[A-Za-z0-9_-]*\.[A-Za-z0-9_-]*\.[A-Za-z0-9_-]*$/, + /^[A-Za-z0-9_-]*\.[A-Za-z0-9_-]*\.[A-Za-z0-9_-]*$/ ); }); }); @@ -336,13 +301,13 @@ test.describe("encode JWTs", () => { const encoderWidget = page.getByTestId(dataTestidDictionary.encoder.id); const headerEditor = encoderWidget.getByTestId( - dataTestidDictionary.encoder.headerEditor.id, + dataTestidDictionary.encoder.headerEditor.id ); const payloadEditor = encoderWidget.getByTestId( - dataTestidDictionary.encoder.payloadEditor.id, + dataTestidDictionary.encoder.payloadEditor.id ); const secretKeyEditor = encoderWidget.getByTestId( - dataTestidDictionary.encoder.secretKeyEditor.id, + dataTestidDictionary.encoder.secretKeyEditor.id ); const jwtOutput = encoderWidget .getByTestId(dataTestidDictionary.encoder.jwt.id) @@ -415,16 +380,13 @@ test.describe("encode JWTs", () => { await expect(jwtOutput).toHaveValue(tokenWithUtf8Secret.jwt); - const formatPicker = secretKeyEditor.locator( - ".react-select__single-value", - ); - await formatPicker.click(); - - await page - .getByRole("option", { - name: tokenWithBase64urlSecret.secretEncoding, - }) - .click(); + const encodingSwitch = await page.getByTestId(dataTestidDictionary.encoder.switch) + expect(encodingSwitch).toBeVisible() + + if ( + tokenWithBase64urlSecret.secretEncoding === EncodingValues.BASE64URL + ) + await encodingSwitch.click(); await checkSecretKeyEncoderEditorStatusBarMessage({ page, @@ -479,12 +441,12 @@ test.describe("encode JWTs", () => { await expect(jwtOutput).toHaveValue(tokenWithPemKey.jwt); } else { await expect(jwtOutput).toHaveValue( - /^[A-Za-z0-9_-]*\.[A-Za-z0-9_-]*\.[A-Za-z0-9_-]*$/, + /^[A-Za-z0-9_-]*\.[A-Za-z0-9_-]*\.[A-Za-z0-9_-]*$/ ); } - const formatPicker = secretKeyEditor.locator( - ".react-select__single-value", + const formatPicker = page.locator( + ".react-select__single-value" ); await formatPicker.click(); @@ -501,7 +463,7 @@ test.describe("encode JWTs", () => { }); await secretKeyEditorInput.fill( - JSON.stringify(tokenWithJwkKey.privateKey, null, 2), + JSON.stringify(tokenWithJwkKey.privateKey, null, 2) ); await checkSecretKeyEncoderEditorStatusBarMessage({ @@ -514,7 +476,7 @@ test.describe("encode JWTs", () => { await expect(jwtOutput).toHaveValue(tokenWithJwkKey.jwt); } else { await expect(jwtOutput).toHaveValue( - /^[A-Za-z0-9_-]*\.[A-Za-z0-9_-]*\.[A-Za-z0-9_-]*$/, + /^[A-Za-z0-9_-]*\.[A-Za-z0-9_-]*\.[A-Za-z0-9_-]*$/ ); } diff --git a/next.config.mjs b/next.config.mjs index f4672921f..8421cd464 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -3,18 +3,26 @@ import createMDX from "@next/mdx"; /** @type {import('next').NextConfig} */ const nextConfig = { webpack(config) { - config.module.rules.push({ - test: /\.svg$/, - use: { - loader: "@svgr/webpack", - options: { - svgoConfig: { - plugins: ["prefixIds"], + config.module.rules.push( + { + test: /\.svg$/, + resourceQuery: { not: /raw/ }, + use: { + loader: "@svgr/webpack", + options: { + svgoConfig: { + plugins: ["prefixIds"], + }, + ref: true, }, - ref: true, }, }, - }); + { + test: /\.svg$/i, + resourceQuery: /raw/, // Only apply this rule if '?raw' is present + type: "asset/source", + } + ); return config; }, diff --git a/public/images/ebook-image.png b/public/images/ebook-image.png deleted file mode 100644 index c24a572a3..000000000 Binary files a/public/images/ebook-image.png and /dev/null differ diff --git a/public/images/ebook.svg b/public/images/ebook.svg new file mode 100644 index 000000000..05ada0220 --- /dev/null +++ b/public/images/ebook.svg @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/images/en.dark.auth0-flow.png b/public/images/en.dark.auth0-flow.png deleted file mode 100644 index 5c7ae1adf..000000000 Binary files a/public/images/en.dark.auth0-flow.png and /dev/null differ diff --git a/public/images/en.diagram.png b/public/images/en.diagram.png new file mode 100644 index 000000000..5ed13e24a Binary files /dev/null and b/public/images/en.diagram.png differ diff --git a/public/images/en.light.auth0-flow.png b/public/images/en.light.auth0-flow.png deleted file mode 100644 index 0e07d32c4..000000000 Binary files a/public/images/en.light.auth0-flow.png and /dev/null differ diff --git a/public/images/ja.dark.auth0-flow.png b/public/images/ja.dark.auth0-flow.png deleted file mode 100644 index 3faed6166..000000000 Binary files a/public/images/ja.dark.auth0-flow.png and /dev/null differ diff --git a/public/images/ja.diagram.png b/public/images/ja.diagram.png new file mode 100644 index 000000000..5815c1e2b Binary files /dev/null and b/public/images/ja.diagram.png differ diff --git a/public/images/ja.light.auth0-flow.png b/public/images/ja.light.auth0-flow.png deleted file mode 100644 index 39b6d1124..000000000 Binary files a/public/images/ja.light.auth0-flow.png and /dev/null differ diff --git a/public/images/mobile.dark.auth0-flow-bg.svg b/public/images/mobile.dark.auth0-flow-bg.svg deleted file mode 100644 index 8f8616056..000000000 --- a/public/images/mobile.dark.auth0-flow-bg.svg +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/public/images/mobile.en.dark.auth0-flow.svg b/public/images/mobile.en.dark.auth0-flow.svg deleted file mode 100644 index bed986852..000000000 --- a/public/images/mobile.en.dark.auth0-flow.svg +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/public/images/mobile.en.light.auth0-flow.svg b/public/images/mobile.en.light.auth0-flow.svg deleted file mode 100644 index 9a15f08e4..000000000 --- a/public/images/mobile.en.light.auth0-flow.svg +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/public/images/mobile.ja.dark.auth0-flow.svg b/public/images/mobile.ja.dark.auth0-flow.svg deleted file mode 100644 index 88adfb6ea..000000000 --- a/public/images/mobile.ja.dark.auth0-flow.svg +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/public/images/mobile.ja.light.auth0-flow.svg b/public/images/mobile.ja.light.auth0-flow.svg deleted file mode 100644 index 9f9f0d12f..000000000 --- a/public/images/mobile.ja.light.auth0-flow.svg +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/public/images/mobile.light.auth0-flow-bg.svg b/public/images/mobile.light.auth0-flow-bg.svg deleted file mode 100644 index 2701f5ddb..000000000 --- a/public/images/mobile.light.auth0-flow-bg.svg +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/public/images/tablet.dark.auth0-flow-bg.svg b/public/images/tablet.dark.auth0-flow-bg.svg deleted file mode 100644 index 86b3ae546..000000000 --- a/public/images/tablet.dark.auth0-flow-bg.svg +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/public/images/tablet.en.dark.auth0-flow.svg b/public/images/tablet.en.dark.auth0-flow.svg deleted file mode 100644 index 03d06c6de..000000000 --- a/public/images/tablet.en.dark.auth0-flow.svg +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/public/images/tablet.en.light.auth0-flow.svg b/public/images/tablet.en.light.auth0-flow.svg deleted file mode 100644 index c0854376f..000000000 --- a/public/images/tablet.en.light.auth0-flow.svg +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/public/images/tablet.ja.dark.auth0-flow.svg b/public/images/tablet.ja.dark.auth0-flow.svg deleted file mode 100644 index fc01b4c13..000000000 --- a/public/images/tablet.ja.dark.auth0-flow.svg +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/public/images/tablet.ja.light.auth0-flow.svg b/public/images/tablet.ja.light.auth0-flow.svg deleted file mode 100644 index 5c9855e29..000000000 --- a/public/images/tablet.ja.light.auth0-flow.svg +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/public/images/tablet.light.auth0-flow-bg.svg b/public/images/tablet.light.auth0-flow-bg.svg deleted file mode 100644 index 9e875a455..000000000 --- a/public/images/tablet.light.auth0-flow-bg.svg +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/public/img/jwt-logo.svg b/public/img/jwt-logo.svg new file mode 100644 index 000000000..54d020e97 --- /dev/null +++ b/public/img/jwt-logo.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/img/jwt-symbol.svg b/public/img/jwt-symbol.svg new file mode 100644 index 000000000..63da72ae0 --- /dev/null +++ b/public/img/jwt-symbol.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/img/jwt-wordmark.svg b/public/img/jwt-wordmark.svg new file mode 100644 index 000000000..3a2ecbd06 --- /dev/null +++ b/public/img/jwt-wordmark.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/app/[language]/page.tsx b/src/app/[language]/page.tsx index 4793d8e6f..ef6a16371 100644 --- a/src/app/[language]/page.tsx +++ b/src/app/[language]/page.tsx @@ -16,12 +16,6 @@ import { DECODED_PAYLOAD_DESCRIPTION_KEY, DECODED_PAYLOAD_FORMAT_KEY, } from "@/features/decoder/config/decoder.config"; -import { - JWT_INFO_STATE_KEY, - JWT_WARNING_STATE_KEY, -} from "@/features/home/config/home.config"; -import { HeroModalStateValues } from "@/features/home/values/hero-modal-state.values"; -import { getSanitizedHeroModalStateValue } from "@/features/common/services/hero.utils"; import { getSanitizedDescriptionVisibilityValue } from "@/features/common/services/decoder.utils"; import { ClaimDescriptionVisibilityValues } from "@/features/common/values/claim-description-visibility.values"; import { getSanitizedDebuggerModeValues } from "@/features/common/services/debugger.utils"; @@ -60,15 +54,6 @@ export default function Home({ cookies().get(DECODED_PAYLOAD_DESCRIPTION_KEY)?.value || null, ) || ClaimDescriptionVisibilityValues.VISIBLE; - const jwtInfoState = - getSanitizedHeroModalStateValue( - cookies().get(JWT_INFO_STATE_KEY)?.value || null, - ) || HeroModalStateValues.OPEN; - const jwtWarningState = - getSanitizedHeroModalStateValue( - cookies().get(JWT_WARNING_STATE_KEY)?.value || null, - ) || HeroModalStateValues.OPEN; - const debuggerInitialMode: DebuggerModeValues = getSanitizedDebuggerModeValues( cookies().get(DEBUGGER_MODE_KEY)?.value || null, @@ -81,8 +66,6 @@ export default function Home({ decodedPayloadInitialTabId={decodedPayloadInitialTabId} decodedHeaderDescriptionVisibility={decodedHeaderDescriptionVisibility} decodedPayloadDescriptionVisibility={decodedPayloadDescriptionVisibility} - jwtInfoState={jwtInfoState} - jwtWarningState={jwtWarningState} // debuggerInitialMode={debuggerInitialMode} /> ); diff --git a/src/app/apple-icon.tsx b/src/app/apple-icon.tsx index f594f1566..852943457 100644 --- a/src/app/apple-icon.tsx +++ b/src/app/apple-icon.tsx @@ -86,62 +86,62 @@ export default function Icon({ id }: { id: string }) { xmlns="http://www.w3.org/2000/svg" > diff --git a/src/app/global-error.tsx b/src/app/global-error.tsx index 911ceda85..6977c3dae 100644 --- a/src/app/global-error.tsx +++ b/src/app/global-error.tsx @@ -22,7 +22,6 @@ export default function GlobalError({ diff --git a/src/app/not-found.tsx b/src/app/not-found.tsx index 2cdb2033c..84c939b17 100644 --- a/src/app/not-found.tsx +++ b/src/app/not-found.tsx @@ -15,7 +15,6 @@ export default function NotFound() { diff --git a/src/features/common/assets/arrow-head-icon.component.tsx b/src/features/common/assets/arrow-head-icon.component.tsx new file mode 100644 index 000000000..0910b453a --- /dev/null +++ b/src/features/common/assets/arrow-head-icon.component.tsx @@ -0,0 +1,21 @@ +import React from "react"; + +export const ArrowHeadIconComponent: React.FC = () => { + return ( + + + + ); +}; diff --git a/src/features/common/assets/auth0-logo.component.tsx b/src/features/common/assets/auth0-logo.component.tsx new file mode 100644 index 000000000..22f18ce76 --- /dev/null +++ b/src/features/common/assets/auth0-logo.component.tsx @@ -0,0 +1,53 @@ +interface Auth0LogoComponentProps { + title: string; +} + +export const Auth0LogoComponent: React.FC = ({title}) => { + return ( + + {title} + + + + + + + + + + + ); +}; diff --git a/src/features/common/assets/auth0-logo.png b/src/features/common/assets/auth0-logo.png deleted file mode 100644 index 51ff67358..000000000 Binary files a/src/features/common/assets/auth0-logo.png and /dev/null differ diff --git a/src/features/common/assets/download-icon.component.tsx b/src/features/common/assets/download-icon.component.tsx index c2a92fdae..f401a279d 100644 --- a/src/features/common/assets/download-icon.component.tsx +++ b/src/features/common/assets/download-icon.component.tsx @@ -3,33 +3,26 @@ import React from "react"; export const DownloadIconComponent: React.FC = () => { return ( + > - + > ); }; diff --git a/src/features/common/assets/jwt-flower.png b/src/features/common/assets/jwt-flower.png deleted file mode 100644 index 96b2e5124..000000000 Binary files a/src/features/common/assets/jwt-flower.png and /dev/null differ diff --git a/src/features/common/assets/jwt-logo.component.tsx b/src/features/common/assets/jwt-logo.component.tsx new file mode 100644 index 000000000..540dc3714 --- /dev/null +++ b/src/features/common/assets/jwt-logo.component.tsx @@ -0,0 +1,82 @@ +export const JwtLogoComponent: React.FC = () => { + return ( + + + + + + + + + + + + + ); +}; \ No newline at end of file diff --git a/src/features/common/assets/jwt-wordmark.component.tsx b/src/features/common/assets/jwt-wordmark.component.tsx new file mode 100644 index 000000000..1a9032807 --- /dev/null +++ b/src/features/common/assets/jwt-wordmark.component.tsx @@ -0,0 +1,30 @@ +export const JwtWordmarkComponent: React.FC = () => { + return ( + + + + + + ); +}; \ No newline at end of file diff --git a/src/features/common/components/article/article.module.scss b/src/features/common/components/article/article.module.scss index 97f5a8cff..1f5ef8a44 100644 --- a/src/features/common/components/article/article.module.scss +++ b/src/features/common/components/article/article.module.scss @@ -7,26 +7,13 @@ .content { @include InnerContentGrid; - - padding: 3rem 0 3rem 0; - gap: 2rem; - - @media #{$breakpoint-dimension-sm} { - padding: 3rem 0 4rem 0; - } - - @media #{$breakpoint-dimension-md} { - gap: 3rem; - padding: 4rem 0 4rem 0; - } } .article { display: flex; flex-direction: column; - grid-column: span 6; - max-width: 48.5rem; + max-width: 56rem; justify-self: center; @media #{$breakpoint-dimension-sm} { @@ -47,7 +34,7 @@ font-size: 2rem; line-height: 2.5rem; font-style: normal; - font-weight: 400; + font-weight: 500; letter-spacing: -0.05rem; margin-bottom: 1.5rem; font-family: var(--font-secondary), sans-serif; @@ -68,13 +55,12 @@ h3 { color: var(--color_fg_bold); - font-size: 1.5rem; line-height: 2rem; font-style: normal; - font-weight: 400; + font-weight: 500; letter-spacing: -0.05rem; - margin-bottom: 2rem; + margin-bottom: 1.5rem; font-family: var(--font-secondary), sans-serif; :global(html[lang="ja"]) & { @@ -89,11 +75,11 @@ "clig" off, "liga" off; font-size: 1rem; - line-height: 1.5em; + line-height: 1.45; font-style: normal; font-weight: 400; letter-spacing: -0.005rem; - margin-bottom: 2rem; + margin-bottom: 1rem; :global(html[lang="ja"]) & { @include LocaleLineHeight("ja", 1.5rem); @@ -107,12 +93,10 @@ ul, ol { - list-style-position: inside; margin-top: 0; ul, ol { - list-style-position: inside; margin-left: 1.5rem; padding-left: 0; } @@ -121,11 +105,11 @@ li { margin-bottom: 0.75rem; font-size: 1rem; - line-height: 2rem; + line-height: 1.45; color: var(--color_fg_default); letter-spacing: -0.01px; - text-indent: -1.5rem; - padding-left: 1.5rem; + margin-left: 1rem; + padding-left: 1rem; :global(html[lang="ja"]) & { @include LocaleLineHeight("ja", 2rem); @@ -136,9 +120,9 @@ &, &:hover, &:active { - color: var(--color_fg_link_primary); text-decoration: underline; - font-weight: 400; + font-weight: 500; + text-underline-offset: 0.25rem; } } @@ -148,42 +132,70 @@ } pre { - margin-bottom: 2rem; - background-color: var(--color_bg_code-editor); + margin-bottom: 1rem; + background-color: var(--color_bg_layer_alternate); color: var(--color_fg_default); font-size: 0.875rem; line-height: 1.375rem; font-style: normal; font-weight: 400; letter-spacing: 0.15px; - padding: 0.75rem; + padding: 0.25rem; border: 1px solid var(--color_border_bold); - border-radius: 0.25rem; + border-radius: 1rem; code { - color: var(--color_code_dark_blue2); + display: block; + width: 100%; + color: var(--color_code_gray); background-color: var(--color_bg_code-editor); font-weight: 500; - } - - @media #{$breakpoint-dimension-sm} { - border-radius: 0.5rem; - padding: 1rem; + font-size: 0.875rem; + line-height: 1.35; + border-radius: 0.75rem; + padding: 0.75rem; + box-shadow: + 0 0 0 0.5px rgba(0, 0, 0, 0.12), + 0 2px 2px -1px rgba(0, 0, 0, 0.04), + 0 4px 4px -2px rgba(0, 0, 0, 0.04), + 0 6px 6px -3px rgba(0, 0, 0, 0.04); } } blockquote { - background-color: var(--color_bg_state_info_subtle); - padding: 1rem 1.5rem; - margin: 2rem 0 2rem 0; - border-radius: 0 0.5rem 0.5rem 0; - border-left: 4px solid var(--color_border_state_info); + background-color: var(--color_bg_layer); + font-size: 0.875rem; + padding: 1rem; + margin: 2rem 0; + border-radius: 1rem; + border: 1px solid var(--color_border_default); + box-shadow: + 0 0 0 0.5px rgba(0, 0, 0, 0.12), + 0 2px 2px -1px rgba(0, 0, 0, 0.04), + 0 4px 4px -2px rgba(0, 0, 0, 0.04), + 0 6px 6px -3px rgba(0, 0, 0, 0.04); & * { - color: var(--color_fg_on_state_info_subtle); + color: var(--color_fg_default); padding: 0; margin: 0; } + + p { + display: flex; + flex-direction: row; + font-size: 0.875rem; + align-items: center; + gap: 0.75rem; + } + + ::before { + content: url("data:image/svg+xml,%3Csvg width='12' height='12' viewBox='0 0 12 12' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6 0.5C9.03757 0.5 11.5 2.96243 11.5 6C11.5 9.03757 9.03757 11.5 6 11.5C2.96243 11.5 0.5 9.03757 0.5 6C0.5 2.96243 2.96243 0.5 6 0.5ZM6 5.25C5.72386 5.25 5.5 5.47386 5.5 5.75V8.75H6.5V5.75C6.5 5.47386 6.27614 5.25 6 5.25ZM6 3.125C5.65482 3.125 5.375 3.40482 5.375 3.75C5.375 4.09518 5.65482 4.375 6 4.375C6.34518 4.375 6.625 4.09518 6.625 3.75C6.625 3.40482 6.34518 3.125 6 3.125Z' fill='%235C5650'/%3E%3C/svg%3E%0A"); + display: block; + padding: 0.25rem 0.4rem 0.125rem; + border-radius: 9999px; + background-color: var(--color_bg_layer_alternate); + } } *:has(+ blockquote) { diff --git a/src/features/common/components/auth0-cta/auth0-cta.component.tsx b/src/features/common/components/auth0-cta/auth0-cta.component.tsx index 2bbb4bcab..28248ce73 100644 --- a/src/features/common/components/auth0-cta/auth0-cta.component.tsx +++ b/src/features/common/components/auth0-cta/auth0-cta.component.tsx @@ -2,10 +2,9 @@ import React from "react"; import { getLocalizedSecondaryFont } from "@/libs/theme/fonts"; import clsx from "clsx"; import { Auth0DictionaryModel } from "@/features/localization/models/auth0-dictionary.model"; -import { BoxComponent } from "@/features/common/components/box/box.component"; import styles from "./auth0-cta.module.scss"; import Link from "next/link"; -import NextArrow from "@/features/common/assets/arrow-right.svg"; +import { ArrowHeadIconComponent } from "../../assets/arrow-head-icon.component"; interface Auth0CtaComponentProps { languageCode: string; @@ -17,40 +16,36 @@ export const Auth0CtaComponent: React.FC = ({ dictionary, }) => { return ( - -
-
-
-

- {dictionary.title} -

-

{dictionary.description}

-
- {dictionary.ctaButton && ( - - {dictionary.ctaButton.label} -
- +
+
+
+
+
+
+

+ {dictionary.title} +

+

+ {dictionary.description} +

- - )} + + {dictionary.ctaButton.label} + + +
+
+
-
- +
); }; diff --git a/src/features/common/components/auth0-cta/auth0-cta.module.scss b/src/features/common/components/auth0-cta/auth0-cta.module.scss index 8f79f1ef9..de8a0cf09 100644 --- a/src/features/common/components/auth0-cta/auth0-cta.module.scss +++ b/src/features/common/components/auth0-cta/auth0-cta.module.scss @@ -1,11 +1,22 @@ @use "@/libs/theme/styles/variables" as *; @use "@/libs/theme/styles/mixins" as *; -.container { - @include Container; +.cta_container { position: relative; overflow: hidden; background: var(--color_bg_auth0-cta); + grid-column: span 8; + border-radius: 1rem; + max-width: 1008px; + border: 1px solid var(--color_border_default); + box-shadow: 0 2px 12px -4px rgba(0,0,0,.08),0 2px 1px -.5px rgba(0,0,0,.04),0 2px 4px -4px rgba(0,0,0,.05),inset -.5px -.5px 2px rgba(0,0,0,.04); + + @media #{$breakpoint-dimension-md} { + margin: 0 auto; + &:before { + background: none; + } + } &:before { position: absolute; @@ -15,83 +26,20 @@ width: 100%; height: 100%; } - - :global(html[data-theme="light"]) &:before { - background-image: url("/images/mobile.light.auth0-flow-bg.svg"); - background-size: cover; - } - :global(html[data-theme="system-light"]) &:before { - background-image: url("/images/mobile.light.auth0-flow-bg.svg"); - background-size: cover; - } - :global(html[data-theme="dark"]) &:before { - background-image: url("/images/mobile.dark.auth0-flow-bg.svg"); - background-size: cover; - } - :global(html[data-theme="system-dark"]) &:before { - background-image: url("/images/mobile.dark.auth0-flow-bg.svg"); - background-size: cover; - } - - @media #{$breakpoint-dimension-sm} { - :global(html[data-theme="light"]) &:before { - background-image: url("/images/tablet.light.auth0-flow-bg.svg"); - background-size: cover; - } - :global(html[data-theme="system-light"]) &:before { - background-image: url("/images/tablet.light.auth0-flow-bg.svg"); - background-size: cover; - } - :global(html[data-theme="dark"]) &:before { - background-image: url("/images/tablet.dark.auth0-flow-bg.svg"); - background-size: cover; - } - :global(html[data-theme="system-dark"]) &:before { - background-image: url("/images/tablet.dark.auth0-flow-bg.svg"); - background-size: cover; - } - } - - @media #{$breakpoint-dimension-md} { - padding-bottom: 7.5rem; - background: unset; - - &:before { - background: none; - } - - :global(html[data-theme="light"]) &:before { - background-image: none; - } - :global(html[data-theme="system-light"]) &:before { - background-image: none; - } - :global(html[data-theme="dark"]) &:before { - background-image: none; - } - :global(html[data-theme="system-dark"]) &:before { - background-image: none; - } - - &:after { - display: none; - background: none; - } - } } -.wrapper { - @include ExtendedGrid; +.cta_wrapper { + max-width: 1536px; + margin: 0 auto; position: relative; justify-content: center; - - border-radius: 0; + border-radius: 1rem; overflow: hidden; + width: 100%; + height: 100%; @media #{$breakpoint-dimension-md} { background: var(--color_bg_auth0-cta); - border-radius: 1.5rem; - &:before { position: absolute; bottom: 0; @@ -100,83 +48,63 @@ width: 100%; height: 100%; } - - :global(html[data-theme="light"]) &:before { - background: url("/images/light.auth0-flow-bg.svg") no-repeat right - bottom; - background-size: cover; - } - :global(html[data-theme="system-light"]) &:before { - background: url("/images/light.auth0-flow-bg.svg") no-repeat right - bottom; - background-size: cover; - } - :global(html[data-theme="dark"]) &:before { - background: url("/images/dark.auth0-flow-bg.svg") no-repeat right - bottom; - background-size: cover; - } - :global(html[data-theme="system-dark"]) &:before { - background: url("/images/dark.auth0-flow-bg.svg") no-repeat right - bottom; - background-size: cover; - } } } -.content { - @include InnerContentFlex; +.cta_content { + display: flex; justify-content: center; + width: 100%; + height: 100%; - @media #{$breakpoint-dimension-sm} { - @include InnerContentGrid; + @media #{$breakpoint-dimension-md} { + display: grid; + grid-template-columns: repeat(12,minmax(0,1fr)); + width: 100%; } } -.cta { +.cta_cta { z-index: 1; width: 100%; display: flex; flex-direction: column; - padding: 2.5rem 0; + padding: .25rem; align-items: center; gap: 2rem; - @media #{$breakpoint-dimension-sm} { - padding: 3rem 0; - grid-column: 1 / -1; + @media #{$breakpoint-dimension-md} { + grid-column: 1/-1; display: grid; grid-template-columns: subgrid; } - - @media #{$breakpoint-dimension-md} { - padding: 4rem 0; - } } .cta__copy { - grid-column: 1 / -1; + grid-column: 1/-1; display: flex; flex-direction: column; gap: 1.5rem; - align-items: center; - - @media #{$breakpoint-dimension-sm} { - align-items: unset; - } + align-items: flex-start; + padding: 2.5rem; @media #{$breakpoint-dimension-md} { - align-items: center; - flex-direction: row; + grid-column: span 6; + align-items: flex-start; + flex-direction: column; gap: 2.5rem; } + + @media #{$breakpoint-dimension-sm} { + align-items: unset; + } } .cta__text { width: 100%; display: flex; flex-direction: column; - gap: 0.75rem; + gap: .75rem; @media #{$breakpoint-dimension-sm} { gap: 1rem; @@ -187,26 +115,15 @@ width: 100%; margin: 0; text-align: left; - font-size: 2.25rem; - line-height: 2.75rem; - letter-spacing: -0.03rem; - font-weight: 400; - color: var(--color_fg_bold); + font-size: 1.5rem; + line-height: 1.15; + color: #fff; + font-feature-settings: lining-nums proportional-nums; font-variant-numeric: lining-nums proportional-nums; font-style: normal; - :global(html[lang="ja"]) & { - @include LocaleLineHeight("ja", 2.25rem); - } - - @media #{$breakpoint-dimension-sm} { - font-size: 2.5rem; - line-height: 3rem; - letter-spacing: -0.08rem; - - :global(html[lang="ja"]) & { - @include LocaleLineHeight("ja", 2.5rem); - } + @media #{$breakpoint-dimension-lg} { + font-size: 2.5rem; } } @@ -216,167 +133,42 @@ line-height: 1.5rem; font-weight: 400; - :global(html[lang="ja"]) & { - @include LocaleLineHeight("ja", 1rem); - } - @media #{$breakpoint-dimension-sm} { max-width: 40rem; - font-size: 1.25rem; - line-height: 1.75rem; - letter-spacing: 0.01rem; - - :global(html[lang="ja"]) & { - @include LocaleLineHeight("ja", 1.25rem); - } - } - - @media #{$breakpoint-dimension-md} { - font-size: 1.25rem; - line-height: 1.75rem; - letter-spacing: 0.1px; - - :global(html[lang="ja"]) & { - @include LocaleLineHeight("ja", 1.25rem); - } - } -} - -.cta__media { - position: relative; - grid-column: 1 / -1; - align-self: center; - justify-self: center; - display: flex; - align-items: center; - justify-content: center; - gap: 2.4rem; - - overflow: hidden; - - width: 100%; - - background-size: 100%; - - aspect-ratio: 281 / 547; - - :global(html[lang="en"][data-theme="light"]) & { - background-image: url("/images/mobile.en.light.auth0-flow.svg"); - } - :global(html[lang="en"][data-theme="dark"]) & { - background-image: url("/images/mobile.en.dark.auth0-flow.svg"); - } - :global(html[lang="ja"][data-theme="light"]) & { - background-image: url("/images/mobile.ja.light.auth0-flow.svg"); - } - :global(html[lang="ja"][data-theme="dark"]) & { - background-image: url("/images/mobile.ja.dark.auth0-flow.svg"); - } - - :global(html[lang="en"][data-theme="system-light"]) & { - background-image: url("/images/mobile.en.light.auth0-flow.svg"); - } - :global(html[lang="en"][data-theme="system-dark"]) & { - background-image: url("/images/mobile.en.dark.auth0-flow.svg"); - } - :global(html[lang="ja"][data-theme="system-light"]) & { - background-image: url("/images/mobile.ja.light.auth0-flow.svg"); - } - :global(html[lang="ja"][data-theme="system-dark"]) & { - background-image: url("/images/mobile.ja.dark.auth0-flow.svg"); - } - - @media #{$breakpoint-dimension-sm} { - aspect-ratio: 672 / 251; - - :global(html[lang="en"][data-theme="light"]) & { - background-image: url("/images/tablet.en.light.auth0-flow.svg"); - } - :global(html[lang="en"][data-theme="dark"]) & { - background-image: url("/images/tablet.en.dark.auth0-flow.svg"); - } - :global(html[lang="ja"][data-theme="light"]) & { - background-image: url("/images/tablet.ja.light.auth0-flow.svg"); - } - :global(html[lang="ja"][data-theme="dark"]) & { - background-image: url("/images/tablet.ja.dark.auth0-flow.svg"); - } - - :global(html[lang="en"][data-theme="system-light"]) & { - background-image: url("/images/tablet.en.light.auth0-flow.svg"); - } - :global(html[lang="en"][data-theme="system-dark"]) & { - background-image: url("/images/tablet.en.dark.auth0-flow.svg"); - } - :global(html[lang="ja"][data-theme="system-light"]) & { - background-image: url("/images/tablet.ja.light.auth0-flow.svg"); - } - :global(html[lang="ja"][data-theme="system-dark"]) & { - background-image: url("/images/tablet.ja.dark.auth0-flow.svg"); - } + font-size: 1rem; + line-height: 1.5rem; + letter-spacing: -.01rem; } @media #{$breakpoint-dimension-md} { - aspect-ratio: 3216 / 861; - - :global(html[lang="en"][data-theme="light"]) & { - background-image: url("/images/en.light.auth0-flow.png"); - } - :global(html[lang="en"][data-theme="dark"]) & { - background-image: url("/images/en.dark.auth0-flow.png"); - } - :global(html[lang="ja"][data-theme="light"]) & { - background-image: url("/images/ja.light.auth0-flow.png"); - } - :global(html[lang="ja"][data-theme="dark"]) & { - background-image: url("/images/ja.dark.auth0-flow.png"); - } - - :global(html[lang="en"][data-theme="system-light"]) & { - background-image: url("/images/en.light.auth0-flow.png"); - } - :global(html[lang="en"][data-theme="system-dark"]) & { - background-image: url("/images/en.dark.auth0-flow.png"); - } - :global(html[lang="ja"][data-theme="system-light"]) & { - background-image: url("/images/ja.light.auth0-flow.png"); - } - :global(html[lang="ja"][data-theme="system-dark"]) & { - background-image: url("/images/ja.dark.auth0-flow.png"); - } + font-size: 1rem; + line-height: 1.5rem; + letter-spacing: -.1px; } } -.button { +.cta__button { display: flex; - padding: 1rem 2rem; + padding: .25rem .75rem; justify-content: center; align-items: center; - gap: 0.5rem; - flex-shrink: 0; - - border: 1px solid var(--color_border_button_outline); - border-radius: 0.375rem; - background: transparent; - backdrop-filter: blur(1.5rem); - - color: var(--color_fg_on_button_outline); - font-size: 1rem; - line-height: 1.5rem; - font-style: normal; + gap: .5rem; + border-radius: 9999px; + background: var(--color_bg_layer); + border: 1px solid var(--color_border_default); + box-shadow: 0 1px 1px -.5px rgba(0,0,0,.04),0 3px 3px -1.5px rgba(0,0,0,.04),0 6px 6px -3px rgba(0,0,0,.04),0 12px 12px -6px rgba(0,0,0,.04),0 24px 24px -12px rgba(0,0,0,.04),inset 0 0 0 1px rgba(0,0,0,.08); + color: var(--color_fg_default); + font-size: .875rem; + font-weight: 700; + line-height: 1.375rem; font-weight: 500; - letter-spacing: 0.2px; - - width: 100%; + letter-spacing: -.2px; + transition: all .3s ease-in-out; - :global(html[lang="ja"]) & { - @include LocaleLineHeight("ja", 1rem); - } - - &:focus-visible { - outline: solid 1px var(--color_border_focus); - outline-offset: 0.125rem; - border-radius: 0.125rem; + &:hover { + border: 1px solid var(--color_border_bold); + box-shadow: 0 0 0 4px var(--color_button_focus_inverse); + transition: all .2s ease-out; } @media #{$breakpoint-dimension-sm} { @@ -384,34 +176,41 @@ } } -.button__arrow { - flex-shrink: 0; +.cta__media { + position: relative; + grid-column: 1/-1; + align-self: center; + justify-self: center; display: flex; align-items: center; justify-content: center; - height: 0.75rem; - width: 0.75rem; - - svg { - height: 0.75rem; - width: 0.75rem; + gap: 2.4rem; + min-height: 348px; + overflow: hidden; + width: 100%; + height: 100%; + border-radius: .75rem; + background-size: cover; + background-position: 50%; + background-repeat: no-repeat; - path { - fill: var(--color_fg_on_button_outline); - } + :global(html[lang="en"]) & { + background-image: url("/images/en.diagram.png"); } - @media #{$breakpoint-dimension-sm} { - height: 1rem; - width: 1rem; + :global(html[lang="ja"]) & { + background-image: url("/images/ja.diagram.png"); + } - svg { - height: 0.875rem; - width: 0.875rem; - } + @media #{$breakpoint-dimension-md} { + border-bottom-left-radius: 12rem; + grid-column: span 6; + align-items: flex-start; + flex-direction: column; + gap: 2.5rem; } - &[data-rotation="true"] { - animation: rotate 2s linear infinite; + @media #{$breakpoint-dimension-sm} { + align-items: unset; } -} +} \ No newline at end of file diff --git a/src/features/common/components/bars/ribbon/assets/dark-icon.component.tsx b/src/features/common/components/bars/ribbon/assets/dark-icon.component.tsx index 1f7d42513..3961a806b 100644 --- a/src/features/common/components/bars/ribbon/assets/dark-icon.component.tsx +++ b/src/features/common/components/bars/ribbon/assets/dark-icon.component.tsx @@ -3,20 +3,18 @@ import React from "react"; export const DarkIconComponent: React.FC = () => { return ( - + ); }; diff --git a/src/features/common/components/bars/ribbon/assets/globe-icon.component.tsx b/src/features/common/components/bars/ribbon/assets/globe-icon.component.tsx index 7552b6c27..71ee01944 100644 --- a/src/features/common/components/bars/ribbon/assets/globe-icon.component.tsx +++ b/src/features/common/components/bars/ribbon/assets/globe-icon.component.tsx @@ -3,10 +3,11 @@ import React from "react"; export const GlobeIconComponent: React.FC = () => { return (
{dictionary.cta.title} = ({
-
- - label={null} - compactLabel={null} - icon={ - isSystemThemePreference(currentTheme.code) ? ( - - ) : isLightThemePreference(currentTheme.code) ? ( - - ) : ( - - ) - } - languageCode={languageCode} - selectedOptionCode={currentTheme.code} - handleSelection={handleThemeSelection} - options={themeOptions} - aria={{ - buttonLabel: dictionary.themePicker.button.ariaLabel, - listLabel: dictionary.themePicker.list.ariaLabel, - }} - /> - {dictionary.languagePicker.options.length > 1 && ( - } - label={currentLanguage.label} - compactLabel={currentLanguage.code.toUpperCase()} - languageCode={languageCode} - selectedOptionCode={languageCode} - handleSelection={handleLanguageSelection} - options={languageOptions} - aria={{ - buttonLabel: dictionary.languagePicker.button.ariaLabel, - listLabel: dictionary.languagePicker.list.ariaLabel, - }} - /> - )} -
- - ); }; diff --git a/src/features/common/components/bars/ribbon/ribbon.module.scss b/src/features/common/components/bars/ribbon/ribbon.module.scss index 8959d4eff..7436d9220 100644 --- a/src/features/common/components/bars/ribbon/ribbon.module.scss +++ b/src/features/common/components/bars/ribbon/ribbon.module.scss @@ -1,38 +1,10 @@ @use "@/libs/theme/styles/variables" as *; @use "@/libs/theme/styles/mixins" as *; -.container { - @include Container; - - background: var(--color_bg_app_bar); - border-bottom: 1px solid; - border-image-slice: 1; - border-image-source: linear-gradient( - 135deg, - rgb(76, 183, 163) 0%, - rgb(63, 89, 228) 50%, - rgb(64, 22, 160) 100% - ); -} - -.wrapper { - @include ExtendedGrid; - height: $ribbon-height; -} - -.content { - position: relative; - @include InnerContentFlex; - height: 100%; - grid-column: 1 / -1; - align-items: center; - justify-content: space-between; - - color: $neutrals-light-100-snow; -} - .cta { display: flex; + align-items: center; + justify-content: center; font-size: 0.75rem; line-height: 1.25rem; color: $Neutral0; @@ -88,11 +60,3 @@ } } -.actions { - display: flex; - gap: 0.5rem; - - @media #{$breakpoint-dimension-md} { - gap: 1rem; - } -} diff --git a/src/features/common/components/card-message/card-message.module.scss b/src/features/common/components/card-message/card-message.module.scss index a4a46757d..c96542cda 100644 --- a/src/features/common/components/card-message/card-message.module.scss +++ b/src/features/common/components/card-message/card-message.module.scss @@ -4,7 +4,7 @@ .span, .p, .code { - font-size: 0.75rem; + font-size: .875rem; line-height: 1.125rem; } diff --git a/src/features/common/components/card-tabs/card-tabs.component.tsx b/src/features/common/components/card-tabs/card-tabs.component.tsx index 00af36eea..435b1b168 100644 --- a/src/features/common/components/card-tabs/card-tabs.component.tsx +++ b/src/features/common/components/card-tabs/card-tabs.component.tsx @@ -129,16 +129,20 @@ const CardTabs: React.FC = ({ {compactTitle} + {activeCard.slots?.toolbar && ( +
+
+ {activeCard.slots.toolbar} +
+
+ )} ); })} - {activeCard.slots?.toolbar && ( -
- {activeCard.slots.toolbar} -
- )} {cards.map((card) => { return ( @@ -181,7 +185,7 @@ const CardTabs: React.FC = ({ onSelectionChange={(e) => { handleActiveCardChange(e.toString()); }} - className={clsx(MonoFont.className, styles.cardTabs)} + className={styles.cardTabs} > <> @@ -197,16 +201,18 @@ const CardTabs: React.FC = ({ {compactTitle} + {activeCard.slots?.toolbar && ( +
+
+ {activeCard.slots.toolbar} +
+
+ )} ); })}
- {activeCard.slots?.toolbar && ( -
- {activeCard.slots.toolbar} -
- )} {cards.map((card) => { return ( diff --git a/src/features/common/components/card-tabs/card-tabs.module.scss b/src/features/common/components/card-tabs/card-tabs.module.scss index 8e7a0c445..2db5a3b36 100644 --- a/src/features/common/components/card-tabs/card-tabs.module.scss +++ b/src/features/common/components/card-tabs/card-tabs.module.scss @@ -8,46 +8,42 @@ width: 100%; max-height: fit-content; flex-direction: column; - row-gap: 0.5rem; + row-gap: 1rem; cursor: default; } .cardTabs__title { - grid-column: 1 / -1; + grid-column: 1/-1; display: flex; align-items: center; - gap: 0.25rem; - text-transform: uppercase; + gap: .25rem; color: var(--color_fg_default); - font-size: 0.875rem; - line-height: 1.375rem; - font-weight: 500; - letter-spacing: 0.24px; - margin-right: 8px; + font-size: 1rem; + line-height: 1.15rem; + font-weight: 700; + letter-spacing: -.1px; } .cardTabs { - position: relative; - grid-column: span 6; - display: flex; - height: 100%; - width: 100%; - flex-direction: column; - border-radius: 0.5rem; - border: 1px solid var(--color_border_bold); - background: var(--color_bg_layer_alternate); - overflow: hidden; + grid-column: span 6; + display: flex; + flex-direction: column; + border-radius: 1rem; + border: .5px solid var(--color_border_default); + background: var(--color_bg_layer_alternate-bold); + letter-spacing: -.1px; + gap: .25rem; } $cardTabs__tabList__height: 2.5rem; .cardTabs__tabList { - position: relative; - display: flex; - border-bottom: 1px solid var(--color_border_bold); - height: $cardTabs__tabList__height; - flex-shrink: 0; + position: relative; + display: flex; + height: 2.5rem; + padding: .5rem; + gap: .25rem; } .cardTabs__title__container { @@ -56,23 +52,21 @@ $cardTabs__tabList__height: 2.5rem; } .cardTab__title { - position: relative; - display: flex; - align-items: center; - gap: 0.25rem; - text-transform: uppercase; - padding: 0.5rem 0.75rem; - border-bottom: 0.125rem solid transparent; - color: var(--color_fg_default); - font-size: 0.75rem; - line-height: 1.125rem; - font-weight: 500; - letter-spacing: 0.24px; - cursor: pointer; + display: flex; + align-items: center; + gap: .25rem; + border-radius: .5rem; + padding: 0 .5rem; + color: var(--color_fg_default); + font-size: .875rem; + line-height: 1.125rem; + font-weight: 500; + letter-spacing: -.1px; + cursor: pointer; &[data-selected="true"] { - color: var(--color_fg_selected); - border-bottom: 0.125rem solid var(--color_border_selected); + background-color: var(--color_bg_layer); + box-shadow: 0 0 0 1px rgba(0,0,0,.04),0 1px 1px -.5px rgba(0,0,0,.04),inset 0 0 0 1px rgba(0,0,0,.04); } &[data-focus-visible]:after { @@ -86,6 +80,7 @@ $cardTabs__tabList__height: 2.5rem; .cardTab__title__full { display: none; + font-weight: 500; @media #{$breakpoint-dimension-sm} { display: flex; @@ -99,14 +94,24 @@ $cardTabs__tabList__height: 2.5rem; } .cardTabs__actionButtons { - position: absolute; - right: 0.75rem; - top: 0; - display: flex; - align-items: center; - justify-content: center; - gap: 0.5rem; - height: $cardTabs__tabList__height; + position: absolute; + right: 0.75rem; + top: 50%; + transform: translateY(-50%); + display: flex; + align-items: center; + justify-content: center; + gap: 0.5rem; +} + +.cardTabs__tooltipContainer { + position: relative; + display: inline-block; + &:hover { + .button__tooltip { + opacity: 1; + } + } } .cardTabs__body { diff --git a/src/features/common/components/card-toolbar-button/card-toolbar-button.component.tsx b/src/features/common/components/card-toolbar-button/card-toolbar-button.component.tsx index 212703a20..5742102df 100644 --- a/src/features/common/components/card-toolbar-button/card-toolbar-button.component.tsx +++ b/src/features/common/components/card-toolbar-button/card-toolbar-button.component.tsx @@ -7,12 +7,13 @@ import { MonoFont } from "@/libs/theme/fonts"; export interface CardToolbarButtonComponentProps extends AriaButtonOptions<"span"> { variant: "standard" | "icon"; + tooltipText?: string; } export const CardToolbarButtonComponent: React.FC< PropsWithChildren > = (props) => { - const { variant, children } = props; + const { variant, tooltipText, children } = props; const ref = useRef(null); @@ -22,20 +23,26 @@ export const CardToolbarButtonComponent: React.FC< elementType: "span", preventFocusOnPress: true, }, - ref, + ref ); return ( - + {tooltipText && ( + {tooltipText} )} - data-style="compact" - > - {children} - +
); }; diff --git a/src/features/common/components/card-toolbar-button/card-toolbar-button.module.scss b/src/features/common/components/card-toolbar-button/card-toolbar-button.module.scss index b4fb851e4..eff9edaf2 100644 --- a/src/features/common/components/card-toolbar-button/card-toolbar-button.module.scss +++ b/src/features/common/components/card-toolbar-button/card-toolbar-button.module.scss @@ -1,25 +1,44 @@ +.button__tooltipContainer { + position: relative; + display: inline-block; + &:hover { + .button__tooltip { + opacity: 1; + } + } +} .button__standard { - gap: 0.75rem; - border-radius: 0.25rem; - border: 1px solid var(--color_border_button); + gap: .75rem; + border-radius: .5rem; color: var(--color_fg_on_button_subtle); - font-variant-numeric: slashed-zero; - font-feature-settings: - "clig" off, - "liga" off; + z-index: 2; background-color: transparent; text-transform: uppercase; cursor: pointer; - letter-spacing: 0.2px; + padding: .75rem; + letter-spacing: .2px; appearance: none; display: flex; align-items: center; + justify-content: center; + border: 1px solid transparent; + transition: all .2s ease-out; + width: 2rem; + height: 2rem; + font-size: .875rem; + line-height: 1.375rem; &[aria-disabled="true"] { opacity: 0.48; cursor: not-allowed; } + &:hover { + background-color: var(--color_bg_layer); + border: 1px solid var(--color_border_default); + transition: all .2s ease-out; + } + padding: 0 0.75rem; width: 5rem; height: 2rem; @@ -27,11 +46,11 @@ line-height: 1.375rem; &[data-style="compact"] { - padding: 0.125rem 0.375rem; - width: unset; - height: unset; - font-size: 0.75rem; - line-height: 1.25rem; + padding: .25rem; + width: 2rem; + height: 2rem; + font-size: .8125rem; + line-height: 1.35; } svg { @@ -46,6 +65,25 @@ } } +.button__tooltip { + position: absolute; + top: -30px; + left: 50%; + transform: translateX(-50%); + padding: 4px 8px; + color: var(--color_fg_bold); + background-color: var(--color_bg_layer); + border: 1px solid var(--color_border_default); + border-radius: .5rem; + font-size: .75rem; + white-space: nowrap; + opacity: 0; + pointer-events: none; + transition: opacity .2s ease-in-out; + box-shadow: 0 2px 4px rgba(0,0,0,.1); + z-index: 1000; +} + .button__icon { gap: 0.75rem; border-radius: 0.25rem; @@ -72,10 +110,9 @@ } &:hover { - background-color: var(--color_bg_layer_alternate-bold); - svg { - stroke: var(--color_fg_selected); - } + background-color: var(--color_bg_layer); + border: 1px solid var(--color_border_default); + transition: all .2s ease-out; } &:focus-visible { diff --git a/src/features/common/components/card-toolbar-buttons/card-toolbar-clear-button/card-toolbar-clear-button.component.tsx b/src/features/common/components/card-toolbar-buttons/card-toolbar-clear-button/card-toolbar-clear-button.component.tsx index bb046555a..2afb78799 100644 --- a/src/features/common/components/card-toolbar-buttons/card-toolbar-clear-button/card-toolbar-clear-button.component.tsx +++ b/src/features/common/components/card-toolbar-buttons/card-toolbar-clear-button/card-toolbar-clear-button.component.tsx @@ -4,6 +4,7 @@ import { CardToolbarButtonComponent, CardToolbarButtonComponentProps, } from "@/features/common/components/card-toolbar-button/card-toolbar-button.component"; +import { ClearIcon } from "../../icons/clear/clear-icon"; interface CardToolbarClearButtonComponentProps extends Omit { @@ -16,8 +17,12 @@ export const CardToolbarClearButtonComponent: React.FC< const dictionary = getButtonsUiDictionary(languageCode); return ( - - {dictionary.clearButton.label} + + ); }; diff --git a/src/features/common/components/card-toolbar-buttons/card-toolbar-copy-button/card-toolbar-copy-button.component.tsx b/src/features/common/components/card-toolbar-buttons/card-toolbar-copy-button/card-toolbar-copy-button.component.tsx index 788e411a6..757c73b4b 100644 --- a/src/features/common/components/card-toolbar-buttons/card-toolbar-copy-button/card-toolbar-copy-button.component.tsx +++ b/src/features/common/components/card-toolbar-buttons/card-toolbar-copy-button/card-toolbar-copy-button.component.tsx @@ -4,6 +4,8 @@ import { CardToolbarButtonComponentProps, } from "@/features/common/components/card-toolbar-button/card-toolbar-button.component"; import { getButtonsUiDictionary } from "@/features/localization/services/ui-language-dictionary.service"; +import { CopyIcon } from "../../icons/copy/copy-icon"; +import { CheckIcon } from "../../icons/check/check-icon"; interface CardToolbarCopyButtonComponentProps extends Omit, "variant"> { @@ -15,7 +17,6 @@ export const CardToolbarCopyButtonComponent: React.FC< CardToolbarCopyButtonComponentProps > = ({ languageCode, value, isDisabled, ...props }) => { const dictionary = getButtonsUiDictionary(languageCode); - const [isCopied, setIsCopied] = useState(false); const resetCopy = () => { @@ -36,10 +37,13 @@ export const CardToolbarCopyButtonComponent: React.FC< onPress={copyValue} onBlur={resetCopy} variant="standard" + tooltipText={ + isCopied + ? dictionary.copyButton.done.label + : dictionary.copyButton.idle.label + } > - {isCopied - ? dictionary.copyButton.done.label - : dictionary.copyButton.idle.label} + {isCopied ? : } ); }; diff --git a/src/features/common/components/card-toolbar-buttons/card-toolbar-description-button/card-toolbar-description-button.component.tsx b/src/features/common/components/card-toolbar-buttons/card-toolbar-description-button/card-toolbar-description-button.component.tsx index 0cc9e1bac..0304d2ca9 100644 --- a/src/features/common/components/card-toolbar-buttons/card-toolbar-description-button/card-toolbar-description-button.component.tsx +++ b/src/features/common/components/card-toolbar-buttons/card-toolbar-description-button/card-toolbar-description-button.component.tsx @@ -11,6 +11,8 @@ import { CardToolbarButtonComponent, CardToolbarButtonComponentProps, } from "@/features/common/components/card-toolbar-button/card-toolbar-button.component"; +import { EyeOpenIcon } from "../../icons/eye-open/eye-open-icon"; +import { EyeCloseIcon } from "../../icons/eye-close/eye-close-icon"; interface CardToolbarDescriptionButtonComponentProps extends Omit { @@ -26,12 +28,12 @@ export const CardToolbarDescriptionButtonComponent: React.FC< const setDescriptionVisibility$ = useDebuggerStore((state) => outputType === "header" ? state.setDecodedHeaderDescriptionVisibility$ - : state.setDecodedPayloadDescriptionVisibility$, + : state.setDecodedPayloadDescriptionVisibility$ ); const descriptionVisibility$ = useDebuggerStore((state) => outputType === "header" ? state.decodedHeaderDescriptionVisibility$ - : state.decodedPayloadDescriptionVisibility$, + : state.decodedPayloadDescriptionVisibility$ ); const [descVisibility, setDescVisibility] = @@ -47,7 +49,7 @@ export const CardToolbarDescriptionButtonComponent: React.FC< ClaimDescriptionVisibilityValues.HIDDEN, { secure: true, - }, + } ); setDescriptionVisibility$(ClaimDescriptionVisibilityValues.HIDDEN); @@ -63,7 +65,7 @@ export const CardToolbarDescriptionButtonComponent: React.FC< ClaimDescriptionVisibilityValues.VISIBLE, { secure: true, - }, + } ); setDescriptionVisibility$(ClaimDescriptionVisibilityValues.VISIBLE); @@ -79,15 +81,22 @@ export const CardToolbarDescriptionButtonComponent: React.FC< - {descVisibility === ClaimDescriptionVisibilityValues.VISIBLE - ? dictionary.hideDetailsButton.label - : dictionary.showDetailsButton.label} + {descVisibility === ClaimDescriptionVisibilityValues.VISIBLE ? ( + + ) : ( + + )} ); }; diff --git a/src/features/common/components/card/card.component.tsx b/src/features/common/components/card/card.component.tsx index bb9e59125..39d92ed90 100644 --- a/src/features/common/components/card/card.component.tsx +++ b/src/features/common/components/card/card.component.tsx @@ -1,14 +1,21 @@ import React, { PropsWithChildren, useId } from "react"; import styles from "./card.module.scss"; import { clsx } from "clsx"; -import { getLocalizedSecondaryFont, MonoFont } from "@/libs/theme/fonts"; +import { getLocalizedSecondaryFont } from "@/libs/theme/fonts"; import { CardMessageComponent } from "@/features/common/components/card-message/card-message.component"; +import { HeaderIcon } from "../icons/header/header-icon"; +import { CheckIcon } from "../icons/check/check-icon"; +import { EncodingFormatToggleSwitchComponent } from "@/features/decoder/components/encoding-format-toggle-swith/encoding-format-toggle-switch"; +import { useDecoderStore } from "@/features/decoder/services/decoder.store"; +import { isHmacAlg } from "../../services/jwt.service"; +import { TokenDecoderKeyFormatPickerComponent } from "@/features/decoder/components/token-decoder-key-format-picker.component"; export interface CardComponentProps extends PropsWithChildren { id: string; languageCode: string; title: string; compactTitle: string; + hasHeaderIcon?: boolean; options: Partial<{ noPadding: boolean; fullWidth: boolean; @@ -44,6 +51,7 @@ export const CardComponent: React.FC = (props) => { }, messages, slots, + hasHeaderIcon = false, } = props; const cardId = useId(); @@ -61,12 +69,12 @@ export const CardComponent: React.FC = (props) => { aria-label={canRenderTitle ? undefined : title} heap-ignore="true" className={clsx( - MonoFont.className, styles.card, options && options.fullWidth && styles.card__hasFullWidth, - options && options.fullHeight && styles.card__hasFullHeight, + options && options.fullHeight && styles.card__hasFullHeight )} data-type={options && options.isOutput ? "output" : "input"} + data-no-padding={options ? options.noPadding : undefined} data-frameless={options && options.frameless} > {!options?.hideTitle && ( @@ -74,21 +82,9 @@ export const CardComponent: React.FC = (props) => { {titleKey && (
{titleKey && !compactTitle && ( -

- - {titleKey} - {titleValue && `: `} - - {titleValue && ( - - {titleValue} - - )} -

- )} - {titleKey && compactTitle && ( - <> -

+
+ {hasHeaderIcon && } +

{titleKey} {titleValue && `: `} @@ -99,6 +95,24 @@ export const CardComponent: React.FC = (props) => { )}

+
+ )} + {titleKey && compactTitle && ( + <> +
+ {hasHeaderIcon && } +

+ + {titleKey} + {titleValue && `: `} + + {titleValue && ( + + {titleValue} + + )} +

+

{compactTitle} @@ -111,6 +125,16 @@ export const CardComponent: React.FC = (props) => { )} )} +
+
+ {children} +
+
{messages && messages.errors && messages.errors.length > 0 ? (
= (props) => { > {messages.success.map((line, index) => { return ( - {line} +
+ + {line} +
); })}
) : null} + {slots?.notification} {messages && messages.warnings && messages.warnings.length > 0 && (
= (props) => { })}
)} - {slots?.notification} -
- {children} -
{slots?.footer && (
{slots.footer}
)} @@ -183,31 +202,40 @@ export const CardWithHeadlineComponent: React.FC< CardWithHeadlineComponentProps > = ({ sectionHeadline, languageCode, ...props }) => { const regionId = useId(); + const alg$ = useDecoderStore((state) => state.alg); return (
{sectionHeadline && ( - <> -

- {sectionHeadline.title} - {sectionHeadline.titleTag && ( - - {sectionHeadline.titleTag} - +
+
+

+ {sectionHeadline.title} + {sectionHeadline.titleTag && ( + + {sectionHeadline.titleTag} + + )} +

+ {sectionHeadline.description && ( +

+ {sectionHeadline.description} +

)} -

- {sectionHeadline.description && ( -

- {sectionHeadline.description} -

+
+ + {isHmacAlg(alg$) ? ( + + ) : ( + )} - +

)}
diff --git a/src/features/common/components/card/card.module.scss b/src/features/common/components/card/card.module.scss index a320b31ef..a7104dc9f 100644 --- a/src/features/common/components/card/card.module.scss +++ b/src/features/common/components/card/card.module.scss @@ -2,17 +2,17 @@ @use "@/libs/theme/styles/mixins" as *; .cardHeadline__title { - grid-column: 1 / -1; - display: flex; - align-items: center; - gap: 0.25rem; - text-transform: uppercase; - padding: 0.5rem 0; - color: var(--color_fg_default); - font-size: 0.875rem; - line-height: 1.375rem; - font-weight: 500; - letter-spacing: 0.24px; + grid-column: 1/-1; + display: flex; + align-items: center; + gap: .25rem; + font-family: var(--font-primary); + padding-top: .75rem; + color: var(--color_fg_default); + font-size: 1rem; + line-height: 1.15rem; + font-weight: 700; + letter-spacing: -.2px; & * { font-size: inherit; @@ -56,24 +56,44 @@ } } +.headline__container { + display: flex; + flex-direction: column; + gap: 0; +} + +.title__container { + grid-column: 1/-1; + width: 100%; + color: var(--color_fg_bold); + font-size: 1.75rem; + font-weight: 500; + line-height: 1.5; + margin-bottom: .5rem; + display: flex; + justify-content: space-between; +} + .card { isolation: isolate; + flex: 1 1; grid-column: span 6; display: flex; - flex: 1; flex-direction: column; - border-radius: 0.5rem; - border: 1px solid var(--color_border_bold); - background: var(--color_bg_code-editor); - overflow: hidden; - - &[data-type="output"] { - background: var(--color_bg_layer_alternate); - } + border-radius: 1rem; + border: 1px solid var(--color_border_default); + background: var(--color_bg_layer_alternate-bold); + padding: 0.25rem; + letter-spacing: -.1px; +} - &[data-frameless="true"] { - border-radius: 0; - border: none; +.card__heading_title_container { + display: flex; + flex-direction: row; + align-items: center; + svg { + color: var(--color_fg_default); + margin-right: 2px; } } @@ -106,10 +126,7 @@ justify-content: space-between; padding: 0.5rem 1rem; height: 3rem; - - border-bottom: 1px solid var(--color_border_bold); gap: 0.25rem; - text-transform: uppercase; } .card__fullTitle { @@ -143,22 +160,19 @@ } .card__titleKey { - color: var(--color_fg_default); - font-size: 0.875rem; - line-height: 1.375rem; - font-style: normal; - font-weight: 500; - letter-spacing: 0.24px; - text-transform: uppercase; + color: var(--color_fg_default); + font-size: .875rem; + line-height: 1.375rem; + font-weight: 500; + letter-spacing: .24px; } .card__titleValue { color: var(--color_fg_default); - font-size: 0.875rem; + font-size: .875rem; line-height: 1.375rem; font-weight: 500; - letter-spacing: 0.24px; - text-transform: uppercase; + letter-spacing: .24px; } .card__action { @@ -173,6 +187,13 @@ border-top: 1px solid var(--color_border_bold); } +.card__content { + background-color: var(--color_bg_layer); + height: 100%; + border-radius: .75rem; + box-shadow: 0 0 0 .5px rgba(0,0,0,.12),0 2px 2px -1px rgba(0,0,0,.04),0 4px 4px -2px rgba(0,0,0,.04),0 6px 6px -3px rgba(0,0,0,.04); +} + .card__body { display: flex; flex: 1; @@ -197,20 +218,19 @@ } .card__status { + flex: 1 1; display: flex; - flex-direction: column; - flex-shrink: 0; - padding: 0.5rem 1rem; - gap: 0.25rem; - font-size: 0.875rem; + align-items: center; + justify-content: flex-start; + padding: .75rem .75rem .5rem; + gap: .25rem; + font-size: .875rem; line-height: 1.375rem; color: var(--color_fg_default); - border-top: 1px solid var(--color_border_bold); } .card__success { - background-color: var(--color_bg_state_success_subtle); - + svg, span, p, code { @@ -227,8 +247,7 @@ } .card__error { - background-color: var(--color_bg_state_danger_subtle); - + span, p, code { @@ -245,7 +264,6 @@ } .card__warning { - background-color: var(--color_bg_state_caution_subtle); span, p, diff --git a/src/features/common/components/checkbox/checkbox.module.scss b/src/features/common/components/checkbox/checkbox.module.scss index 307edf43b..94b4e498f 100644 --- a/src/features/common/components/checkbox/checkbox.module.scss +++ b/src/features/common/components/checkbox/checkbox.module.scss @@ -2,6 +2,7 @@ --selected-color: var(--color_bg_state_success); --selected-color-pressed: var(--color_fg_on_state_success_subtle); --checkmark-color: var(--color_border_state_success); + width: 250px; display: flex; /* This is needed so the HiddenInput is positioned correctly */ diff --git a/src/features/common/components/context-menu/context-menu.module.scss b/src/features/common/components/context-menu/context-menu.module.scss new file mode 100644 index 000000000..8bfe011b6 --- /dev/null +++ b/src/features/common/components/context-menu/context-menu.module.scss @@ -0,0 +1,61 @@ +.container { + max-width: calc(-24px + 100vw); + max-height: calc(-24px + 100vh); + position: fixed; + background-color: var(--color_bg_layer); + border: 1px solid var(--color_border_default); + font-size: 0.875rem; + z-index: 9009; + cursor: default; + border-radius: 1rem; + overflow: hidden; + padding: 0.25rem; + min-width: 180px; + box-shadow: + 0 1px 1px -0.5px rgba(0, 0, 0, 0.04), + 0 3px 3px -1.5px rgba(0, 0, 0, 0.04), + 0 6px 6px -3px rgba(0, 0, 0, 0.04), + 0 12px 12px -6px rgba(0, 0, 0, 0.04), + inset 0 0 0 1px rgba(0, 0, 0, 0.04); +} + +.groupLabel { + width: 100%; + padding: 0.5rem 0.75rem 0.25rem; + font-size: 0.8125rem; + color: var(--color_fg_default); +} + +.list { + display: flex; + align-items: center; + list-style-type: none; + flex-direction: column; +} + +.menuItem { + width: 100%; + justify-content: flex-start; + position: relative; + padding: 0.5rem 0.75rem; + border-radius: 0.75rem; + color: var(--color_fg_bold); + gap: 0.5rem; + font-family: var(--font-primary); + border: none; + background-color: var(--color_bg_layer); + display: flex; + align-items: center; + + &:hover { + cursor: pointer; + background-color: var(--color_bg_layer_alternate-bold); + } +} + +.separator { + width: 100%; + height: 1px; + background-color: var(--color_border_default); + margin: 0.25rem 0; +} diff --git a/src/features/common/components/context-menu/context-menu.tsx b/src/features/common/components/context-menu/context-menu.tsx new file mode 100644 index 000000000..8ecb97ba4 --- /dev/null +++ b/src/features/common/components/context-menu/context-menu.tsx @@ -0,0 +1,101 @@ +"use client"; + +import React, { FC } from "react"; +import { BrandDictionaryModel } from "@/features/localization/models/brand-dictionary.model"; +import styles from "./context-menu.module.scss"; +import jwtLogoString from "@/public/img/jwt-logo.svg?raw"; +import jwtSymbolString from "@/public/img/jwt-symbol.svg?raw"; +import jwtWordmarkString from "@/public/img/jwt-wordmark.svg?raw"; +import { Button } from "react-aria-components"; +import { CopyIcon } from "../icons/copy/copy-icon"; +import { DownloadIconComponent } from "../../assets/download-icon.component"; + +interface ContextMenuProps { + dictionary: BrandDictionaryModel; + position: { x: number; y: number } | null; + setIsCopied: (value: React.SetStateAction) => void; +} + +const ContextMenu: FC = ({ + dictionary, + position, + setIsCopied, +}) => { + if (!position) return null; + + const handleIconCopy = async (svgString: string) => { + if (!navigator.clipboard) { + console.error("Clipboard API not available"); + return; + } + try { + await navigator.clipboard.writeText(svgString); + setIsCopied(true); + } catch (err) { + console.error("Failed to copy SVG: ", err); + } + }; + + return ( +
+
{dictionary.menu.brand.label}
+
+ + + + {dictionary.menu.brand.svg.downloadLabel} + + + + + {dictionary.menu.brand.symbol.downloadLabel} + + + + + {dictionary.menu.brand.wordmark.downloadLabel} + +
+
+
{dictionary.menu.tools.label}
+ {dictionary.menu.tools.items.map((el) => ( + {el.label} + ))} +
+ ); +}; + +export default ContextMenu; diff --git a/src/features/common/components/debugger-picker/debugger-picker.component.tsx b/src/features/common/components/debugger-picker/debugger-picker.component.tsx index df256aa4a..c62873c28 100644 --- a/src/features/common/components/debugger-picker/debugger-picker.component.tsx +++ b/src/features/common/components/debugger-picker/debugger-picker.component.tsx @@ -5,7 +5,6 @@ import { DebuggerPickerOptionModel } from "@/features/common/models/debugger-pic import { LibraryFilterLabel } from "@/features/libraries/models/library-filters.model"; import { isGroupedOptionsType } from "./utils"; - interface PickerLabelProps { label: string | null; } @@ -17,12 +16,12 @@ const getGroupLabel = ( >, selected: DebuggerPickerOptionModel ): LibraryFilterLabel | undefined => { - if(!isGroupedOptionsType(options)) return undefined + if (!isGroupedOptionsType(options)) return undefined; const group = (options as GroupBase[]).find( (group) => group.options.some((opt) => opt.value === selected.value) ); - return group ? group.label as LibraryFilterLabel : undefined; + return group ? (group.label as LibraryFilterLabel) : undefined; }; const PickerLabel: React.FC = ({ label }) => { @@ -41,7 +40,7 @@ interface DebuggerPickerComponentProps { GroupBase >; isGrouped?: boolean; - selectedOptionCode: DebuggerPickerOptionModel | null; + selectedOptionCode?: DebuggerPickerOptionModel | null; handleSelection: ( selection: string, parentLabel?: LibraryFilterLabel @@ -55,16 +54,14 @@ export const DebuggerPickerComponent: React.FC< > = ({ label, options, - handleSelection, selectedOptionCode, + handleSelection, placeholder, minWidth, }) => { const [isClient, setIsClient] = useState(false); - const handleChange = ( - selection: SingleValue - ) => { + const handleChange = (selection: SingleValue) => { if (!selection) { return; } @@ -78,31 +75,45 @@ export const DebuggerPickerComponent: React.FC< if (!isClient) { return ( -
+ <>
-
+ ); } return ( -
+ <> {label && } -
+ ); }; diff --git a/src/features/common/components/debugger-picker/debugger-picker.module.scss b/src/features/common/components/debugger-picker/debugger-picker.module.scss index 8541f7520..ab25a72c9 100644 --- a/src/features/common/components/debugger-picker/debugger-picker.module.scss +++ b/src/features/common/components/debugger-picker/debugger-picker.module.scss @@ -21,8 +21,8 @@ $picker-list-offset-lg: calc(($picker-list-width-lg - $picker-width-lg) / 2); background: transparent; border: none; color: var(--color_fg_bold); - cursor: pointer; - gap: 0.75rem; + gap: .75rem; + width: 100%; //width: $picker-width-sm; @@ -34,20 +34,17 @@ $picker-list-offset-lg: calc(($picker-list-width-lg - $picker-width-lg) / 2); } .picker__label { - display: flex; - align-items: center; - justify-content: center; - padding: 0; - list-style-type: none; - margin: 0; - gap: 0.5rem; - font-size: 0.8125rem; - line-height: 1.3125rem; - letter-spacing: -0.05px; - - width: 100%; - - height: 100%; + display: flex; + align-items: center; + justify-content: flex-start; + padding: 0; + list-style-type: none; + margin: 0; + gap: .5rem; + font-size: .875rem; + line-height: 1.35; + width: 100%; + height: 100%; & svg { stroke: var(--color_fg_bold); @@ -56,4 +53,5 @@ $picker-list-offset-lg: calc(($picker-list-width-lg - $picker-width-lg) / 2); .picker__fullName { display: flex; -} + font-weight: 600; +} \ No newline at end of file diff --git a/src/features/common/components/ebook/ebook.component.tsx b/src/features/common/components/ebook/ebook.component.tsx index b76bdd2be..8a0b20e07 100644 --- a/src/features/common/components/ebook/ebook.component.tsx +++ b/src/features/common/components/ebook/ebook.component.tsx @@ -22,11 +22,44 @@ export const EbookComponent: React.FC = ({ wrapperClassName={styles.wrapper} contentClassName={styles.content} > +
+        
+          {`{\n       "sub"`}
+          : 
+          {`"1234567890"`}
+          ,
+        
+        
+          {" "}
+          {`      "name"`}
+          : 
+          {`"John Doe"`}
+          ,
+        
+        
+          {" "}
+          {`      "admin"`}
+          : 
+          true
+          ,
+        
+        
+          {" "}
+          {`      "iat"`}
+          : 
+          1516239022
+        
+        {`}`}
+      
{dictionary.title} diff --git a/src/features/common/components/ebook/ebook.module.scss b/src/features/common/components/ebook/ebook.module.scss index f17afce68..ca1088966 100644 --- a/src/features/common/components/ebook/ebook.module.scss +++ b/src/features/common/components/ebook/ebook.module.scss @@ -2,10 +2,10 @@ @use "@/libs/theme/styles/mixins" as *; .container { - @include Container; - position: relative; - overflow: hidden; - background: var(--color_bg_auth0-cta); + width: 100%; + position: relative; + margin: 4rem 0; + overflow: clip; &:before { position: absolute; @@ -14,99 +14,75 @@ content: ""; width: 100%; height: 100%; - - background: url("https://cdn.auth0.com/website/passkeys-playground/assets/cta-mobile.png") - no-repeat; - background-size: cover; - } - - @media only screen and (min-width: 480px) { - &:before { - background: url("https://cdn.auth0.com/website/passkeys-playground/assets/cta-mobile.png") - no-repeat; - background-size: cover; - } - } - - @media #{$breakpoint-dimension-sm} { - &:before { - background: url("/images/auth0-background.svg") no-repeat right - center; - background-size: cover; - } } @media #{$breakpoint-dimension-md} { - background: unset; - - &:before { - background: none; - } - - &:after { - display: none; - background: none; - } + overflow: unset; } + } .wrapper { @include ExtendedGrid; position: relative; justify-content: center; - - border-radius: 0; - overflow: hidden; - - @media #{$breakpoint-dimension-xl} { - border-radius: 1.5rem; - } + border-radius: 1rem; } .content { - @include InnerContentGrid; + display: flex; + width: calc(100% - 2rem); + max-width: 1312px; + margin: 0 auto; position: relative; padding: 1.5rem 0 14rem; - isolation: isolate; + border-radius: 1rem; + border: 1px dashed var(--color_border_bold); + background-color: var(--color_bg_layer_alternate); + background-image: linear-gradient(90deg,hsla(0,0%,50%,.071) 1px,transparent 0),linear-gradient(180deg,hsla(0,0%,50%,.071) 1px,transparent 0); + background-size: 24px 24px; + &:after { position: absolute; content: ""; - bottom: -1.5rem; - right: 0; - background: url("/images/ebook-image.png") center no-repeat; - background-size: contain; - width: 100%; - height: 75%; + top: 10rem; + left: 18rem; + background-image: url("/images/ebook.svg"); + border-radius: .25rem; + transform: rotate(-7.5deg); + height: 320px; + width: 240px; + z-index: 10; } - @media #{$breakpoint-dimension-xs} { - padding-bottom: 1.5rem; - column-gap: 6rem; + &:hover:after { + perspective: 100px; + transform: rotate(5deg) translateX(-24px) translateY(0) scale(1.1); + transition: all .2s ease-in-out; + } - &:after { - position: absolute; - content: ""; - top: 0; - right: 0; - background: url("/images/ebook-image.png") center no-repeat; - background-size: cover; - height: 100%; - width: 32%; - z-index: 10; - } + @media #{$breakpoint-dimension-xs} { + column-gap: 0; } @media #{$breakpoint-dimension-xs} { column-gap: 0; } + @media only screen and (min-width: 992px) and (min-width: 768px) { + width: calc(100% - 4rem); + grid-template-columns: repeat(12, minmax(0, 1fr)); + } + @media #{$breakpoint-dimension-md} { - background: var(--color_bg_auth0-cta); - padding: 2rem 2.5rem; + padding: 4rem 2.5rem; border-radius: 1rem; - overflow: hidden; - + display: grid; + max-width: 1312px; + margin: 0 auto; + transition: all .2s ease-in-out; + &:before { position: absolute; bottom: 0; @@ -114,68 +90,175 @@ content: ""; width: 100%; height: 100%; - background-size: contain; + border-radius: 1rem; + background-color: var(--color_bg_layer_alternate); + background-image: linear-gradient(90deg,hsla(0,0%,50%,.071) 1px,transparent 0),linear-gradient(180deg,hsla(0,0%,50%,.071) 1px,transparent 0); + background-size: 24px 24px; + } - background: url("/images/auth0-background.svg") no-repeat right - bottom; - background-size: cover; + &:after { + position: absolute; + content: ""; + top: -1.75rem; + left: 4rem; + background-image: url("/images/ebook.svg"); + border-radius: .25rem; + transform: rotate(-7.5deg); + height: 320px; + width: 240px; + z-index: 10; + transition: all .2s ease-in-out; } } + + @media #{$breakpoint-dimension-sm} { + width: calc(100% - 4rem); + } +} + +.ebookBanner__code { + pointer-events: none; + position: absolute; + display: flex; + flex-direction: column; + align-items: flex-start; + justify-content: center; + grid-column: 3/span 3; + height: fit-content; + transform: translateY(0); + top: auto; + bottom: 0; + left: 0; + width: 100%; + text-wrap: wrap; + padding: 1rem; + background: #191919; + color: var(--color_fg_code); + border-radius: 1.25rem; + border-top-left-radius: .25rem; + border-top-right-radius: .25rem; + border: 1px solid var(--color_border_bold); + font-size: .875rem; + white-space: pre; + word-wrap: break-word; + text-overflow: ellipsis; + text-wrap-mode: wrap; + text-wrap-style: balance; + overflow: clip; + box-shadow: 0 0 0 1px rgba(0,0,0,.12),0 4px 4px -2px rgba(0,0,0,.04),0 2px 2px -1px rgba(0,0,0,.04); + transition: all .4s ease-in-out; + + span { + padding: .25rem 0; + transition: color .1s ease; + } + + @media #{$breakpoint-dimension-md} { + border-radius: 1.25rem; + left: 0; + top: 50%; + transform: translateY(-50%); + } +} + +.ebookBanner__code_dot { + display: inline; + position: relative; + color: var(--color_border_inverse_static); + padding: .125rem 0; +} + +.ebookBanner__code_string { + display: inline; + position: relative; + color: var(--color_jwt_signature); + padding: .125rem 0; +} + +.ebookBanner__code_boolean { + display: inline; + position: relative; + color: var(--color_jwt_header); + padding: .125rem 0; +} + +.ebookBanner__code_number { + display: inline; + position: relative; + color: var(--color_jwt_payload); + padding: .125rem 0; } .ebookBanner__copy { - grid-column: 1 / span 6; + grid-column: 1/span 6; display: flex; flex-direction: column; + padding: 0 2.5rem; z-index: 1; + margin-top: 2rem; @media #{$breakpoint-dimension-xs} { - grid-column: 1 / span 4; + grid-column: 1/span 4; } @media #{$breakpoint-dimension-sm} { - grid-column: 1 / span 8; + grid-column: 6/span 6; + } + + @media #{$breakpoint-dimension-md} { + margin-top: 0; } } .ebookBanner__title { - color: var(--color_fg_bold); - + width: 100%; + margin: 0; + text-align: left; font-size: 1.5rem; - line-height: 2rem; - letter-spacing: 0.05px; + line-height: 1.15; font-weight: 500; + color: var(--color_fg_bold); + font-feature-settings: lining-nums proportional-nums; + font-variant-numeric: lining-nums proportional-nums; + font-style: normal; + + @media #{$breakpoint-dimension-lg} { + font-size: 2.5rem; + } } .ebookBanner__description { color: var(--color_fg_default); font-size: 1rem; - line-height: 1.25rem; - margin-top: 0.5rem; + line-height: 1.5; + margin-top: .5rem; } .ebookBanner__link { - margin-top: 1.5rem; - display: flex; - padding: 0.5rem 1rem; - justify-content: center; - align-items: center; - gap: 0.5rem; - align-self: stretch; - - border-radius: 0.375rem; - background: linear-gradient( - 120deg, - #191919 -29.78%, - #4016a0 11.61%, - #3f59e4 100.07% - ); - - color: $neutrals-light-100-snow; - font-size: 0.875rem; - line-height: 1.375rem; - font-weight: 500; - letter-spacing: 0.2px; + width: fit-content; + margin-top: 1.5rem; + display: flex; + padding: .25rem .75rem; + justify-content: center; + align-items: center; + gap: .5rem; + align-self: stretch; + border-radius: 9999px; + background: var(--color_fg_on_button); + box-shadow: 0 1px 1px -.5px rgba(0,0,0,.04),0 3px 3px -1.5px rgba(0,0,0,.04),0 6px 6px -3px rgba(0,0,0,.04),0 12px 12px -6px rgba(0,0,0,.04),0 24px 24px -12px rgba(0,0,0,.04),inset 0 0 0 1px rgba(0,0,0,.08); + color: var(--color_bg_layer); + font-size: .875rem; + font-weight: 700; + line-height: 1.375rem; + font-weight: 500; + letter-spacing: -.2px; + transition: all .3s ease-in-out; + + &:hover { + background: var(--color_fg_on_button_primary); + box-shadow: 0 0 0 4px rgba(0,0,0,.2); + transition: all .2s ease-out; + } :global(html[lang="ja"]) & { @include LocaleLineHeight("ja", 1rem); @@ -203,6 +286,6 @@ svg { height: 0.75rem; width: 0.75rem; - fill: $neutrals-light-100-snow; + fill: var(--color_bg_layer); } } diff --git a/src/features/common/components/errors/error-page/error-page.component.tsx b/src/features/common/components/errors/error-page/error-page.component.tsx index 35d320651..96f0f8c58 100644 --- a/src/features/common/components/errors/error-page/error-page.component.tsx +++ b/src/features/common/components/errors/error-page/error-page.component.tsx @@ -1,29 +1,24 @@ import React from "react"; import styles from "./error-page.module.scss"; import { ShellComponent } from "@/features/common/components/shell/shell.component"; -import { RibbonComponent } from "@/features/common/components/bars/ribbon/ribbon.component"; import { MobileHeaderComponent } from "@/features/common/components/headers/mobile-header/mobile-header.component"; import { HeaderComponent } from "@/features/common/components/headers/header/header.component"; import { FooterComponent } from "@/features/common/components/footer/footer.component"; -import { LayoutDictionaryModel } from "@/features/localization/models/layout-dictionary.model"; import { ThemeCookieValues } from "@/features/common/values/theme.values"; -import { getImageDictionary } from "@/features/localization/services/images-dictionary.service"; -import { SiteLogoComponent } from "@/features/common/components/site-logo/site-logo.component"; +import { getLayoutDictionary } from "@/features/localization/services/language-dictionary.service"; interface ErrorPageComponentProps { languageCode: string; themeCode: ThemeCookieValues; - dictionary: LayoutDictionaryModel; children: React.ReactNode; } export const ErrorPageComponent: React.FC = ({ languageCode, themeCode, - dictionary, children, }) => { - const images = getImageDictionary(languageCode); + const layoutDictionary = getLayoutDictionary(languageCode); return ( @@ -31,35 +26,19 @@ export const ErrorPageComponent: React.FC = ({
} - ribbon={ - - } + dictionary={layoutDictionary} + themeCode={themeCode} /> } - ribbon={ - - } + dictionary={layoutDictionary} + themeCode={themeCode} />
{children}
} + dictionary={layoutDictionary.footer} /> diff --git a/src/features/common/components/footer/footer.component.tsx b/src/features/common/components/footer/footer.component.tsx index 42859a070..3e9277ae2 100644 --- a/src/features/common/components/footer/footer.component.tsx +++ b/src/features/common/components/footer/footer.component.tsx @@ -1,6 +1,12 @@ "use client"; -import React, { MouseEvent, useState } from "react"; +import React, { MouseEvent, useEffect, useState } from "react"; +import Select, { + SingleValue, + OptionsOrGroups, + GroupBase, + NonceProvider, +} from "react-select"; import { FooterIconsComponent } from "./footer-Icons.component"; import { MonoFont, SecondaryFont } from "@/libs/theme/fonts"; import Image from "next/image"; @@ -15,25 +21,43 @@ import { DEFAULT_LANGUAGE_CODE } from "@/features/localization/localization.conf import { sitePaths } from "@/features/seo/site-tree"; import { createUrlPath } from "@/libs/utils/path.utils"; import { SiteBrandComponent } from "@/features/common/components/site-brand/site-brand.component"; -import { StaticImageMetadataModel } from "@/features/common/models/static-image-metadata.model"; import { Button } from "react-aria-components"; +import { Auth0LogoComponent } from "../../assets/auth0-logo.component"; +import { getBrandDictionary } from "@/features/localization/services/brand-dictionary.service"; +import { savePreferredLanguage } from "@/features/localization/services/ui-language.utils"; +import { UiLanguageModel } from "../../models/ui-language.model"; +import { GlobeIconComponent } from "../bars/ribbon/assets/globe-icon.component"; interface FooterComponentProps { languageCode: string; dictionary: LayoutDictionaryModel["footer"]; - auth0Logo: StaticImageMetadataModel; - siteLogo: React.ReactNode; } export const FooterComponent: React.FC = ({ languageCode, dictionary, - auth0Logo, - siteLogo, }) => { + const currentLanguage = dictionary.languagePicker.options.filter( + (element) => element.value === languageCode + )[0]; + + const handleChange = (selection: SingleValue) => { + if (!selection) { + return; + } + savePreferredLanguage(selection.value); + }; + const [modalState, setModalState] = useState( - ModalStateValues.CLOSED, + ModalStateValues.CLOSED ); + const [portalTarget, setPortalTarget] = useState(null); + + useEffect(() => { + setPortalTarget(document.body); + }, []); + + const images = getBrandDictionary(languageCode); const languagePathPrefix: string = languageCode === DEFAULT_LANGUAGE_CODE @@ -66,9 +90,10 @@ export const FooterComponent: React.FC = ({ contentClassName={styles.content} >
- - {siteLogo} - +
@@ -114,7 +139,7 @@ export const FooterComponent: React.FC = ({ }} className={clsx( styles.resource__button, - SecondaryFont.className, + SecondaryFont.className )} > {trigger.text} @@ -162,21 +187,80 @@ export const FooterComponent: React.FC = ({ target="_blank" href="https://auth0.com/" > - {auth0Logo.alt} + {dictionary.copyright} + {dictionary.languagePicker.options.length > 1 && ( +
+ + + + +
+
+ ); +}; diff --git a/src/features/decoder/components/jwt-editor.component.tsx b/src/features/decoder/components/jwt-editor.component.tsx index 36f05a36c..3475fc066 100644 --- a/src/features/decoder/components/jwt-editor.component.tsx +++ b/src/features/decoder/components/jwt-editor.component.tsx @@ -73,7 +73,7 @@ export const JwtEditorComponent: React.FC = ({ padding="1rem" style={{ fontFamily: '"Roboto Mono", monospace', - fontSize: 14, + fontSize: 16, lineHeight: 1.4, border: "none", outline: "none", diff --git a/src/features/decoder/components/jwt-input.component.tsx b/src/features/decoder/components/jwt-input.component.tsx index 17274b926..c906aae53 100644 --- a/src/features/decoder/components/jwt-input.component.tsx +++ b/src/features/decoder/components/jwt-input.component.tsx @@ -72,7 +72,7 @@ export const JwtInputComponent: React.FC = ({ isSelected={autoFocusEnabled} onChange={(e) => handleCheckboxChange(e)} > - Enable auto-focus + {dictionary.autoFocusLabel}
= ({ success: [dictionary.successMessage], errors: decodeErrors$, }} + hasHeaderIcon slots={{ notification: ( = ({ value={token} /> ), diff --git a/src/features/decoder/components/jwt-input.module.scss b/src/features/decoder/components/jwt-input.module.scss index 386b07eb9..09165b651 100644 --- a/src/features/decoder/components/jwt-input.module.scss +++ b/src/features/decoder/components/jwt-input.module.scss @@ -1,14 +1,12 @@ .headline { - grid-column: 1 / -1; - display: flex; - align-items: center; - gap: 0.25rem; - text-transform: uppercase; - color: var(--color_fg_default); - font-size: 0.875rem; - line-height: 1.375rem; - font-weight: 500; - letter-spacing: 0.24px; + display: flex; + align-items: center; + width: 100%; + font-size: 1rem; + font-weight: 700; + line-height: 1.15; + letter-spacing: -.1px; + color: var(--color_fg_default); } .checkbox__label { diff --git a/src/features/decoder/components/secret-key-input.component.tsx b/src/features/decoder/components/secret-key-input.component.tsx index 43eda43e2..35a937b5c 100644 --- a/src/features/decoder/components/secret-key-input.component.tsx +++ b/src/features/decoder/components/secret-key-input.component.tsx @@ -1,10 +1,8 @@ import React, { ChangeEvent, useEffect, useState } from "react"; -import { TokenDecoderEncodingFormatPickerComponent } from "@/features/decoder/components/token-decoder-encoding-format-picker.component"; import { SignatureVerificationSecretInputComponent } from "@/features/decoder/components/signature-verification-secret-input.component"; import { SignatureVerificationPublicKeyInputComponent } from "@/features/decoder/components/signature-verification-public-key-input.component"; import { CardWithHeadlineComponent } from "@/features/common/components/card/card.component"; import { DEFAULT_JWT } from "@/features/decoder/services/token-decoder.service"; -import { TokenDecoderKeyFormatPickerComponent } from "@/features/decoder/components/token-decoder-key-format-picker.component"; import { useDecoderStore } from "@/features/decoder/services/decoder.store"; import { HomeDictionaryModel } from "@/features/localization/models/home-dictionary.model"; import { useDebuggerStore } from "@/features/debugger/services/debugger.store"; @@ -20,6 +18,7 @@ import { CardToolbarCopyButtonComponent } from "@/features/common/components/car import { CardToolbarClearButtonComponent } from "@/features/common/components/card-toolbar-buttons/card-toolbar-clear-button/card-toolbar-clear-button.component"; import { NOOP_ALG } from "@/features/common/values/constants"; + type SecretKeyInputComponentProps = { languageCode: string; dictionary: HomeDictionaryModel["decoder"]["signatureVerification"]; @@ -58,7 +57,7 @@ export const SecretKeyInputComponent: React.FC< decoderInputs$.algType === SigningAlgCategoryValues.SYMMETRIC && decoderInputs$.symmetricSecretKey ? decoderInputs$.symmetricSecretKey - : DEFAULT_JWT.secret, + : DEFAULT_JWT.secret ); const [publicKey, setPublicKey] = useState(""); @@ -128,6 +127,7 @@ export const SecretKeyInputComponent: React.FC< ? dictionary.description.secret : dictionary.description.publicKey, }} + hasHeaderIcon languageCode={languageCode} messages={{ errors: verificationInputErrors$, @@ -137,7 +137,7 @@ export const SecretKeyInputComponent: React.FC< : dictionary.editor.successMessage.publicKey, ], }} - options={{ noPadding: true }} + options={{ noPadding: false }} title={ isHmacAlg(alg$) ? dictionary.editor.title.secret @@ -161,14 +161,7 @@ export const SecretKeyInputComponent: React.FC< isDisabled={isHmacAlg(alg$) ? !secret : !publicKey} /> - ), - footer: isHmacAlg(alg$) ? ( - - ) : ( - - ), + ) }} > {isHmacAlg(alg$) && ( diff --git a/src/features/decoder/components/secret-key-input.module.scss b/src/features/decoder/components/secret-key-input.module.scss index a4d81ca0c..00a893a10 100644 --- a/src/features/decoder/components/secret-key-input.module.scss +++ b/src/features/decoder/components/secret-key-input.module.scss @@ -14,17 +14,17 @@ } .grid__subtitle { - grid-column: 1 / -1; - display: flex; - align-items: center; - gap: 0.25rem; - text-transform: uppercase; - padding: 0.5rem 0; - color: var(--color_fg_default); - font-size: 0.875rem; - line-height: 1.375rem; - font-weight: 500; - letter-spacing: 0.24px; + grid-column: 1/-1; + display: flex; + align-items: center; + gap: .25rem; + font-family: var(--font-primary); + padding-top: .75rem; + color: var(--color_fg_default); + font-size: 1rem; + line-height: 1.15rem; + font-weight: 700; + letter-spacing: -.2px; & * { font-size: inherit; diff --git a/src/features/decoder/components/token-decoder-key-format-picker.module.scss b/src/features/decoder/components/token-decoder-key-format-picker.module.scss index c172cbca0..d85867ad6 100644 --- a/src/features/decoder/components/token-decoder-key-format-picker.module.scss +++ b/src/features/decoder/components/token-decoder-key-format-picker.module.scss @@ -12,11 +12,17 @@ } .label { - color: var(--color_fg_default); - font-size: 0.875rem; - line-height: 1.375rem; - font-weight: 500; - letter-spacing: 0.1px; + display: flex; + align-items: center; + justify-content: flex-start; + padding: 0; + list-style-type: none; + margin: 0; + gap: .5rem; + font-size: .875rem; + line-height: 1.35; + width: 100%; + height: 100%; } .select { diff --git a/src/features/decoder/components/token-decoder-signature-validation.component.tsx b/src/features/decoder/components/token-decoder-signature-validation.component.tsx index 369943f9b..5b20fa802 100644 --- a/src/features/decoder/components/token-decoder-signature-validation.component.tsx +++ b/src/features/decoder/components/token-decoder-signature-validation.component.tsx @@ -5,6 +5,7 @@ import { clsx } from "clsx"; import { useDecoderStore } from "@/features/decoder/services/decoder.store"; import { JwtSignatureStatusValues } from "@/features/common/values/jwt-signature-status.values"; import { CardMessageComponent } from "@/features/common/components/card-message/card-message.component"; +import { CheckIcon } from "@/features/common/components/icons/check/check-icon"; interface TokenDecoderSignatureValidationComponentProps { id: string; @@ -35,6 +36,7 @@ export const TokenDecoderSignatureValidationComponent: React.FC< role="status" className={clsx(styles.container, styles.valid)} > + {StringValues.editor.signatureVerified}
); diff --git a/src/features/decoder/components/token-decoder-signature-validation.module.scss b/src/features/decoder/components/token-decoder-signature-validation.module.scss index 2d3839028..9681555d3 100644 --- a/src/features/decoder/components/token-decoder-signature-validation.module.scss +++ b/src/features/decoder/components/token-decoder-signature-validation.module.scss @@ -1,25 +1,25 @@ @use "@/libs/theme/styles/variables" as *; .container { + flex: 1 1; display: flex; - flex-direction: column; - transition: background-color 0.13s ease-in-out; - padding: 0.5rem 1rem; - font-size: 0.75rem; - line-height: 1.125rem; + align-items: center; + justify-content: flex-start; + padding: .75rem .75rem .5rem; + gap: .25rem; + font-size: .875rem; + line-height: 1.375rem; + color: var(--color_fg_default); } .valid { - background-color: var(--color_bg_state_success_subtle); - color: var(--color_fg_on_state_success_subtle); + color: var(--color_fg_on_state_success_subtle); } .invalid { - background-color: var(--color_bg_state_danger_subtle); color: var(--color_fg_on_state_danger_subtle); } .warning { - background-color: var(--color_bg_state_caution_subtle); color: var(--color_fg_on_state_caution_subtle); } diff --git a/src/features/decoder/components/token-decoder.component.tsx b/src/features/decoder/components/token-decoder.component.tsx index 721ef51d5..27faea8e3 100644 --- a/src/features/decoder/components/token-decoder.component.tsx +++ b/src/features/decoder/components/token-decoder.component.tsx @@ -20,6 +20,8 @@ import { AsymmetricKeyFormatValues } from "@/features/common/values/asymmetric-k import { WidgetComponent } from "@/features/common/components/widget/widget/widget.component"; import { dataTestidDictionary } from "@/libs/testing/data-testid.dictionary"; import { DebuggerWidgetValues } from "@/features/common/values/debugger-widget.values"; +import { WidgetAlgPickerComponent } from "@/features/debugger/components/debugger-alg-picker/debugger-alg-picker.component"; +import styles from "./token-decoder.module.scss"; interface TokenDecoderComponentProps { languageCode: string; @@ -49,7 +51,7 @@ export const TokenDecoderComponent: React.FC = ({ const loadDecoderInputs = useDecoderStore((state) => state.loadDecoderInputs); const handleJwtChange$ = useDecoderStore((state) => state.handleJwtChange); const showUseHashWarning$ = useDecoderStore( - (state) => state.showUseHashWarning, + (state) => state.showUseHashWarning ); useEffect(() => { @@ -184,41 +186,51 @@ export const TokenDecoderComponent: React.FC = ({ }, [decoderInputs$, loadDecoderInputs, headlineConfig.isVisible]); return ( - +
+ {dictionary.description} + - } - contentOutput={ - <> - - - + - - } - warnings={null} - /> + } + contentOutput={ + <> + + + + + } + warnings={null} + /> + ); }; diff --git a/src/features/decoder/components/token-decoder.module.scss b/src/features/decoder/components/token-decoder.module.scss index 39909fa57..b57e7dc28 100644 --- a/src/features/decoder/components/token-decoder.module.scss +++ b/src/features/decoder/components/token-decoder.module.scss @@ -1,2 +1,32 @@ @use "@/libs/theme/styles/variables" as *; @use "@/libs/theme/styles/mixins" as *; + +.input__description { + display: flex; + width: calc(100% - 2rem); + max-width: 1312px; + flex-direction: column; + grid-row-gap: 0; + margin: 0 auto 2rem; + color: var(--color_fg_default); + font-size: .875rem; + line-height: 1.375rem; + margin-bottom: .5rem; + + & strong { + font-weight: 500; + } + + @media #{$breakpoint-dimension-sm} { + width: calc(100% - 4rem); + grid-column: span 12; + flex-direction: row; + align-items: center; + justify-content: space-between; + } + + @media #{$breakpoint-dimension-lg} { + width: calc(100% - 8rem); + } + +} \ No newline at end of file diff --git a/src/features/encoder/components/encoded-jwt-output.component.tsx b/src/features/encoder/components/encoded-jwt-output.component.tsx index 6f167a10f..3a01b5d7f 100644 --- a/src/features/encoder/components/encoded-jwt-output.component.tsx +++ b/src/features/encoder/components/encoded-jwt-output.component.tsx @@ -6,6 +6,7 @@ import { HomeDictionaryModel } from "@/features/localization/models/home-diction import { dataTestidDictionary } from "@/libs/testing/data-testid.dictionary"; import { CardToolbarComponent } from "@/features/common/components/card-toolbar/card-toolbar.component"; import { CardToolbarCopyButtonComponent } from "@/features/common/components/card-toolbar-buttons/card-toolbar-copy-button/card-toolbar-copy-button.component"; +import styles from "./encoded-jwt-output.module.scss"; type EncodedJwtOutputComponentProps = { languageCode: string; @@ -20,28 +21,32 @@ export const EncodedJwtOutputComponent: React.FC< const encodingErrors = useEncoderStore((state) => state.encodingErrors); return ( - - - - ), - }} - > - - + <> +

{dictionary.heading}

+ + + + ), + }} + > + + + ); }; diff --git a/src/features/encoder/components/encoded-jwt-output.module.scss b/src/features/encoder/components/encoded-jwt-output.module.scss new file mode 100644 index 000000000..3e2c03440 --- /dev/null +++ b/src/features/encoder/components/encoded-jwt-output.module.scss @@ -0,0 +1,14 @@ +@use "@/libs/theme/styles/variables" as *; +@use "@/libs/theme/styles/mixins" as *; + +.headline { + display: flex; + grid-column: 1/-1; + width: 100%; + font-size: 1rem; + font-weight: 700; + line-height: 1.15; + letter-spacing: -.1px; + color: var(--color_fg_default); + padding-bottom: 0.5rem; +} \ No newline at end of file diff --git a/src/features/encoder/components/token-encoder-encoding-format-picker.component.tsx b/src/features/encoder/components/token-encoder-encoding-format-picker.component.tsx deleted file mode 100644 index 631dd252b..000000000 --- a/src/features/encoder/components/token-encoder-encoding-format-picker.component.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import React, { useEffect, useState } from "react"; -import styles from "./token-encoder-encoding-format-picker.module.scss"; -import { EncodingValues } from "@/features/common/values/encoding.values"; -import { useEncoderStore } from "@/features/encoder/services/encoder.store"; -import { getPickersUiDictionary } from "@/features/localization/services/ui-language-dictionary.service"; -import { DebuggerPickerComponent } from "@/features/common/components/debugger-picker/debugger-picker.component"; - -interface TokenEncoderEncodingFormatPickerComponentProps { - languageCode: string; -} - -export const TokenEncoderEncodingFormatPickerComponent: React.FC< - TokenEncoderEncodingFormatPickerComponentProps -> = ({ languageCode }) => { - const dictionary = getPickersUiDictionary(languageCode); - - const handleSymmetricSecretKeyEncodingChange = useEncoderStore( - (state) => state.handleSymmetricSecretKeyEncodingChange, - ); - const controlledSymmetricSecretKey = useEncoderStore( - (state) => state.controlledSymmetricSecretKey, - ); - - const [secretEncodingFormat, setSecretEncodingFormat] = - useState(EncodingValues.UTF8); - - useEffect(() => { - if (controlledSymmetricSecretKey) { - setSecretEncodingFormat(controlledSymmetricSecretKey.encoding); - } - }, [controlledSymmetricSecretKey]); - - const onSecretEncodingFormatChange = (value: string) => { - setSecretEncodingFormat(value as EncodingValues); - - handleSymmetricSecretKeyEncodingChange(value as EncodingValues); - }; - - return ( -
- -
- ); -}; diff --git a/src/features/encoder/components/token-encoder-encoding-format-picker.module.scss b/src/features/encoder/components/token-encoder-encoding-format-picker.module.scss deleted file mode 100644 index 1429bdc15..000000000 --- a/src/features/encoder/components/token-encoder-encoding-format-picker.module.scss +++ /dev/null @@ -1,70 +0,0 @@ -@use "@/libs/theme/styles/variables" as *; - -.container { - position: relative; - display: flex; - align-items: center; - gap: 0.5rem; - - @media #{$breakpoint-dimension-sm} { - align-self: unset; - } -} - -.label { - color: var(--color_fg_default); - font-size: 0.875rem; - line-height: 1.375rem; - font-weight: 500; - letter-spacing: 0.1px; -} - -.select { - display: flex; - padding: 0.125rem 1.75rem 0.125rem 0.875rem; - align-items: center; - gap: 0.75rem; - align-self: stretch; - - border-radius: 0.25rem; - border: 1px solid var(--color_border_button); - - color: var(--color_fg_default); - font-variant-numeric: slashed-zero; - font-feature-settings: - "clig" off, - "liga" off; - font-size: 0.875rem; - line-height: 1.375rem; - letter-spacing: 0.2px; - appearance: none; - - z-index: 2; - - background-color: transparent; -} - -.icon { - position: absolute; - top: 50%; - right: 0.5rem; - transform: translateY(-40%); - - svg { - height: 1rem; - width: 1rem; - - path { - fill: var(--color_fg_default); - } - } - - @media #{$breakpoint-dimension-sm} { - transform: translateY(-45%); - - svg { - height: 1.25rem; - width: 1.25rem; - } - } -} diff --git a/src/features/encoder/components/token-encoder-input.component.tsx b/src/features/encoder/components/token-encoder-input.component.tsx index e33005514..46f63c23b 100644 --- a/src/features/encoder/components/token-encoder-input.component.tsx +++ b/src/features/encoder/components/token-encoder-input.component.tsx @@ -1,13 +1,18 @@ "use client"; -import React, { ChangeEvent, useCallback, useEffect, useState } from "react"; +import React, { + ChangeEvent, + Fragment, + useCallback, + useEffect, + useState, +} from "react"; import { HeaderEditorComponent } from "@/features/encoder/components/header-editor.component"; import { CardComponent, CardComponentProps, } from "@/features/common/components/card/card.component"; import { PayloadEditorComponent } from "@/features/encoder/components/payload-editor.component"; -import { TokenEncoderEncodingFormatPickerComponent } from "@/features/encoder/components/token-encoder-encoding-format-picker.component"; import { TokenEncoderKeyFormatPickerComponent } from "@/features/encoder/components/token-encoder-key-format-picker.component"; import { SigningSecretEditorComponent } from "@/features/encoder/components/signing-secret-editor.component"; import { SigningPrivateKeyEditorComponent } from "@/features/encoder/components/signing-private-key-editor.component"; @@ -28,6 +33,7 @@ import { import { dataTestidDictionary } from "@/libs/testing/data-testid.dictionary"; import { CardToolbarComponent } from "@/features/common/components/card-toolbar/card-toolbar.component"; import { CardToolbarClearButtonComponent } from "@/features/common/components/card-toolbar-buttons/card-toolbar-clear-button/card-toolbar-clear-button.component"; +import { EncodingFormatToggleSwitchComponent } from "@/features/decoder/components/encoding-format-toggle-swith/encoding-format-toggle-switch"; type HeaderInputComponentProps = { languageCode: string; @@ -41,32 +47,32 @@ export const TokenEncoderInputComponent: React.FC< const headerErrors$ = useEncoderStore((state) => state.headerErrors && state.headerErrors.length > 0 ? state.headerErrors - : null, + : null ); const headerWarnings$ = useEncoderStore((state) => state.headerWarnings && state.headerWarnings.length > 0 ? state.headerWarnings - : null, + : null ); const payloadErrors$ = useEncoderStore((state) => state.payloadErrors && state.payloadErrors.length > 0 ? state.payloadErrors - : null, + : null ); const signingErrors$ = useEncoderStore((state) => state.signingErrors && state.signingErrors.length > 0 ? state.signingErrors - : null, + : null ); const controlledHeader$ = useEncoderStore((state) => state.controlledHeader); const controlledPayload$ = useEncoderStore( - (state) => state.controlledPayload, + (state) => state.controlledPayload ); const controlledSymmetricSecretKey$ = useEncoderStore( - (state) => state.controlledSymmetricSecretKey, + (state) => state.controlledSymmetricSecretKey ); const controlledAsymmetricPrivateKey$ = useEncoderStore( - (state) => state.controlledAsymmetricPrivateKey, + (state) => state.controlledAsymmetricPrivateKey ); const [header, setHeader] = useState(DEFAULT_HEADER); @@ -95,28 +101,28 @@ export const TokenEncoderInputComponent: React.FC< }, [controlledAsymmetricPrivateKey$]); const handleHeaderChange$ = useEncoderStore( - (state) => state.handleHeaderChange, + (state) => state.handleHeaderChange ); const resetControlledHeader$ = useEncoderStore( - (state) => state.resetControlledHeader, + (state) => state.resetControlledHeader ); const handlePayloadChange$ = useEncoderStore( - (state) => state.handlePayloadChange, + (state) => state.handlePayloadChange ); const resetControlledPayload$ = useEncoderStore( - (state) => state.resetControlledPayload, + (state) => state.resetControlledPayload ); const handleSymmetricSecretKeyChange$ = useEncoderStore( - (state) => state.handleSymmetricSecretKeyChange, + (state) => state.handleSymmetricSecretKeyChange ); const resetControlledSymmetricSecretKey$ = useEncoderStore( - (state) => state.resetControlledSymmetricSecretKey, + (state) => state.resetControlledSymmetricSecretKey ); const handleAsymmetricPrivateKeyChange$ = useEncoderStore( - (state) => state.handleAsymmetricPrivateKeyChange, + (state) => state.handleAsymmetricPrivateKeyChange ); const resetControlledAsymmetricPrivateKey$ = useEncoderStore( - (state) => state.resetControlledAsymmetricPrivateKey, + (state) => state.resetControlledAsymmetricPrivateKey ); const clearHeader = async () => { @@ -153,7 +159,7 @@ export const TokenEncoderInputComponent: React.FC< handleHeaderChange$(cleanValue); }, - [handleHeaderChange$], + [handleHeaderChange$] ); const handlePayloadChange = useCallback( @@ -164,11 +170,11 @@ export const TokenEncoderInputComponent: React.FC< handlePayloadChange$(cleanValue); }, - [handlePayloadChange$], + [handlePayloadChange$] ); const handleSymmetricSecretKeyChange = async ( - e: ChangeEvent, + e: ChangeEvent ) => { const key = e.target.value; @@ -180,7 +186,7 @@ export const TokenEncoderInputComponent: React.FC< }; const handleAsymmetricPrivateKeyChange = async ( - e: ChangeEvent, + e: ChangeEvent ) => { const key = e.target.value; @@ -197,6 +203,7 @@ export const TokenEncoderInputComponent: React.FC< languageCode: languageCode, title: dictionary.headerEditor.title, compactTitle: dictionary.headerEditor.compactTitle, + hasHeaderIcon: true, children: ( ), + hasHeaderIcon: true, messages: { success: [dictionary.payloadEditor.successMessage], errors: payloadErrors$, @@ -255,6 +263,7 @@ export const TokenEncoderInputComponent: React.FC< cards.push({ id: dataTestidDictionary.encoder.secretKeyEditor.id, languageCode: languageCode, + hasHeaderIcon: true, title: isHmacAlg(alg$) ? dictionary.signatureEditor.title.secret : dictionary.signatureEditor.title.privateKey, @@ -307,13 +316,6 @@ export const TokenEncoderInputComponent: React.FC< /> ), - footer: isHmacAlg(alg$) ? ( - - ) : ( - - ), }, }); } @@ -322,7 +324,26 @@ export const TokenEncoderInputComponent: React.FC< <>
{cards.map((props) => ( - + + {props.id === dataTestidDictionary.encoder.secretKeyEditor.id ? ( +
+

{props.compactTitle}

+ {isHmacAlg(alg$) ? ( + + ) : ( + + )} +
+ ) : ( +

{props.compactTitle}

+ )} + +
))}
diff --git a/src/features/encoder/components/token-encoder-input.module.scss b/src/features/encoder/components/token-encoder-input.module.scss index 7ddf3a0df..30c16d152 100644 --- a/src/features/encoder/components/token-encoder-input.module.scss +++ b/src/features/encoder/components/token-encoder-input.module.scss @@ -24,3 +24,21 @@ display: none; } } +.headline_container { + display: flex; + grid-column: 1/-1; + width: 100%; + justify-content: space-between; + align-items: center; +} + +.headline { + display: flex; + grid-column: 1/-1; + width: 100%; + font-size: 1rem; + font-weight: 700; + line-height: 1.15; + letter-spacing: -.1px; + color: var(--color_fg_default); +} \ No newline at end of file diff --git a/src/features/encoder/components/token-encoder-key-format-picker.component.tsx b/src/features/encoder/components/token-encoder-key-format-picker.component.tsx index 523bcfc9b..a005f448a 100644 --- a/src/features/encoder/components/token-encoder-key-format-picker.component.tsx +++ b/src/features/encoder/components/token-encoder-key-format-picker.component.tsx @@ -15,14 +15,14 @@ export const TokenEncoderKeyFormatPickerComponent: React.FC< const dictionary = getPickersUiDictionary(languageCode); const handlePrivateKeyFormatChange = useEncoderStore( - (state) => state.handleAsymmetricPrivateKeyFormatChange, + (state) => state.handleAsymmetricPrivateKeyFormatChange ); const controlledAsymmetricPrivateKey$ = useEncoderStore( - (state) => state.controlledAsymmetricPrivateKey, + (state) => state.controlledAsymmetricPrivateKey ); const [keyFormat, setKeyFormat] = useState( - AsymmetricKeyFormatValues.PEM, + AsymmetricKeyFormatValues.PEM ); useEffect(() => { @@ -38,28 +38,32 @@ export const TokenEncoderKeyFormatPickerComponent: React.FC< }; return ( -
- +
+
+
+ +
+
); }; diff --git a/src/features/encoder/components/token-encoder-key-format-picker.module.scss b/src/features/encoder/components/token-encoder-key-format-picker.module.scss index 1429bdc15..f292b294f 100644 --- a/src/features/encoder/components/token-encoder-key-format-picker.module.scss +++ b/src/features/encoder/components/token-encoder-key-format-picker.module.scss @@ -1,22 +1,47 @@ @use "@/libs/theme/styles/variables" as *; + +.encoder__switch { + display: flex; + width: 100%; + justify-content: flex-end; +} + .container { position: relative; display: flex; align-items: center; - gap: 0.5rem; + gap: .5rem; @media #{$breakpoint-dimension-sm} { align-self: unset; } } +.picker { + position: relative; + display: flex; + justify-content: space-between; + align-items: center; + background: transparent; + border: none; + color: var(--color_fg_bold); + gap: .75rem; + width: 100%; +} + .label { - color: var(--color_fg_default); - font-size: 0.875rem; - line-height: 1.375rem; - font-weight: 500; - letter-spacing: 0.1px; + display: flex; + align-items: center; + justify-content: flex-start; + padding: 0; + list-style-type: none; + margin: 0; + gap: .5rem; + font-size: .875rem; + line-height: 1.35; + width: 100%; + height: 100%; } .select { diff --git a/src/features/encoder/components/token-encoder.component.tsx b/src/features/encoder/components/token-encoder.component.tsx index d2a045bf7..6ebe901d0 100644 --- a/src/features/encoder/components/token-encoder.component.tsx +++ b/src/features/encoder/components/token-encoder.component.tsx @@ -1,6 +1,7 @@ "use client"; import React, { useEffect, useRef } from "react"; +import styles from "./token-encoder.module.scss" import { EncodedJwtOutputComponent } from "@/features/encoder/components/encoded-jwt-output.component"; import { TokenEncoderInputComponent } from "@/features/encoder/components/token-encoder-input.component"; import { useEncoderStore } from "@/features/encoder/services/encoder.store"; @@ -10,6 +11,7 @@ import { SigningAlgCategoryValues } from "@/features/common/values/signing-alg-c import { WidgetComponent } from "@/features/common/components/widget/widget/widget.component"; import { dataTestidDictionary } from "@/libs/testing/data-testid.dictionary"; import { DebuggerWidgetValues } from "@/features/common/values/debugger-widget.values"; +import { WidgetAlgPickerComponent } from "@/features/debugger/components/debugger-alg-picker/debugger-alg-picker.component"; interface TokenEncoderComponentProps { languageCode: string; @@ -99,27 +101,37 @@ export const TokenEncoderComponent: React.FC = ({ }, [encoderInputs$, loadEncoderInputs, headlineConfig.isVisible]); return ( - +
+ {dictionary.description} + - } - contentOutput={ - - } - warnings={encodingWarnings$} - /> +
+ + } + contentOutput={ + + } + warnings={encodingWarnings$} + /> + ); }; diff --git a/src/features/encoder/components/token-encoder.module.scss b/src/features/encoder/components/token-encoder.module.scss new file mode 100644 index 000000000..b57e7dc28 --- /dev/null +++ b/src/features/encoder/components/token-encoder.module.scss @@ -0,0 +1,32 @@ +@use "@/libs/theme/styles/variables" as *; +@use "@/libs/theme/styles/mixins" as *; + +.input__description { + display: flex; + width: calc(100% - 2rem); + max-width: 1312px; + flex-direction: column; + grid-row-gap: 0; + margin: 0 auto 2rem; + color: var(--color_fg_default); + font-size: .875rem; + line-height: 1.375rem; + margin-bottom: .5rem; + + & strong { + font-weight: 500; + } + + @media #{$breakpoint-dimension-sm} { + width: calc(100% - 4rem); + grid-column: span 12; + flex-direction: row; + align-items: center; + justify-content: space-between; + } + + @media #{$breakpoint-dimension-lg} { + width: calc(100% - 8rem); + } + +} \ No newline at end of file diff --git a/src/features/home/components/assets/assets.component.tsx b/src/features/home/components/assets/assets.component.tsx index e1ba6e3a7..441e7795d 100644 --- a/src/features/home/components/assets/assets.component.tsx +++ b/src/features/home/components/assets/assets.component.tsx @@ -16,139 +16,53 @@ import iconWithLabelImg from "./jwt-label.icon.png"; import { createUrlPath } from "@/libs/utils/path.utils"; import { DEFAULT_LANGUAGE_CODE } from "@/features/localization/localization.config"; import { Button } from "react-aria-components"; - -interface DownloadButtonProps { - asset: StaticImageData; - filename: string; -} - -const DownloadButton: React.FC = ({ asset, filename }) => { - const downloadSVG = useCallback( - (image: StaticImageData, filename: string) => { - const link = document.createElement("a"); - link.href = image.src; - link.download = filename; - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); - }, - [], - ); - - return ( - - ); -}; +import { ArrowHeadIconComponent } from "@/features/common/assets/arrow-head-icon.component"; +import { Auth0DictionaryModel } from "@/features/localization/models/auth0-dictionary.model"; +import { Auth0CtaComponent } from "@/features/common/components/auth0-cta/auth0-cta.component"; type AssetsComponentProps = { languageCode: string; - dictionary: JwtDictionaryModel; + jwtDictionary: JwtDictionaryModel; + auth0Dictionary: Auth0DictionaryModel; }; export const AssetsComponent: React.FC = ({ languageCode, - dictionary, + jwtDictionary, + auth0Dictionary, }) => { const libraryLinkPath = createUrlPath([ languageCode === DEFAULT_LANGUAGE_CODE ? "" : languageCode, - dictionary.libraries.ctaButton.path - ? dictionary.libraries.ctaButton.path + jwtDictionary.libraries.ctaButton.path + ? jwtDictionary.libraries.ctaButton.path : "", ]); return ( - +

- {dictionary.libraries.title} + {jwtDictionary.libraries.title}

- {dictionary.libraries.description} + {jwtDictionary.libraries.description}

- {dictionary.libraries.ctaButton.label} + {jwtDictionary.libraries.ctaButton.label} +
-
-

- {dictionary.assets.badges.title} -

-
-
- {dictionary.assets.badges.images.viewOn.alt} - -
-
- {dictionary.assets.badges.images.compatible.alt} - -
-
-
-
-

- {dictionary.assets.logotype.title} -

-
-
- {dictionary.assets.logotype.images.icon.alt} - -
-
- {dictionary.assets.logotype.images.iconWithLabel.alt} - -
-
-
- + +
); }; diff --git a/src/features/home/components/assets/assets.module.scss b/src/features/home/components/assets/assets.module.scss index b4d0b4080..5654af3f8 100644 --- a/src/features/home/components/assets/assets.module.scss +++ b/src/features/home/components/assets/assets.module.scss @@ -6,22 +6,45 @@ } .content { - @include InnerContentGrid; - padding-top: 4rem; - padding-bottom: 4rem; + display: flex; + width: calc(100% - 2rem); + max-width: 1312px; + margin: 0 auto; + flex-direction: column; row-gap: 2rem; + @media #{$breakpoint-dimension-sm} { + width: calc(100% - 4rem); + grid-template-columns: repeat(12,minmax(0,1fr)); + } + + @media #{$breakpoint-dimension-lg} { + width: calc(100% - 128px); + display: grid; + grid-template-columns: repeat(12, minmax(0, 1fr)); + grid-column-gap: 1rem; + column-gap: 1rem; + width: calc(100% - 2rem); + max-width: 1312px; + margin: 0 auto; + grid-row-gap: unset; row-gap: unset; } + } .assets__column { - grid-column: span 6; + grid-column: span 1; color: var(--color_fg_default); display: flex; flex-direction: column; gap: 1.25rem; + border: 1px solid var(--color_border_default); + border-radius: 1rem; + padding: 2.5rem; + background-color: var(--color_bg_layer); + box-shadow: 0 2px 12px -4px rgba(0,0,0,.08),0 2px 1px -.5px rgba(0,0,0,.04),0 2px 4px -4px rgba(0,0,0,.05),inset -.5px -.5px 2px rgba(0,0,0,.04); @media #{$breakpoint-dimension-sm} { grid-column: span 4; @@ -30,14 +53,19 @@ } .assets__title { - color: var(--color_fg_bold); + width: 100%; + margin: 0; + text-align: left; font-size: 1.5rem; - line-height: 2rem; - font-style: normal; + line-height: 1.15; font-weight: 500; - letter-spacing: -0.5px; + color: var(--color_fg_bold); + font-feature-settings: lining-nums proportional-nums; + font-variant-numeric: lining-nums proportional-nums; + font-style: normal; - @media #{$breakpoint-dimension-sm} { + @media #{$breakpoint-dimension-lg} { + font-size: 2.5rem; } } @@ -49,22 +77,19 @@ .asset__link { width: fit-content; display: flex; - height: 48px; - padding: 1rem 1rem; + padding: .25rem .75rem; justify-content: center; align-items: center; - gap: 0.5rem; - - border-radius: 6px; - background: var(--color_bg_button_primary); - color: var(--color_fg_on_button_primary); - border: 1px solid var(--color_border_button); - - font-size: 1rem; - font-style: normal; - font-weight: 400; - line-height: 1.5rem; - letter-spacing: 0.32px; + gap: .25rem; + border-radius: 9999px; + background: var(--color_bg_layer); + border: 1px solid var(--color_border_default); + font-size: .875rem; + font-weight: 700; + line-height: 1.375rem; + font-weight: 500; + letter-spacing: -.2px; + transition: all .3s ease-in-out; &:focus-visible { outline: solid 1px var(--color_border_focus); @@ -72,6 +97,12 @@ border-radius: 0.125rem; } + &:hover { + border: 1px solid var(--color_border_bold); + box-shadow: 0 0 0 4px rgba(0,0,0,.12); + transition: all .2s ease-out; + } + @media #{$breakpoint-dimension-sm} { margin-top: 40px; } @@ -114,19 +145,3 @@ padding: 2rem 15px; } } - -.downloadButton { - background: var(--color_bg_layer); - border-radius: 0.25rem; - outline: none; - border: none; - - height: 2rem; - width: 2rem; - - &:focus-visible { - outline: solid 1px var(--color_border_focus); - outline-offset: 0.125rem; - border-radius: 0.125rem; - } -} diff --git a/src/features/home/components/home-page/home-page.component.tsx b/src/features/home/components/home-page/home-page.component.tsx index ab9f907bb..6ec77ab50 100644 --- a/src/features/home/components/home-page/home-page.component.tsx +++ b/src/features/home/components/home-page/home-page.component.tsx @@ -1,6 +1,6 @@ import React from "react"; +import styles from "./home-page.module.scss" import { HeroComponent } from "@/features/common/components/hero/hero.component"; -import { Auth0CtaComponent } from "@/features/common/components/auth0-cta/auth0-cta.component"; import { getHomeDictionary, getJwtDictionary, @@ -8,7 +8,6 @@ import { import { AssetsComponent } from "@/features/home/components/assets/assets.component"; import { EbookComponent } from "@/features/common/components/ebook/ebook.component"; import { StructuredData } from "@/features/seo/components/structured-data.component"; -import { HeroModalStateValues } from "@/features/home/values/hero-modal-state.values"; import { ClaimDescriptionVisibilityValues } from "@/features/common/values/claim-description-visibility.values"; import { DebuggerWidgetComponent } from "@/features/debugger/components/debugger-widget/debugger-widget.component"; import { getAuth0Dictionary } from "@/features/localization/services/ui-language-dictionary.service"; @@ -19,8 +18,6 @@ interface HomePageComponentProps { decodedPayloadInitialTabId: string; decodedHeaderDescriptionVisibility: ClaimDescriptionVisibilityValues; decodedPayloadDescriptionVisibility: ClaimDescriptionVisibilityValues; - jwtInfoState: HeroModalStateValues; - jwtWarningState: HeroModalStateValues; // debuggerInitialMode: DebuggerModeValues; } @@ -30,8 +27,6 @@ export const HomePageComponent: React.FC = ({ decodedPayloadInitialTabId, decodedHeaderDescriptionVisibility, decodedPayloadDescriptionVisibility, - jwtInfoState, - jwtWarningState, // debuggerInitialMode, }) => { const homeDictionary = getHomeDictionary(languageCode); @@ -131,17 +126,10 @@ export const HomePageComponent: React.FC = ({ }, ]} /> +

{homeDictionary.metadata.title}

= ({ dictionary={auth0Dictionary.ebook} /> - {/**/} diff --git a/src/features/home/components/home-page/home-page.module.scss b/src/features/home/components/home-page/home-page.module.scss index 204049cc2..21eb3d364 100644 --- a/src/features/home/components/home-page/home-page.module.scss +++ b/src/features/home/components/home-page/home-page.module.scss @@ -1,2 +1,11 @@ -.container { +.visually_hidden { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0,0,0,0); + white-space: nowrap; + border: 0 } \ No newline at end of file diff --git a/src/features/home/config/home.config.ts b/src/features/home/config/home.config.ts deleted file mode 100644 index 7aa5eaf45..000000000 --- a/src/features/home/config/home.config.ts +++ /dev/null @@ -1,2 +0,0 @@ -export const JWT_INFO_STATE_KEY = "jwt-info-state"; -export const JWT_WARNING_STATE_KEY = "jwt-warning-state"; diff --git a/src/features/home/values/hero-modal-state.values.ts b/src/features/home/values/hero-modal-state.values.ts deleted file mode 100644 index af1a0f152..000000000 --- a/src/features/home/values/hero-modal-state.values.ts +++ /dev/null @@ -1,4 +0,0 @@ -export enum HeroModalStateValues { - OPEN = "open", - CLOSED = "closed", -} diff --git a/src/features/home/values/hero-modal-type.values.ts b/src/features/home/values/hero-modal-type.values.ts deleted file mode 100644 index 6d8a21678..000000000 --- a/src/features/home/values/hero-modal-type.values.ts +++ /dev/null @@ -1,4 +0,0 @@ -export enum HeroModalTypeValues { - INFO = "info", - WARNING = "warning", -} diff --git a/src/features/introduction/components/ebook-ad/ebook-ad.component.tsx b/src/features/introduction/components/ebook-ad/ebook-ad.component.tsx index 574ad88a0..9a9092f14 100644 --- a/src/features/introduction/components/ebook-ad/ebook-ad.component.tsx +++ b/src/features/introduction/components/ebook-ad/ebook-ad.component.tsx @@ -8,7 +8,7 @@ type EbookAdComponentProps = { export const EbookAdComponent: React.FC = ({ copy }) => { return ( - +

{copy}

); diff --git a/src/features/introduction/components/ebook-ad/ebook-ad.module.scss b/src/features/introduction/components/ebook-ad/ebook-ad.module.scss index bcb519a5d..21e2db10c 100644 --- a/src/features/introduction/components/ebook-ad/ebook-ad.module.scss +++ b/src/features/introduction/components/ebook-ad/ebook-ad.module.scss @@ -1,23 +1,29 @@ @use "@/libs/theme/styles/variables" as *; @use "@/libs/theme/styles/mixins" as *; +.container { + margin-bottom: 1.5rem; +} + .content { @include InnerContentFlex; position: relative; max-width: $article-max-width; - - background: linear-gradient(290deg, #f4d -18.75%, #3f59e4 98.79%); - - border-radius: 0.5rem; padding: 1rem; - margin: 1rem auto 2rem auto; - color: $Neutral0; - font-size: 1rem; - line-height: 1.25rem; + border-radius: 1rem; + border: 1px solid var(--color_border_default); + box-shadow: + 0 0 0 0.5px rgba(0, 0, 0, 0.12), + 0 2px 2px -1px rgba(0, 0, 0, 0.04), + 0 4px 4px -2px rgba(0, 0, 0, 0.04), + 0 6px 6px -3px rgba(0, 0, 0, 0.04); } .copy { font-weight: 400; + line-height: 1.25rem; + font-size: 0.875rem; + color: var(--color_fg_default); & strong { font-weight: 500; diff --git a/src/features/introduction/components/introduction-article/introduction-article.component.tsx b/src/features/introduction/components/introduction-article/introduction-article.component.tsx index e121b5e0d..6d14b06a4 100644 --- a/src/features/introduction/components/introduction-article/introduction-article.component.tsx +++ b/src/features/introduction/components/introduction-article/introduction-article.component.tsx @@ -5,20 +5,30 @@ import { getIntroductionContent } from "@/features/localization/services/ui-lang import { ArticleComponent } from "@/features/common/components/article/article.component"; import styles from "./introduction-article.module.scss"; import { SidebarNavComponent } from "../sidebar-nav/sidebar-nav.component"; +import { EbookAdComponent } from "../ebook-ad/ebook-ad.component"; +import { getComponentDictionary } from "@/features/localization/services/component-dictionary.service"; +import { IntroductionDictionaryModel } from "@/features/localization/models/introduction-dictionary.model"; +import { IntroductionHeroComponent } from "../introduction-hero/introduction-hero.component"; interface IntroductionArticleComponentProps { languageCode: string; + introductionDictionary: IntroductionDictionaryModel; } export const IntroductionArticleComponent: React.FC< IntroductionArticleComponentProps -> = ({ languageCode }) => { +> = ({ languageCode, introductionDictionary }) => { const Introduction = getIntroductionContent({ languageCode }); + const componentDictionary = getComponentDictionary(languageCode); return (
- - {Introduction} + +
+ + + {Introduction} +
); }; diff --git a/src/features/introduction/components/introduction-article/introduction-article.module.scss b/src/features/introduction/components/introduction-article/introduction-article.module.scss index 3c8d256ff..6fd1e2cec 100644 --- a/src/features/introduction/components/introduction-article/introduction-article.module.scss +++ b/src/features/introduction/components/introduction-article/introduction-article.module.scss @@ -1,11 +1,24 @@ @use "@/libs/theme/styles/variables" as *; +@use "@/libs/theme/styles/mixins" as *; .container { - min-height: 100vh; - display: flex; - flex-direction: column; - - @media #{$breakpoint-dimension-sm} { - flex-direction: row; - } + @include InnerContentFlex; + justify-content: start; + margin-bottom: 5rem; } + +.title { + color: var(--color_fg_bold); + font-size: 2rem; + line-height: 2.5rem; + font-weight: 400; + letter-spacing: -0.96px; + + @media #{$breakpoint-dimension-xs} { + font-size: 2.5rem; + } + + @media #{$breakpoint-dimension-sm} { + font-size: 3rem; + } +} \ No newline at end of file diff --git a/src/features/introduction/components/introduction-hero/introduction-hero.module.scss b/src/features/introduction/components/introduction-hero/introduction-hero.module.scss index 02baf3c48..1f12e8b2d 100644 --- a/src/features/introduction/components/introduction-hero/introduction-hero.module.scss +++ b/src/features/introduction/components/introduction-hero/introduction-hero.module.scss @@ -3,32 +3,23 @@ .container { @include Container; - - background: var(--color_bg_page); - border-bottom: 1px solid var(--color_border_bold); + margin: 1.5rem 0rem; } .content { @include InnerContentFlex; - flex-direction: column; - align-items: center; - - padding-top: 2.5rem; - padding-bottom: 2.5rem; - - @media #{$breakpoint-dimension-xs} { - padding-top: 4.5rem; - padding-bottom: 4.5rem; - } } .title { + width: 100%; color: var(--color_fg_bold); - text-align: center; + text-align: left; font-size: 2rem; - line-height: 2.5rem; - font-weight: 400; - letter-spacing: -0.96px; + line-height: 1.15; + font-weight: 500; + letter-spacing: -.96px; + max-width: 42rem; + text-wrap-style: balance; @media #{$breakpoint-dimension-xs} { font-size: 2.5rem; diff --git a/src/features/introduction/components/introduction-page/introduction-page.component.tsx b/src/features/introduction/components/introduction-page/introduction-page.component.tsx index 7e4a65a46..17ed41fed 100644 --- a/src/features/introduction/components/introduction-page/introduction-page.component.tsx +++ b/src/features/introduction/components/introduction-page/introduction-page.component.tsx @@ -4,10 +4,7 @@ import { generateArticleStructuredData } from "@/features/seo/services/structure import { Auth0CtaComponent } from "@/features/common/components/auth0-cta/auth0-cta.component"; import { getIntroductionDictionary } from "@/features/localization/services/language-dictionary.service"; import { IntroductionArticleComponent } from "@/features/introduction/components/introduction-article/introduction-article.component"; -import { IntroductionHeroComponent } from "@/features/introduction/components/introduction-hero/introduction-hero.component"; -import { EbookAdComponent } from "@/features/introduction/components/ebook-ad/ebook-ad.component"; import { getAuth0Dictionary } from "@/features/localization/services/ui-language-dictionary.service"; -import { getComponentDictionary } from "@/features/localization/services/component-dictionary.service"; interface IntroductionPageComponentProps { languageCode: string; @@ -18,7 +15,6 @@ export const IntroductionPageComponent: React.FC< > = ({ languageCode }) => { const introductionDictionary = getIntroductionDictionary(languageCode); const auth0Dictionary = getAuth0Dictionary(languageCode); - const componentDictionary = getComponentDictionary(languageCode); return ( <> @@ -121,12 +117,10 @@ export const IntroductionPageComponent: React.FC< }), ]} /> - - - { @@ -18,9 +18,8 @@ const scrollToElementWithOffset = (id: string, offset = 0) => { }; export const SidebarNavComponent: React.FC = ({ - languageCode, + introductionDictionary, }) => { - const introductionDictionary = getIntroductionDictionary(languageCode); const headings = introductionDictionary.content.headings; const [activeId, setActiveId] = useState(null); diff --git a/src/features/introduction/components/sidebar-nav/sidebar-nav.module.scss b/src/features/introduction/components/sidebar-nav/sidebar-nav.module.scss index 9902c7575..b6ed7a7b5 100644 --- a/src/features/introduction/components/sidebar-nav/sidebar-nav.module.scss +++ b/src/features/introduction/components/sidebar-nav/sidebar-nav.module.scss @@ -1,33 +1,35 @@ @use "@/libs/theme/styles/variables" as *; .container { - display:none; - @media #{$breakpoint-dimension-sm} { - display: inline-block; - height: 100vh; - position: sticky; - color: var(--color_fg_link); - flex-shrink: 0; - top: 0; - padding: 160px 30px 0px; - margin-bottom: 100px; - border-right: 1px solid var(--color_border_bold); - max-width: 250px; - overflow-y: auto; - } + display: none; + + @media #{$breakpoint-dimension-sm} { + display: block; + flex-shrink: 1; + position: sticky; + color: var(--color_fg_link); + margin: 2rem 0rem;; + padding: 0rem 1rem; + top: $main-nav-height + 2rem; // additional value must be equal to top margin + top padding + border-right: 1px solid var(--color_border_bold); + font-size: 0.875rem; + max-width: 20rem; + height: fit-content; + } } .title { - margin-bottom: 36px; - padding-right: 8px; - cursor: pointer; + cursor: pointer; } .title__active { - color: var(--color_fg_selected); - border-bottom: 1px solid var(--color_border_selected); + color: var(--color_fg_selected); + text-decoration: underline; } .list { - list-style-type: none; + list-style-type: none; + display: flex; + flex-direction: column; + gap: 2rem; } diff --git a/src/features/libraries/components/check-mark.component.tsx b/src/features/libraries/components/check-mark.component.tsx index 9c2b96cdc..3a35d09ee 100644 --- a/src/features/libraries/components/check-mark.component.tsx +++ b/src/features/libraries/components/check-mark.component.tsx @@ -1,25 +1,23 @@ import React from "react"; +import styles from "./check-mark.module.scss"; type CheckMarkComponentProps = {}; export const CheckMarkComponent: React.FC = () => { return ( - + ); diff --git a/src/features/libraries/components/check-mark.module.scss b/src/features/libraries/components/check-mark.module.scss new file mode 100644 index 000000000..b60d1611b --- /dev/null +++ b/src/features/libraries/components/check-mark.module.scss @@ -0,0 +1,5 @@ +@use "@/libs/theme/styles/variables" as *; + +.check { + color: var(--color_bg_state_success); +} \ No newline at end of file diff --git a/src/features/libraries/components/library-card/library-card..module.scss b/src/features/libraries/components/library-card/library-card..module.scss index 53e284ab5..5eb5ca768 100644 --- a/src/features/libraries/components/library-card/library-card..module.scss +++ b/src/features/libraries/components/library-card/library-card..module.scss @@ -4,25 +4,27 @@ grid-column: span 1; display: flex; flex-direction: column; - - border-radius: 1rem; - border: 1px solid var(--color_border_bold); + background-color: var(--color_bg_layer); + border-radius: 1.5rem; + border: 1px solid var(--color_border_default); overflow: hidden; + transition: all .3s ease-out; } .header { display: flex; align-items: center; - gap: 1rem; - padding: 1rem 1.5rem; - color: var(--color_fg_bold); - - font-size: 1rem; + gap: .5rem; + padding: 1rem; font-style: normal; - line-height: 1.25rem; - border-bottom: 1px solid var(--color_border_bold); - background: var(--color_bg_layer_alternate); + span { + color: var(--color_fg_bold); + font-size: .875rem; + font-family: var(--font-primary); + line-height: 1.35; + font-weight: 700; + } } .logo { @@ -34,20 +36,16 @@ .content { display: grid; - grid-template-columns: repeat(2, 1fr); - padding: 1.5rem; - border-bottom: 1px solid var(--color_border_bold); - background: var(--color_bg_layer_alternate); + grid-template-columns: repeat(2,1fr); + padding: 1.5rem 1.5rem 2.5rem; } .minVersion { - grid-column: 1 / -1; - background-color: var(--color_bg_state_caution_subtle); + grid-column: 1/-1; color: var(--color_fg_on_state_caution_subtle); - padding: 0.5rem 1.5rem; - text-transform: uppercase; - font-size: 0.75rem; - letter-spacing: 0.2px; + padding: 1rem; + font-size: .875rem; + letter-spacing: .2px; display: flex; justify-content: space-between; } @@ -63,47 +61,52 @@ display: flex; flex-direction: column; list-style-type: none; - gap: 0.75rem; + gap: 0.5rem; + + & svg { + width: 1.25rem; + height: 1.25rem; + } & li { - height: 1.5rem; + height: 1.25rem; code { - padding: 1px 0.125rem; - border-radius: 0.125rem; - color: var(--color_code_dark_blue); - background-color: var(--color_bg_layer_bold); - font-size: 0.875rem; + padding: .125rem .25rem; + border-radius: .5rem; + color: var(--color_fg_bold); + background-color: var(--color_bg_layer_alternate); + box-shadow: 0 0 0 .5px rgba(0,0,0,.12),0 2px 2px -1px rgba(0,0,0,.04),0 4px 4px -2px rgba(0,0,0,.04); + font-size: .75rem; font-style: normal; font-weight: 500; - line-height: 1.25rem; /* 142.857% */ + line-height: 1.5; } } } -.listItem { +.listItem, .metadata { display: flex; align-items: center; - gap: 0.5rem; color: var(--color_fg_default); + font-size: .875rem; + font-weight: 500; +} + +.listItem { + gap: 0.5rem; } .metadata { - display: flex; - align-items: center; justify-content: space-between; - padding: 1.25rem 1.5rem; - - border-bottom: 1px solid var(--color_border_bold); + padding: .5rem; + width: calc(100% - 1rem); + margin: 0 auto; + border-radius: .5rem; background: var(--color_bg_layer_alternate); - - color: var(--color_fg_default); - font-size: 0.75rem; font-style: normal; - font-weight: 500; line-height: 140%; - letter-spacing: 0.18px; - white-space: nowrap; + letter-spacing: .18px; svg { path { @@ -125,7 +128,7 @@ .repo { display: flex; - gap: 1rem; + gap: 0.5rem; } .repo__stars { @@ -139,23 +142,24 @@ display: flex; align-items: center; line-height: 0; - gap: 0.25rem; + padding: .25rem .5rem; + border-radius: 9999px; + transition: all .2s ease-out; } .command { - flex: 1; display: flex; flex-direction: column; - padding: 1.5rem; - - background: var(--color_bg_code-editor); - color: var(--color_code_inverse); - text-wrap: wrap; - overflow: hidden; - word-break: break-word; - - font-size: 0.75rem; - font-style: normal; - font-weight: 500; - line-height: 1.25rem; + padding: 1rem 1.5rem; + border-bottom: 1px solid var(--color_border_bold); + p { + color: var(--color_fg_bold); + text-wrap: wrap; + overflow: hidden; + word-break: break-word; + font-size: .75rem; + font-style: normal; + font-weight: 300; + line-height: 1.5; + } } diff --git a/src/features/libraries/components/library-card/library-card.component.tsx b/src/features/libraries/components/library-card/library-card.component.tsx index 319bb9884..800054139 100644 --- a/src/features/libraries/components/library-card/library-card.component.tsx +++ b/src/features/libraries/components/library-card/library-card.component.tsx @@ -117,6 +117,48 @@ export const LibraryCardComponent: React.FC = ({ {library.gitHubRepoPath || library.altRepoPath || name} +
+
+ {authorUrl ? ( + +
+ + {authorName} +
+ + ) : ( +
+
+ + {authorName} +
+
+ )} +
+ {support && ( +
+ + {stars} +
+ )} + + + {dictionary.viewRepo.label} + +
+
+
+ {command}
    @@ -187,47 +229,8 @@ export const LibraryCardComponent: React.FC = ({
-
- {authorUrl ? ( - -
- - {authorName} -
- - ) : ( -
-
- - {authorName} -
-
- )} -
- {support && ( -
- - {stars} -
- )} - - - {dictionary.viewRepo.label} - -
-
{minimumVersion && ( -
+
{`${dictionary.minimumVersion.label} ${minimumVersion}`} = ({
)} -
- {command} -
); }; diff --git a/src/features/libraries/components/library-hero/library-hero.component.tsx b/src/features/libraries/components/library-hero/library-hero.component.tsx index 1fda944e6..c91d8424b 100644 --- a/src/features/libraries/components/library-hero/library-hero.component.tsx +++ b/src/features/libraries/components/library-hero/library-hero.component.tsx @@ -64,7 +64,7 @@ export const LibraryHeroComponent: React.FC = ({ const options = useMemo(() => { return [ { - label: "ProgrammingLanguage", + label: "Language", options: [ { value: dictionary.filterPicker.defaultValue.value, diff --git a/src/features/libraries/components/library-hero/library-hero.module.scss b/src/features/libraries/components/library-hero/library-hero.module.scss index dbff04ba2..01153e56a 100644 --- a/src/features/libraries/components/library-hero/library-hero.module.scss +++ b/src/features/libraries/components/library-hero/library-hero.module.scss @@ -44,16 +44,15 @@ .heroTitle { color: var(--color_fg_bold); - font-size: 2rem; font-style: normal; - font-weight: 400; - line-height: 2.5rem; + font-weight: 500; + line-height: 1.15; letter-spacing: -0.8px; @media #{$breakpoint-dimension-xs} { font-size: 2.5rem; - line-height: 3rem; + line-height: 1.15; } } @@ -65,9 +64,10 @@ .label { color: var(--color_fg_bold); - font-size: 1rem; + font-size: .875rem; + font-weight: 700; line-height: 1.5rem; - letter-spacing: 0.1px; + letter-spacing: .1px; } .select__wrapper { diff --git a/src/features/libraries/components/question-mark.component.tsx b/src/features/libraries/components/question-mark.component.tsx index 9e27648e8..2c2380252 100644 --- a/src/features/libraries/components/question-mark.component.tsx +++ b/src/features/libraries/components/question-mark.component.tsx @@ -9,13 +9,12 @@ export const QuestionMarkComponent: React.FC = () => { width="24" height="24" viewBox="0 0 24 24" - fill="none" + fill="currentColor" > ); diff --git a/src/features/libraries/components/x-mark.component.tsx b/src/features/libraries/components/x-mark.component.tsx index dfddcc807..c72312df3 100644 --- a/src/features/libraries/components/x-mark.component.tsx +++ b/src/features/libraries/components/x-mark.component.tsx @@ -1,25 +1,25 @@ import React from "react"; +import styles from "./x-mark.module.scss" type CheckMarkComponentProps = {}; export const XMarkComponent: React.FC = () => { return ( ); diff --git a/src/features/libraries/components/x-mark.module.scss b/src/features/libraries/components/x-mark.module.scss new file mode 100644 index 000000000..4ea752ab0 --- /dev/null +++ b/src/features/libraries/components/x-mark.module.scss @@ -0,0 +1,5 @@ +@use "@/libs/theme/styles/variables" as *; + +.mark { + color: var(--color_bg_state_danger); +} \ No newline at end of file diff --git a/src/features/localization/dictionaries/home/en.ts b/src/features/localization/dictionaries/home/en.ts index 8e437dbe0..236f3cbc5 100644 --- a/src/features/localization/dictionaries/home/en.ts +++ b/src/features/localization/dictionaries/home/en.ts @@ -54,17 +54,8 @@ export const enHomeDictionary: HomeDictionaryModel = { description: null, }, info: { - summary: "What is a JWT?", description: "Decode, verify, and generate JSON Web Tokens, which are an open, industry standard RFC 7519 method for representing claims securely between two parties.", - ctaButton: { - label: "Learn more about JWT", - path: sitePaths.introduction, - }, - secondaryCtaButton: { - label: "See JWT libraries", - path: sitePaths.libraries, - }, resources: { spec: { name: "RFC 7519", @@ -72,13 +63,6 @@ export const enHomeDictionary: HomeDictionaryModel = { }, }, }, - warning: { - summary: "Warning about using JWTs", - title: - "For your protection, all JWT debugging and validation happens in the browser.", - description: - "Be careful where you paste or share JWTs as they can represent credentials that grant access to resources. This site does not store or transmit your JSON Web Tokens outside of the browser.", - }, decoder: { title: "JWT Decoder", compactTitle: "Decoder", @@ -92,11 +76,12 @@ export const enHomeDictionary: HomeDictionaryModel = { label: "JWT example generator", }, jwtEditor: { - headline: "Encoded value", + headline: "Encoded Token", label: "JWT editor", title: "JSON Web Token (JWT)", compactTitle: "JWT", successMessage: "Valid JWT", + autoFocusLabel: "Enable auto-focus", }, decodedHeader: { title: "Decoded Header", @@ -105,7 +90,7 @@ export const enHomeDictionary: HomeDictionaryModel = { label: "JSON", }, claims: { - label: "Claims Table", + label: "Claims Breakdown", }, }, }, @@ -116,7 +101,7 @@ export const enHomeDictionary: HomeDictionaryModel = { label: "JSON", }, claims: { - label: "Claims Table", + label: "Claims Breakdown", }, }, }, @@ -157,18 +142,18 @@ export const enHomeDictionary: HomeDictionaryModel = { label: "Header, payload, and signature example generator", }, headerEditor: { - title: "Header: Algorithm & Token Type", + title: "Algorithm & Token Type", compactTitle: "Header", successMessage: "Valid header", }, payloadEditor: { - title: "Payload: Data", + title: "Data", compactTitle: "Payload", successMessage: "Valid payload", }, signatureEditor: { title: { - secret: "Sign JWT: Secret", + secret: "Secret", privateKey: "Sign JWT: Private Key", }, compactTitle: { @@ -185,7 +170,8 @@ export const enHomeDictionary: HomeDictionaryModel = { }, }, encodedJwt: { - title: "JSON Web Token", + title: "Encoded JWT", + heading: "JWT Signature", }, }, }; diff --git a/src/features/localization/dictionaries/home/ja.ts b/src/features/localization/dictionaries/home/ja.ts index d75fe5053..c93d254c9 100644 --- a/src/features/localization/dictionaries/home/ja.ts +++ b/src/features/localization/dictionaries/home/ja.ts @@ -54,17 +54,8 @@ export const jaHomeDictionary: HomeDictionaryModel = { description: null, }, info: { - summary: "JWTとは?", description: "JSON Web Tokenをデコード、検証、生成します。JSON Web Tokenは、2つの当事者間でクレームを安全に表現するための、オープンな業界標準(RFC 7519)です。", - ctaButton: { - label: "JWTの詳細情報", - path: sitePaths.introduction, - }, - secondaryCtaButton: { - label: "JWTライブラリを見る", - path: sitePaths.libraries, - }, resources: { spec: { name: "RFC 7519", @@ -72,13 +63,6 @@ export const jaHomeDictionary: HomeDictionaryModel = { }, }, }, - warning: { - summary: "JWTを使用する際の注意事項", - title: - "セキュリティを確保するため、すべてのJWTのデバッグと検証はブラウザ内で行われます。", - description: - "JWTはリソースへのアクセス権を示す認証情報として機能する可能性があるため、貼り付けや共有を行う際には十分注意してください。このサイトでは、JSON Web Tokenをブラウザの外部に保存したり送信したりすることはありません。", - }, decoder: { title: "JWTデコーダー", compactTitle: "デコーダー", @@ -96,6 +80,7 @@ export const jaHomeDictionary: HomeDictionaryModel = { title: "JSON Web Token (JWT)", compactTitle: "JWT", successMessage: "有効なJWT", + autoFocusLabel: "オートフォーカスを有効にする", }, decodedHeader: { title: "デコードされたヘッダー", @@ -157,18 +142,18 @@ export const jaHomeDictionary: HomeDictionaryModel = { label: "ヘッダー、ペイロード、署名サンプルジェネレーター", }, headerEditor: { - title: "ヘッダー:アルゴリズムとトークンタイプ", + title: "アルゴリズムとトークンタイプ", compactTitle: "ヘッダー", successMessage: "有効なヘッダー", }, payloadEditor: { - title: "ペイロード:データ", + title: "データ", compactTitle: "ペイロード", successMessage: "有効なペイロード", }, signatureEditor: { title: { - secret: "JWTに署名:シークレット", + secret: "シークレット", privateKey: "JWTに署名:秘密鍵", }, compactTitle: { diff --git a/src/features/localization/dictionaries/images/en.tsx b/src/features/localization/dictionaries/images/en.tsx index 3c571f8d9..e7829e9d9 100644 --- a/src/features/localization/dictionaries/images/en.tsx +++ b/src/features/localization/dictionaries/images/en.tsx @@ -1,20 +1,32 @@ -import auth0Logo from "@/features/common/assets/auth0-logo.png"; -import jwtLogo from "@/features/common/assets/jwt-flower.png"; -import { ImagesDictionaryModel } from "@/features/localization/models/images-dictionary.model"; +import { BrandDictionaryModel } from "../../models/brand-dictionary.model"; -export const enImagesDictionary: ImagesDictionaryModel = { - logos: { - site: { - src: jwtLogo.src, - alt: "A token that resembles a flower with petals of a different color.", - width: jwtLogo.width, - height: jwtLogo.height, +export const enBrandDictionary: BrandDictionaryModel = { + alertMessage: "SVG copied to clipboard", + tooltip: "Right-click or long-press for logo options", + menu: { + brand: { + label: "Brand", + svg: { + copyLabel: "Copy Logo SVG", + downloadLabel: "Download Logo", + }, + symbol: { + copyLabel: "Copy Symbol SVG", + downloadLabel: "Download Symbol", + }, + wordmark: { + copyLabel: "Copy Wordmark SVG", + downloadLabel: "Download Wordmark", + }, }, - auth0: { - src: auth0Logo.src, - alt: "This logo has the word “Auth0” and a shield on its left side. The shield has a four-pointed star inside, which spans across its surface.", - width: auth0Logo.width, - height: auth0Logo.height, + tools: { + label: "Tools", + items: [ + { label: "Passkeys Playground", url: "https://learnpasskeys.io" }, + { label: "WebAuthn Playground", url: "https://webauthn.me" }, + { label: "OIDC Playground", url: "https://openidconnect.net" }, + { label: "SAML Tool", url: "https://samltool.io" }, + ], }, }, }; diff --git a/src/features/localization/dictionaries/images/ja.tsx b/src/features/localization/dictionaries/images/ja.tsx index 112f37b38..ae3e3c345 100644 --- a/src/features/localization/dictionaries/images/ja.tsx +++ b/src/features/localization/dictionaries/images/ja.tsx @@ -1,20 +1,32 @@ -import auth0Logo from "@/features/common/assets/auth0-logo.png"; -import jwtLogo from "@/features/common/assets/jwt-flower.png"; -import { ImagesDictionaryModel } from "@/features/localization/models/images-dictionary.model"; +import { BrandDictionaryModel } from "../../models/brand-dictionary.model"; -export const jaImagesDictionary: ImagesDictionaryModel = { - logos: { - site: { - src: jwtLogo.src, - alt: "異なる色の花びらを持つ花に似たトークン。", - width: jwtLogo.width, - height: jwtLogo.height, +export const jaBrandDictionary: BrandDictionaryModel = { + alertMessage: "SVG がクリップボードにコピーされました", + tooltip: "右クリックまたは長押し (ロゴオプション)", + menu: { + brand: { + label: "ブランド", + svg: { + copyLabel: "ロゴ SVG をコピー", + downloadLabel: "ロゴをダウンロード", + }, + symbol: { + copyLabel: "シンボル SVG をコピー", + downloadLabel: "シンボルをダウンロード", + }, + wordmark: { + copyLabel: "ワードマーク SVG をコピー", + downloadLabel: "ワードマークをダウンロード", + }, }, - auth0: { - src: auth0Logo.src, - alt: "“Auth0”ロゴ。盾の中央から四方八方に伸びる星が描かれている。", - width: auth0Logo.width, - height: auth0Logo.height, + tools: { + label: "ツール", + items: [ + { label: "Passkeys Playground", url: "https://learnpasskeys.io" }, + { label: "WebAuthn Playground", url: "https://webauthn.me" }, + { label: "OIDC Playground", url: "https://openidconnect.net" }, + { label: "SAMLツール", url: "https://samltool.io" }, + ], }, }, }; diff --git a/src/features/localization/dictionaries/layout/en.tsx b/src/features/localization/dictionaries/layout/en.tsx index 1bbe8fa3e..14da086d5 100644 --- a/src/features/localization/dictionaries/layout/en.tsx +++ b/src/features/localization/dictionaries/layout/en.tsx @@ -39,20 +39,6 @@ export const enLayoutDictionary: LayoutDictionaryModel = { }, ], }, - languagePicker: { - button: { - ariaLabel: "Select page language", - }, - list: { - ariaLabel: "list of page languages", - }, - options: [ - { - code: "en", - label: "English", - }, - ], - }, }, header: { links: [ @@ -162,6 +148,20 @@ export const enLayoutDictionary: LayoutDictionaryModel = { }, ], }, + languagePicker: { + button: { + ariaLabel: "Select page language", + }, + list: { + ariaLabel: "list of page languages", + }, + options: [ + { + value: "en", + label: "English", + }, + ], + }, }, errors: { notFound: { @@ -187,8 +187,8 @@ export const enLayoutDictionary: LayoutDictionaryModel = { }; if (withJapanese) { - enLayoutDictionary.ribbon.languagePicker.options.push({ + enLayoutDictionary.footer.languagePicker.options.push({ label: "日本語", - code: "ja", + value: "ja", }); } diff --git a/src/features/localization/dictionaries/layout/ja.tsx b/src/features/localization/dictionaries/layout/ja.tsx index c24af7503..de2f0697c 100644 --- a/src/features/localization/dictionaries/layout/ja.tsx +++ b/src/features/localization/dictionaries/layout/ja.tsx @@ -39,20 +39,6 @@ export const jaLayoutDictionary: LayoutDictionaryModel = { }, ], }, - languagePicker: { - button: { - ariaLabel: "ページの言語を選択してください", - }, - list: { - ariaLabel: "ページ言語の一覧", - }, - options: [ - { - code: "en", - label: "English", - }, - ], - }, }, header: { links: [ @@ -162,6 +148,20 @@ export const jaLayoutDictionary: LayoutDictionaryModel = { }, ], }, + languagePicker: { + button: { + ariaLabel: "ページの言語を選択してください", + }, + list: { + ariaLabel: "ページ言語の一覧", + }, + options: [ + { + value: "en", + label: "English", + }, + ], + }, }, errors: { notFound: { @@ -187,8 +187,8 @@ export const jaLayoutDictionary: LayoutDictionaryModel = { }; if (withJapanese) { - jaLayoutDictionary.ribbon.languagePicker.options.push({ + jaLayoutDictionary.footer.languagePicker.options.push({ label: "日本語", - code: "ja", + value: "ja", }); } diff --git a/src/features/localization/dictionaries/ui/pickers/en.tsx b/src/features/localization/dictionaries/ui/pickers/en.tsx index b2b4f6b74..6149197eb 100644 --- a/src/features/localization/dictionaries/ui/pickers/en.tsx +++ b/src/features/localization/dictionaries/ui/pickers/en.tsx @@ -9,7 +9,7 @@ export const enPickersUiDictionary: PickersUiDictionaryModel = { exampleAlgPicker: { label: "Generate example", compactLabel: "Alg", - defaultValue: "Select a signing algorithm", + defaultValue: "Select signing algorithm", description: "Generate a JWT", closeButton: { label: "Close signing algorithm list", @@ -24,4 +24,7 @@ export const enPickersUiDictionary: PickersUiDictionaryModel = { privateKeyFormatPicker: { label: "Private Key Format", }, + base64checkbox: { + label: "Base64URL Encoded", + }, }; diff --git a/src/features/localization/dictionaries/ui/pickers/ja.tsx b/src/features/localization/dictionaries/ui/pickers/ja.tsx index b756f47d5..a2648cb68 100644 --- a/src/features/localization/dictionaries/ui/pickers/ja.tsx +++ b/src/features/localization/dictionaries/ui/pickers/ja.tsx @@ -24,4 +24,7 @@ export const jaPickersUiDictionary: PickersUiDictionaryModel = { privateKeyFormatPicker: { label: "秘密鍵の形式", }, + base64checkbox: { + label: "Base64URLエンコード", + }, }; diff --git a/src/features/localization/models/brand-dictionary.model.ts b/src/features/localization/models/brand-dictionary.model.ts new file mode 100644 index 000000000..4dfcce357 --- /dev/null +++ b/src/features/localization/models/brand-dictionary.model.ts @@ -0,0 +1,30 @@ +interface ToolsMenuItem { + label: string, + url: string, +} +export interface BrandMenuItem { + copyLabel: string, + downloadLabel: string, +} +interface BrandMenuSection { + label: string; + svg: BrandMenuItem, + symbol: BrandMenuItem, + wordmark: BrandMenuItem, +} + +interface ToolsMenuSection { + label: string; + items: ToolsMenuItem[]; +} + +interface BrandMenu { + brand: BrandMenuSection; + tools: ToolsMenuSection; +} + +export interface BrandDictionaryModel { + tooltip: string; + alertMessage: string; + menu: BrandMenu; +} diff --git a/src/features/localization/models/decoder-dictionary.model.ts b/src/features/localization/models/decoder-dictionary.model.ts index ade14593c..0ee81ebef 100644 --- a/src/features/localization/models/decoder-dictionary.model.ts +++ b/src/features/localization/models/decoder-dictionary.model.ts @@ -12,6 +12,7 @@ export interface DecoderDictionaryModel { title: string; compactTitle: string; successMessage: string; + autoFocusLabel: string; }; exampleGenerator: { label: string; diff --git a/src/features/localization/models/encoder-dictionary.model.ts b/src/features/localization/models/encoder-dictionary.model.ts index cafec5286..3dd677ef7 100644 --- a/src/features/localization/models/encoder-dictionary.model.ts +++ b/src/features/localization/models/encoder-dictionary.model.ts @@ -42,5 +42,6 @@ export interface EncoderDictionaryModel { }; encodedJwt: { title: string; + heading?: string; }; } diff --git a/src/features/localization/models/home-dictionary.model.ts b/src/features/localization/models/home-dictionary.model.ts index 8b120ba9a..37edaf74f 100644 --- a/src/features/localization/models/home-dictionary.model.ts +++ b/src/features/localization/models/home-dictionary.model.ts @@ -2,18 +2,12 @@ import { PageMetadataModel } from "@/features/common/models/page-metadata.model" import { HeroMetadataModel } from "@/features/common/models/hero-metadata.model"; import { EncoderDictionaryModel } from "@/features/localization/models/encoder-dictionary.model"; import { DecoderDictionaryModel } from "@/features/localization/models/decoder-dictionary.model"; -import { LinkMetadataModel } from "@/features/common/models/link-metadata.model"; -import { ImageMetadataModel } from "@/features/common/models/image-metadata.model"; export interface HomeDictionaryModel { metadata: PageMetadataModel; hero: HeroMetadataModel; info: { - summary: string; description: string; - ctaButton?: LinkMetadataModel; - secondaryCtaButton?: LinkMetadataModel; - image?: ImageMetadataModel; resources: { spec: { name: string; @@ -21,11 +15,6 @@ export interface HomeDictionaryModel { }; }; }; - warning: { - summary: string; - title: string; - description: string; - }; decoder: DecoderDictionaryModel; encoder: EncoderDictionaryModel; } diff --git a/src/features/localization/models/images-dictionary.model.ts b/src/features/localization/models/images-dictionary.model.ts deleted file mode 100644 index 392e4e752..000000000 --- a/src/features/localization/models/images-dictionary.model.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { StaticImageMetadataModel } from "@/features/common/models/static-image-metadata.model"; - -export interface ImagesDictionaryModel { - logos: { - site: StaticImageMetadataModel; - auth0: StaticImageMetadataModel; - }; -} diff --git a/src/features/localization/models/layout-dictionary.model.ts b/src/features/localization/models/layout-dictionary.model.ts index df259944b..3b57231aa 100644 --- a/src/features/localization/models/layout-dictionary.model.ts +++ b/src/features/localization/models/layout-dictionary.model.ts @@ -26,7 +26,6 @@ export interface LayoutDictionaryModel { }; }; themePicker: RibbonPickerModel; - languagePicker: RibbonPickerModel; }; header: { links: LinkMetadataModel[]; @@ -69,6 +68,7 @@ export interface LayoutDictionaryModel { id: string; }[]; }; + languagePicker: RibbonPickerModel; }; errors: { notFound: { diff --git a/src/features/localization/models/ui/pickers-ui-dictionary.model.ts b/src/features/localization/models/ui/pickers-ui-dictionary.model.ts index f57138bc8..c3c1f7fba 100644 --- a/src/features/localization/models/ui/pickers-ui-dictionary.model.ts +++ b/src/features/localization/models/ui/pickers-ui-dictionary.model.ts @@ -22,4 +22,7 @@ export interface PickersUiDictionaryModel { privateKeyFormatPicker: { label: string; }; + base64checkbox: { + label: string; + }; } diff --git a/src/features/localization/services/brand-dictionary.service.tsx b/src/features/localization/services/brand-dictionary.service.tsx new file mode 100644 index 000000000..9afc22cb0 --- /dev/null +++ b/src/features/localization/services/brand-dictionary.service.tsx @@ -0,0 +1,13 @@ +import { enBrandDictionary } from "@/features/localization/dictionaries/images/en"; +import { jaBrandDictionary } from "@/features/localization/dictionaries/images/ja"; +import { BrandDictionaryModel } from "../models/brand-dictionary.model"; + +const brandDictionaries: { + [index: string]: BrandDictionaryModel; +} = { + en: enBrandDictionary, + ja: jaBrandDictionary, +}; + +export const getBrandDictionary = (language: string) => + brandDictionaries[language]; diff --git a/src/features/localization/services/images-dictionary.service.tsx b/src/features/localization/services/images-dictionary.service.tsx deleted file mode 100644 index acd51002f..000000000 --- a/src/features/localization/services/images-dictionary.service.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { ImagesDictionaryModel } from "@/features/localization/models/images-dictionary.model"; -import { enImagesDictionary } from "@/features/localization/dictionaries/images/en"; -import { jaImagesDictionary } from "@/features/localization/dictionaries/images/ja"; - -const imagesDictionaries: { - [index: string]: ImagesDictionaryModel; -} = { - en: enImagesDictionary, - ja: jaImagesDictionary, -}; - -export const getImageDictionary = (language: string) => - imagesDictionaries[language]; diff --git a/src/libs/testing/data-testid.dictionary.ts b/src/libs/testing/data-testid.dictionary.ts index 5285be6fa..74057789b 100644 --- a/src/libs/testing/data-testid.dictionary.ts +++ b/src/libs/testing/data-testid.dictionary.ts @@ -74,6 +74,7 @@ export const dataTestidDictionary = { }, encoder: { id: "encoder", + switch: 'encoder_switch', headerEditor: { id: "encoder__headerEditor", statusBar: { diff --git a/src/libs/theme/styles/_variables.scss b/src/libs/theme/styles/_variables.scss index e5a0bd159..75fa4b29d 100644 --- a/src/libs/theme/styles/_variables.scss +++ b/src/libs/theme/styles/_variables.scss @@ -148,10 +148,10 @@ $gradient-app-card---resting: linear-gradient( #3f59e4 67.69% ); -$ribbon-height: 2.5rem; -$ribbon-height-mobile: 2.5rem; -$navbar-height: 3rem; -$navbar-height-mobile: 3rem; +$ribbon-height: 2rem; +$ribbon-height-mobile: 2rem; +$navbar-height: 6rem; +$navbar-height-mobile: 4.5rem; $main-nav-height: calc($ribbon-height + $navbar-height); $main-nav-height-mobile: calc($ribbon-height-mobile + $navbar-height-mobile); diff --git a/src/libs/theme/styles/globals.scss b/src/libs/theme/styles/globals.scss index 051ef32b4..5b23baa0b 100644 --- a/src/libs/theme/styles/globals.scss +++ b/src/libs/theme/styles/globals.scss @@ -48,16 +48,17 @@ --color_fg_default: var(--functional-gray-200); --color_fg_link_primary: var(--cloud); - --color_bg_app_bar: rgba(17, 17, 17, 0.66); + --color_bg_app_bar: hsla(0, 0%, 95%, 0.04); + --color_bg_app_bar_border: hsla(0, 0%, 95%, 0.12); --color_bg_app_bar_plain: rgba(17, 17, 17); --color_fg_link: var(--functional-gray-50); --color_fg_link_hover: var(--functional-gray-50); --color_fg_link_pressed: var(--functional-gray-50); - --color_fg_selected: #99a7f1; - --color_border_selected: #99a7f1; - --color_border_focus: #99a7f1; + --color_fg_selected: var(--functional-gray-100); + --color_border_selected: var(--functional-gray-850); + --color_border_focus: var(--functional-gray-850); --color_bg_auth0-cta: linear-gradient(251deg, #1e1e1e 2.29%, #191919 87.03%); @@ -65,7 +66,7 @@ --color_bg_layer_bold: var(--functional-gray-700); --color_bg_layer_boldest: var(--functional-gray-50); --color_bg_layer_alternate: var(--functional-gray-850); - --color_bg_layer_alternate-bold: var(--functional-gray-800); + --color_bg_layer_alternate-bold: var(--functional-gray-850); --color_bg_layer_elevated: var(--functional-gray-900); --color_bg_layer_highlight1: var(--ocean); @@ -77,11 +78,12 @@ --color_code_blue2: #7487eb; --color_code_blue3: #7487eb; --color_code_dark_blue: #fafbfe; - --color_code_dark_blue2: #b9c3f5; + --color_code_dark_blue2: #3f59e4; --color_code_purple: #ccbcfa; - --color_code_orange: #f1b99b; + --color_code_orange: #e7834e; --color_code_inverse: #fefaf8; --color_code_teal: #3b8d7e; + --color_code_green: #52af6d; --color_code_dark_teal: #8ed2c5; --color_code_dark_neutral: #808080; @@ -113,17 +115,18 @@ --color_border_button_outline: var(--functional-gray-50); --color_fg_on_button_outline: var(--functional-gray-50); - --color_fg_code: #8ed2c5; + --color_fg_code: #fff; --color_bg_code-editor: #000; - --color_bg_state_success: #10783f; + --color_bg_state_success: #149750; --color_fg_on_state_success: #fff; --color_fg_on_state_success_subtle: #98d2b2; --color_bg_state_success_subtle: #062a16; --color_border_state_success: #67bc8e; --color_fg_strong: #99a7f1; - + + --color_bg_state_danger: #f2ac84; --color_bg_state_danger_subtle: #46110e; --color_fg_on_state_danger_subtle: #f0b7b4; --color_border_state_danger: #e89590; @@ -138,9 +141,9 @@ --color_fg_on_state_caution: #000000; --color_fg_on_state_caution_subtle: #e3c423; - --color_jwt_header: #6dc993; - --color_jwt_payload: #e5e5e5; - --color_jwt_signature: #8c9bef; + --color_jwt_header: #e27133; + --color_jwt_payload: #9472f7; + --color_jwt_signature: #8fc88a; --color_jwt_dot: #ff69e4; --color_bg_scrollbar: #6b7380; @@ -148,15 +151,16 @@ html[data-theme="light"], html[data-theme="system-light"] { - --color_jwt_header: #096256; - --color_jwt_payload: #383838; - --color_jwt_signature: #2c3ea0; - --color_jwt_dot: #cc36b1; + --color_jwt_header: #e27133; + --color_jwt_payload: #9472f7; + --color_jwt_signature: #149750; + --color_jwt_dot: #151619; --color_bg_state_info_subtle: #eef0fd; --color_fg_on_state_info_subtle: #263588; --color_border_state_info: #3f59e4; + --color_bg_state_danger: #e27133; --color_bg_state_danger_subtle: #fbeeed; --color_fg_on_state_danger_subtle: #761c17; --color_border_state_danger: #c32f26; @@ -169,18 +173,18 @@ html[data-theme="system-light"] { --color_fg_strong: #3f59e4; - --color_bg_state_success: #10783f; + --color_bg_state_success: #8fc88a; --color_fg_on_state_success: #fff; - --color_fg_on_state_success_subtle: #094726; + --color_fg_on_state_success_subtle: #149750; --color_bg_state_success_subtle: #e6f4ec; --color_border_state_success: #10783f; - --color_fg_code: #3b8d7e; + --color_fg_code: #fff; --color_bg_code-editor: #fff; --color_fg_on_button: var(--charcoal2); --color_fg_on_button_subtle: var(--functional-gray-600); - --color_fg_on_button_primary: var(--functional-gray-0); + --color_fg_on_button_primary: var(--functional-gray-1000); --color_bg_button: var(--functional-gray-0); --color_bg_button_hover: var(--functional-gray-150); --color_bg_button_pressed: #e8e8e8; @@ -193,23 +197,24 @@ html[data-theme="system-light"] { --color_border_button_outline: var(--functional-gray-550); --color_fg_on_button_outline: var(--charcoal2); - --color_bg_page: var(--functional-gray-0); + --color_bg_page: var(--functional-gray-100); --color_fg_bold: var(--charcoal2); - --color_fg_default: var(--functional-gray-650); + --color_fg_default: var(--functional-gray-500); --color_fg_link_primary: var(--sky); - --color_bg_app_bar: rgba(241, 241, 241, 0.66); + --color_bg_app_bar: hsla(0, 0%, 7%, 0.04); --color_bg_app_bar_plain: rgba(241, 241, 241); + --color_bg_app_bar_border: hsla(0, 0%, 7%, 0.12); --color_fg_link: var(--charcoal2); --color_fg_link_hover: var(--charcoal2); --color_fg_link_pressed: var(--charcoal2); - --color_fg_selected: #3f59e4; - --color_border_selected: #3f59e4; - --color_border_focus: #3f59e4; + --color_fg_selected: var(--functional-gray-850); + --color_border_selected: var(--functional-gray-850); + --color_border_focus: var(--functional-gray-850); - --color_bg_auth0-cta: var(--functional-gray-150); + --color_bg_auth0-cta: var(--functional-gray-950); --color_bg_layer: var(--functional-gray-0); --color_bg_layer_bold: var(--functional-gray-250); @@ -223,6 +228,8 @@ html[data-theme="system-light"] { --color_bg_layer_highlight3: var(--violet); --color_bg_layer_highlight4: #a35125; + --color_button_focus_inverse: hsla(0, 0%, 100%, .24); + --color_border_default: #e8e8e8; --color_border_bold: var(--functional-gray-250); --color_border_inverse_static: var(--functional-gray-550); @@ -230,6 +237,7 @@ html[data-theme="system-light"] { --color_bg_disabled: var(--functional-gray-150); --color_fg_disabled: var(--functional-gray-500); + --color_fg_default: var(--functional-gray-500); --color_bg_input: var(--functional-gray-0); --color_fg_input_placeholder: var(--functional-gray-500); @@ -241,9 +249,9 @@ html[data-theme="system-light"] { --color_code_blue2: #7487eb; --color_code_blue3: #7487eb; --color_code_dark_blue: #10163a; - --color_code_dark_blue2: #263588; + --color_code_dark_blue2: #3f59e4; --color_code_purple: #9979f5; - --color_code_orange: #a35125; + --color_code_orange: #e7834e; --color_code_inverse: #291409; --color_code_teal: #3b8d7e; --color_code_dark_teal: #419d8c; @@ -416,15 +424,18 @@ pre[class*="language-"] { .token.property, .token.tag, -.token.number, .token.constant, .token.symbol, .token.deleted { - color: var(--color_code_orange); + color: var(--color_code_dark_blue); +} + +.token.number { + color: var(--color_code_dark_blue2) } .token.boolean { - color: var(--color_fg_code); + color: var(--color_code_orange); } .token.selector, @@ -433,7 +444,7 @@ pre[class*="language-"] { .token.char, .token.builtin, .token.inserted { - color: var(--color_code_dark_blue); + color: var(--color_code_green); } .token.operator, @@ -503,19 +514,24 @@ $picker-list-offset-lg: calc(($picker-list-width-lg - $picker-width-lg) / 2); background: transparent; color: var(--color_fg_bold); font-family: var(--font-primary), monospace !important; - height: 2rem !important; } .react-select__control { background-color: transparent !important; border-color: var(--color_border_button) !important; + background-color: var(--color_bg_layer); + border: 1px solid var(--color_border_default) !important; height: 100% !important; - border: 1px solid var(--color_border_inverse_static) !important; + &:hover { + border-color: var(--color_border_bold) !important; + transition: 0.2s ease-out !important; + } } .react-select__control--is-focused { - border-color: var(--color_border_focus) !important; - box-shadow: 0 0 0 1px var(--color_border_focus) !important; + transition: 0.2s ease-out; + border-color: var(--color_border_default) !important; + box-shadow: 0 0 0 3px var(--color_border_default) !important; } .react-select__value-container { @@ -537,20 +553,26 @@ $picker-list-offset-lg: calc(($picker-list-width-lg - $picker-width-lg) / 2); height: 100% !important; } -.react-select__menu { - background-color: var(--color_bg_layer_alternate-bold) !important; - color: var(--color_fg_bold) !important; - border: 1px solid var(--color_border_bold) !important; - font-size: 0.875rem !important; - font-family: var(--font-primary), monospace !important; - width: max-content !important; - min-width: 100% !important; +.react-select__menu, +.language-select__menu { + background-color: var(--color_bg_layer) !important; + border-radius: 0.75rem !important; + box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 0px 1px, rgba(0, 0, 0, 0.1) 0px 4px 11px !important; + margin-bottom: 8px !important; + margin-top: 8px !important; + box-sizing: border-box !important; + border: 1px solid var(--color_border_default); + padding: 0.25rem; + overflow: hidden; + width: max-content !important; + min-width: 100% !important; } .react-select__menu-portal { } -.react-select__menu-list { +.react-select__menu-list, +.language-select__menu-list { font-family: var(--font-primary), monospace !important; padding: 0 !important; @@ -576,32 +598,35 @@ $picker-list-offset-lg: calc(($picker-list-width-lg - $picker-width-lg) / 2); } } -.react-select__option { - display: flex !important; - align-items: center !important; - color: var(--color_fg_default) !important; - position: relative !important; - height: 2.5rem !important; - border-bottom: 1px solid var(--color_border_bold) !important; - padding: 0.25rem 1rem !important; - background-color: transparent !important; - font-family: var(--font-primary), monospace !important; - - gap: 0.5rem !important; - font-size: 0.8125rem !important; - line-height: 1.3125rem !important; - letter-spacing: -0.05px !important; - - &:last-child { - border-bottom: unset; - } - - &:hover { - cursor: pointer; - } +.react-select__option, +.language-select__option { + cursor: pointer !important; + display: flex !important; + font-size: 0.875rem !important; + width: 100% !important; + user-select: none !important; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0) !important; + background-color: transparent !important; + color: var(--color_fg_default) !important; + padding: 8px 12px 8px 1.25rem !important; + box-sizing: border-box !important; + -webkit-box-align: center !important; + align-items: center !important; + position: relative !important; + height: 1.5rem !important; + border-radius: 0.5rem !important; + font-family: var(--font-primary),monospace !important; + line-height: 1.3125rem !important; + letter-spacing: -0.05px !important; + font-weight: 500 !important; + opacity: 1 !important; + &:hover { + background-color: var(--color_bg_layer_alternate) !important; + } } -.react-select__option--is-selected { +.react-select__option--is-selected, +.language-select__option--is-selected { color: var(--color_fg_bold) !important; font-weight: 500; @@ -616,7 +641,7 @@ $picker-list-offset-lg: calc(($picker-list-width-lg - $picker-width-lg) / 2); transform: translateY(-50%); height: 0.375rem; width: 0.375rem; - background-color: var(--color_fg_selected); + background-color: var(--color_fg_bold); border-radius: 50%; } } @@ -624,7 +649,7 @@ $picker-list-offset-lg: calc(($picker-list-width-lg - $picker-width-lg) / 2); .react-select__option--is-disabled { color: var(--color_fg_bold) !important; font-weight: 500; - opacity: 0.32; + opacity: 0.32 !important; cursor: not-allowed !important; } diff --git a/tsconfig.json b/tsconfig.json index b1701cf69..6930c0193 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -20,7 +20,8 @@ } ], "paths": { - "@/*": ["./src/*"] + "@/*": ["./src/*"], + "@/public/*": ["./public/*"] } }, "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], diff --git a/types/svg.d.ts b/types/svg.d.ts new file mode 100644 index 000000000..c284f7d6e --- /dev/null +++ b/types/svg.d.ts @@ -0,0 +1,4 @@ +declare module "*.svg?raw" { + const content: string; + export default content; +}