mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-08-25 07:42:20 +10:00
feat: add semantic CSS stylesheets (#3274)
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor Agent
parent
4ac19f81b3
commit
d2ffbf9618
@@ -0,0 +1,342 @@
|
||||
import type { SemanticNodeKind } from "../types";
|
||||
import { SEMANTIC_NODE_KINDS } from "./semantic";
|
||||
|
||||
export type PropertyDefinition = {
|
||||
category:
|
||||
| "flexbox"
|
||||
| "layout"
|
||||
| "dimension"
|
||||
| "color"
|
||||
| "text"
|
||||
| "image"
|
||||
| "spacing"
|
||||
| "border"
|
||||
| "transform"
|
||||
| "structural";
|
||||
inheritable: boolean;
|
||||
appliesTo: readonly SemanticNodeKind[];
|
||||
values: readonly string[];
|
||||
units: readonly string[];
|
||||
};
|
||||
|
||||
export type PropertyRegistry = Readonly<Record<string, PropertyDefinition | undefined>>;
|
||||
|
||||
export const SEMANTIC_CSS_CSS_WIDE_KEYWORDS_V1 = ["inherit", "initial", "revert", "unset"] as const;
|
||||
export const SEMANTIC_CSS_LENGTH_UNITS_V1 = ["pt", "px", "in", "mm", "cm", "%", "vw", "vh", "em", "rem"] as const;
|
||||
export const SEMANTIC_CSS_BORDER_STYLE_VALUES_V1 = ["dotted", "dashed", "solid"] as const;
|
||||
export const SEMANTIC_CSS_LENGTH_VALUE_KEYWORDS_V1 = [
|
||||
"auto",
|
||||
"none",
|
||||
"normal",
|
||||
"max-content",
|
||||
"min-content",
|
||||
"fit-content",
|
||||
"thin",
|
||||
"medium",
|
||||
"thick",
|
||||
] as const;
|
||||
export const SEMANTIC_CSS_LENGTH_PROPERTIES_V1 = [
|
||||
"bottom",
|
||||
"border-bottom-left-radius",
|
||||
"border-bottom-right-radius",
|
||||
"border-bottom-width",
|
||||
"border-left-width",
|
||||
"border-radius",
|
||||
"border-right-width",
|
||||
"border-top-left-radius",
|
||||
"border-top-right-radius",
|
||||
"border-top-width",
|
||||
"border-width",
|
||||
"column-gap",
|
||||
"flex-basis",
|
||||
"font-size",
|
||||
"gap",
|
||||
"height",
|
||||
"left",
|
||||
"letter-spacing",
|
||||
"margin-bottom",
|
||||
"margin-left",
|
||||
"margin-right",
|
||||
"margin-top",
|
||||
"max-height",
|
||||
"max-width",
|
||||
"min-height",
|
||||
"min-width",
|
||||
"padding-bottom",
|
||||
"padding-left",
|
||||
"padding-right",
|
||||
"padding-top",
|
||||
"right",
|
||||
"row-gap",
|
||||
"text-indent",
|
||||
"top",
|
||||
"width",
|
||||
"-resume-min-presence-ahead",
|
||||
"-resume-shadow-width",
|
||||
] as const;
|
||||
|
||||
const containerNodes = [
|
||||
"page",
|
||||
"region",
|
||||
"header",
|
||||
"contact-list",
|
||||
"contact-item",
|
||||
"section",
|
||||
"section-heading",
|
||||
"section-items",
|
||||
"item",
|
||||
"item-header",
|
||||
"rich-text",
|
||||
"list",
|
||||
"list-item",
|
||||
"horizontal-rule",
|
||||
"template-part",
|
||||
] as const satisfies readonly SemanticNodeKind[];
|
||||
|
||||
const textNodes = [
|
||||
"name",
|
||||
"headline",
|
||||
"section-heading",
|
||||
"combined-text",
|
||||
"field",
|
||||
"rich-heading",
|
||||
"blockquote",
|
||||
"paragraph",
|
||||
"list-item-content",
|
||||
"list-marker",
|
||||
"strong",
|
||||
"emphasis",
|
||||
"underline",
|
||||
"strike",
|
||||
"code",
|
||||
"text-span",
|
||||
"mark",
|
||||
"hard-break",
|
||||
] as const satisfies readonly SemanticNodeKind[];
|
||||
|
||||
const linkContainerNodes = [...containerNodes, "link"] as SemanticNodeKind[];
|
||||
const textAndLinkNodes = [...textNodes, "link"] as SemanticNodeKind[];
|
||||
const colorNodes = [...containerNodes, ...textNodes, "link", "icon", "level"] as SemanticNodeKind[];
|
||||
const spacingNodes = [...containerNodes, ...textNodes, "link", "picture"] as SemanticNodeKind[];
|
||||
const structuralNodes = [...SEMANTIC_NODE_KINDS.filter((kind) => kind !== "resume")] as SemanticNodeKind[];
|
||||
const lengthProperties = new Set<string>(SEMANTIC_CSS_LENGTH_PROPERTIES_V1);
|
||||
const numericLengthUnits = SEMANTIC_CSS_LENGTH_UNITS_V1.filter((unit) => unit !== "%");
|
||||
const borderStyleProperties = /^(?:border-style|border-(?:top|right|bottom|left)-style)$/;
|
||||
const borderShorthandProperties = /^(?:border|border-(?:top|right|bottom|left))$/;
|
||||
const propertyValueHints = {
|
||||
"align-content": ["flex-start", "flex-end", "center", "stretch", "space-between", "space-around", "space-evenly"],
|
||||
"align-items": ["flex-start", "flex-end", "center", "stretch", "baseline"],
|
||||
"align-self": ["auto", "flex-start", "flex-end", "center", "stretch", "baseline"],
|
||||
flex: ["none", "auto"],
|
||||
"flex-direction": ["row", "row-reverse", "column", "column-reverse"],
|
||||
"flex-wrap": ["nowrap", "wrap", "wrap-reverse"],
|
||||
"flex-flow": ["row", "row-reverse", "column", "column-reverse", "nowrap", "wrap", "wrap-reverse"],
|
||||
"justify-content": ["flex-start", "flex-end", "center", "space-between", "space-around", "space-evenly"],
|
||||
display: ["flex", "none"],
|
||||
position: ["absolute", "relative", "static"],
|
||||
overflow: ["hidden"],
|
||||
direction: ["ltr", "rtl"],
|
||||
"font-style": ["normal", "italic"],
|
||||
"font-weight": [
|
||||
"thin",
|
||||
"hairline",
|
||||
"ultralight",
|
||||
"extralight",
|
||||
"light",
|
||||
"normal",
|
||||
"medium",
|
||||
"semibold",
|
||||
"demibold",
|
||||
"bold",
|
||||
"ultrabold",
|
||||
"extrabold",
|
||||
"heavy",
|
||||
"black",
|
||||
],
|
||||
"line-height": ["normal"],
|
||||
"text-align": ["left", "right", "center", "justify"],
|
||||
"text-decoration": ["none", "underline", "line-through", "line-through underline", "underline line-through"],
|
||||
"text-overflow": ["ellipsis"],
|
||||
"text-transform": ["none", "capitalize", "lowercase", "uppercase", "upperfirst"],
|
||||
"vertical-align": ["sub", "super"],
|
||||
"object-fit": ["contain", "cover", "fill", "none", "scale-down"],
|
||||
"object-position": ["left", "right", "top", "bottom", "center"],
|
||||
"transform-origin": ["left", "right", "top", "bottom", "center"],
|
||||
"break-before": ["auto", "page"],
|
||||
"break-inside": ["auto", "avoid"],
|
||||
size: ["A4", "letter"],
|
||||
"-resume-fixed": ["true", "false", "0", "1"],
|
||||
} as const satisfies Readonly<Record<string, readonly string[]>>;
|
||||
|
||||
function propertyValues(name: string): readonly string[] {
|
||||
const values = borderStyleProperties.test(name)
|
||||
? SEMANTIC_CSS_BORDER_STYLE_VALUES_V1
|
||||
: borderShorthandProperties.test(name)
|
||||
? SEMANTIC_CSS_BORDER_STYLE_VALUES_V1.map((style) => `1pt ${style}`)
|
||||
: (propertyValueHints[name as keyof typeof propertyValueHints] ?? []);
|
||||
return [...SEMANTIC_CSS_CSS_WIDE_KEYWORDS_V1, ...values];
|
||||
}
|
||||
|
||||
function propertyUnits(name: string): readonly string[] {
|
||||
if (name === "size" || name === "-resume-min-presence-ahead") return numericLengthUnits;
|
||||
return lengthProperties.has(name) || name === "line-height" ? SEMANTIC_CSS_LENGTH_UNITS_V1 : [];
|
||||
}
|
||||
|
||||
function entries(
|
||||
names: readonly string[],
|
||||
definition: Omit<PropertyDefinition, "units" | "values">,
|
||||
): Readonly<Record<string, PropertyDefinition | undefined>> {
|
||||
return Object.fromEntries(
|
||||
names.map((name) => [
|
||||
name,
|
||||
{
|
||||
...definition,
|
||||
appliesTo: [...new Set(definition.appliesTo)],
|
||||
values: propertyValues(name),
|
||||
units: propertyUnits(name),
|
||||
},
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
const properties = {
|
||||
...entries(
|
||||
[
|
||||
"align-content",
|
||||
"align-items",
|
||||
"align-self",
|
||||
"flex",
|
||||
"flex-direction",
|
||||
"flex-wrap",
|
||||
"flex-flow",
|
||||
"flex-grow",
|
||||
"flex-shrink",
|
||||
"flex-basis",
|
||||
"justify-content",
|
||||
"gap",
|
||||
"row-gap",
|
||||
"column-gap",
|
||||
],
|
||||
{ category: "flexbox", inheritable: false, appliesTo: linkContainerNodes },
|
||||
),
|
||||
...entries(["aspect-ratio", "bottom"], {
|
||||
category: "layout",
|
||||
inheritable: false,
|
||||
appliesTo: linkContainerNodes,
|
||||
}),
|
||||
...entries(["display"], {
|
||||
category: "layout",
|
||||
inheritable: false,
|
||||
appliesTo: [...linkContainerNodes, "list-item-content", "list-marker"],
|
||||
}),
|
||||
...entries(["left", "position", "right", "top", "overflow", "z-index"], {
|
||||
category: "layout",
|
||||
inheritable: false,
|
||||
appliesTo: linkContainerNodes,
|
||||
}),
|
||||
...entries(["width", "height", "min-width", "min-height", "max-width", "max-height"], {
|
||||
category: "dimension",
|
||||
inheritable: false,
|
||||
appliesTo: [...linkContainerNodes, "picture"],
|
||||
}),
|
||||
...entries(["color"], { category: "color", inheritable: true, appliesTo: colorNodes }),
|
||||
...entries(["background-color"], { category: "color", inheritable: false, appliesTo: linkContainerNodes }),
|
||||
...entries(["opacity"], { category: "color", inheritable: false, appliesTo: colorNodes }),
|
||||
...entries(["direction"], { category: "text", inheritable: true, appliesTo: textAndLinkNodes }),
|
||||
...entries(["font-size"], {
|
||||
category: "text",
|
||||
inheritable: true,
|
||||
appliesTo: [...textAndLinkNodes, "icon", "level"],
|
||||
}),
|
||||
...entries(["font-style", "font-weight", "letter-spacing", "line-height"], {
|
||||
category: "text",
|
||||
inheritable: true,
|
||||
appliesTo: textAndLinkNodes,
|
||||
}),
|
||||
...entries(["max-lines"], { category: "text", inheritable: false, appliesTo: textAndLinkNodes }),
|
||||
...entries(["text-align"], { category: "text", inheritable: true, appliesTo: textAndLinkNodes }),
|
||||
...entries(["text-decoration", "text-decoration-color", "text-decoration-style"], {
|
||||
category: "text",
|
||||
inheritable: false,
|
||||
appliesTo: textAndLinkNodes,
|
||||
}),
|
||||
...entries(["text-indent"], { category: "text", inheritable: true, appliesTo: textAndLinkNodes }),
|
||||
...entries(["text-overflow"], { category: "text", inheritable: false, appliesTo: textAndLinkNodes }),
|
||||
...entries(["text-transform"], { category: "text", inheritable: true, appliesTo: textAndLinkNodes }),
|
||||
...entries(["vertical-align"], { category: "text", inheritable: false, appliesTo: textAndLinkNodes }),
|
||||
...entries(["object-fit", "object-position"], { category: "image", inheritable: false, appliesTo: ["picture"] }),
|
||||
...entries(["-resume-shadow-color", "-resume-shadow-width"], {
|
||||
category: "image",
|
||||
inheritable: false,
|
||||
appliesTo: ["picture"],
|
||||
}),
|
||||
...entries(
|
||||
[
|
||||
"margin",
|
||||
"margin-top",
|
||||
"margin-right",
|
||||
"margin-bottom",
|
||||
"margin-left",
|
||||
"margin-horizontal",
|
||||
"margin-vertical",
|
||||
"padding",
|
||||
"padding-top",
|
||||
"padding-right",
|
||||
"padding-bottom",
|
||||
"padding-left",
|
||||
"padding-horizontal",
|
||||
"padding-vertical",
|
||||
],
|
||||
{ category: "spacing", inheritable: false, appliesTo: spacingNodes },
|
||||
),
|
||||
...entries(
|
||||
[
|
||||
"border",
|
||||
"border-color",
|
||||
"border-style",
|
||||
"border-width",
|
||||
"border-top",
|
||||
"border-right",
|
||||
"border-bottom",
|
||||
"border-left",
|
||||
"border-top-color",
|
||||
"border-top-style",
|
||||
"border-top-width",
|
||||
"border-right-color",
|
||||
"border-right-style",
|
||||
"border-right-width",
|
||||
"border-bottom-color",
|
||||
"border-bottom-style",
|
||||
"border-bottom-width",
|
||||
"border-left-color",
|
||||
"border-left-style",
|
||||
"border-left-width",
|
||||
"border-radius",
|
||||
"border-top-left-radius",
|
||||
"border-top-right-radius",
|
||||
"border-bottom-right-radius",
|
||||
"border-bottom-left-radius",
|
||||
],
|
||||
{ category: "border", inheritable: false, appliesTo: [...linkContainerNodes, "picture"] },
|
||||
),
|
||||
...entries(["transform", "transform-origin"], {
|
||||
category: "transform",
|
||||
inheritable: false,
|
||||
appliesTo: [...linkContainerNodes, "picture"],
|
||||
}),
|
||||
...entries(["order", "break-before", "break-inside"], {
|
||||
category: "structural",
|
||||
inheritable: false,
|
||||
appliesTo: structuralNodes,
|
||||
}),
|
||||
...entries(["orphans", "widows"], { category: "structural", inheritable: false, appliesTo: textNodes }),
|
||||
...entries(["size"], { category: "structural", inheritable: false, appliesTo: ["page"] }),
|
||||
...entries(["-resume-fixed"], { category: "structural", inheritable: false, appliesTo: structuralNodes }),
|
||||
...entries(["-resume-min-presence-ahead"], {
|
||||
category: "structural",
|
||||
inheritable: false,
|
||||
appliesTo: structuralNodes,
|
||||
}),
|
||||
} satisfies PropertyRegistry;
|
||||
|
||||
export const PROPERTY_REGISTRY_V1: PropertyRegistry = properties;
|
||||
Reference in New Issue
Block a user