mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-10-03 10:13:47 +10:00
fix(web): restyle the custom CSS editor in the app's inks and show its toolbar icons
This commit is contained in:
@@ -34,6 +34,7 @@
|
||||
"@dnd-kit/sortable": "^10.0.0",
|
||||
"@dnd-kit/utilities": "^3.2.2",
|
||||
"@fontsource-variable/manrope": "^5.3.0",
|
||||
"@lezer/highlight": "^1.2.4",
|
||||
"@lingui/core": "^6.8.0",
|
||||
"@lingui/react": "^6.8.0",
|
||||
"@orpc/client": "^1.15.4",
|
||||
|
||||
@@ -6,7 +6,7 @@ import type { SemanticCssColorToken } from "./color-tokens";
|
||||
import type { SemanticCssEditorMetadata } from "./protocol";
|
||||
import { defaultKeymap, indentWithTab } from "@codemirror/commands";
|
||||
import { css } from "@codemirror/lang-css";
|
||||
import { defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
|
||||
import { HighlightStyle, syntaxHighlighting } from "@codemirror/language";
|
||||
import { Annotation, Compartment, EditorState, Prec, Transaction } from "@codemirror/state";
|
||||
import {
|
||||
drawSelection,
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
keymap,
|
||||
lineNumbers,
|
||||
} from "@codemirror/view";
|
||||
import { tags } from "@lezer/highlight";
|
||||
import { t } from "@lingui/core/macro";
|
||||
import { Trans } from "@lingui/react/macro";
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
@@ -54,6 +55,18 @@ type EditorCompartments = {
|
||||
intelligence: Compartment;
|
||||
};
|
||||
|
||||
/** CSS in the app's own inks, so it reads the same in light and dark. */
|
||||
const highlightStyle = HighlightStyle.define([
|
||||
{ tag: [tags.comment, tags.meta], color: "var(--ink-3)", fontStyle: "italic" },
|
||||
{ tag: [tags.tagName, tags.className, tags.labelName], color: "var(--accent-text)" },
|
||||
{ tag: [tags.propertyName, tags.attributeName], color: "var(--info-text)" },
|
||||
{ tag: [tags.string, tags.number, tags.unit, tags.color, tags.atom], color: "var(--warn-text)" },
|
||||
{ tag: [tags.keyword, tags.modifier, tags.definitionKeyword, tags.controlKeyword], color: "var(--danger-text)" },
|
||||
{ tag: [tags.variableName, tags.function(tags.variableName)], color: "var(--ink)", fontWeight: "500" },
|
||||
{ tag: [tags.punctuation, tags.operator, tags.bracket], color: "var(--ink-2)" },
|
||||
{ tag: tags.invalid, color: "var(--danger-text)", textDecoration: "underline wavy" },
|
||||
]);
|
||||
|
||||
const editorTheme = (dark: boolean): Extension =>
|
||||
EditorView.theme(
|
||||
{
|
||||
@@ -65,7 +78,7 @@ const editorTheme = (dark: boolean): Extension =>
|
||||
},
|
||||
".cm-scroller": {
|
||||
overflow: "auto",
|
||||
fontFamily: '"JetBrains Mono Variable", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace',
|
||||
fontFamily: "var(--font-mono)",
|
||||
lineHeight: "1.5",
|
||||
},
|
||||
".cm-content": { minHeight: "100%", padding: "0.75rem 0" },
|
||||
@@ -162,7 +175,7 @@ export function StylesheetCodeEditor({
|
||||
drawSelection(),
|
||||
highlightActiveLine(),
|
||||
css(),
|
||||
syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
|
||||
syntaxHighlighting(highlightStyle),
|
||||
EditorView.editorAttributes.of({ dir: "ltr" }),
|
||||
EditorView.contentAttributes.of({ "aria-label": initial.label, dir: "ltr", spellcheck: "false" }),
|
||||
Prec.high(
|
||||
|
||||
@@ -21,7 +21,7 @@ export function LegacyStylesheetBanner({ disabled, onActivate }: LegacyStyleshee
|
||||
</p>
|
||||
<Button type="button" size="sm" disabled={disabled} onClick={onActivate}>
|
||||
<Trans>Activate Semantic CSS</Trans>
|
||||
<Icon name="arrow_forward" size={16} data-icon="inline-end" />
|
||||
<Icon name="arrow_forward" size={16} />
|
||||
</Button>
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
|
||||
@@ -23,19 +23,19 @@ export function StylesheetStatus({ mode, status, diagnostics }: StylesheetStatus
|
||||
<div className="space-y-2" aria-live="polite">
|
||||
{hasFatalErrors ? (
|
||||
<Badge variant="danger">
|
||||
<Icon name="error" size={16} data-icon="inline-start" />
|
||||
<Icon name="error" size={16} />
|
||||
<Trans>Fatal error</Trans>
|
||||
</Badge>
|
||||
) : isPending ? (
|
||||
<Badge variant="outline">{mode === "legacy" ? <Trans>Checking draft</Trans> : <Trans>Checking</Trans>}</Badge>
|
||||
) : hasRecoverableErrors ? (
|
||||
<Badge variant="warn">
|
||||
<Icon name="error" size={16} data-icon="inline-start" />
|
||||
<Icon name="error" size={16} />
|
||||
{mode === "legacy" ? <Trans>Ready to activate with errors</Trans> : <Trans>Valid with errors</Trans>}
|
||||
</Badge>
|
||||
) : warnings.length > 0 ? (
|
||||
<Badge variant="warn">
|
||||
<Icon name="warning" size={16} data-icon="inline-start" />
|
||||
<Icon name="warning" size={16} />
|
||||
{mode === "legacy" ? <Trans>Ready to activate with warnings</Trans> : <Trans>Valid with warnings</Trans>}
|
||||
</Badge>
|
||||
) : (
|
||||
|
||||
@@ -52,23 +52,19 @@ export function StylesheetToolbar({
|
||||
return (
|
||||
<div className="flex flex-wrap items-center gap-1" role="toolbar" aria-label={t`Stylesheet editor`}>
|
||||
<ToolbarButton label={t`Undo stylesheet edit`} disabled={disabled || !canUndo} onClick={onUndo}>
|
||||
<Icon name="undo" size={16} data-icon="inline-start" />
|
||||
<Icon name="undo" size={16} />
|
||||
</ToolbarButton>
|
||||
<ToolbarButton label={t`Redo stylesheet edit`} disabled={disabled || !canRedo} onClick={onRedo}>
|
||||
<Icon name="redo" size={16} data-icon="inline-start" />
|
||||
<Icon name="redo" size={16} />
|
||||
</ToolbarButton>
|
||||
<ToolbarButton label={t`Copy stylesheet`} onClick={() => void copySourceToClipboard(source)}>
|
||||
<Icon name="content_copy" size={16} data-icon="inline-start" />
|
||||
<Icon name="content_copy" size={16} />
|
||||
</ToolbarButton>
|
||||
<ToolbarButton label={t`Format stylesheet`} disabled={disabled} onClick={onFormat}>
|
||||
<Icon name="auto_fix_high" size={16} data-icon="inline-start" />
|
||||
<Icon name="auto_fix_high" size={16} />
|
||||
</ToolbarButton>
|
||||
<ToolbarButton label={focused ? t`Exit focus mode` : t`Open focus mode`} onClick={onFocusToggle}>
|
||||
{focused ? (
|
||||
<Icon name="close_fullscreen" size={16} data-icon="inline-start" />
|
||||
) : (
|
||||
<Icon name="open_in_full" size={16} data-icon="inline-start" />
|
||||
)}
|
||||
{focused ? <Icon name="close_fullscreen" size={16} /> : <Icon name="open_in_full" size={16} />}
|
||||
</ToolbarButton>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -19,6 +19,11 @@ describe("Icon", () => {
|
||||
expect(container.querySelector("button")).toHaveTextContent(/^Search$/);
|
||||
});
|
||||
|
||||
it("keeps its glyph when a caller passes its own data-icon", () => {
|
||||
const { container } = render(<Icon name="undo" {...{ "data-icon": "inline-start" }} />);
|
||||
expect(container.querySelector('[data-slot="icon"]')).toHaveAttribute("data-icon", "undo");
|
||||
});
|
||||
|
||||
it("uses the filled glyph only when asked", () => {
|
||||
const { container } = render(<Icon name="description" filled />);
|
||||
expect(container.querySelector('[data-slot="icon"]')?.getAttribute("style")).toContain('"FILL" 1');
|
||||
|
||||
@@ -29,6 +29,8 @@ function Icon({ name, filled = false, size = 20, className, style, ...props }: I
|
||||
<span
|
||||
aria-hidden="true"
|
||||
translate="no"
|
||||
{...props}
|
||||
// After the props: `data-icon` is the glyph, so a stray one never blanks it.
|
||||
data-slot="icon"
|
||||
data-icon={name}
|
||||
className={cn("material-symbol", DIRECTIONAL_ICONS.has(name) && "rtl:-scale-x-100", className)}
|
||||
@@ -37,7 +39,6 @@ function Icon({ name, filled = false, size = 20, className, style, ...props }: I
|
||||
fontVariationSettings: `"FILL" ${filled ? 1 : 0}, "wght" 300, "GRAD" 0, "opsz" ${size >= 24 ? 24 : 20}`,
|
||||
...style,
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
Generated
+3
@@ -549,6 +549,9 @@ importers:
|
||||
'@fontsource-variable/manrope':
|
||||
specifier: ^5.3.0
|
||||
version: 5.3.0
|
||||
'@lezer/highlight':
|
||||
specifier: ^1.2.4
|
||||
version: 1.2.4
|
||||
'@lingui/core':
|
||||
specifier: ^6.8.0
|
||||
version: 6.8.0(@babel/core@8.0.6)(babel-plugin-macros@3.1.0)
|
||||
|
||||
Reference in New Issue
Block a user