feat(css): add framework-agnostic design system

This commit is contained in:
Dax Raad 2026-07-22 13:49:01 +00:00
commit c251ead206
23 changed files with 1285 additions and 0 deletions

View file

@ -0,0 +1,33 @@
[data-component="badge"] {
box-sizing: border-box;
display: inline-flex;
flex-direction: row;
align-items: center;
justify-content: center;
gap: 4px;
height: 16px;
padding: 0 4px;
user-select: none;
border-radius: 2px;
border: 0.5px solid var(--oc-border-base);
background: var(--oc-bg-layer-02);
font-style: normal;
font-weight: 530;
font-size: 11px;
line-height: 1;
letter-spacing: 0.05px;
color: var(--oc-text-muted);
font-variant-numeric: tabular-nums;
}
[data-component="badge"][data-high-contrast] {
border-color: var(--oc-border-strong);
}
[data-component="badge"][data-variant="accent"] {
border: 0;
background: var(--oc-bg-accent);
color: var(--oc-text-contrast);
}

View file

@ -0,0 +1,246 @@
[data-component="button"] {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 6px;
border-radius: 6px;
font-style: normal;
font-weight: 530;
font-size: 13px;
line-height: 20px;
color: var(--oc-text-base);
text-shadow: none;
font-variant-numeric: tabular-nums;
letter-spacing: -0.04px;
user-select: none;
cursor: pointer;
outline: none;
}
[data-component="button"]:focus {
outline: none;
}
[data-component="button"]:is(:focus-visible, [data-state="focus"]):not(:disabled):not([data-variant="loading"]) {
outline: 2px solid var(--oc-border-focus);
outline-offset: 2.5px;
}
[data-component="button"][data-size="normal"] {
height: 28px;
padding: 0 11px;
}
[data-component="button"][data-size="small"] {
height: 24px;
padding: 0 9px;
border-radius: 4px;
}
[data-component="button"][data-size="large"] {
height: 32px;
padding: 0 15px;
}
[data-component="button"][data-icon][data-size="small"] {
padding-left: 9px;
}
[data-component="button"][data-icon][data-size="normal"] {
padding-left: 11px;
}
[data-component="button"][data-icon][data-size="large"] {
padding-left: 15px;
}
[data-component="button"] [data-slot="icon-svg"] {
color: currentColor;
}
/* Neutral */
[data-component="button"][data-variant="neutral"] {
background-color: var(--oc-bg-button-neutral);
color: var(--oc-text-base);
box-shadow: var(--oc-elevation-button-neutral);
}
[data-component="button"][data-variant="neutral"]:is(:hover, [data-state="hover"]):not(:disabled) {
background-image:
linear-gradient(90deg, var(--oc-overlay-hover) 0%, var(--oc-overlay-hover) 100%),
linear-gradient(90deg, var(--oc-bg-button-neutral) 0%, var(--oc-bg-button-neutral) 100%);
}
[data-component="button"][data-variant="neutral"]:is(:active, [data-state="pressed"]):not(:disabled) {
background-image:
linear-gradient(90deg, var(--oc-overlay-pressed) 0%, var(--oc-overlay-pressed) 100%),
linear-gradient(90deg, var(--oc-bg-button-neutral) 0%, var(--oc-bg-button-neutral) 100%);
}
[data-component="button"][data-variant="neutral"]:is(:disabled, [data-state="disabled"]) {
opacity: 0.5;
cursor: not-allowed;
}
/* Danger */
[data-component="button"][data-variant="danger"] {
background-color: var(--oc-bg-button-neutral);
color: var(--oc-state-fg-danger);
box-shadow: var(--oc-elevation-button-neutral);
}
[data-component="button"][data-variant="danger"]:is(:hover, [data-state="hover"]):not(:disabled) {
background-image:
linear-gradient(90deg, var(--oc-overlay-hover) 0%, var(--oc-overlay-hover) 100%),
linear-gradient(90deg, var(--oc-bg-button-neutral) 0%, var(--oc-bg-button-neutral) 100%);
}
[data-component="button"][data-variant="danger"]:is(:active, [data-state="pressed"]):not(:disabled) {
background-image:
linear-gradient(90deg, var(--oc-overlay-pressed) 0%, var(--oc-overlay-pressed) 100%),
linear-gradient(90deg, var(--oc-bg-button-neutral) 0%, var(--oc-bg-button-neutral) 100%);
}
[data-component="button"][data-variant="danger"]:is(:disabled, [data-state="disabled"]) {
opacity: 0.5;
cursor: not-allowed;
}
[data-component="button"][data-variant="warning"] {
background-color: var(--oc-bg-button-neutral);
color: var(--oc-state-fg-warning);
box-shadow: var(--oc-elevation-button-neutral);
}
[data-component="button"][data-variant="warning"]:is(:hover, [data-state="hover"]):not(:disabled) {
background-image:
linear-gradient(90deg, var(--oc-overlay-hover) 0%, var(--oc-overlay-hover) 100%),
linear-gradient(90deg, var(--oc-bg-button-neutral) 0%, var(--oc-bg-button-neutral) 100%);
}
[data-component="button"][data-variant="warning"]:is(:active, [data-state="pressed"]):not(:disabled) {
background-image:
linear-gradient(90deg, var(--oc-overlay-pressed) 0%, var(--oc-overlay-pressed) 100%),
linear-gradient(90deg, var(--oc-bg-button-neutral) 0%, var(--oc-bg-button-neutral) 100%);
}
[data-component="button"][data-variant="warning"]:is(:disabled, [data-state="disabled"]) {
opacity: 0.5;
cursor: not-allowed;
}
/* Outline */
[data-component="button"][data-variant="outline"] {
background-color: transparent;
color: var(--oc-text-base);
box-shadow: inset 0 0 0 1px var(--oc-border-muted);
}
[data-component="button"][data-variant="outline"]:is(:hover, [data-state="hover"]):not(:disabled) {
background-color: var(--oc-overlay-hover);
}
[data-component="button"][data-variant="outline"]:is(:active, [data-state="pressed"]):not(:disabled) {
background-color: var(--oc-overlay-pressed);
}
[data-component="button"][data-variant="outline"]:is(:disabled, [data-state="disabled"]) {
opacity: 0.5;
cursor: not-allowed;
}
/* Contrast */
[data-component="button"][data-variant="contrast"] {
background-image:
linear-gradient(180deg, var(--oc-alpha-light-20) 0%, var(--oc-alpha-light-0) 100%),
linear-gradient(90deg, var(--oc-bg-contrast) 0%, var(--oc-bg-contrast) 100%);
color: var(--oc-text-contrast);
text-shadow: 0 0.5px 0.5px rgba(0, 0, 0, 0.3);
box-shadow: var(--oc-elevation-button-contrast);
}
[data-component="button"][data-variant="contrast"]:is(:hover, [data-state="hover"]):not(:disabled) {
background-image:
linear-gradient(90deg, var(--oc-overlay-contrast-hover) 0%, var(--oc-overlay-contrast-hover) 100%),
linear-gradient(180deg, var(--oc-alpha-light-20) 0%, var(--oc-alpha-light-0) 100%),
linear-gradient(90deg, var(--oc-bg-contrast) 0%, var(--oc-bg-contrast) 100%);
}
[data-component="button"][data-variant="contrast"]:is(:active, [data-state="pressed"]):not(:disabled) {
background-image:
linear-gradient(90deg, var(--oc-overlay-contrast-pressed) 0%, var(--oc-overlay-contrast-pressed) 100%),
linear-gradient(180deg, var(--oc-alpha-light-20) 0%, var(--oc-alpha-light-0) 100%),
linear-gradient(90deg, var(--oc-bg-contrast) 0%, var(--oc-bg-contrast) 100%);
}
[data-component="button"][data-variant="contrast"]:is(:disabled, [data-state="disabled"]) {
opacity: 0.4;
cursor: not-allowed;
}
/* Loading */
[data-component="button"][data-variant="loading"] {
background: #f2f2f2;
color: var(--oc-text-base);
box-shadow: inset 0 0 0 0.5px rgba(0, 0, 0, 0.08);
cursor: default;
pointer-events: none;
}
/* Ghost */
[data-component="button"][data-variant="ghost"] {
background-color: transparent;
color: var(--oc-text-base);
}
[data-component="button"][data-variant="ghost"]:is(:hover, [data-state="hover"]):not(:disabled):not([data-expanded]) {
background-color: var(--oc-overlay-hover);
}
[data-component="button"][data-variant="ghost"]:is(:active, [data-state="pressed"]):not(:disabled) {
background-color: var(--oc-overlay-pressed);
}
[data-component="button"][data-variant="ghost"]:where([data-expanded]):not(:disabled) {
background-color: var(--oc-overlay-pressed);
}
[data-component="button"][data-variant="ghost"]:is(:disabled, [data-state="disabled"]) {
opacity: 0.5;
cursor: not-allowed;
}
/* Ghost muted */
[data-component="button"][data-variant="ghost-muted"] {
background-color: transparent;
color: var(--oc-text-muted);
}
[data-component="button"][data-variant="ghost-muted"] [data-slot="icon-svg"] {
color: var(--oc-icon-muted);
}
[data-component="button"][data-variant="ghost-muted"]:is(:hover, [data-state="hover"]):not(:disabled):not(
[data-expanded]
) {
background-color: var(--oc-overlay-hover);
}
[data-component="button"][data-variant="ghost-muted"]:is(:active, [data-state="pressed"]):not(:disabled) {
background-color: var(--oc-overlay-pressed);
}
[data-component="button"][data-variant="ghost-muted"]:where([data-expanded]):not(:disabled) {
background-color: var(--oc-overlay-pressed);
color: var(--oc-text-base);
}
[data-component="button"][data-variant="ghost-muted"]:where([data-expanded]):not(:disabled) [data-slot="icon-svg"] {
color: var(--oc-icon-base);
}
[data-component="button"][data-variant="ghost-muted"]:is(:disabled, [data-state="disabled"]) {
opacity: 0.5;
cursor: not-allowed;
}

View file

@ -0,0 +1,20 @@
[data-component="check"] {
display: inline-flex;
align-items: center;
gap: 8px;
color: var(--oc-text-base);
font-size: 13px;
user-select: none;
}
[data-component="check"] :is(input[type="checkbox"], input[type="radio"]) {
width: 16px;
height: 16px;
margin: 0;
accent-color: var(--oc-bg-accent);
}
[data-component="check"]:has(input:disabled) {
opacity: 0.5;
cursor: not-allowed;
}

View file

@ -0,0 +1,11 @@
[data-component="divider"] {
box-sizing: border-box;
width: 100%;
height: 1px;
transform: scaleY(0.5);
border: none;
background: var(--oc-border-strong);
flex: none;
align-self: stretch;
flex-grow: 0;
}

View file

@ -0,0 +1,24 @@
[data-component="field"] {
display: grid;
gap: 6px;
min-width: 0;
}
[data-component="field"] [data-slot="field-label"] {
color: var(--oc-text-base);
font-size: 13px;
font-weight: 530;
line-height: 1.25;
}
[data-component="field"] [data-slot="field-description"] {
margin: 0;
color: var(--oc-text-muted);
font-size: 11px;
}
[data-component="field"] [data-slot="field-error"] {
margin: 0;
color: var(--oc-state-fg-danger);
font-size: 11px;
}

View file

@ -0,0 +1,55 @@
[data-component="input"],
[data-component="select"],
[data-component="textarea"] {
width: 100%;
min-width: 0;
border: 0;
border-radius: 6px;
outline: 1px solid transparent;
background: linear-gradient(180deg, var(--oc-alpha-light-2) 0%, var(--oc-alpha-light-0) 100%), var(--oc-bg-base);
box-shadow: var(--oc-elevation-button-neutral);
color: var(--oc-text-base);
font: inherit;
font-size: 13px;
transition:
outline-color 85ms ease-out,
background 85ms ease-out;
}
[data-component="input"],
[data-component="select"] {
height: 32px;
padding: 0 10px;
}
[data-component="textarea"] {
min-height: 88px;
padding: 8px 10px;
line-height: 1.5;
resize: vertical;
}
:is([data-component="input"], [data-component="select"], [data-component="textarea"])::placeholder {
color: var(--oc-text-faint);
}
:is([data-component="input"], [data-component="select"], [data-component="textarea"]):hover:not(:disabled) {
background: linear-gradient(0deg, var(--oc-overlay-hover), var(--oc-overlay-hover)), var(--oc-bg-base);
}
:is([data-component="input"], [data-component="select"], [data-component="textarea"]):focus-visible {
outline: 2px solid var(--oc-border-focus);
outline-offset: 1px;
}
:is([data-component="input"], [data-component="select"], [data-component="textarea"]):is(:disabled, [data-disabled]) {
opacity: 0.5;
cursor: not-allowed;
}
:is([data-component="input"], [data-component="select"], [data-component="textarea"]):is(
[aria-invalid="true"],
[data-invalid]
) {
outline-color: var(--oc-state-fg-danger);
}

View file

@ -0,0 +1,64 @@
[data-component="page"] {
width: min(100% - 32px, var(--oc-page-max-width, 1200px));
margin-inline: auto;
padding-block: var(--oc-page-padding-block, 56px);
}
[data-component="page"] [data-slot="page-header"] {
display: flex;
align-items: flex-end;
justify-content: space-between;
gap: 24px;
margin-bottom: 32px;
}
[data-component="page"] [data-slot="page-heading"] {
min-width: 0;
}
[data-component="page"] [data-slot="page-eyebrow"] {
margin: 0 0 4px;
color: var(--oc-text-muted);
font-size: 13px;
}
[data-component="page"] [data-slot="page-title"] {
margin: 0;
color: var(--oc-text-base);
font-size: clamp(36px, 6vw, 64px);
font-weight: 440;
line-height: 0.95;
letter-spacing: -0.045em;
}
[data-component="page"] [data-slot="page-description"] {
max-width: 64ch;
margin: 12px 0 0;
color: var(--oc-text-muted);
}
[data-component="page"] [data-slot="page-actions"] {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 8px;
flex: none;
}
[data-component="page"] [data-slot="page-content"] {
display: grid;
gap: 16px;
}
@media (max-width: 640px) {
[data-component="page"] {
width: min(100% - 24px, var(--oc-page-max-width, 1200px));
padding-block: 32px;
}
[data-component="page"] [data-slot="page-header"] {
align-items: flex-start;
flex-direction: column;
margin-bottom: 24px;
}
}

View file

@ -0,0 +1,38 @@
[data-component="surface"] {
overflow: hidden;
border: 1px solid var(--oc-border-muted);
border-radius: 12px;
background: var(--oc-bg-layer-01);
box-shadow: var(--oc-elevation-raised);
}
[data-component="surface"][data-variant="flat"] {
box-shadow: none;
}
[data-component="surface"] [data-slot="surface-header"] {
padding: 24px 24px 16px;
}
[data-component="surface"] [data-slot="surface-title"] {
margin: 0;
color: var(--oc-text-base);
font-size: 16px;
font-weight: 530;
line-height: 1.25;
letter-spacing: -0.01em;
}
[data-component="surface"] [data-slot="surface-description"] {
margin: 6px 0 0;
color: var(--oc-text-muted);
font-size: 13px;
}
[data-component="surface"] [data-slot="surface-content"] {
padding: 0 24px 24px;
}
[data-component="surface"][data-padding="none"] [data-slot="surface-content"] {
padding: 0;
}

View file

@ -0,0 +1,52 @@
[data-component="table-container"] {
width: 100%;
overflow-x: auto;
}
[data-component="table"] {
width: 100%;
border-collapse: collapse;
color: var(--oc-text-base);
font-size: 13px;
font-variant-numeric: tabular-nums;
}
[data-component="table"] :is(th, td) {
height: 48px;
padding: 0 16px;
border-bottom: 1px solid var(--oc-border-muted);
text-align: left;
vertical-align: middle;
white-space: nowrap;
}
[data-component="table"] th {
height: 40px;
color: var(--oc-text-muted);
font-size: 11px;
font-weight: 530;
letter-spacing: 0.08em;
text-transform: uppercase;
}
[data-component="table"] tbody tr:last-child td {
border-bottom: 0;
}
[data-component="table"] tbody tr:is(:hover, [data-state="hover"]) td {
background: var(--oc-overlay-hover);
}
[data-component="table"] [data-align="end"] {
text-align: right;
}
[data-component="table"] [data-numeric] {
font-family: ui-monospace, "SFMono-Regular", Consolas, monospace;
}
[data-component="table"] [data-slot="table-actions"] {
display: flex;
justify-content: flex-end;
gap: 8px;
}