mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-10-03 10:13:47 +10:00
refactor(ui): retire the shadcn colour aliases
Every class that used the old names (muted, primary, card, border, input and the rest) now uses the Desk & Paper token it resolved to, with text colours on their text tokens (accent-text, danger-text, ink-3). The compatibility block in the theme is gone.
This commit is contained in:
@@ -43,7 +43,7 @@ function ChipDragPreview({ chip }: ChipDragPreviewProps) {
|
||||
return (
|
||||
<Badge
|
||||
variant="outline"
|
||||
className="h-6 max-w-44 cursor-grabbing select-none justify-start rounded-md border-ring bg-muted px-2 font-medium text-foreground text-xs shadow-lg ring-2 ring-ring/25 sm:max-w-52"
|
||||
className="h-6 max-w-44 cursor-grabbing select-none justify-start rounded-md border-accent bg-sunken px-2 font-medium text-ink text-xs shadow-lg ring-2 ring-accent/25 sm:max-w-52"
|
||||
>
|
||||
<span className="truncate">{chip}</span>
|
||||
</Badge>
|
||||
@@ -84,9 +84,9 @@ function ChipItem({ id, chip, index, isEditing, onEdit, onRemove }: ChipItemProp
|
||||
<Badge
|
||||
variant="outline"
|
||||
className={cn(
|
||||
"h-6 max-w-full cursor-grab select-none justify-start gap-0 rounded-md border-border bg-muted/55 px-2 font-medium text-foreground text-xs transition-colors hover:border-foreground/20 hover:bg-muted active:cursor-grabbing",
|
||||
isEditing && "border-primary bg-primary/10 ring-1 ring-primary/40",
|
||||
isDragging && "border-ring bg-muted shadow-sm",
|
||||
"h-6 max-w-full cursor-grab select-none justify-start gap-0 rounded-md border-line bg-sunken/55 px-2 font-medium text-ink text-xs transition-colors hover:border-ink/20 hover:bg-sunken active:cursor-grabbing",
|
||||
isEditing && "border-accent bg-accent/10 ring-1 ring-accent/40",
|
||||
isDragging && "border-accent bg-sunken shadow-sm",
|
||||
)}
|
||||
>
|
||||
<span className="max-w-32 truncate sm:max-w-44">{chip}</span>
|
||||
@@ -99,7 +99,7 @@ function ChipItem({ id, chip, index, isEditing, onEdit, onRemove }: ChipItemProp
|
||||
<button
|
||||
type="button"
|
||||
tabIndex={-1}
|
||||
className="rounded-sm p-0.5 text-foreground/70 transition-colors hover:bg-secondary hover:text-foreground focus:outline-none"
|
||||
className="rounded-sm p-0.5 text-ink/70 transition-colors hover:bg-sunken hover:text-ink focus:outline-none"
|
||||
aria-label={t({
|
||||
comment:
|
||||
"Screen reader label for button that edits a keyword chip. Variable is the current keyword text.",
|
||||
@@ -115,7 +115,7 @@ function ChipItem({ id, chip, index, isEditing, onEdit, onRemove }: ChipItemProp
|
||||
<button
|
||||
type="button"
|
||||
tabIndex={-1}
|
||||
className="rounded-sm p-0.5 text-foreground/70 transition-colors hover:bg-destructive/10 hover:text-destructive focus:outline-none"
|
||||
className="rounded-sm p-0.5 text-ink/70 transition-colors hover:bg-danger/10 hover:text-danger-text focus:outline-none"
|
||||
aria-label={t({
|
||||
comment:
|
||||
"Screen reader label for button that removes a keyword chip. Variable is the current keyword text.",
|
||||
@@ -344,11 +344,11 @@ export function ChipInput({
|
||||
<div
|
||||
role="none"
|
||||
onClick={() => inputRef.current?.focus()}
|
||||
className="overflow-hidden rounded-lg border border-input bg-background/40 transition-colors focus-within:border-ring focus-within:ring-3 focus-within:ring-ring/50 dark:bg-input/20"
|
||||
className="overflow-hidden rounded-lg border border-line-2 bg-bg/40 transition-colors focus-within:border-accent focus-within:ring-3 focus-within:ring-accent/50 dark:bg-line-2/20"
|
||||
>
|
||||
<div className="flex flex-col">
|
||||
<div
|
||||
className={cn("max-h-24 overflow-y-auto px-2 py-1.5", hasChips ? "border-border/70 border-b" : "hidden")}
|
||||
className={cn("max-h-24 overflow-y-auto px-2 py-1.5", hasChips ? "border-line/70 border-b" : "hidden")}
|
||||
>
|
||||
<SortableContext items={chips} strategy={rectSortingStrategy}>
|
||||
<div className="flex flex-wrap gap-1">
|
||||
@@ -390,8 +390,8 @@ export function ChipInput({
|
||||
className={cn(
|
||||
"flex h-6 min-w-6 shrink-0 items-center justify-center rounded-md border px-1.5 font-medium text-[0.7rem] tabular-nums",
|
||||
isEditingKeyword
|
||||
? "border-primary/30 bg-primary/10 text-primary"
|
||||
: "border-border bg-muted/50 text-foreground/80 opacity-80",
|
||||
? "border-accent/30 bg-accent/10 text-accent-text"
|
||||
: "border-line bg-sunken/50 text-ink/80 opacity-80",
|
||||
)}
|
||||
>
|
||||
{isEditingKeyword ? <Trans>Edit</Trans> : chips.length}
|
||||
@@ -404,7 +404,7 @@ export function ChipInput({
|
||||
</DndContext>
|
||||
|
||||
{!hideDescription && (
|
||||
<p className="text-muted-foreground text-xs">
|
||||
<p className="text-ink-3 text-xs">
|
||||
<Trans>
|
||||
Press <Kbd>{RETURN_KEY}</Kbd> or <Kbd>{COMMA_KEY}</Kbd> to add or save the current keyword.
|
||||
</Trans>
|
||||
|
||||
@@ -65,7 +65,7 @@ export function ColorPicker({
|
||||
{trigger ?? (
|
||||
<PopoverTrigger>
|
||||
<div
|
||||
className="size-6 shrink-0 cursor-pointer rounded-full border border-foreground/60 transition-transform duration-150 ease-out-strong focus-visible:outline-hidden active:scale-[0.97]"
|
||||
className="size-6 shrink-0 cursor-pointer rounded-full border border-ink/60 transition-transform duration-150 ease-out-strong focus-visible:outline-hidden active:scale-[0.97]"
|
||||
style={{ backgroundColor: currentValue }}
|
||||
/>
|
||||
</PopoverTrigger>
|
||||
@@ -80,11 +80,11 @@ export function ColorPicker({
|
||||
)}
|
||||
|
||||
<div className="flex flex-col gap-2">
|
||||
<span className="font-medium text-muted-foreground text-xs">
|
||||
<span className="font-medium text-ink-3 text-xs">
|
||||
<Trans>Presets</Trans>
|
||||
</span>
|
||||
|
||||
<div className="grid grid-cols-8 gap-3 rounded bg-muted p-3">
|
||||
<div className="grid grid-cols-8 gap-3 rounded bg-sunken p-3">
|
||||
{presetColors.map((color) => (
|
||||
<button
|
||||
key={color}
|
||||
@@ -95,8 +95,8 @@ export function ColorPicker({
|
||||
aria-pressed={currentValue === color}
|
||||
onClick={() => setCurrentValue(color)}
|
||||
className={cn(
|
||||
"size-5 shrink-0 cursor-pointer rounded-full transition-transform duration-150 ease-out-strong focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring active:scale-[0.97]",
|
||||
currentValue === color && "border border-foreground/60",
|
||||
"size-5 shrink-0 cursor-pointer rounded-full transition-transform duration-150 ease-out-strong focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent active:scale-[0.97]",
|
||||
currentValue === color && "border border-ink/60",
|
||||
)}
|
||||
/>
|
||||
))}
|
||||
@@ -104,11 +104,11 @@ export function ColorPicker({
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-2">
|
||||
<span className="font-medium text-muted-foreground text-xs">
|
||||
<span className="font-medium text-ink-3 text-xs">
|
||||
<Trans>Custom</Trans>
|
||||
</span>
|
||||
|
||||
<div className="rounded bg-muted p-3 *:w-full! [&_.w-color-alpha>div]:rounded-full! [&_.w-color-alpha]:mt-4! [&_.w-color-alpha]:h-4! [&_.w-color-hue]:mt-4! [&_.w-color-hue]:h-4! [&_.w-color-hue]:rounded-full! [&_.w-color-saturation]:h-36! [&_.w-color-saturation]:rounded-[calc(var(--radius-lg)-0.25rem)]!">
|
||||
<div className="rounded bg-sunken p-3 *:w-full! [&_.w-color-alpha>div]:rounded-full! [&_.w-color-alpha]:mt-4! [&_.w-color-alpha]:h-4! [&_.w-color-hue]:mt-4! [&_.w-color-hue]:h-4! [&_.w-color-hue]:rounded-full! [&_.w-color-saturation]:h-36! [&_.w-color-saturation]:rounded-[calc(var(--radius-lg)-0.25rem)]!">
|
||||
<ReactColorColorful color={color} onChange={onColorChange} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -565,8 +565,8 @@ export function RichInput({
|
||||
"data-fullscreen": isFullscreen ? "true" : "false",
|
||||
class: cn(
|
||||
"wysiwyg group/editor overflow-y-auto p-3 pb-4 [&_[data-resume-whitespace=preserve]]:whitespace-pre-wrap",
|
||||
"rounded-md rounded-t-none border outline-none focus-visible:border-ring",
|
||||
"[td:has(.selectedCell)]:bg-primary",
|
||||
"rounded-md rounded-t-none border outline-none focus-visible:border-accent",
|
||||
"[td:has(.selectedCell)]:bg-accent",
|
||||
"data-[fullscreen=false]:max-h-[400px] data-[fullscreen=false]:min-h-[100px]",
|
||||
"data-[fullscreen=true]:max-h-none data-[fullscreen=true]:min-h-full",
|
||||
editorClassName,
|
||||
@@ -596,7 +596,7 @@ export function RichInput({
|
||||
const editorElement = (
|
||||
<div className="relative">
|
||||
{hasUnsupportedTable ? (
|
||||
<div role="status" className="rounded-md rounded-b-none border border-b-0 bg-muted px-3 py-2 text-sm">
|
||||
<div role="status" className="rounded-md rounded-b-none border border-b-0 bg-sunken px-3 py-2 text-sm">
|
||||
<span>
|
||||
<Trans>
|
||||
Original table formatting is preserved. This content is read-only because it cannot be edited safely.
|
||||
@@ -897,7 +897,7 @@ function renderEditorToolbar(state: EditorToolbarState, isFullscreen: boolean) {
|
||||
size={isFullscreen ? "lg" : "sm"}
|
||||
tabIndex={-1}
|
||||
variant="ghost"
|
||||
className={cn("rounded-none px-2", state.isHighlight && "bg-muted text-foreground")}
|
||||
className={cn("rounded-none px-2", state.isHighlight && "bg-sunken text-ink")}
|
||||
title={t`Highlight`}
|
||||
disabled={!state.canHighlightColor}
|
||||
>
|
||||
@@ -916,7 +916,7 @@ function renderEditorToolbar(state: EditorToolbarState, isFullscreen: boolean) {
|
||||
<PopoverHeader className="flex-row items-start justify-between gap-2">
|
||||
<div className="flex items-center gap-2.5">
|
||||
<span
|
||||
className="grid size-9 place-items-center rounded-lg border border-border bg-muted/60 text-sm shadow-xs"
|
||||
className="grid size-9 place-items-center rounded-lg border border-line bg-sunken/60 text-sm shadow-xs"
|
||||
style={{ backgroundColor: visibleHighlightColor ?? defaultHighlightColor }}
|
||||
>
|
||||
<HighlighterCircleIcon className="size-4" />
|
||||
@@ -926,7 +926,7 @@ function renderEditorToolbar(state: EditorToolbarState, isFullscreen: boolean) {
|
||||
<PopoverTitle>
|
||||
<Trans>Highlight Color</Trans>
|
||||
</PopoverTitle>
|
||||
<span className="text-muted-foreground text-xs">
|
||||
<span className="text-ink-3 text-xs">
|
||||
<Trans comment="Preset or custom shade refer to the color picker">
|
||||
Choose a preset or custom shade.
|
||||
</Trans>
|
||||
@@ -957,7 +957,7 @@ function renderEditorToolbar(state: EditorToolbarState, isFullscreen: boolean) {
|
||||
size={isFullscreen ? "lg" : "sm"}
|
||||
tabIndex={-1}
|
||||
variant="ghost"
|
||||
className={cn("rounded-none px-2", state.textColor && "bg-muted text-foreground")}
|
||||
className={cn("rounded-none px-2", state.textColor && "bg-sunken text-ink")}
|
||||
title={t`Text Color`}
|
||||
disabled={!state.canTextColor}
|
||||
>
|
||||
@@ -976,7 +976,7 @@ function renderEditorToolbar(state: EditorToolbarState, isFullscreen: boolean) {
|
||||
<PopoverHeader className="flex-row items-start justify-between gap-2">
|
||||
<div className="flex items-center gap-2.5">
|
||||
<span
|
||||
className="grid size-9 place-items-center rounded-lg border border-border bg-muted/60 font-semibold text-sm shadow-xs"
|
||||
className="grid size-9 place-items-center rounded-lg border border-line bg-sunken/60 font-semibold text-sm shadow-xs"
|
||||
style={{ color: state.textColor ?? "currentColor" }}
|
||||
>
|
||||
A
|
||||
@@ -986,7 +986,7 @@ function renderEditorToolbar(state: EditorToolbarState, isFullscreen: boolean) {
|
||||
<PopoverTitle>
|
||||
<Trans>Text Color</Trans>
|
||||
</PopoverTitle>
|
||||
<span className="text-muted-foreground text-xs">
|
||||
<span className="text-ink-3 text-xs">
|
||||
<Trans comment="Preset or custom shade refer to the color picker">
|
||||
Choose a preset or custom shade.
|
||||
</Trans>
|
||||
@@ -1006,7 +1006,7 @@ function renderEditorToolbar(state: EditorToolbarState, isFullscreen: boolean) {
|
||||
</PopoverHeader>
|
||||
</ColorPicker>
|
||||
|
||||
<div className="mx-1 h-5 w-px bg-border" />
|
||||
<div className="mx-1 h-5 w-px bg-line" />
|
||||
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger
|
||||
@@ -1141,7 +1141,7 @@ function renderEditorToolbar(state: EditorToolbarState, isFullscreen: boolean) {
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
||||
<div className="mx-1 h-5 w-px bg-border" />
|
||||
<div className="mx-1 h-5 w-px bg-line" />
|
||||
|
||||
<Toggle
|
||||
size={isFullscreen ? "lg" : "sm"}
|
||||
@@ -1191,7 +1191,7 @@ function renderEditorToolbar(state: EditorToolbarState, isFullscreen: boolean) {
|
||||
<TextIndentIcon className="size-3.5" />
|
||||
</Button>
|
||||
|
||||
<div className="mx-1 h-5 w-px bg-border" />
|
||||
<div className="mx-1 h-5 w-px bg-line" />
|
||||
|
||||
{state.isLink ? (
|
||||
<Button
|
||||
@@ -1251,7 +1251,7 @@ function renderEditorToolbar(state: EditorToolbarState, isFullscreen: boolean) {
|
||||
<MinusIcon className="size-3.5" />
|
||||
</Button>
|
||||
|
||||
<span className="ml-auto px-2 text-muted-foreground text-xs tabular-nums" aria-live="polite">
|
||||
<span className="ml-auto px-2 text-ink-3 text-xs tabular-nums" aria-live="polite">
|
||||
<Trans comment="Character count readout for the rich-text editor">{state.characterCount} characters</Trans>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Spinner } from "@reactive-resume/ui/components/spinner";
|
||||
|
||||
export function LoadingScreen() {
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 flex h-svh w-svw flex-col items-center justify-center gap-y-6 bg-background">
|
||||
<div className="fixed inset-0 z-50 flex h-svh w-svw flex-col items-center justify-center gap-y-6 bg-bg">
|
||||
<BrandIcon variant="icon" className="size-12" />
|
||||
<Spinner className="size-6" />
|
||||
</div>
|
||||
|
||||
@@ -38,7 +38,7 @@ export function FontDisplay({ family, label, type, url }: FontDisplayProps) {
|
||||
>
|
||||
{label}
|
||||
</span>
|
||||
{label !== family && <span className="text-muted-foreground text-xs">{family}</span>}
|
||||
{label !== family && <span className="text-ink-3 text-xs">{family}</span>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -224,7 +224,7 @@ function Combobox<TValue extends string | number = string>(props: ComboboxProps<
|
||||
render ?? (
|
||||
<Button
|
||||
variant="secondary"
|
||||
className={cn("justify-start text-left font-normal hover:bg-muted/20", className)}
|
||||
className={cn("justify-start text-left font-normal hover:bg-sunken/20", className)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -254,7 +254,7 @@ function Combobox<TValue extends string | number = string>(props: ComboboxProps<
|
||||
<ComboboxClear
|
||||
aria-label={t`Clear selection`}
|
||||
disabled={disabled}
|
||||
className="absolute end-7 top-1/2 z-10 -translate-y-1/2 text-muted-foreground opacity-70 hover:opacity-100 focus-visible:opacity-100"
|
||||
className="absolute end-7 top-1/2 z-10 -translate-y-1/2 text-ink-3 opacity-70 hover:opacity-100 focus-visible:opacity-100"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -44,7 +44,7 @@ describe("Copyright", () => {
|
||||
const { container } = renderCopyright({ className: "extra-class" });
|
||||
const wrapper = container.firstChild as HTMLElement;
|
||||
expect(wrapper.className).toContain("extra-class");
|
||||
expect(wrapper.className).toContain("text-muted-foreground");
|
||||
expect(wrapper.className).toContain("text-ink-3");
|
||||
});
|
||||
|
||||
it("opens external links in a new tab", () => {
|
||||
|
||||
@@ -5,7 +5,7 @@ type Props = React.ComponentProps<"div">;
|
||||
|
||||
export function Copyright({ className, ...props }: Props) {
|
||||
return (
|
||||
<div className={cn("text-muted-foreground/80 text-xs leading-relaxed", className)} {...props}>
|
||||
<div className={cn("text-ink-3/80 text-xs leading-relaxed", className)} {...props}>
|
||||
<p>
|
||||
<Trans>
|
||||
Licensed under{" "}
|
||||
|
||||
@@ -313,7 +313,7 @@ export function EnableTwoFactorDialog(_: DialogProps<"auth.two-factor.enable">)
|
||||
<div className="space-y-4">
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
{backupCodes.map((code) => (
|
||||
<div key={code} className="rounded-md border border-border p-2 text-center font-mono text-sm">
|
||||
<div key={code} className="rounded-md border border-line p-2 text-center font-mono text-sm">
|
||||
{code}
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -212,16 +212,16 @@ export function ApplicationFormSheet({ open, onOpenChange, application }: Props)
|
||||
{/* Pasted job description: stored with the application and used for every AI action.
|
||||
Collapsed by default so the form stays short; hidden entirely when AI is off. */}
|
||||
{aiEnabled && (
|
||||
<Accordion className="rounded-lg border border-border border-dashed px-3">
|
||||
<Accordion className="rounded-lg border border-line border-dashed px-3">
|
||||
<AccordionItem value="job-description">
|
||||
<AccordionTrigger>
|
||||
<span className="flex items-center gap-1.5">
|
||||
<SparkleIcon className="text-primary" />
|
||||
<SparkleIcon className="text-accent-text" />
|
||||
<Trans>Job description</Trans>
|
||||
</span>
|
||||
</AccordionTrigger>
|
||||
<AccordionContent className="flex flex-col gap-2">
|
||||
<p className="text-muted-foreground text-xs">
|
||||
<p className="text-ink-3 text-xs">
|
||||
<Trans>
|
||||
Copy the entire job description from the posting and paste it below. We'll fill in the fields for
|
||||
you and keep the text with this application for match scoring and tailoring.
|
||||
@@ -239,7 +239,7 @@ export function ApplicationFormSheet({ open, onOpenChange, application }: Props)
|
||||
onPaste={(event) => runAutofill(event.clipboardData.getData("text"))}
|
||||
/>
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<p className="text-[11px] text-muted-foreground">
|
||||
<p className="text-[11px] text-ink-3">
|
||||
{autofill.isPending ? (
|
||||
<Trans>Reading the posting…</Trans>
|
||||
) : (
|
||||
@@ -348,7 +348,7 @@ export function ApplicationFormSheet({ open, onOpenChange, application }: Props)
|
||||
attachLabel={t`Or upload a resume PDF`}
|
||||
onChange={(value) => set("resumeFile", value)}
|
||||
/>
|
||||
<p className="text-[11px] text-muted-foreground">
|
||||
<p className="text-[11px] text-ink-3">
|
||||
<Trans>Link a Reactive Resume to use AI match scoring and tailoring.</Trans>
|
||||
</p>
|
||||
</div>
|
||||
@@ -401,9 +401,9 @@ export function ApplicationFormSheet({ open, onOpenChange, application }: Props)
|
||||
function Field({ label, required, children }: { label: string; required?: boolean; children: React.ReactNode }) {
|
||||
return (
|
||||
<div className="grid gap-1.5">
|
||||
<Label className="text-muted-foreground text-xs">
|
||||
<Label className="text-ink-3 text-xs">
|
||||
{label}
|
||||
{required && <span className="text-destructive"> *</span>}
|
||||
{required && <span className="text-danger-text"> *</span>}
|
||||
</Label>
|
||||
{children}
|
||||
</div>
|
||||
@@ -455,13 +455,13 @@ function TagsField({ value, suggestions, onChange }: TagsFieldProps) {
|
||||
{value.map((tag) => (
|
||||
<span
|
||||
key={tag}
|
||||
className="inline-flex items-center gap-1 rounded-full bg-muted px-2 py-0.5 text-muted-foreground text-xs"
|
||||
className="inline-flex items-center gap-1 rounded-full bg-sunken px-2 py-0.5 text-ink-3 text-xs"
|
||||
>
|
||||
{tag}
|
||||
<button
|
||||
type="button"
|
||||
title={t`Remove tag`}
|
||||
className="hover:text-destructive"
|
||||
className="hover:text-danger-text"
|
||||
onClick={() => onChange(value.filter((t) => t !== tag))}
|
||||
>
|
||||
<XIcon className="size-3" />
|
||||
|
||||
@@ -88,7 +88,7 @@ export function ApplicationCalendar({ applications, allApplications, onOpen }: A
|
||||
<div className="flex flex-wrap items-center gap-x-3 gap-y-2">
|
||||
<div className="flex items-baseline gap-2">
|
||||
<h2 className="font-semibold text-lg capitalize">{monthFormat.format(month)}</h2>
|
||||
<span className="text-muted-foreground text-sm">
|
||||
<span className="text-ink-3 text-sm">
|
||||
{monthCount === 0 ? (
|
||||
<Trans>No interviews</Trans>
|
||||
) : monthCount === 1 ? (
|
||||
@@ -121,11 +121,11 @@ export function ApplicationCalendar({ applications, allApplications, onOpen }: A
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid shrink-0 grid-cols-7 overflow-hidden rounded-xl border border-border bg-card">
|
||||
<div className="grid shrink-0 grid-cols-7 overflow-hidden rounded-xl border border-line bg-surface">
|
||||
{days.slice(0, 7).map((day) => (
|
||||
<div
|
||||
key={`weekday-${day.getDay()}`}
|
||||
className="border-border border-b px-2 py-2 text-center font-medium text-[11px] text-muted-foreground uppercase tracking-wide"
|
||||
className="border-line border-b px-2 py-2 text-center font-medium text-[11px] text-ink-3 uppercase tracking-wide"
|
||||
>
|
||||
{weekdayFormat.format(day)}
|
||||
</div>
|
||||
@@ -144,10 +144,10 @@ export function ApplicationCalendar({ applications, allApplications, onOpen }: A
|
||||
key={key}
|
||||
data-day={key}
|
||||
className={cn(
|
||||
"group/day relative flex min-h-16 flex-col gap-1 border-border p-1 sm:min-h-24 sm:p-1.5",
|
||||
"group/day relative flex min-h-16 flex-col gap-1 border-line p-1 sm:min-h-24 sm:p-1.5",
|
||||
i % 7 !== 6 && "border-e",
|
||||
i < 35 && "border-b",
|
||||
!inMonth && "bg-muted/30",
|
||||
!inMonth && "bg-sunken/30",
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
@@ -155,7 +155,7 @@ export function ApplicationCalendar({ applications, allApplications, onOpen }: A
|
||||
type="button"
|
||||
title={scheduleLabel}
|
||||
aria-label={scheduleLabel}
|
||||
className="flex size-6 items-center justify-center rounded-md text-muted-foreground opacity-0 transition-opacity hover:bg-muted hover:text-foreground focus-visible:opacity-100 group-hover/day:opacity-100 max-sm:hidden"
|
||||
className="flex size-6 items-center justify-center rounded-md text-ink-3 opacity-0 transition-opacity hover:bg-sunken hover:text-ink focus-visible:opacity-100 group-hover/day:opacity-100 max-sm:hidden"
|
||||
onClick={() => schedule(day)}
|
||||
>
|
||||
<PlusIcon className="size-3.5" />
|
||||
@@ -163,8 +163,8 @@ export function ApplicationCalendar({ applications, allApplications, onOpen }: A
|
||||
<span
|
||||
className={cn(
|
||||
"flex size-6 items-center justify-center rounded-full text-xs",
|
||||
!inMonth && "text-muted-foreground/60",
|
||||
isToday && "bg-primary font-semibold text-primary-foreground",
|
||||
!inMonth && "text-ink-3/60",
|
||||
isToday && "bg-accent font-semibold text-on-accent",
|
||||
)}
|
||||
>
|
||||
{day.getDate()}
|
||||
@@ -184,7 +184,7 @@ export function ApplicationCalendar({ applications, allApplications, onOpen }: A
|
||||
render={
|
||||
<button
|
||||
type="button"
|
||||
className="self-start rounded-md px-1.5 py-0.5 text-[11px] text-muted-foreground hover:bg-muted hover:text-foreground"
|
||||
className="self-start rounded-md px-1.5 py-0.5 text-[11px] text-ink-3 hover:bg-sunken hover:text-ink"
|
||||
/>
|
||||
}
|
||||
>
|
||||
@@ -208,7 +208,7 @@ export function ApplicationCalendar({ applications, allApplications, onOpen }: A
|
||||
})}
|
||||
</div>
|
||||
|
||||
<div className="flex flex-wrap items-center gap-x-4 gap-y-1 text-muted-foreground text-xs">
|
||||
<div className="flex flex-wrap items-center gap-x-4 gap-y-1 text-ink-3 text-xs">
|
||||
{INTERVIEW_KINDS.map((kind) => (
|
||||
<span key={kind.value} className="flex items-center gap-1.5">
|
||||
<span className="size-2 rounded-full" style={{ background: kind.color }} />
|
||||
@@ -224,15 +224,15 @@ export function ApplicationCalendar({ applications, allApplications, onOpen }: A
|
||||
</h3>
|
||||
|
||||
{upcoming.length === 0 ? (
|
||||
<div className="flex flex-col items-center gap-3 rounded-xl border border-border border-dashed px-4 py-8 text-center">
|
||||
<div className="flex size-10 items-center justify-center rounded-full bg-muted">
|
||||
<CalendarBlankIcon className="size-5 text-muted-foreground" />
|
||||
<div className="flex flex-col items-center gap-3 rounded-xl border border-line border-dashed px-4 py-8 text-center">
|
||||
<div className="flex size-10 items-center justify-center rounded-full bg-sunken">
|
||||
<CalendarBlankIcon className="size-5 text-ink-3" />
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<p className="font-medium text-sm">
|
||||
<Trans>Nothing scheduled yet</Trans>
|
||||
</p>
|
||||
<p className="text-muted-foreground text-xs">
|
||||
<p className="text-ink-3 text-xs">
|
||||
<Trans>Add screening calls and technical interviews to see them here and on the calendar.</Trans>
|
||||
</p>
|
||||
</div>
|
||||
@@ -247,7 +247,7 @@ export function ApplicationCalendar({ applications, allApplications, onOpen }: A
|
||||
if (!first) return null;
|
||||
return (
|
||||
<div key={dayKey(first.start)} className="flex flex-col gap-2">
|
||||
<h4 className="font-medium text-muted-foreground text-xs">{dayHeading(first.start)}</h4>
|
||||
<h4 className="font-medium text-ink-3 text-xs">{dayHeading(first.start)}</h4>
|
||||
{group.map((item) => (
|
||||
<UpcomingCard
|
||||
key={item.interview.id}
|
||||
@@ -289,26 +289,26 @@ function UpcomingCard({ item, timeRange, locale, onEdit, onOpenApplication }: Up
|
||||
return (
|
||||
<div
|
||||
data-upcoming-interview={item.interview.id}
|
||||
className="relative overflow-hidden rounded-xl border border-border bg-card ps-4 text-sm"
|
||||
className="relative overflow-hidden rounded-xl border border-line bg-surface ps-4 text-sm"
|
||||
>
|
||||
<span className="absolute inset-y-0 start-0 w-1" style={{ background: kind?.color }} />
|
||||
<button type="button" className="block w-full py-3 pe-3 text-start hover:opacity-80" onClick={onEdit}>
|
||||
<span className="flex items-center justify-between gap-2 text-xs">
|
||||
<span className="font-medium">{timeRange}</span>
|
||||
<span className="text-muted-foreground">{formatDuration(item.interview.durationMinutes, locale)}</span>
|
||||
<span className="text-ink-3">{formatDuration(item.interview.durationMinutes, locale)}</span>
|
||||
</span>
|
||||
<span className="mt-1 block truncate font-semibold">{item.application.company}</span>
|
||||
<span className="block truncate text-muted-foreground text-xs">
|
||||
<span className="block truncate text-ink-3 text-xs">
|
||||
{kind?.label ?? item.interview.kind} · {item.application.role}
|
||||
</span>
|
||||
{item.interview.location && (
|
||||
<span className="mt-1.5 flex items-center gap-1 text-muted-foreground text-xs">
|
||||
<span className="mt-1.5 flex items-center gap-1 text-ink-3 text-xs">
|
||||
<MapPinIcon className="shrink-0" />
|
||||
<span className="truncate">{item.interview.location}</span>
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
<button type="button" className="mb-2 text-primary text-xs hover:underline" onClick={onOpenApplication}>
|
||||
<button type="button" className="mb-2 text-accent-text text-xs hover:underline" onClick={onOpenApplication}>
|
||||
<Trans>View application</Trans>
|
||||
</button>
|
||||
</div>
|
||||
@@ -327,13 +327,13 @@ function InterviewChip({ item, time, onOpen }: InterviewChipProps) {
|
||||
<button
|
||||
type="button"
|
||||
title={`${time} · ${kind?.label ?? item.interview.kind} · ${item.application.company} — ${item.application.role}`}
|
||||
className="flex min-w-0 items-center gap-1.5 rounded-md border-s-2 bg-muted/60 px-1.5 py-0.5 text-start text-[11px] leading-tight hover:bg-muted max-sm:justify-center max-sm:border-s-0 max-sm:bg-transparent"
|
||||
className="flex min-w-0 items-center gap-1.5 rounded-md border-s-2 bg-sunken/60 px-1.5 py-0.5 text-start text-[11px] leading-tight hover:bg-sunken max-sm:justify-center max-sm:border-s-0 max-sm:bg-transparent"
|
||||
style={{ borderInlineStartColor: kind?.color }}
|
||||
onClick={onOpen}
|
||||
>
|
||||
<span className="size-2 shrink-0 rounded-full sm:hidden" style={{ background: kind?.color }} />
|
||||
<span className="flex min-w-0 items-baseline gap-1.5 max-sm:hidden">
|
||||
<span className="shrink-0 text-muted-foreground tabular-nums">{time}</span>
|
||||
<span className="shrink-0 text-ink-3 tabular-nums">{time}</span>
|
||||
<span className="truncate font-medium">{item.application.company}</span>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
@@ -97,11 +97,11 @@ export function ExportApplicationsSheet({ open, onOpenChange, applications, filt
|
||||
</div>
|
||||
</div>
|
||||
{!validRange && (
|
||||
<p role="alert" className="text-destructive text-sm">
|
||||
<p role="alert" className="text-danger-text text-sm">
|
||||
<Trans>Start date must be on or before end date.</Trans>
|
||||
</p>
|
||||
)}
|
||||
<p className="text-muted-foreground text-sm">
|
||||
<p className="text-ink-3 text-sm">
|
||||
<Plural value={selected.length} one="# application to export" other="# applications to export" />
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -55,8 +55,8 @@ export function FileAttachmentField({ value, onChange, attachLabel, disabled }:
|
||||
return (
|
||||
<>
|
||||
{value ? (
|
||||
<div className="flex items-center gap-3 rounded-lg border border-border p-2.5">
|
||||
<span className="flex size-8 items-center justify-center rounded-md bg-primary/10 text-primary">
|
||||
<div className="flex items-center gap-3 rounded-lg border border-line p-2.5">
|
||||
<span className="flex size-8 items-center justify-center rounded-md bg-accent/10 text-accent-text">
|
||||
<FilePdfIcon />
|
||||
</span>
|
||||
<a
|
||||
@@ -71,7 +71,7 @@ export function FileAttachmentField({ value, onChange, attachLabel, disabled }:
|
||||
type="button"
|
||||
title={t`Remove file`}
|
||||
disabled={disabled}
|
||||
className="text-muted-foreground hover:text-destructive disabled:opacity-40"
|
||||
className="text-ink-3 hover:text-danger-text disabled:opacity-40"
|
||||
onClick={clear}
|
||||
>
|
||||
<XIcon />
|
||||
@@ -82,7 +82,7 @@ export function FileAttachmentField({ value, onChange, attachLabel, disabled }:
|
||||
type="button"
|
||||
disabled={disabled || upload.isPending}
|
||||
onClick={() => inputRef.current?.click()}
|
||||
className="flex w-full items-center gap-2 rounded-lg border border-border border-dashed p-2.5 text-muted-foreground text-sm hover:bg-muted/50 disabled:opacity-60"
|
||||
className="flex w-full items-center gap-2 rounded-lg border border-line border-dashed p-2.5 text-ink-3 text-sm hover:bg-sunken/50 disabled:opacity-60"
|
||||
>
|
||||
<UploadSimpleIcon />
|
||||
{upload.isPending ? <Trans>Uploading…</Trans> : attachLabel}
|
||||
|
||||
@@ -200,9 +200,7 @@ export function InterviewDialog({
|
||||
aria-pressed={selected}
|
||||
className={cn(
|
||||
"flex items-center gap-1.5 rounded-full border px-3 py-1 text-xs transition-colors",
|
||||
selected
|
||||
? "border-foreground bg-foreground text-background"
|
||||
: "border-border text-muted-foreground hover:bg-muted hover:text-foreground",
|
||||
selected ? "border-ink bg-ink text-bg" : "border-line text-ink-3 hover:bg-sunken hover:text-ink",
|
||||
)}
|
||||
onClick={() => set("kind", kind.value)}
|
||||
>
|
||||
@@ -259,7 +257,7 @@ export function InterviewDialog({
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
className="text-destructive"
|
||||
className="text-danger-text"
|
||||
disabled={pending}
|
||||
onClick={async () => {
|
||||
const confirmed = await confirm(t`Delete this interview?`, {
|
||||
@@ -294,9 +292,9 @@ type FieldProps = { label: string; htmlFor?: string; required?: boolean; childre
|
||||
function Field({ label, htmlFor, required, children }: FieldProps) {
|
||||
return (
|
||||
<div className="grid gap-1.5">
|
||||
<Label htmlFor={htmlFor} className="text-muted-foreground text-xs">
|
||||
<Label htmlFor={htmlFor} className="text-ink-3 text-xs">
|
||||
{label}
|
||||
{required && <span className="text-destructive"> *</span>}
|
||||
{required && <span className="text-danger-text"> *</span>}
|
||||
</Label>
|
||||
{children}
|
||||
</div>
|
||||
|
||||
@@ -21,13 +21,13 @@ export function FindingRow({ finding }: FindingRowProps) {
|
||||
const evidence = finding.evidence;
|
||||
|
||||
return (
|
||||
<li className="space-y-2 rounded-md border bg-card p-3">
|
||||
<li className="space-y-2 rounded-md border bg-surface p-3">
|
||||
<div className="flex items-start gap-2">
|
||||
<span className={cn("mt-1.5 size-2 shrink-0 rounded-full", severityDotClass(finding.severity))} aria-hidden />
|
||||
|
||||
<div className="min-w-0 flex-1 space-y-1">
|
||||
<p className="font-medium text-sm leading-snug">{message.title}</p>
|
||||
<p className="text-muted-foreground text-xs leading-normal">{message.action}</p>
|
||||
<p className="text-ink-3 text-xs leading-normal">{message.action}</p>
|
||||
</div>
|
||||
|
||||
<Badge variant="neutral" className="shrink-0">
|
||||
@@ -38,7 +38,7 @@ export function FindingRow({ finding }: FindingRowProps) {
|
||||
{(evidence?.snippet || evidence?.page !== undefined) && (
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
{evidence.snippet && (
|
||||
<code className="min-w-0 truncate rounded bg-muted px-1.5 py-0.5 font-mono text-muted-foreground text-xs">
|
||||
<code className="min-w-0 truncate rounded bg-sunken px-1.5 py-0.5 font-mono text-ink-3 text-xs">
|
||||
{evidence.snippet}
|
||||
</code>
|
||||
)}
|
||||
|
||||
@@ -16,7 +16,7 @@ type JdCoverageProps = {
|
||||
export function JdCoverage({ jd }: JdCoverageProps) {
|
||||
if (jd.totalTerms === 0) {
|
||||
return (
|
||||
<p className="rounded-md border border-dashed p-3 text-muted-foreground text-xs leading-normal">
|
||||
<p className="rounded-md border border-dashed p-3 text-ink-3 text-xs leading-normal">
|
||||
<Trans>
|
||||
No specific terms could be pulled out of that job description, so it may be mostly boilerplate. Paste the
|
||||
requirements section for a more useful comparison.
|
||||
@@ -29,21 +29,21 @@ export function JdCoverage({ jd }: JdCoverageProps) {
|
||||
const missing = jd.terms.filter((term) => term.resumeCount === 0);
|
||||
|
||||
return (
|
||||
<div className="space-y-3 rounded-md border bg-card p-3">
|
||||
<div className="space-y-3 rounded-md border bg-surface p-3">
|
||||
<div className="space-y-1">
|
||||
<p className="font-medium text-sm leading-none">
|
||||
<Trans>
|
||||
{jd.matchedCount} of {jd.totalTerms} terms found
|
||||
</Trans>
|
||||
</p>
|
||||
<p className="text-muted-foreground text-xs leading-normal">
|
||||
<p className="text-ink-3 text-xs leading-normal">
|
||||
<Trans>Counted separately from the parse score. Coverage does not predict anything.</Trans>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{missing.length > 0 && (
|
||||
<div className="space-y-1.5">
|
||||
<p className="font-medium text-muted-foreground text-xs">
|
||||
<p className="font-medium text-ink-3 text-xs">
|
||||
<Trans>Not in your resume</Trans>
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-1.5">
|
||||
@@ -58,7 +58,7 @@ export function JdCoverage({ jd }: JdCoverageProps) {
|
||||
|
||||
{matched.length > 0 && (
|
||||
<div className="space-y-1.5">
|
||||
<p className="font-medium text-muted-foreground text-xs">
|
||||
<p className="font-medium text-ink-3 text-xs">
|
||||
<Trans>Already covered</Trans>
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-1.5">
|
||||
@@ -72,7 +72,7 @@ export function JdCoverage({ jd }: JdCoverageProps) {
|
||||
)}
|
||||
|
||||
{jd.stuffedTerms.length > 0 && (
|
||||
<p className="text-muted-foreground text-xs leading-normal">
|
||||
<p className="text-ink-3 text-xs leading-normal">
|
||||
<Trans>
|
||||
Repeated far more often than the posting itself uses them: {jd.stuffedTerms.join(", ")}. Recruiters notice.
|
||||
</Trans>
|
||||
@@ -80,7 +80,7 @@ export function JdCoverage({ jd }: JdCoverageProps) {
|
||||
)}
|
||||
|
||||
{jd.documentHasHiddenText && (
|
||||
<p className="text-muted-foreground text-xs leading-normal">
|
||||
<p className="text-ink-3 text-xs leading-normal">
|
||||
<Trans>This file contains text a reader cannot see, so some of these matches may be against it.</Trans>
|
||||
</p>
|
||||
)}
|
||||
|
||||
@@ -43,7 +43,7 @@ export function AtsPdfReportView({ report, className }: ReportViewProps) {
|
||||
<ScoreHeader report={report} />
|
||||
|
||||
{report.document.truncated && (
|
||||
<p className="text-muted-foreground text-xs leading-normal">
|
||||
<p className="text-ink-3 text-xs leading-normal">
|
||||
<Trans>
|
||||
Only the first {report.document.pageCount} pages were checked, so this report does not cover the whole file.
|
||||
</Trans>
|
||||
@@ -64,7 +64,7 @@ export function AtsPdfReportView({ report, className }: ReportViewProps) {
|
||||
|
||||
{report.jd && <JdCoverage jd={report.jd} />}
|
||||
|
||||
<p className="text-muted-foreground text-xs leading-normal">
|
||||
<p className="text-ink-3 text-xs leading-normal">
|
||||
<Trans>
|
||||
This measures how faithfully software can extract this file's text. It does not predict whether an application
|
||||
will be rejected, and no tool can. Your file was read in this browser and never uploaded.
|
||||
@@ -89,7 +89,7 @@ function CategorySection({ category, findings }: CategorySectionProps) {
|
||||
<span className={categoryTone(category.score)}>{category.score}</span>
|
||||
</Badge>
|
||||
{findings.length > 0 && (
|
||||
<span className="shrink-0 font-normal text-muted-foreground text-xs">
|
||||
<span className="shrink-0 font-normal text-ink-3 text-xs">
|
||||
<Trans>{findings.length} to fix</Trans>
|
||||
</span>
|
||||
)}
|
||||
@@ -97,7 +97,7 @@ function CategorySection({ category, findings }: CategorySectionProps) {
|
||||
</AccordionTrigger>
|
||||
|
||||
<AccordionContent className="space-y-3">
|
||||
<p className="text-muted-foreground text-xs leading-normal">
|
||||
<p className="text-ink-3 text-xs leading-normal">
|
||||
{getPdfCategoryDescription(category.category)}{" "}
|
||||
<Trans>
|
||||
{category.passedChecks} of {category.applicableChecks} applicable checks passed.
|
||||
@@ -107,7 +107,7 @@ function CategorySection({ category, findings }: CategorySectionProps) {
|
||||
{findings.length === 0 ? (
|
||||
<div className="flex items-center gap-2 rounded-md border border-dashed p-2.5">
|
||||
<CheckCircleIcon className="size-4 shrink-0 text-accent-text" />
|
||||
<span className="text-muted-foreground text-xs leading-normal">
|
||||
<span className="text-ink-3 text-xs leading-normal">
|
||||
<Trans>Nothing to fix here.</Trans>
|
||||
</span>
|
||||
</div>
|
||||
@@ -141,12 +141,12 @@ function WritingSection({ tips }: WritingSectionProps) {
|
||||
</AccordionTrigger>
|
||||
|
||||
<AccordionContent className="space-y-3">
|
||||
<p className="text-muted-foreground text-xs leading-normal">{getPdfCategoryDescription("content")}</p>
|
||||
<p className="text-ink-3 text-xs leading-normal">{getPdfCategoryDescription("content")}</p>
|
||||
|
||||
{tips.length === 0 ? (
|
||||
<div className="flex items-center gap-2 rounded-md border border-dashed p-2.5">
|
||||
<CheckCircleIcon className="size-4 shrink-0 text-accent-text" />
|
||||
<span className="text-muted-foreground text-xs leading-normal">
|
||||
<span className="text-ink-3 text-xs leading-normal">
|
||||
<Trans>Nothing to suggest.</Trans>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -21,15 +21,15 @@ export function ScoreHeader({ report }: ScoreHeaderProps) {
|
||||
const [cap] = report.cappedBy;
|
||||
|
||||
return (
|
||||
<div className="space-y-3 rounded-md border bg-card p-3">
|
||||
<div className="space-y-3 rounded-md border bg-surface p-3">
|
||||
<div className="flex items-baseline gap-2">
|
||||
<span className={cn("font-bold text-4xl tabular-nums leading-none", tone.text)}>{report.score}</span>
|
||||
<span className="text-muted-foreground text-sm">
|
||||
<span className="text-ink-3 text-sm">
|
||||
<Trans>out of 100</Trans>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="h-1.5 overflow-hidden rounded-full bg-muted">
|
||||
<div className="h-1.5 overflow-hidden rounded-full bg-sunken">
|
||||
<div
|
||||
className={cn(
|
||||
"h-full translate-x-(--fill) rounded-full transition-[translate] duration-300 ease-out-strong rtl:-translate-x-(--fill)",
|
||||
@@ -39,7 +39,7 @@ export function ScoreHeader({ report }: ScoreHeaderProps) {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-wrap items-center gap-x-2 gap-y-1 text-muted-foreground text-xs">
|
||||
<div className="flex flex-wrap items-center gap-x-2 gap-y-1 text-ink-3 text-xs">
|
||||
<span>
|
||||
<Trans>
|
||||
{report.passedChecks} of {report.applicableChecks} applicable checks passed
|
||||
@@ -67,7 +67,7 @@ export function ScoreHeader({ report }: ScoreHeaderProps) {
|
||||
</div>
|
||||
|
||||
{cap && (
|
||||
<p className="rounded-md bg-muted/60 p-2 text-muted-foreground text-xs leading-normal">
|
||||
<p className="rounded-md bg-sunken/60 p-2 text-ink-3 text-xs leading-normal">
|
||||
<Trans>The score is capped because of a blocking problem: {getPdfFindingMessage(cap).title}</Trans>
|
||||
</p>
|
||||
)}
|
||||
|
||||
@@ -58,7 +58,7 @@ export function OAuthConsentPage({ oauthQuery, email }: OAuthConsentPageProps) {
|
||||
<h1 className="font-semibold text-2xl tracking-tight">
|
||||
<Trans>Connect an application</Trans>
|
||||
</h1>
|
||||
<p className="wrap-anywhere text-muted-foreground text-sm">
|
||||
<p className="wrap-anywhere text-ink-3 text-sm">
|
||||
<Trans>Signed in as {email}</Trans>
|
||||
</p>
|
||||
</div>
|
||||
@@ -74,7 +74,7 @@ export function OAuthConsentPage({ oauthQuery, email }: OAuthConsentPageProps) {
|
||||
<div className="space-y-4">
|
||||
<div className="wrap-anywhere space-y-1">
|
||||
<p className="font-medium">{client.client_name || clientId}</p>
|
||||
<p className="text-muted-foreground text-xs">
|
||||
<p className="text-ink-3 text-xs">
|
||||
<Trans>Client ID</Trans>: {clientId}
|
||||
</p>
|
||||
</div>
|
||||
@@ -104,7 +104,7 @@ export function OAuthConsentPage({ oauthQuery, email }: OAuthConsentPageProps) {
|
||||
)}
|
||||
</ul>
|
||||
{error && (
|
||||
<p role="alert" className="text-destructive text-sm">
|
||||
<p role="alert" className="text-danger-text text-sm">
|
||||
{error}
|
||||
</p>
|
||||
)}
|
||||
|
||||
@@ -57,7 +57,7 @@ export function ForgotPasswordPage() {
|
||||
<Trans>Forgot your password?</Trans>
|
||||
</h1>
|
||||
|
||||
<div className="text-muted-foreground">
|
||||
<div className="text-ink-3">
|
||||
<Trans>
|
||||
Remember your password?{" "}
|
||||
<Button
|
||||
@@ -122,7 +122,7 @@ function PostForgotPasswordScreen() {
|
||||
<h1 className="font-semibold text-2xl tracking-tight">
|
||||
<Trans>You've got mail!</Trans>
|
||||
</h1>
|
||||
<p className="text-muted-foreground">
|
||||
<p className="text-ink-3">
|
||||
<Trans>Check your email for a link to reset your password.</Trans>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -124,7 +124,7 @@ export function LoginPage({ disableEmailAuth, disableSignups }: Props) {
|
||||
</h1>
|
||||
|
||||
{!disableSignups && (
|
||||
<div className="text-muted-foreground">
|
||||
<div className="text-ink-3">
|
||||
<Trans>
|
||||
Don't have an account?{" "}
|
||||
<Button
|
||||
|
||||
@@ -94,7 +94,7 @@ export function RegisterPage({ disableEmailAuth }: Props) {
|
||||
<Trans>Create a new account</Trans>
|
||||
</h1>
|
||||
|
||||
<div className="text-muted-foreground">
|
||||
<div className="text-ink-3">
|
||||
<Trans>
|
||||
Already have an account?{" "}
|
||||
<Button
|
||||
@@ -268,7 +268,7 @@ function PostSignupScreen() {
|
||||
<h1 className="font-semibold text-2xl tracking-tight">
|
||||
<Trans>You've got mail!</Trans>
|
||||
</h1>
|
||||
<p className="text-muted-foreground">
|
||||
<p className="text-ink-3">
|
||||
<Trans>Check your email for a link to verify your account.</Trans>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -62,7 +62,7 @@ export function ResetPasswordPage({ token }: Props) {
|
||||
<Trans>Reset your password</Trans>
|
||||
</h1>
|
||||
|
||||
<div className="text-muted-foreground">
|
||||
<div className="text-ink-3">
|
||||
<Trans>Enter a new password for your account</Trans>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -81,7 +81,7 @@ export function ResumePasswordPage({ username, slug, redirectPath }: ResumePassw
|
||||
<Trans>This resume is password protected</Trans>
|
||||
</h1>
|
||||
|
||||
<div className="text-muted-foreground leading-relaxed">
|
||||
<div className="text-ink-3 leading-relaxed">
|
||||
<Trans>Enter the password the resume owner shared with you.</Trans>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -74,7 +74,7 @@ function TwoFactorVerificationPage({ backupCode = false }: TwoFactorVerification
|
||||
<h1 className="font-semibold text-2xl tracking-tight">
|
||||
{backupCode ? <Trans>Verify with a Backup Code</Trans> : <Trans>Two-Factor Authentication</Trans>}
|
||||
</h1>
|
||||
<div className="text-muted-foreground">
|
||||
<div className="text-ink-3">
|
||||
{backupCode ? (
|
||||
<Trans>Enter one of your saved backup codes to access your account</Trans>
|
||||
) : (
|
||||
|
||||
@@ -122,7 +122,7 @@ export function CommandPalette() {
|
||||
comment: "Accessible label for command list region inside command palette",
|
||||
message: "Command Palette",
|
||||
})}
|
||||
className="[&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5 **:[[cmdk-group-heading]]:px-2 **:[[cmdk-group-heading]]:font-medium **:[[cmdk-group-heading]]:text-muted-foreground **:[[cmdk-group]]:px-2 **:[[cmdk-input]]:h-12 **:[[cmdk-item]]:px-2 **:[[cmdk-item]]:py-3"
|
||||
className="[&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5 **:[[cmdk-group-heading]]:px-2 **:[[cmdk-group-heading]]:font-medium **:[[cmdk-group-heading]]:text-ink-3 **:[[cmdk-group]]:px-2 **:[[cmdk-input]]:h-12 **:[[cmdk-item]]:px-2 **:[[cmdk-item]]:py-3"
|
||||
>
|
||||
<CommandInput
|
||||
ref={inputRef}
|
||||
|
||||
@@ -11,7 +11,7 @@ export function LanguageCommandPage() {
|
||||
<BaseCommandGroup page="language" heading={<Trans>Language</Trans>}>
|
||||
{Object.entries(localeMap).map(([value, label]) => (
|
||||
<CommandItem key={value} onSelect={() => changeLocale(value)}>
|
||||
<span className="font-mono text-muted-foreground text-xs">{value}</span>
|
||||
<span className="font-mono text-ink-3 text-xs">{value}</span>
|
||||
{i18n.t(label)}
|
||||
</CommandItem>
|
||||
))}
|
||||
|
||||
@@ -181,7 +181,7 @@ export function ResumesCommandGroup() {
|
||||
>
|
||||
<BriefcaseIcon />
|
||||
<span className="min-w-0 truncate">{application.company}</span>
|
||||
<span className="truncate text-muted-foreground text-xs">{application.role}</span>
|
||||
<span className="truncate text-ink-3 text-xs">{application.role}</span>
|
||||
</CommandItem>
|
||||
))
|
||||
)}
|
||||
@@ -207,7 +207,7 @@ export function ResumesCommandGroup() {
|
||||
>
|
||||
<ChatCircleDotsIcon />
|
||||
<span className="min-w-0 truncate">{thread.title}</span>
|
||||
<span className="truncate text-muted-foreground text-xs">{documentName}</span>
|
||||
<span className="truncate text-ink-3 text-xs">{documentName}</span>
|
||||
</CommandItem>
|
||||
);
|
||||
})
|
||||
|
||||
@@ -10,7 +10,7 @@ export const getLocaleOptions = () => {
|
||||
value: value as Locale,
|
||||
label: (
|
||||
<span className="flex items-center gap-x-2">
|
||||
<span className="font-mono text-muted-foreground text-xs">{value}</span>
|
||||
<span className="font-mono text-ink-3 text-xs">{value}</span>
|
||||
{name}
|
||||
</span>
|
||||
),
|
||||
|
||||
@@ -96,7 +96,7 @@ export function ResumePasswordDialog({ onSubmit, onClose }: ResumePasswordDialog
|
||||
aria-invalid={!!error}
|
||||
aria-describedby={`${id}-hint${error ? ` ${id}-error` : ""}`}
|
||||
/>
|
||||
<p id={`${id}-hint`} className="text-muted-foreground text-sm">
|
||||
<p id={`${id}-hint`} className="text-ink-3 text-sm">
|
||||
<Trans>Use between 6 and 64 characters.</Trans>
|
||||
</p>
|
||||
</div>
|
||||
@@ -119,7 +119,7 @@ export function ResumePasswordDialog({ onSubmit, onClose }: ResumePasswordDialog
|
||||
/>
|
||||
</div>
|
||||
{error && (
|
||||
<p id={`${id}-error`} role="alert" className="text-destructive text-sm">
|
||||
<p id={`${id}-error`} role="alert" className="text-danger-text text-sm">
|
||||
{error}
|
||||
</p>
|
||||
)}
|
||||
|
||||
@@ -79,7 +79,7 @@ function PicturePreviewControls({
|
||||
type="button"
|
||||
onClick={picture.url ? onDeletePicture : onSelectPicture}
|
||||
aria-label={picture.url ? t`Delete picture` : t`Upload picture`}
|
||||
className="group/picture relative size-18 cursor-pointer overflow-hidden rounded-md bg-secondary transition-colors hover:bg-secondary/50"
|
||||
className="group/picture relative size-18 cursor-pointer overflow-hidden rounded-md bg-sunken transition-colors hover:bg-sunken/50"
|
||||
>
|
||||
{normalizedPictureUrl && (
|
||||
<img
|
||||
@@ -293,7 +293,7 @@ function PictureGeometryFields({ form, onAutoSave }: PictureFieldProps) {
|
||||
onAutoSave();
|
||||
}}
|
||||
>
|
||||
<div className="aspect-square min-h-3 min-w-3 border border-primary" />
|
||||
<div className="aspect-square min-h-3 min-w-3 border border-accent" />
|
||||
</Button>
|
||||
<Button
|
||||
size="icon"
|
||||
@@ -307,7 +307,7 @@ function PictureGeometryFields({ form, onAutoSave }: PictureFieldProps) {
|
||||
onAutoSave();
|
||||
}}
|
||||
>
|
||||
<div className="aspect-1.5/1 min-h-3 min-w-3 border border-primary" />
|
||||
<div className="aspect-1.5/1 min-h-3 min-w-3 border border-accent" />
|
||||
</Button>
|
||||
<Button
|
||||
size="icon"
|
||||
@@ -321,7 +321,7 @@ function PictureGeometryFields({ form, onAutoSave }: PictureFieldProps) {
|
||||
onAutoSave();
|
||||
}}
|
||||
>
|
||||
<div className="aspect-1/1.5 min-h-3 min-w-3 border border-primary" />
|
||||
<div className="aspect-1/1.5 min-h-3 min-w-3 border border-accent" />
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
@@ -368,7 +368,7 @@ function PictureGeometryFields({ form, onAutoSave }: PictureFieldProps) {
|
||||
onAutoSave();
|
||||
}}
|
||||
>
|
||||
<div className="size-3 rounded-none border border-primary" />
|
||||
<div className="size-3 rounded-none border border-accent" />
|
||||
</Button>
|
||||
<Button
|
||||
size="icon"
|
||||
@@ -379,7 +379,7 @@ function PictureGeometryFields({ form, onAutoSave }: PictureFieldProps) {
|
||||
onAutoSave();
|
||||
}}
|
||||
>
|
||||
<div className="size-3 rounded-[10%] border border-primary" />
|
||||
<div className="size-3 rounded-[10%] border border-accent" />
|
||||
</Button>
|
||||
<Button
|
||||
size="icon"
|
||||
@@ -390,7 +390,7 @@ function PictureGeometryFields({ form, onAutoSave }: PictureFieldProps) {
|
||||
onAutoSave();
|
||||
}}
|
||||
>
|
||||
<div className="size-3 rounded-full border border-primary" />
|
||||
<div className="size-3 rounded-full border border-accent" />
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
@@ -632,7 +632,7 @@ export function PictureSettings() {
|
||||
</DialogHeader>
|
||||
|
||||
{cropState && (
|
||||
<div className="relative h-64 w-full overflow-hidden rounded-md bg-secondary ring-1 ring-border ring-inset">
|
||||
<div className="relative h-64 w-full overflow-hidden rounded-md bg-sunken ring-1 ring-line ring-inset">
|
||||
<Cropper
|
||||
image={cropState.imageSrc}
|
||||
crop={crop}
|
||||
@@ -652,10 +652,10 @@ export function PictureSettings() {
|
||||
<FormLabel className="mb-0">
|
||||
<Trans>Zoom</Trans>
|
||||
</FormLabel>
|
||||
<span className="text-muted-foreground text-xs tabular-nums">{zoom.toFixed(1)}×</span>
|
||||
<span className="text-ink-3 text-xs tabular-nums">{zoom.toFixed(1)}×</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-x-3">
|
||||
<MagnifyingGlassMinusIcon className="size-4 shrink-0 text-muted-foreground" />
|
||||
<MagnifyingGlassMinusIcon className="size-4 shrink-0 text-ink-3" />
|
||||
<Slider
|
||||
min={1}
|
||||
max={3}
|
||||
@@ -667,7 +667,7 @@ export function PictureSettings() {
|
||||
setZoom(Array.isArray(value) ? value[0] : value);
|
||||
}}
|
||||
/>
|
||||
<MagnifyingGlassPlusIcon className="size-4 shrink-0 text-muted-foreground" />
|
||||
<MagnifyingGlassPlusIcon className="size-4 shrink-0 text-ink-3" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -185,7 +185,7 @@ export function PdfCanvasPage({
|
||||
<figure className="shrink-0">
|
||||
{caption ??
|
||||
(showPageNumbers ? (
|
||||
<figcaption className="mb-1 font-medium text-[0.625rem] text-muted-foreground">
|
||||
<figcaption className="mb-1 font-medium text-[0.625rem] text-ink-3">
|
||||
Page {pageNumber} of {totalPages}
|
||||
</figcaption>
|
||||
) : null)}
|
||||
|
||||
@@ -66,7 +66,7 @@ export function ResumePreviewLoader({
|
||||
return (
|
||||
<figure key={pageNumber} className="shrink-0">
|
||||
{showPageNumbers ? (
|
||||
<figcaption className="mb-1 font-medium text-[0.625rem] text-muted-foreground">
|
||||
<figcaption className="mb-1 font-medium text-[0.625rem] text-ink-3">
|
||||
Page {pageNumber} of {pageCount}
|
||||
</figcaption>
|
||||
) : null}
|
||||
|
||||
@@ -245,11 +245,11 @@ export function PdfViewer({
|
||||
</div>
|
||||
|
||||
{error ? (
|
||||
<div className="absolute inset-0 flex items-center justify-center bg-background px-6 text-center text-muted-foreground text-sm">
|
||||
<div className="absolute inset-0 flex items-center justify-center bg-bg px-6 text-center text-ink-3 text-sm">
|
||||
Unable to display PDF preview.
|
||||
</div>
|
||||
) : isReady ? null : (
|
||||
<div className="absolute inset-0 flex items-center justify-center bg-background">
|
||||
<div className="absolute inset-0 flex items-center justify-center bg-bg">
|
||||
<Spinner className="size-6" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -330,7 +330,7 @@ export function StylesheetCodeEditor({
|
||||
type="button"
|
||||
title={t`Edit color ${selectedColor.token.value}`}
|
||||
aria-label={t`Edit color ${selectedColor.token.value}`}
|
||||
className="pointer-events-auto size-3 rounded-full border border-foreground/40"
|
||||
className="pointer-events-auto size-3 rounded-full border border-ink/40"
|
||||
style={{ backgroundColor: selectedColor.token.value }}
|
||||
/>
|
||||
}
|
||||
@@ -514,12 +514,12 @@ function StylesheetEditorShell({ readOnly = false }: StylesheetEditorShellProps)
|
||||
onFocusToggle={toggleFocus}
|
||||
/>
|
||||
|
||||
<p className="flex items-center gap-1.5 text-muted-foreground text-xs">
|
||||
<p className="flex items-center gap-1.5 text-ink-3 text-xs">
|
||||
<BookOpenIcon aria-hidden="true" className="shrink-0" />
|
||||
<span>
|
||||
<Trans>Not sure what to write?</Trans>{" "}
|
||||
<a
|
||||
className="text-primary underline underline-offset-4"
|
||||
className="text-accent-text underline underline-offset-4"
|
||||
href="https://docs.rxresu.me/applying-custom-styles"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
|
||||
@@ -72,7 +72,7 @@ export function StylesheetStatus({ mode, status, diagnostics }: StylesheetStatus
|
||||
{diagnostics.map((diagnostic) => (
|
||||
<li key={`${diagnostic.code}-${diagnostic.range.start.offset}`} className="space-y-0.5">
|
||||
<p className="font-medium">{diagnostic.message}</p>
|
||||
<p className="text-muted-foreground">
|
||||
<p className="text-ink-3">
|
||||
<Trans>
|
||||
Line {diagnostic.range.start.line}, column {diagnostic.range.start.column}
|
||||
</Trans>
|
||||
|
||||
@@ -61,7 +61,7 @@ export function Footer() {
|
||||
|
||||
<div className="space-y-2">
|
||||
<h2 className="font-semibold text-lg tracking-tight">Reactive Resume</h2>
|
||||
<p className="max-w-xs text-muted-foreground text-sm leading-relaxed">
|
||||
<p className="max-w-xs text-ink-3 text-sm leading-relaxed">
|
||||
<Trans>
|
||||
A free and open-source resume builder that makes it easy to create, update, and share your resume.
|
||||
</Trans>
|
||||
@@ -109,7 +109,7 @@ export function Footer() {
|
||||
function FooterLinkGroup({ title, links }: FooterLinkGroupProps) {
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<h2 className="font-medium text-muted-foreground text-sm tracking-tight">{title}</h2>
|
||||
<h2 className="font-medium text-ink-3 text-sm tracking-tight">{title}</h2>
|
||||
|
||||
<ul className="space-y-3">
|
||||
{links.map((link) => (
|
||||
@@ -127,7 +127,7 @@ function FooterLink({ url, label }: FooterLinkItem) {
|
||||
href={url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="relative inline-block text-sm transition-colors after:pointer-events-none after:absolute after:inset-x-0 after:-bottom-0.5 after:h-px after:origin-left after:scale-x-0 after:rounded-md after:bg-primary after:content-[''] hover:text-foreground hover:after:scale-x-100 rtl:after:origin-right after:[transition:scale_200ms_var(--ease-out-strong)]"
|
||||
className="relative inline-block text-sm transition-colors after:pointer-events-none after:absolute after:inset-x-0 after:-bottom-0.5 after:h-px after:origin-left after:scale-x-0 after:rounded-md after:bg-accent after:content-[''] hover:text-ink hover:after:scale-x-100 rtl:after:origin-right after:[transition:scale_200ms_var(--ease-out-strong)]"
|
||||
>
|
||||
{label}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ export function Header() {
|
||||
return (
|
||||
<header
|
||||
data-hidden={hidden}
|
||||
className="fade-in animation-duration-300 fixed inset-x-0 top-0 z-50 animate-in border-transparent border-b bg-background/80 backdrop-blur-lg ease-out-strong [transition:translate_250ms_var(--ease-out-strong)] data-[hidden=true]:-translate-y-full"
|
||||
className="fade-in animation-duration-300 fixed inset-x-0 top-0 z-50 animate-in border-transparent border-b bg-bg/80 backdrop-blur-lg ease-out-strong [transition:translate_250ms_var(--ease-out-strong)] data-[hidden=true]:-translate-y-full"
|
||||
>
|
||||
<nav aria-label={t`Main navigation`} className="container mx-auto flex items-center gap-x-4 p-3 lg:px-12">
|
||||
<Link to="/" className="transition-opacity hover:opacity-80" aria-label={t`Reactive Resume - Go to homepage`}>
|
||||
|
||||
@@ -16,7 +16,7 @@ function RouteComponent() {
|
||||
{!isHomepage && (
|
||||
<a
|
||||
href="#main-content"
|
||||
className="sr-only focus:not-sr-only focus:fixed focus:inset-s-4 focus:top-4 focus:z-100 focus:rounded-md focus:bg-background focus:px-4 focus:py-2 focus:text-foreground focus:shadow-lg focus:ring-2 focus:ring-ring"
|
||||
className="sr-only focus:not-sr-only focus:fixed focus:inset-s-4 focus:top-4 focus:z-100 focus:rounded-md focus:bg-bg focus:px-4 focus:py-2 focus:text-ink focus:shadow-lg focus:ring-2 focus:ring-accent"
|
||||
>
|
||||
<Trans>Skip to main content</Trans>
|
||||
</a>
|
||||
|
||||
@@ -7,7 +7,7 @@ export function CustomStylesSectionBuilder() {
|
||||
return (
|
||||
<SectionBase type="styles" className="space-y-4">
|
||||
<Suspense
|
||||
fallback={<div role="status" className="h-72 animate-pulse rounded-md bg-muted" aria-label="Loading editor" />}
|
||||
fallback={<div role="status" className="h-72 animate-pulse rounded-md bg-sunken" aria-label="Loading editor" />}
|
||||
>
|
||||
<StylesheetEditorShell />
|
||||
</Suspense>
|
||||
|
||||
@@ -180,7 +180,7 @@ function QuickColorCircle({ color, active, onSelect, className, ...props }: Quic
|
||||
onClick={() => onSelect(color)}
|
||||
className={cn(
|
||||
"relative flex size-8 items-center justify-center rounded-md bg-transparent",
|
||||
"transition-[scale,background-color] duration-150 ease-out-strong hover:bg-secondary/80 active:scale-[0.97]",
|
||||
"transition-[scale,background-color] duration-150 ease-out-strong hover:bg-sunken/80 active:scale-[0.97]",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
@@ -196,7 +196,7 @@ function QuickColorCircle({ color, active, onSelect, className, ...props }: Quic
|
||||
transition={{ duration: 0.16, ease: EASE_OUT_STRONG }}
|
||||
className="absolute inset-0 flex size-8 items-center justify-center"
|
||||
>
|
||||
<div className="size-4 rounded-md bg-foreground" />
|
||||
<div className="size-4 rounded-md bg-ink" />
|
||||
</m.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
@@ -4,7 +4,7 @@ const source = await import("./pages?raw").then((module) => module.default);
|
||||
|
||||
describe("layout page header", () => {
|
||||
it("uses container queries to prevent narrow sidebar control collisions", () => {
|
||||
expect(source).toContain("@container bg-secondary/50");
|
||||
expect(source).toContain("@container bg-sunken/50");
|
||||
expect(source).toContain("grid-cols-[minmax(0,1fr)_auto]");
|
||||
expect(source).toContain("@max-[22rem]:grid-cols-1");
|
||||
expect(source).toContain("flex min-w-0 flex-wrap");
|
||||
|
||||
@@ -299,8 +299,8 @@ function PageContainer({
|
||||
const fullWidthSwitchId = useId();
|
||||
|
||||
return (
|
||||
<div className="space-y-3 rounded-md border border-dashed bg-background/40">
|
||||
<div className="@container bg-secondary/50 px-4 py-3">
|
||||
<div className="space-y-3 rounded-md border border-dashed bg-bg/40">
|
||||
<div className="@container bg-sunken/50 px-4 py-3">
|
||||
<div className="grid @max-[22rem]:grid-cols-1 grid-cols-[minmax(0,1fr)_auto] items-center gap-x-3 gap-y-2">
|
||||
<div className="flex min-w-0 flex-wrap items-center gap-x-4 gap-y-2">
|
||||
<span className="font-medium text-xs">
|
||||
@@ -314,7 +314,7 @@ function PageContainer({
|
||||
onCheckedChange={(checked) => onToggleFullWidth(pageIndex, checked)}
|
||||
/>
|
||||
|
||||
<span className="font-medium text-muted-foreground text-xs">
|
||||
<span className="font-medium text-ink-3 text-xs">
|
||||
<Trans comment="Layout editor toggle label that makes a page single-column">Full Width</Trans>
|
||||
</span>
|
||||
</label>
|
||||
@@ -390,7 +390,7 @@ function LayoutColumn({
|
||||
ref={setNodeRef}
|
||||
className={cn(
|
||||
"space-y-2.5 rounded-md border border-dashed p-3 pb-8 transition-colors",
|
||||
isOver && !disabled ? "border-primary/60 bg-primary/5" : "bg-background/40",
|
||||
isOver && !disabled ? "border-accent/60 bg-accent/5" : "bg-bg/40",
|
||||
)}
|
||||
>
|
||||
{items.map((id) => (
|
||||
@@ -398,7 +398,7 @@ function LayoutColumn({
|
||||
))}
|
||||
|
||||
{items.length === 0 && (
|
||||
<div className="rounded-md border border-dashed p-4 font-medium text-muted-foreground text-xs">
|
||||
<div className="rounded-md border border-dashed p-4 font-medium text-ink-3 text-xs">
|
||||
<Trans>Drag and drop sections here to move them between columns</Trans>
|
||||
</div>
|
||||
)}
|
||||
@@ -573,7 +573,7 @@ function SectionBreakItems({ id }: SectionBreakItemsProps) {
|
||||
<Trans comment="Layout editor toggle that prevents a section from splitting across pages">Keep together</Trans>
|
||||
</DropdownMenuCheckboxItem>
|
||||
|
||||
<p className="px-2 pb-1 text-muted-foreground text-xs">
|
||||
<p className="px-2 pb-1 text-ink-3 text-xs">
|
||||
<Trans comment="Helper note explaining the keep-together limitation">
|
||||
Only applies when the section fits on a single page.
|
||||
</Trans>
|
||||
@@ -620,9 +620,9 @@ function LayoutItemContent({
|
||||
data-overlay={isOverlay ? "true" : undefined}
|
||||
data-dragging={isDragging ? "true" : undefined}
|
||||
className={cn(
|
||||
"group/item flex cursor-grab touch-none select-none items-center gap-x-2 rounded-md border border-border bg-background px-2 py-1.5 font-medium text-sm transition-[background-color,border-color] duration-150",
|
||||
"hover:bg-secondary/40 active:cursor-grabbing active:border-primary/60 active:bg-secondary/40",
|
||||
"data-[overlay=true]:cursor-grabbing data-[overlay=true]:border-primary/60 data-[overlay=true]:bg-background data-[overlay=true]:shadow-md",
|
||||
"group/item flex cursor-grab touch-none select-none items-center gap-x-2 rounded-md border border-line bg-bg px-2 py-1.5 font-medium text-sm transition-[background-color,border-color] duration-150",
|
||||
"hover:bg-sunken/40 active:cursor-grabbing active:border-accent/60 active:bg-sunken/40",
|
||||
"data-[overlay=true]:cursor-grabbing data-[overlay=true]:border-accent/60 data-[overlay=true]:bg-bg data-[overlay=true]:shadow-md",
|
||||
"data-[dragging=true]:cursor-grabbing data-[dragging=true]:opacity-40",
|
||||
className,
|
||||
)}
|
||||
@@ -637,7 +637,7 @@ function LayoutItemContent({
|
||||
<DropdownMenuTrigger
|
||||
aria-label={t`Move section to another column or page`}
|
||||
onPointerDown={(event) => event.stopPropagation()}
|
||||
className="flex cursor-context-menu items-center rounded p-0.5 opacity-40 transition-opacity hover:bg-secondary/40 focus:outline-none focus-visible:ring-1 group-hover/item:opacity-100"
|
||||
className="flex cursor-context-menu items-center rounded p-0.5 opacity-40 transition-opacity hover:bg-sunken/40 focus:outline-none focus-visible:ring-1 group-hover/item:opacity-100"
|
||||
>
|
||||
<DotsThreeVerticalIcon />
|
||||
</DropdownMenuTrigger>
|
||||
|
||||
@@ -30,7 +30,7 @@ function NotesSectionForm() {
|
||||
|
||||
<RichInput value={notes} onChange={onChange} />
|
||||
|
||||
<p className="text-muted-foreground">
|
||||
<p className="text-ink-3">
|
||||
<Trans>For example, note which companies you sent this resume to, or links to the job descriptions.</Trans>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -19,7 +19,7 @@ function OTPFieldInput({ className, ...props }: OTPFieldPrimitive.Input.Props) {
|
||||
<OTPFieldPrimitive.Input
|
||||
data-slot="otp-field-input"
|
||||
className={cn(
|
||||
"size-9 rounded-lg border border-input bg-transparent text-center font-mono text-sm outline-none transition-[color,background-color,border-color,box-shadow] focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 group-aria-invalid:border-destructive group-aria-invalid:ring-3 group-aria-invalid:ring-destructive/20",
|
||||
"size-9 rounded-lg border border-line-2 bg-transparent text-center font-mono text-sm outline-none transition-[color,background-color,border-color,box-shadow] focus-visible:border-accent focus-visible:ring-3 focus-visible:ring-accent/50 disabled:cursor-not-allowed disabled:bg-line-2/50 disabled:opacity-50 group-aria-invalid:border-danger group-aria-invalid:ring-3 group-aria-invalid:ring-danger/20",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
||||
@@ -6,7 +6,7 @@ function ScrollArea({ className, children, ...props }: ScrollAreaPrimitive.Root.
|
||||
<ScrollAreaPrimitive.Root data-slot="scroll-area" className={cn("relative", className)} {...props}>
|
||||
<ScrollAreaPrimitive.Viewport
|
||||
data-slot="scroll-area-viewport"
|
||||
className="size-full rounded-[inherit] outline-none transition-[color,box-shadow] focus-visible:outline-1 focus-visible:ring-[3px] focus-visible:ring-ring/50"
|
||||
className="size-full rounded-[inherit] outline-none transition-[color,box-shadow] focus-visible:outline-1 focus-visible:ring-[3px] focus-visible:ring-accent/50"
|
||||
>
|
||||
{children}
|
||||
</ScrollAreaPrimitive.Viewport>
|
||||
@@ -28,7 +28,7 @@ function ScrollBar({ className, orientation = "vertical", ...props }: ScrollArea
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<ScrollAreaPrimitive.Thumb data-slot="scroll-area-thumb" className="relative flex-1 rounded-full bg-border" />
|
||||
<ScrollAreaPrimitive.Thumb data-slot="scroll-area-thumb" className="relative flex-1 rounded-full bg-line" />
|
||||
</ScrollAreaPrimitive.Scrollbar>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -196,40 +196,6 @@
|
||||
--ease-out-strong: cubic-bezier(0.23, 1, 0.32, 1);
|
||||
--ease-in-out-strong: cubic-bezier(0.77, 0, 0.175, 1);
|
||||
--ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);
|
||||
|
||||
/*
|
||||
* Compatibility: the previous shadcn-style names resolve to Desk & Paper tokens so screens that
|
||||
* haven't been rebuilt stay legible. Remove once every screen uses the names above (plan M12).
|
||||
*/
|
||||
--color-background: var(--bg);
|
||||
--color-foreground: var(--ink);
|
||||
--color-card: var(--surface);
|
||||
--color-card-foreground: var(--ink);
|
||||
--color-popover: var(--raised);
|
||||
--color-popover-foreground: var(--ink);
|
||||
--color-primary: var(--accent);
|
||||
--color-primary-foreground: var(--on-accent);
|
||||
--color-secondary: var(--sunken);
|
||||
--color-secondary-foreground: var(--ink);
|
||||
--color-muted: var(--sunken);
|
||||
--color-muted-foreground: var(--ink-3);
|
||||
--color-destructive: var(--danger);
|
||||
--color-border: var(--line);
|
||||
--color-input: var(--line-2);
|
||||
--color-ring: var(--accent);
|
||||
--color-chart-1: var(--ink-3);
|
||||
--color-chart-2: var(--ink-2);
|
||||
--color-chart-3: var(--accent);
|
||||
--color-chart-4: var(--stage-applied);
|
||||
--color-chart-5: var(--stage-interview);
|
||||
--color-sidebar: var(--surface);
|
||||
--color-sidebar-foreground: var(--ink);
|
||||
--color-sidebar-primary: var(--accent);
|
||||
--color-sidebar-primary-foreground: var(--on-accent);
|
||||
--color-sidebar-accent: var(--sunken);
|
||||
--color-sidebar-accent-foreground: var(--ink);
|
||||
--color-sidebar-border: var(--line);
|
||||
--color-sidebar-ring: var(--accent);
|
||||
}
|
||||
|
||||
@layer base {
|
||||
|
||||
Reference in New Issue
Block a user