@quilltap/theme-storybook 1.0.60 → 1.0.62
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/{chunk-XSNC4J5T.mjs → chunk-TESCTXU3.mjs} +52 -0
- package/dist/index.css +64 -0
- package/dist/index.js +52 -0
- package/dist/index.mjs +1 -1
- package/dist/stories/index.js +52 -0
- package/dist/stories/index.mjs +1 -1
- package/package.json +2 -2
- package/src/css/qt-components.css +122 -0
- package/src/stories/components/Surfaces.tsx +52 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@quilltap/theme-storybook` will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [1.0.62] - 2026-08-25
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- `qt-text-on-primary`, `qt-text-on-success`, and `qt-text-on-destructive`: the rest of the on-a-filled-surface foreground family that `qt-text-on-accent` started, each mapping to the theme's matching `*Foreground` token. Plus the hand-written hover partners `hover:qt-text-on-accent/-primary/-success/-destructive`, for controls that sit quiet at rest and take a filled background on hover. Mirrors the app-side definitions.
|
|
9
|
+
- `Surfaces` story: a "Foregrounds on filled surfaces" section previewing all four fills with their foregrounds, and a hover row for the hover partners. It also spells out the naming trap — the classes are `-on-<fill>`, never `-<fill>-foreground`, which is the Tailwind spelling and no `qt-` class at all.
|
|
10
|
+
|
|
5
11
|
## [1.0.44] - 2026-06-14
|
|
6
12
|
|
|
7
13
|
### Added
|
|
@@ -1043,6 +1043,11 @@ var note = {
|
|
|
1043
1043
|
};
|
|
1044
1044
|
var Surfaces = () => {
|
|
1045
1045
|
return /* @__PURE__ */ jsxs9("div", { style: { padding: "1.5rem" }, children: [
|
|
1046
|
+
/* @__PURE__ */ jsx9("style", { children: `
|
|
1047
|
+
.surfaces-demo-fill-primary:hover { background-color: var(--color-primary); }
|
|
1048
|
+
.surfaces-demo-fill-success:hover { background-color: var(--color-success); }
|
|
1049
|
+
.surfaces-demo-fill-destructive:hover { background-color: var(--color-destructive); }
|
|
1050
|
+
` }),
|
|
1046
1051
|
/* @__PURE__ */ jsx9("h2", { style: { fontSize: "1.5rem", fontWeight: 700, marginBottom: "0.5rem" }, children: "Surfaces" }),
|
|
1047
1052
|
/* @__PURE__ */ jsxs9("p", { style: { ...note, maxWidth: "44rem" }, children: [
|
|
1048
1053
|
"How accent-coloured surfaces stay legible no matter how bold a theme makes its ",
|
|
@@ -1079,6 +1084,53 @@ var Surfaces = () => {
|
|
|
1079
1084
|
/* @__PURE__ */ jsx9("kbd", { className: "qt-bg-accent qt-text-on-accent", style: { padding: "0.125rem 0.375rem", borderRadius: "0.25rem", fontSize: "0.75rem" }, children: "\u21B5" })
|
|
1080
1085
|
] })
|
|
1081
1086
|
] }),
|
|
1087
|
+
/* @__PURE__ */ jsxs9("section", { style: { marginBottom: "2rem" }, children: [
|
|
1088
|
+
/* @__PURE__ */ jsxs9("h3", { style: sectionHeading2, children: [
|
|
1089
|
+
"Foregrounds on filled surfaces \u2014 the ",
|
|
1090
|
+
/* @__PURE__ */ jsx9("code", { children: "qt-text-on-*" }),
|
|
1091
|
+
" family"
|
|
1092
|
+
] }),
|
|
1093
|
+
/* @__PURE__ */ jsxs9("p", { style: note, children: [
|
|
1094
|
+
"The same contract, extended to every filled surface the app paints:",
|
|
1095
|
+
" ",
|
|
1096
|
+
/* @__PURE__ */ jsx9("code", { children: "qt-text-on-accent" }),
|
|
1097
|
+
", ",
|
|
1098
|
+
/* @__PURE__ */ jsx9("code", { children: "qt-text-on-primary" }),
|
|
1099
|
+
",",
|
|
1100
|
+
" ",
|
|
1101
|
+
/* @__PURE__ */ jsx9("code", { children: "qt-text-on-success" }),
|
|
1102
|
+
", and ",
|
|
1103
|
+
/* @__PURE__ */ jsx9("code", { children: "qt-text-on-destructive" }),
|
|
1104
|
+
", each mapping to the theme's matching ",
|
|
1105
|
+
/* @__PURE__ */ jsx9("code", { children: "*Foreground" }),
|
|
1106
|
+
" token. Note the naming \u2014 ",
|
|
1107
|
+
/* @__PURE__ */ jsxs9("code", { children: [
|
|
1108
|
+
"-on-",
|
|
1109
|
+
/* @__PURE__ */ jsx9("em", { children: "fill" })
|
|
1110
|
+
] }),
|
|
1111
|
+
", never ",
|
|
1112
|
+
/* @__PURE__ */ jsxs9("code", { children: [
|
|
1113
|
+
"-",
|
|
1114
|
+
/* @__PURE__ */ jsx9("em", { children: "fill" }),
|
|
1115
|
+
"-foreground"
|
|
1116
|
+
] }),
|
|
1117
|
+
", which is the Tailwind spelling and is not a ",
|
|
1118
|
+
/* @__PURE__ */ jsx9("code", { children: "qt-" }),
|
|
1119
|
+
" class at all."
|
|
1120
|
+
] }),
|
|
1121
|
+
/* @__PURE__ */ jsxs9("div", { style: { display: "flex", flexWrap: "wrap", gap: "0.75rem", alignItems: "center" }, children: [
|
|
1122
|
+
/* @__PURE__ */ jsx9("span", { className: "qt-bg-accent qt-text-on-accent", style: { padding: "0.25rem 0.625rem", borderRadius: "0.375rem", fontSize: "0.8125rem", fontWeight: 600 }, children: "on accent" }),
|
|
1123
|
+
/* @__PURE__ */ jsx9("span", { className: "qt-bg-primary qt-text-on-primary", style: { padding: "0.25rem 0.625rem", borderRadius: "0.375rem", fontSize: "0.8125rem", fontWeight: 600 }, children: "on primary" }),
|
|
1124
|
+
/* @__PURE__ */ jsx9("span", { className: "qt-bg-success qt-text-on-success", style: { padding: "0.25rem 0.625rem", borderRadius: "0.375rem", fontSize: "0.8125rem", fontWeight: 600 }, children: "on success" }),
|
|
1125
|
+
/* @__PURE__ */ jsx9("span", { className: "qt-bg-destructive qt-text-on-destructive", style: { padding: "0.25rem 0.625rem", borderRadius: "0.375rem", fontSize: "0.8125rem", fontWeight: 600 }, children: "on destructive" })
|
|
1126
|
+
] }),
|
|
1127
|
+
/* @__PURE__ */ jsx9("p", { style: { ...note, marginTop: "1rem" }, children: "Each has a hover partner for controls that stay quiet at rest and take the fill on hover. Tailwind generates no variants for these classes, so the hover forms are written out by hand \u2014 reach for one that was never written and it is simply inert. Hover the buttons below." }),
|
|
1128
|
+
/* @__PURE__ */ jsxs9("div", { style: { display: "flex", flexWrap: "wrap", gap: "0.75rem", alignItems: "center" }, children: [
|
|
1129
|
+
/* @__PURE__ */ jsx9("button", { className: "qt-bg-card qt-text-secondary surfaces-demo-fill-primary hover:qt-text-on-primary", style: { padding: "0.25rem 0.625rem", borderRadius: "0.375rem", fontSize: "0.8125rem", fontWeight: 600, border: "1px solid var(--color-border)", cursor: "pointer" }, children: "hover:qt-text-on-primary" }),
|
|
1130
|
+
/* @__PURE__ */ jsx9("button", { className: "qt-bg-card qt-text-secondary surfaces-demo-fill-success hover:qt-text-on-success", style: { padding: "0.25rem 0.625rem", borderRadius: "0.375rem", fontSize: "0.8125rem", fontWeight: 600, border: "1px solid var(--color-border)", cursor: "pointer" }, children: "hover:qt-text-on-success" }),
|
|
1131
|
+
/* @__PURE__ */ jsx9("button", { className: "qt-bg-card qt-text-secondary surfaces-demo-fill-destructive hover:qt-text-on-destructive", style: { padding: "0.25rem 0.625rem", borderRadius: "0.375rem", fontSize: "0.8125rem", fontWeight: 600, border: "1px solid var(--color-border)", cursor: "pointer" }, children: "hover:qt-text-on-destructive" })
|
|
1132
|
+
] })
|
|
1133
|
+
] }),
|
|
1082
1134
|
/* @__PURE__ */ jsxs9("section", { style: { marginBottom: "2rem" }, children: [
|
|
1083
1135
|
/* @__PURE__ */ jsxs9("h3", { style: sectionHeading2, children: [
|
|
1084
1136
|
"Hover-highlight rows \u2014 ",
|
package/dist/index.css
CHANGED
|
@@ -286,6 +286,10 @@ body {
|
|
|
286
286
|
--qt-status-danger-bg: color-mix(in srgb, var(--color-destructive) 85%, transparent);
|
|
287
287
|
--qt-status-danger-fg: var(--color-destructive-foreground);
|
|
288
288
|
--qt-status-danger-border: var(--color-destructive);
|
|
289
|
+
--qt-badge-primary-bg: var(--color-primary);
|
|
290
|
+
--qt-badge-primary-fg: var(--color-primary-foreground);
|
|
291
|
+
--qt-badge-secondary-bg: var(--color-secondary);
|
|
292
|
+
--qt-badge-secondary-fg: var(--color-secondary-foreground);
|
|
289
293
|
--qt-alert-success-bg: hsl(142 76% 36% / 0.1);
|
|
290
294
|
--qt-alert-success-fg: hsl(142 76% 30%);
|
|
291
295
|
--qt-alert-success-border: hsl(142 76% 36% / 0.3);
|
|
@@ -888,6 +892,45 @@ body {
|
|
|
888
892
|
color: var(--color-foreground);
|
|
889
893
|
border: 1px solid var(--color-border);
|
|
890
894
|
}
|
|
895
|
+
.qt-badge-provider-openai,
|
|
896
|
+
.qt-badge-provider-ollama,
|
|
897
|
+
.qt-badge-provider-openrouter,
|
|
898
|
+
.qt-badge-provider-nanogpt,
|
|
899
|
+
.qt-badge-provider-builtin {
|
|
900
|
+
display: inline-flex;
|
|
901
|
+
align-items: center;
|
|
902
|
+
justify-content: center;
|
|
903
|
+
flex-shrink: 0;
|
|
904
|
+
padding: var(--qt-badge-padding-y) var(--qt-badge-padding-x);
|
|
905
|
+
border-radius: var(--qt-badge-radius);
|
|
906
|
+
font-size: var(--qt-badge-font-size);
|
|
907
|
+
font-weight: var(--qt-badge-font-weight);
|
|
908
|
+
}
|
|
909
|
+
.qt-badge-provider-openai {
|
|
910
|
+
background: var(--qt-status-success-bg);
|
|
911
|
+
color: var(--qt-status-success-fg);
|
|
912
|
+
border: 1px solid var(--qt-status-success-border);
|
|
913
|
+
}
|
|
914
|
+
.qt-badge-provider-ollama {
|
|
915
|
+
background: var(--qt-badge-secondary-bg);
|
|
916
|
+
color: var(--qt-badge-secondary-fg);
|
|
917
|
+
border: 1px solid var(--qt-badge-secondary-border);
|
|
918
|
+
}
|
|
919
|
+
.qt-badge-provider-openrouter {
|
|
920
|
+
background: var(--qt-status-warning-bg);
|
|
921
|
+
color: var(--qt-status-warning-fg);
|
|
922
|
+
border: 1px solid var(--qt-status-warning-border);
|
|
923
|
+
}
|
|
924
|
+
.qt-badge-provider-nanogpt {
|
|
925
|
+
background: var(--qt-badge-primary-bg);
|
|
926
|
+
color: var(--qt-badge-primary-fg);
|
|
927
|
+
border: 1px solid var(--qt-badge-primary-border);
|
|
928
|
+
}
|
|
929
|
+
.qt-badge-provider-builtin {
|
|
930
|
+
background: var(--qt-status-info-bg);
|
|
931
|
+
color: var(--qt-status-info-fg);
|
|
932
|
+
border: 1px solid var(--qt-status-info-border);
|
|
933
|
+
}
|
|
891
934
|
.qt-badge-wardrobe-top,
|
|
892
935
|
.qt-badge-wardrobe-bottom,
|
|
893
936
|
.qt-badge-wardrobe-footwear,
|
|
@@ -1905,6 +1948,15 @@ body {
|
|
|
1905
1948
|
.qt-text-on-accent {
|
|
1906
1949
|
color: var(--color-accent-foreground);
|
|
1907
1950
|
}
|
|
1951
|
+
.qt-text-on-primary {
|
|
1952
|
+
color: var(--color-primary-foreground);
|
|
1953
|
+
}
|
|
1954
|
+
.qt-text-on-success {
|
|
1955
|
+
color: var(--color-success-foreground);
|
|
1956
|
+
}
|
|
1957
|
+
.qt-text-on-destructive {
|
|
1958
|
+
color: var(--color-destructive-foreground);
|
|
1959
|
+
}
|
|
1908
1960
|
.qt-hover-accent {
|
|
1909
1961
|
transition: background-color 0.15s ease, color 0.15s ease;
|
|
1910
1962
|
}
|
|
@@ -2035,6 +2087,18 @@ body {
|
|
|
2035
2087
|
.hover\:qt-bg-primary\/10:hover {
|
|
2036
2088
|
background-color: color-mix(in srgb, var(--color-primary) 10%, transparent);
|
|
2037
2089
|
}
|
|
2090
|
+
.hover\:qt-text-on-accent:hover {
|
|
2091
|
+
color: var(--color-accent-foreground);
|
|
2092
|
+
}
|
|
2093
|
+
.hover\:qt-text-on-primary:hover {
|
|
2094
|
+
color: var(--color-primary-foreground);
|
|
2095
|
+
}
|
|
2096
|
+
.hover\:qt-text-on-success:hover {
|
|
2097
|
+
color: var(--color-success-foreground);
|
|
2098
|
+
}
|
|
2099
|
+
.hover\:qt-text-on-destructive:hover {
|
|
2100
|
+
color: var(--color-destructive-foreground);
|
|
2101
|
+
}
|
|
2038
2102
|
.qt-bg-overlay {
|
|
2039
2103
|
background-color: var(--qt-overlay-bg, rgb(0 0 0 / 0.85));
|
|
2040
2104
|
}
|
package/dist/index.js
CHANGED
|
@@ -1153,6 +1153,11 @@ var note = {
|
|
|
1153
1153
|
};
|
|
1154
1154
|
var Surfaces = () => {
|
|
1155
1155
|
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: { padding: "1.5rem" }, children: [
|
|
1156
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("style", { children: `
|
|
1157
|
+
.surfaces-demo-fill-primary:hover { background-color: var(--color-primary); }
|
|
1158
|
+
.surfaces-demo-fill-success:hover { background-color: var(--color-success); }
|
|
1159
|
+
.surfaces-demo-fill-destructive:hover { background-color: var(--color-destructive); }
|
|
1160
|
+
` }),
|
|
1156
1161
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h2", { style: { fontSize: "1.5rem", fontWeight: 700, marginBottom: "0.5rem" }, children: "Surfaces" }),
|
|
1157
1162
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("p", { style: { ...note, maxWidth: "44rem" }, children: [
|
|
1158
1163
|
"How accent-coloured surfaces stay legible no matter how bold a theme makes its ",
|
|
@@ -1189,6 +1194,53 @@ var Surfaces = () => {
|
|
|
1189
1194
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("kbd", { className: "qt-bg-accent qt-text-on-accent", style: { padding: "0.125rem 0.375rem", borderRadius: "0.25rem", fontSize: "0.75rem" }, children: "\u21B5" })
|
|
1190
1195
|
] })
|
|
1191
1196
|
] }),
|
|
1197
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("section", { style: { marginBottom: "2rem" }, children: [
|
|
1198
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("h3", { style: sectionHeading2, children: [
|
|
1199
|
+
"Foregrounds on filled surfaces \u2014 the ",
|
|
1200
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("code", { children: "qt-text-on-*" }),
|
|
1201
|
+
" family"
|
|
1202
|
+
] }),
|
|
1203
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("p", { style: note, children: [
|
|
1204
|
+
"The same contract, extended to every filled surface the app paints:",
|
|
1205
|
+
" ",
|
|
1206
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("code", { children: "qt-text-on-accent" }),
|
|
1207
|
+
", ",
|
|
1208
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("code", { children: "qt-text-on-primary" }),
|
|
1209
|
+
",",
|
|
1210
|
+
" ",
|
|
1211
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("code", { children: "qt-text-on-success" }),
|
|
1212
|
+
", and ",
|
|
1213
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("code", { children: "qt-text-on-destructive" }),
|
|
1214
|
+
", each mapping to the theme's matching ",
|
|
1215
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("code", { children: "*Foreground" }),
|
|
1216
|
+
" token. Note the naming \u2014 ",
|
|
1217
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("code", { children: [
|
|
1218
|
+
"-on-",
|
|
1219
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("em", { children: "fill" })
|
|
1220
|
+
] }),
|
|
1221
|
+
", never ",
|
|
1222
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("code", { children: [
|
|
1223
|
+
"-",
|
|
1224
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("em", { children: "fill" }),
|
|
1225
|
+
"-foreground"
|
|
1226
|
+
] }),
|
|
1227
|
+
", which is the Tailwind spelling and is not a ",
|
|
1228
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("code", { children: "qt-" }),
|
|
1229
|
+
" class at all."
|
|
1230
|
+
] }),
|
|
1231
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: { display: "flex", flexWrap: "wrap", gap: "0.75rem", alignItems: "center" }, children: [
|
|
1232
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "qt-bg-accent qt-text-on-accent", style: { padding: "0.25rem 0.625rem", borderRadius: "0.375rem", fontSize: "0.8125rem", fontWeight: 600 }, children: "on accent" }),
|
|
1233
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "qt-bg-primary qt-text-on-primary", style: { padding: "0.25rem 0.625rem", borderRadius: "0.375rem", fontSize: "0.8125rem", fontWeight: 600 }, children: "on primary" }),
|
|
1234
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "qt-bg-success qt-text-on-success", style: { padding: "0.25rem 0.625rem", borderRadius: "0.375rem", fontSize: "0.8125rem", fontWeight: 600 }, children: "on success" }),
|
|
1235
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "qt-bg-destructive qt-text-on-destructive", style: { padding: "0.25rem 0.625rem", borderRadius: "0.375rem", fontSize: "0.8125rem", fontWeight: 600 }, children: "on destructive" })
|
|
1236
|
+
] }),
|
|
1237
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { style: { ...note, marginTop: "1rem" }, children: "Each has a hover partner for controls that stay quiet at rest and take the fill on hover. Tailwind generates no variants for these classes, so the hover forms are written out by hand \u2014 reach for one that was never written and it is simply inert. Hover the buttons below." }),
|
|
1238
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: { display: "flex", flexWrap: "wrap", gap: "0.75rem", alignItems: "center" }, children: [
|
|
1239
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { className: "qt-bg-card qt-text-secondary surfaces-demo-fill-primary hover:qt-text-on-primary", style: { padding: "0.25rem 0.625rem", borderRadius: "0.375rem", fontSize: "0.8125rem", fontWeight: 600, border: "1px solid var(--color-border)", cursor: "pointer" }, children: "hover:qt-text-on-primary" }),
|
|
1240
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { className: "qt-bg-card qt-text-secondary surfaces-demo-fill-success hover:qt-text-on-success", style: { padding: "0.25rem 0.625rem", borderRadius: "0.375rem", fontSize: "0.8125rem", fontWeight: 600, border: "1px solid var(--color-border)", cursor: "pointer" }, children: "hover:qt-text-on-success" }),
|
|
1241
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { className: "qt-bg-card qt-text-secondary surfaces-demo-fill-destructive hover:qt-text-on-destructive", style: { padding: "0.25rem 0.625rem", borderRadius: "0.375rem", fontSize: "0.8125rem", fontWeight: 600, border: "1px solid var(--color-border)", cursor: "pointer" }, children: "hover:qt-text-on-destructive" })
|
|
1242
|
+
] })
|
|
1243
|
+
] }),
|
|
1192
1244
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("section", { style: { marginBottom: "2rem" }, children: [
|
|
1193
1245
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("h3", { style: sectionHeading2, children: [
|
|
1194
1246
|
"Hover-highlight rows \u2014 ",
|
package/dist/index.mjs
CHANGED
package/dist/stories/index.js
CHANGED
|
@@ -1090,6 +1090,11 @@ var note = {
|
|
|
1090
1090
|
};
|
|
1091
1091
|
var Surfaces = () => {
|
|
1092
1092
|
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { padding: "1.5rem" }, children: [
|
|
1093
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("style", { children: `
|
|
1094
|
+
.surfaces-demo-fill-primary:hover { background-color: var(--color-primary); }
|
|
1095
|
+
.surfaces-demo-fill-success:hover { background-color: var(--color-success); }
|
|
1096
|
+
.surfaces-demo-fill-destructive:hover { background-color: var(--color-destructive); }
|
|
1097
|
+
` }),
|
|
1093
1098
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h2", { style: { fontSize: "1.5rem", fontWeight: 700, marginBottom: "0.5rem" }, children: "Surfaces" }),
|
|
1094
1099
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("p", { style: { ...note, maxWidth: "44rem" }, children: [
|
|
1095
1100
|
"How accent-coloured surfaces stay legible no matter how bold a theme makes its ",
|
|
@@ -1126,6 +1131,53 @@ var Surfaces = () => {
|
|
|
1126
1131
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("kbd", { className: "qt-bg-accent qt-text-on-accent", style: { padding: "0.125rem 0.375rem", borderRadius: "0.25rem", fontSize: "0.75rem" }, children: "\u21B5" })
|
|
1127
1132
|
] })
|
|
1128
1133
|
] }),
|
|
1134
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("section", { style: { marginBottom: "2rem" }, children: [
|
|
1135
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("h3", { style: sectionHeading2, children: [
|
|
1136
|
+
"Foregrounds on filled surfaces \u2014 the ",
|
|
1137
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("code", { children: "qt-text-on-*" }),
|
|
1138
|
+
" family"
|
|
1139
|
+
] }),
|
|
1140
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("p", { style: note, children: [
|
|
1141
|
+
"The same contract, extended to every filled surface the app paints:",
|
|
1142
|
+
" ",
|
|
1143
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("code", { children: "qt-text-on-accent" }),
|
|
1144
|
+
", ",
|
|
1145
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("code", { children: "qt-text-on-primary" }),
|
|
1146
|
+
",",
|
|
1147
|
+
" ",
|
|
1148
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("code", { children: "qt-text-on-success" }),
|
|
1149
|
+
", and ",
|
|
1150
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("code", { children: "qt-text-on-destructive" }),
|
|
1151
|
+
", each mapping to the theme's matching ",
|
|
1152
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("code", { children: "*Foreground" }),
|
|
1153
|
+
" token. Note the naming \u2014 ",
|
|
1154
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("code", { children: [
|
|
1155
|
+
"-on-",
|
|
1156
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("em", { children: "fill" })
|
|
1157
|
+
] }),
|
|
1158
|
+
", never ",
|
|
1159
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("code", { children: [
|
|
1160
|
+
"-",
|
|
1161
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("em", { children: "fill" }),
|
|
1162
|
+
"-foreground"
|
|
1163
|
+
] }),
|
|
1164
|
+
", which is the Tailwind spelling and is not a ",
|
|
1165
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("code", { children: "qt-" }),
|
|
1166
|
+
" class at all."
|
|
1167
|
+
] }),
|
|
1168
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { display: "flex", flexWrap: "wrap", gap: "0.75rem", alignItems: "center" }, children: [
|
|
1169
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "qt-bg-accent qt-text-on-accent", style: { padding: "0.25rem 0.625rem", borderRadius: "0.375rem", fontSize: "0.8125rem", fontWeight: 600 }, children: "on accent" }),
|
|
1170
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "qt-bg-primary qt-text-on-primary", style: { padding: "0.25rem 0.625rem", borderRadius: "0.375rem", fontSize: "0.8125rem", fontWeight: 600 }, children: "on primary" }),
|
|
1171
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "qt-bg-success qt-text-on-success", style: { padding: "0.25rem 0.625rem", borderRadius: "0.375rem", fontSize: "0.8125rem", fontWeight: 600 }, children: "on success" }),
|
|
1172
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "qt-bg-destructive qt-text-on-destructive", style: { padding: "0.25rem 0.625rem", borderRadius: "0.375rem", fontSize: "0.8125rem", fontWeight: 600 }, children: "on destructive" })
|
|
1173
|
+
] }),
|
|
1174
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { style: { ...note, marginTop: "1rem" }, children: "Each has a hover partner for controls that stay quiet at rest and take the fill on hover. Tailwind generates no variants for these classes, so the hover forms are written out by hand \u2014 reach for one that was never written and it is simply inert. Hover the buttons below." }),
|
|
1175
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { display: "flex", flexWrap: "wrap", gap: "0.75rem", alignItems: "center" }, children: [
|
|
1176
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { className: "qt-bg-card qt-text-secondary surfaces-demo-fill-primary hover:qt-text-on-primary", style: { padding: "0.25rem 0.625rem", borderRadius: "0.375rem", fontSize: "0.8125rem", fontWeight: 600, border: "1px solid var(--color-border)", cursor: "pointer" }, children: "hover:qt-text-on-primary" }),
|
|
1177
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { className: "qt-bg-card qt-text-secondary surfaces-demo-fill-success hover:qt-text-on-success", style: { padding: "0.25rem 0.625rem", borderRadius: "0.375rem", fontSize: "0.8125rem", fontWeight: 600, border: "1px solid var(--color-border)", cursor: "pointer" }, children: "hover:qt-text-on-success" }),
|
|
1178
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { className: "qt-bg-card qt-text-secondary surfaces-demo-fill-destructive hover:qt-text-on-destructive", style: { padding: "0.25rem 0.625rem", borderRadius: "0.375rem", fontSize: "0.8125rem", fontWeight: 600, border: "1px solid var(--color-border)", cursor: "pointer" }, children: "hover:qt-text-on-destructive" })
|
|
1179
|
+
] })
|
|
1180
|
+
] }),
|
|
1129
1181
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("section", { style: { marginBottom: "2rem" }, children: [
|
|
1130
1182
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("h3", { style: sectionHeading2, children: [
|
|
1131
1183
|
"Hover-highlight rows \u2014 ",
|
package/dist/stories/index.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quilltap/theme-storybook",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.62",
|
|
4
4
|
"description": "Storybook preset and stories for developing Quilltap theme plugins",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"license": "MIT",
|
|
66
66
|
"repository": {
|
|
67
67
|
"type": "git",
|
|
68
|
-
"url": "https://github.com/foundry-9/quilltap-server.git",
|
|
68
|
+
"url": "git+https://github.com/foundry-9/quilltap-server.git",
|
|
69
69
|
"directory": "packages/theme-storybook"
|
|
70
70
|
},
|
|
71
71
|
"homepage": "https://github.com/foundry-9/quilltap-server/tree/main/packages/theme-storybook#readme",
|
|
@@ -160,6 +160,12 @@
|
|
|
160
160
|
--qt-status-danger-fg: var(--color-destructive-foreground);
|
|
161
161
|
--qt-status-danger-border: var(--color-destructive);
|
|
162
162
|
|
|
163
|
+
/* Badge palette tokens - referenced by the provider badges */
|
|
164
|
+
--qt-badge-primary-bg: var(--color-primary);
|
|
165
|
+
--qt-badge-primary-fg: var(--color-primary-foreground);
|
|
166
|
+
--qt-badge-secondary-bg: var(--color-secondary);
|
|
167
|
+
--qt-badge-secondary-fg: var(--color-secondary-foreground);
|
|
168
|
+
|
|
163
169
|
/* Alert tokens - semi-transparent backgrounds with readable text */
|
|
164
170
|
--qt-alert-success-bg: hsl(142 76% 36% / 0.1);
|
|
165
171
|
--qt-alert-success-fg: hsl(142 76% 30%);
|
|
@@ -919,6 +925,80 @@
|
|
|
919
925
|
border: 1px solid var(--color-border);
|
|
920
926
|
}
|
|
921
927
|
|
|
928
|
+
/* ==========================================================================
|
|
929
|
+
PROVIDER BADGES
|
|
930
|
+
========================================================================== */
|
|
931
|
+
|
|
932
|
+
/**
|
|
933
|
+
* Shared geometry for the provider badges (embedding-profile provider chips).
|
|
934
|
+
* These do NOT build on .qt-badge in the app — they carry their own box, so
|
|
935
|
+
* the rule below is self-contained (and, mirroring the app, sets no
|
|
936
|
+
* line-height).
|
|
937
|
+
*/
|
|
938
|
+
.qt-badge-provider-openai,
|
|
939
|
+
.qt-badge-provider-ollama,
|
|
940
|
+
.qt-badge-provider-openrouter,
|
|
941
|
+
.qt-badge-provider-nanogpt,
|
|
942
|
+
.qt-badge-provider-builtin {
|
|
943
|
+
display: inline-flex;
|
|
944
|
+
align-items: center;
|
|
945
|
+
justify-content: center;
|
|
946
|
+
flex-shrink: 0;
|
|
947
|
+
padding: var(--qt-badge-padding-y) var(--qt-badge-padding-x);
|
|
948
|
+
border-radius: var(--qt-badge-radius);
|
|
949
|
+
font-size: var(--qt-badge-font-size);
|
|
950
|
+
font-weight: var(--qt-badge-font-weight);
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
/**
|
|
954
|
+
* OpenAI provider badge (green/success semantic)
|
|
955
|
+
*/
|
|
956
|
+
.qt-badge-provider-openai {
|
|
957
|
+
background: var(--qt-status-success-bg);
|
|
958
|
+
color: var(--qt-status-success-fg);
|
|
959
|
+
border: 1px solid var(--qt-status-success-border);
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
/**
|
|
963
|
+
* Ollama provider badge (secondary/muted)
|
|
964
|
+
* Mirrors the app, quirk included: --qt-badge-secondary-border has no default
|
|
965
|
+
* definition, so the border only renders in themes that define it.
|
|
966
|
+
*/
|
|
967
|
+
.qt-badge-provider-ollama {
|
|
968
|
+
background: var(--qt-badge-secondary-bg);
|
|
969
|
+
color: var(--qt-badge-secondary-fg);
|
|
970
|
+
border: 1px solid var(--qt-badge-secondary-border);
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
/**
|
|
974
|
+
* OpenRouter provider badge (warning/orange semantic)
|
|
975
|
+
*/
|
|
976
|
+
.qt-badge-provider-openrouter {
|
|
977
|
+
background: var(--qt-status-warning-bg);
|
|
978
|
+
color: var(--qt-status-warning-fg);
|
|
979
|
+
border: 1px solid var(--qt-status-warning-border);
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
/**
|
|
983
|
+
* NanoGPT provider badge (primary/accent semantic)
|
|
984
|
+
* Same border quirk as the ollama badge: --qt-badge-primary-border has no
|
|
985
|
+
* default definition.
|
|
986
|
+
*/
|
|
987
|
+
.qt-badge-provider-nanogpt {
|
|
988
|
+
background: var(--qt-badge-primary-bg);
|
|
989
|
+
color: var(--qt-badge-primary-fg);
|
|
990
|
+
border: 1px solid var(--qt-badge-primary-border);
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
/**
|
|
994
|
+
* Built-in provider badge (info/blue semantic)
|
|
995
|
+
*/
|
|
996
|
+
.qt-badge-provider-builtin {
|
|
997
|
+
background: var(--qt-status-info-bg);
|
|
998
|
+
color: var(--qt-status-info-fg);
|
|
999
|
+
border: 1px solid var(--qt-status-info-border);
|
|
1000
|
+
}
|
|
1001
|
+
|
|
922
1002
|
/* ==========================================================================
|
|
923
1003
|
WARDROBE SLOT BADGES
|
|
924
1004
|
========================================================================== */
|
|
@@ -2274,10 +2354,32 @@
|
|
|
2274
2354
|
background-color: var(--color-muted-foreground);
|
|
2275
2355
|
}
|
|
2276
2356
|
|
|
2357
|
+
/* Foregrounds intended for use ON a filled surface — the paired counterparts of
|
|
2358
|
+
the accent/primary/success/destructive fills. Each maps to the token a theme
|
|
2359
|
+
defines for text sitting on that fill, so a badge or a solid button keeps its
|
|
2360
|
+
contrast on every theme instead of inheriting whatever colour the surrounding
|
|
2361
|
+
page happens to be using.
|
|
2362
|
+
|
|
2363
|
+
<span class="qt-bg-accent qt-text-on-accent">…</span>
|
|
2364
|
+
<button class="qt-bg-destructive qt-text-on-destructive">…</button>
|
|
2365
|
+
|
|
2366
|
+
Mind the naming: these are `-on-<fill>`, never `-<fill>-foreground`. */
|
|
2277
2367
|
.qt-text-on-accent {
|
|
2278
2368
|
color: var(--color-accent-foreground);
|
|
2279
2369
|
}
|
|
2280
2370
|
|
|
2371
|
+
.qt-text-on-primary {
|
|
2372
|
+
color: var(--color-primary-foreground);
|
|
2373
|
+
}
|
|
2374
|
+
|
|
2375
|
+
.qt-text-on-success {
|
|
2376
|
+
color: var(--color-success-foreground);
|
|
2377
|
+
}
|
|
2378
|
+
|
|
2379
|
+
.qt-text-on-destructive {
|
|
2380
|
+
color: var(--color-destructive-foreground);
|
|
2381
|
+
}
|
|
2382
|
+
|
|
2281
2383
|
/* Hoverable accent surface — list rows, menu items, and option cards that
|
|
2282
2384
|
should highlight on hover. On hover it paints the accent background AND
|
|
2283
2385
|
forces the accent foreground onto the row and every descendant, so the whole
|
|
@@ -2469,6 +2571,26 @@
|
|
|
2469
2571
|
background-color: color-mix(in srgb, var(--color-primary) 10%, transparent);
|
|
2470
2572
|
}
|
|
2471
2573
|
|
|
2574
|
+
/* Hover foregrounds for filled surfaces — the hover partners of the
|
|
2575
|
+
qt-text-on-* family, for controls that sit quiet at rest and take a filled
|
|
2576
|
+
background on hover (`qt-text-secondary hover:qt-bg-success
|
|
2577
|
+
hover:qt-text-on-success`). */
|
|
2578
|
+
.hover\:qt-text-on-accent:hover {
|
|
2579
|
+
color: var(--color-accent-foreground);
|
|
2580
|
+
}
|
|
2581
|
+
|
|
2582
|
+
.hover\:qt-text-on-primary:hover {
|
|
2583
|
+
color: var(--color-primary-foreground);
|
|
2584
|
+
}
|
|
2585
|
+
|
|
2586
|
+
.hover\:qt-text-on-success:hover {
|
|
2587
|
+
color: var(--color-success-foreground);
|
|
2588
|
+
}
|
|
2589
|
+
|
|
2590
|
+
.hover\:qt-text-on-destructive:hover {
|
|
2591
|
+
color: var(--color-destructive-foreground);
|
|
2592
|
+
}
|
|
2593
|
+
|
|
2472
2594
|
/* ==========================================================================
|
|
2473
2595
|
OVERLAY UTILITIES
|
|
2474
2596
|
For image modals, lightboxes, and overlay UI elements.
|
|
@@ -27,6 +27,14 @@ const note: React.CSSProperties = {
|
|
|
27
27
|
export const Surfaces: React.FC = () => {
|
|
28
28
|
return (
|
|
29
29
|
<div style={{ padding: '1.5rem' }}>
|
|
30
|
+
{/* Story-local: the app pairs the hover foregrounds with Tailwind's
|
|
31
|
+
hover:bg-* fills, which don't exist here. Demo fills only — these are
|
|
32
|
+
not qt-* utilities and must not be copied into an app or a theme. */}
|
|
33
|
+
<style>{`
|
|
34
|
+
.surfaces-demo-fill-primary:hover { background-color: var(--color-primary); }
|
|
35
|
+
.surfaces-demo-fill-success:hover { background-color: var(--color-success); }
|
|
36
|
+
.surfaces-demo-fill-destructive:hover { background-color: var(--color-destructive); }
|
|
37
|
+
`}</style>
|
|
30
38
|
<h2 style={{ fontSize: '1.5rem', fontWeight: 700, marginBottom: '0.5rem' }}>Surfaces</h2>
|
|
31
39
|
<p style={{ ...note, maxWidth: '44rem' }}>
|
|
32
40
|
How accent-coloured surfaces stay legible no matter how bold a theme makes
|
|
@@ -57,6 +65,50 @@ export const Surfaces: React.FC = () => {
|
|
|
57
65
|
</div>
|
|
58
66
|
</section>
|
|
59
67
|
|
|
68
|
+
{/* Foregrounds on filled surfaces */}
|
|
69
|
+
<section style={{ marginBottom: '2rem' }}>
|
|
70
|
+
<h3 style={sectionHeading}>Foregrounds on filled surfaces — the <code>qt-text-on-*</code> family</h3>
|
|
71
|
+
<p style={note}>
|
|
72
|
+
The same contract, extended to every filled surface the app paints:{' '}
|
|
73
|
+
<code>qt-text-on-accent</code>, <code>qt-text-on-primary</code>,{' '}
|
|
74
|
+
<code>qt-text-on-success</code>, and <code>qt-text-on-destructive</code>, each
|
|
75
|
+
mapping to the theme's matching <code>*Foreground</code> token. Note the
|
|
76
|
+
naming — <code>-on-<em>fill</em></code>, never <code>-<em>fill</em>-foreground</code>,
|
|
77
|
+
which is the Tailwind spelling and is not a <code>qt-</code> class at all.
|
|
78
|
+
</p>
|
|
79
|
+
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '0.75rem', alignItems: 'center' }}>
|
|
80
|
+
<span className="qt-bg-accent qt-text-on-accent" style={{ padding: '0.25rem 0.625rem', borderRadius: '0.375rem', fontSize: '0.8125rem', fontWeight: 600 }}>
|
|
81
|
+
on accent
|
|
82
|
+
</span>
|
|
83
|
+
<span className="qt-bg-primary qt-text-on-primary" style={{ padding: '0.25rem 0.625rem', borderRadius: '0.375rem', fontSize: '0.8125rem', fontWeight: 600 }}>
|
|
84
|
+
on primary
|
|
85
|
+
</span>
|
|
86
|
+
<span className="qt-bg-success qt-text-on-success" style={{ padding: '0.25rem 0.625rem', borderRadius: '0.375rem', fontSize: '0.8125rem', fontWeight: 600 }}>
|
|
87
|
+
on success
|
|
88
|
+
</span>
|
|
89
|
+
<span className="qt-bg-destructive qt-text-on-destructive" style={{ padding: '0.25rem 0.625rem', borderRadius: '0.375rem', fontSize: '0.8125rem', fontWeight: 600 }}>
|
|
90
|
+
on destructive
|
|
91
|
+
</span>
|
|
92
|
+
</div>
|
|
93
|
+
<p style={{ ...note, marginTop: '1rem' }}>
|
|
94
|
+
Each has a hover partner for controls that stay quiet at rest and take the fill
|
|
95
|
+
on hover. Tailwind generates no variants for these classes, so the hover forms
|
|
96
|
+
are written out by hand — reach for one that was never written and it is simply
|
|
97
|
+
inert. Hover the buttons below.
|
|
98
|
+
</p>
|
|
99
|
+
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '0.75rem', alignItems: 'center' }}>
|
|
100
|
+
<button className="qt-bg-card qt-text-secondary surfaces-demo-fill-primary hover:qt-text-on-primary" style={{ padding: '0.25rem 0.625rem', borderRadius: '0.375rem', fontSize: '0.8125rem', fontWeight: 600, border: '1px solid var(--color-border)', cursor: 'pointer' }}>
|
|
101
|
+
hover:qt-text-on-primary
|
|
102
|
+
</button>
|
|
103
|
+
<button className="qt-bg-card qt-text-secondary surfaces-demo-fill-success hover:qt-text-on-success" style={{ padding: '0.25rem 0.625rem', borderRadius: '0.375rem', fontSize: '0.8125rem', fontWeight: 600, border: '1px solid var(--color-border)', cursor: 'pointer' }}>
|
|
104
|
+
hover:qt-text-on-success
|
|
105
|
+
</button>
|
|
106
|
+
<button className="qt-bg-card qt-text-secondary surfaces-demo-fill-destructive hover:qt-text-on-destructive" style={{ padding: '0.25rem 0.625rem', borderRadius: '0.375rem', fontSize: '0.8125rem', fontWeight: 600, border: '1px solid var(--color-border)', cursor: 'pointer' }}>
|
|
107
|
+
hover:qt-text-on-destructive
|
|
108
|
+
</button>
|
|
109
|
+
</div>
|
|
110
|
+
</section>
|
|
111
|
+
|
|
60
112
|
{/* Hover-highlight rows */}
|
|
61
113
|
<section style={{ marginBottom: '2rem' }}>
|
|
62
114
|
<h3 style={sectionHeading}>Hover-highlight rows — <code>qt-hover-accent</code></h3>
|