@skewedaspect/sleekspace-ui 0.4.0 → 0.5.0
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/dist/components/Page/SkPage.vue.d.ts +9 -0
- package/dist/components/Page/types.d.ts +3 -0
- package/dist/sleekspace-ui.css +29 -6
- package/dist/sleekspace-ui.es.js +48 -36
- package/dist/sleekspace-ui.umd.js +48 -36
- package/dist/tokens.css +23 -0
- package/docs/guides/design-tokens/foundation-other.md +16 -3
- package/docs/guides/design-tokens/semantic-states.md +26 -11
- package/docs/guides/design-tokens/themes.md +13 -2
- package/docs/guides/getting-started.md +31 -30
- package/docs/guides/theming.md +262 -8
- package/package.json +3 -3
- package/src/components/Page/SkPage.vue +36 -2
- package/src/components/Page/types.ts +6 -0
- package/src/styles/_scrollbar.scss +2 -2
- package/src/styles/base/_global.scss +3 -3
- package/src/styles/components/_page.scss +2 -2
- package/src/styles/tokens/_foundation-colors.scss +4 -0
- package/src/styles/tokens/_foundation-transitions.scss +8 -0
- package/src/styles/tokens/_semantic-surfaces.scss +15 -0
- package/web-types.json +11 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SkThemeName } from '../Theme/types';
|
|
1
2
|
import { SkPageSidebarPosition } from './types';
|
|
2
3
|
export interface SkPageComponentProps {
|
|
3
4
|
/**
|
|
@@ -27,6 +28,13 @@ export interface SkPageComponentProps {
|
|
|
27
28
|
* Only applies when the sidebar slot is provided.
|
|
28
29
|
*/
|
|
29
30
|
sidebarWidth?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Optional theme name. When provided, SkPage acts as a theme provider — setting
|
|
33
|
+
* `data-scheme` on the root element and providing theme context for descendant
|
|
34
|
+
* components (including portal components like dropdowns and modals).
|
|
35
|
+
* When omitted, SkPage has no theme behavior.
|
|
36
|
+
*/
|
|
37
|
+
theme?: SkThemeName;
|
|
30
38
|
}
|
|
31
39
|
declare function __VLS_template(): {
|
|
32
40
|
attrs: Partial<{}>;
|
|
@@ -41,6 +49,7 @@ declare function __VLS_template(): {
|
|
|
41
49
|
};
|
|
42
50
|
type __VLS_TemplateResult = ReturnType<typeof __VLS_template>;
|
|
43
51
|
declare const __VLS_component: import('vue').DefineComponent<SkPageComponentProps, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<SkPageComponentProps> & Readonly<{}>, {
|
|
52
|
+
theme: SkThemeName;
|
|
44
53
|
sidebarPosition: SkPageSidebarPosition;
|
|
45
54
|
fixedHeader: boolean;
|
|
46
55
|
fixedFooter: boolean;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SkThemeName } from '../Theme/types';
|
|
1
2
|
/** Sidebar position */
|
|
2
3
|
export type SkPageSidebarPosition = 'left' | 'right';
|
|
3
4
|
/** Page props interface */
|
|
@@ -10,4 +11,6 @@ export interface SkPageProps {
|
|
|
10
11
|
fixedFooter?: boolean;
|
|
11
12
|
/** Custom sidebar width */
|
|
12
13
|
sidebarWidth?: string;
|
|
14
|
+
/** Optional theme name — when provided, SkPage acts as a theme provider */
|
|
15
|
+
theme?: SkThemeName;
|
|
13
16
|
}
|
package/dist/sleekspace-ui.css
CHANGED
|
@@ -158,6 +158,9 @@
|
|
|
158
158
|
--sk-opacity-medium: 0.40;
|
|
159
159
|
--sk-opacity-strong: 0.60;
|
|
160
160
|
--sk-opacity-opaque: 1;
|
|
161
|
+
/* Semantic opacity aliases */
|
|
162
|
+
--sk-opacity-disabled: 0.5;
|
|
163
|
+
--sk-opacity-loading: 0.6;
|
|
161
164
|
/* ===================================================================
|
|
162
165
|
* Color Mixing Percentages
|
|
163
166
|
* Tokenized mixing amounts for color-mix() function
|
|
@@ -351,6 +354,12 @@
|
|
|
351
354
|
--sk-transition-easing-ease-in: ease-in;
|
|
352
355
|
--sk-transition-easing-ease-out: ease-out;
|
|
353
356
|
--sk-transition-easing-ease-in-out: ease-in-out;
|
|
357
|
+
/* ===================================================================
|
|
358
|
+
* Default Aliases
|
|
359
|
+
* Generic names that resolve to the most common values
|
|
360
|
+
* =================================================================== */
|
|
361
|
+
--sk-transition-duration-base: var(--sk-transition-duration-normal);
|
|
362
|
+
--sk-transition-easing: var(--sk-transition-easing-ease-out);
|
|
354
363
|
/* ===================================================================
|
|
355
364
|
* Common Transition Combinations
|
|
356
365
|
* Convenience tokens for frequently used transitions
|
|
@@ -652,6 +661,10 @@
|
|
|
652
661
|
*
|
|
653
662
|
* Background and text colors for surfaces and general use.
|
|
654
663
|
* These provide a consistent color system independent of component kinds.
|
|
664
|
+
*
|
|
665
|
+
* Defaults are defined on :root as fallbacks. Themes can override any of these
|
|
666
|
+
* via [data-scheme] selectors. The [data-scheme] rule also applies background
|
|
667
|
+
* and text color so that any themed element gets the correct surface treatment.
|
|
655
668
|
*/
|
|
656
669
|
:root {
|
|
657
670
|
/* ===================================================================
|
|
@@ -677,6 +690,16 @@
|
|
|
677
690
|
--sk-border-subtle: var(--sk-color-gray-80); /* Subtle borders/dividers */
|
|
678
691
|
}
|
|
679
692
|
|
|
693
|
+
/**
|
|
694
|
+
* Apply text color to any themed element so descendants inherit the correct
|
|
695
|
+
* color without needing to set it themselves. Background is intentionally NOT
|
|
696
|
+
* set here — page-level containers like SkPage handle their own background
|
|
697
|
+
* via the surface tokens.
|
|
698
|
+
*/
|
|
699
|
+
[data-scheme] {
|
|
700
|
+
color: var(--sk-text-primary);
|
|
701
|
+
}
|
|
702
|
+
|
|
680
703
|
/**
|
|
681
704
|
* Semantic Tokens - Interactive
|
|
682
705
|
*
|
|
@@ -1215,7 +1238,7 @@
|
|
|
1215
1238
|
body {
|
|
1216
1239
|
margin: 0;
|
|
1217
1240
|
min-height: 100svh;
|
|
1218
|
-
color: var(--sk-
|
|
1241
|
+
color: var(--sk-text-primary);
|
|
1219
1242
|
}
|
|
1220
1243
|
img,
|
|
1221
1244
|
svg,
|
|
@@ -1228,8 +1251,8 @@
|
|
|
1228
1251
|
font: inherit;
|
|
1229
1252
|
}
|
|
1230
1253
|
:focus-visible {
|
|
1231
|
-
outline: var(--sk-focus-
|
|
1232
|
-
outline-offset: var(--sk-focus-
|
|
1254
|
+
outline: var(--sk-focus-ring-width) solid currentColor;
|
|
1255
|
+
outline-offset: var(--sk-focus-ring-offset);
|
|
1233
1256
|
}
|
|
1234
1257
|
h1,
|
|
1235
1258
|
h2,
|
|
@@ -1390,7 +1413,7 @@
|
|
|
1390
1413
|
min-height: var(--sk-scrollbar-thumb-min-size);
|
|
1391
1414
|
min-width: var(--sk-scrollbar-thumb-min-size);
|
|
1392
1415
|
/* Smooth transitions for interactive states */
|
|
1393
|
-
transition: background-color var(--sk-transition-duration-fast) var(--sk-transition-easing-
|
|
1416
|
+
transition: background-color var(--sk-transition-duration-fast) var(--sk-transition-easing-ease-out), border-color var(--sk-transition-duration-fast) var(--sk-transition-easing-ease-out);
|
|
1394
1417
|
}
|
|
1395
1418
|
/* Hover State */
|
|
1396
1419
|
*::-webkit-scrollbar-thumb:hover {
|
|
@@ -6252,8 +6275,8 @@
|
|
|
6252
6275
|
display: flex;
|
|
6253
6276
|
flex-direction: column;
|
|
6254
6277
|
min-height: 100vh;
|
|
6255
|
-
background: var(--sk-
|
|
6256
|
-
color: var(--sk-
|
|
6278
|
+
background: var(--sk-surface-base);
|
|
6279
|
+
color: var(--sk-text-primary);
|
|
6257
6280
|
}
|
|
6258
6281
|
.sk-page .sk-page-header {
|
|
6259
6282
|
flex-shrink: 0;
|
package/dist/sleekspace-ui.es.js
CHANGED
|
@@ -15237,7 +15237,7 @@ const _hoisted_5$6 = {
|
|
|
15237
15237
|
stroke: "currentColor",
|
|
15238
15238
|
"stroke-width": "2"
|
|
15239
15239
|
};
|
|
15240
|
-
const _hoisted_6$
|
|
15240
|
+
const _hoisted_6$4 = { class: "sk-alert-content" };
|
|
15241
15241
|
const _sfc_main$P = /* @__PURE__ */ defineComponent({
|
|
15242
15242
|
__name: "SkAlert",
|
|
15243
15243
|
props: {
|
|
@@ -15335,7 +15335,7 @@ const _sfc_main$P = /* @__PURE__ */ defineComponent({
|
|
|
15335
15335
|
])])) : createCommentVNode("", true)
|
|
15336
15336
|
])
|
|
15337
15337
|
])) : createCommentVNode("", true),
|
|
15338
|
-
createElementVNode("div", _hoisted_6$
|
|
15338
|
+
createElementVNode("div", _hoisted_6$4, [
|
|
15339
15339
|
renderSlot(_ctx.$slots, "default")
|
|
15340
15340
|
])
|
|
15341
15341
|
], 6);
|
|
@@ -17008,17 +17008,38 @@ const _sfc_main$s = /* @__PURE__ */ defineComponent({
|
|
|
17008
17008
|
}
|
|
17009
17009
|
});
|
|
17010
17010
|
const SkNumberInput = /* @__PURE__ */ _export_sfc(_sfc_main$s, [["__scopeId", "data-v-b589687f"]]);
|
|
17011
|
-
const
|
|
17011
|
+
const ThemeSymbol = Symbol("SkTheme");
|
|
17012
|
+
function provideTheme(initialTheme = "greyscale") {
|
|
17013
|
+
const currentTheme = ref(initialTheme);
|
|
17014
|
+
const setTheme = (theme) => {
|
|
17015
|
+
currentTheme.value = theme;
|
|
17016
|
+
};
|
|
17017
|
+
const context2 = {
|
|
17018
|
+
currentTheme,
|
|
17019
|
+
setTheme
|
|
17020
|
+
};
|
|
17021
|
+
provide(ThemeSymbol, context2);
|
|
17022
|
+
return context2;
|
|
17023
|
+
}
|
|
17024
|
+
function useTheme() {
|
|
17025
|
+
const context2 = inject(ThemeSymbol);
|
|
17026
|
+
if (!context2) {
|
|
17027
|
+
throw new Error("useTheme must be called within an SkTheme component");
|
|
17028
|
+
}
|
|
17029
|
+
return context2;
|
|
17030
|
+
}
|
|
17031
|
+
const _hoisted_1$e = ["data-scheme"];
|
|
17032
|
+
const _hoisted_2$8 = {
|
|
17012
17033
|
key: 0,
|
|
17013
17034
|
class: "sk-page-header"
|
|
17014
17035
|
};
|
|
17015
|
-
const
|
|
17016
|
-
const
|
|
17036
|
+
const _hoisted_3$6 = { class: "sk-page-main" };
|
|
17037
|
+
const _hoisted_4$5 = {
|
|
17017
17038
|
key: 0,
|
|
17018
17039
|
class: "sk-page-sidebar"
|
|
17019
17040
|
};
|
|
17020
|
-
const
|
|
17021
|
-
const
|
|
17041
|
+
const _hoisted_5$3 = { class: "sk-page-content" };
|
|
17042
|
+
const _hoisted_6$3 = {
|
|
17022
17043
|
key: 1,
|
|
17023
17044
|
class: "sk-page-footer"
|
|
17024
17045
|
};
|
|
@@ -17028,7 +17049,8 @@ const _sfc_main$r = /* @__PURE__ */ defineComponent({
|
|
|
17028
17049
|
sidebarPosition: { default: "left" },
|
|
17029
17050
|
fixedHeader: { type: Boolean, default: false },
|
|
17030
17051
|
fixedFooter: { type: Boolean, default: false },
|
|
17031
|
-
sidebarWidth: { default: void 0 }
|
|
17052
|
+
sidebarWidth: { default: void 0 },
|
|
17053
|
+
theme: { default: void 0 }
|
|
17032
17054
|
},
|
|
17033
17055
|
setup(__props) {
|
|
17034
17056
|
const props = __props;
|
|
@@ -17046,30 +17068,40 @@ const _sfc_main$r = /* @__PURE__ */ defineComponent({
|
|
|
17046
17068
|
"--sk-page-sidebar-width": props.sidebarWidth
|
|
17047
17069
|
};
|
|
17048
17070
|
});
|
|
17071
|
+
if (props.theme) {
|
|
17072
|
+
const { currentTheme, setTheme } = provideTheme(props.theme);
|
|
17073
|
+
provide("sk-theme", currentTheme);
|
|
17074
|
+
watch(() => props.theme, (newTheme) => {
|
|
17075
|
+
if (newTheme) {
|
|
17076
|
+
setTheme(newTheme);
|
|
17077
|
+
}
|
|
17078
|
+
});
|
|
17079
|
+
}
|
|
17049
17080
|
return (_ctx, _cache) => {
|
|
17050
17081
|
return openBlock(), createElementBlock("div", {
|
|
17051
17082
|
class: normalizeClass(classes.value),
|
|
17052
|
-
style: normalizeStyle(customStyles.value)
|
|
17083
|
+
style: normalizeStyle(customStyles.value),
|
|
17084
|
+
"data-scheme": __props.theme
|
|
17053
17085
|
}, [
|
|
17054
|
-
_ctx.$slots.header ? (openBlock(), createElementBlock("header",
|
|
17086
|
+
_ctx.$slots.header ? (openBlock(), createElementBlock("header", _hoisted_2$8, [
|
|
17055
17087
|
renderSlot(_ctx.$slots, "header", {}, void 0, true)
|
|
17056
17088
|
])) : createCommentVNode("", true),
|
|
17057
|
-
createElementVNode("div",
|
|
17058
|
-
_ctx.$slots.sidebar ? (openBlock(), createElementBlock("aside",
|
|
17089
|
+
createElementVNode("div", _hoisted_3$6, [
|
|
17090
|
+
_ctx.$slots.sidebar ? (openBlock(), createElementBlock("aside", _hoisted_4$5, [
|
|
17059
17091
|
renderSlot(_ctx.$slots, "sidebar", {}, void 0, true)
|
|
17060
17092
|
])) : createCommentVNode("", true),
|
|
17061
|
-
createElementVNode("main",
|
|
17093
|
+
createElementVNode("main", _hoisted_5$3, [
|
|
17062
17094
|
renderSlot(_ctx.$slots, "default", {}, void 0, true)
|
|
17063
17095
|
])
|
|
17064
17096
|
]),
|
|
17065
|
-
_ctx.$slots.footer ? (openBlock(), createElementBlock("footer",
|
|
17097
|
+
_ctx.$slots.footer ? (openBlock(), createElementBlock("footer", _hoisted_6$3, [
|
|
17066
17098
|
renderSlot(_ctx.$slots, "footer", {}, void 0, true)
|
|
17067
17099
|
])) : createCommentVNode("", true)
|
|
17068
|
-
],
|
|
17100
|
+
], 14, _hoisted_1$e);
|
|
17069
17101
|
};
|
|
17070
17102
|
}
|
|
17071
17103
|
});
|
|
17072
|
-
const SkPage = /* @__PURE__ */ _export_sfc(_sfc_main$r, [["__scopeId", "data-v-
|
|
17104
|
+
const SkPage = /* @__PURE__ */ _export_sfc(_sfc_main$r, [["__scopeId", "data-v-ad672949"]]);
|
|
17073
17105
|
const _hoisted_1$d = ["disabled", "aria-label", "aria-current"];
|
|
17074
17106
|
const _hoisted_2$7 = { key: 0 };
|
|
17075
17107
|
const _hoisted_3$5 = { key: 1 };
|
|
@@ -18877,26 +18909,6 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
|
|
|
18877
18909
|
};
|
|
18878
18910
|
}
|
|
18879
18911
|
});
|
|
18880
|
-
const ThemeSymbol = Symbol("SkTheme");
|
|
18881
|
-
function provideTheme(initialTheme = "greyscale") {
|
|
18882
|
-
const currentTheme = ref(initialTheme);
|
|
18883
|
-
const setTheme = (theme) => {
|
|
18884
|
-
currentTheme.value = theme;
|
|
18885
|
-
};
|
|
18886
|
-
const context2 = {
|
|
18887
|
-
currentTheme,
|
|
18888
|
-
setTheme
|
|
18889
|
-
};
|
|
18890
|
-
provide(ThemeSymbol, context2);
|
|
18891
|
-
return context2;
|
|
18892
|
-
}
|
|
18893
|
-
function useTheme() {
|
|
18894
|
-
const context2 = inject(ThemeSymbol);
|
|
18895
|
-
if (!context2) {
|
|
18896
|
-
throw new Error("useTheme must be called within an SkTheme component");
|
|
18897
|
-
}
|
|
18898
|
-
return context2;
|
|
18899
|
-
}
|
|
18900
18912
|
const _hoisted_1 = ["data-scheme"];
|
|
18901
18913
|
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
18902
18914
|
__name: "SkTheme",
|
|
@@ -15256,7 +15256,7 @@ Defaulting to \`null\`.`);
|
|
|
15256
15256
|
stroke: "currentColor",
|
|
15257
15257
|
"stroke-width": "2"
|
|
15258
15258
|
};
|
|
15259
|
-
const _hoisted_6$
|
|
15259
|
+
const _hoisted_6$4 = { class: "sk-alert-content" };
|
|
15260
15260
|
const _sfc_main$P = /* @__PURE__ */ vue.defineComponent({
|
|
15261
15261
|
__name: "SkAlert",
|
|
15262
15262
|
props: {
|
|
@@ -15354,7 +15354,7 @@ Defaulting to \`null\`.`);
|
|
|
15354
15354
|
])])) : vue.createCommentVNode("", true)
|
|
15355
15355
|
])
|
|
15356
15356
|
])) : vue.createCommentVNode("", true),
|
|
15357
|
-
vue.createElementVNode("div", _hoisted_6$
|
|
15357
|
+
vue.createElementVNode("div", _hoisted_6$4, [
|
|
15358
15358
|
vue.renderSlot(_ctx.$slots, "default")
|
|
15359
15359
|
])
|
|
15360
15360
|
], 6);
|
|
@@ -17027,17 +17027,38 @@ Defaulting to \`null\`.`);
|
|
|
17027
17027
|
}
|
|
17028
17028
|
});
|
|
17029
17029
|
const SkNumberInput = /* @__PURE__ */ _export_sfc(_sfc_main$s, [["__scopeId", "data-v-b589687f"]]);
|
|
17030
|
-
const
|
|
17030
|
+
const ThemeSymbol = Symbol("SkTheme");
|
|
17031
|
+
function provideTheme(initialTheme = "greyscale") {
|
|
17032
|
+
const currentTheme = vue.ref(initialTheme);
|
|
17033
|
+
const setTheme = (theme) => {
|
|
17034
|
+
currentTheme.value = theme;
|
|
17035
|
+
};
|
|
17036
|
+
const context2 = {
|
|
17037
|
+
currentTheme,
|
|
17038
|
+
setTheme
|
|
17039
|
+
};
|
|
17040
|
+
vue.provide(ThemeSymbol, context2);
|
|
17041
|
+
return context2;
|
|
17042
|
+
}
|
|
17043
|
+
function useTheme() {
|
|
17044
|
+
const context2 = vue.inject(ThemeSymbol);
|
|
17045
|
+
if (!context2) {
|
|
17046
|
+
throw new Error("useTheme must be called within an SkTheme component");
|
|
17047
|
+
}
|
|
17048
|
+
return context2;
|
|
17049
|
+
}
|
|
17050
|
+
const _hoisted_1$e = ["data-scheme"];
|
|
17051
|
+
const _hoisted_2$8 = {
|
|
17031
17052
|
key: 0,
|
|
17032
17053
|
class: "sk-page-header"
|
|
17033
17054
|
};
|
|
17034
|
-
const
|
|
17035
|
-
const
|
|
17055
|
+
const _hoisted_3$6 = { class: "sk-page-main" };
|
|
17056
|
+
const _hoisted_4$5 = {
|
|
17036
17057
|
key: 0,
|
|
17037
17058
|
class: "sk-page-sidebar"
|
|
17038
17059
|
};
|
|
17039
|
-
const
|
|
17040
|
-
const
|
|
17060
|
+
const _hoisted_5$3 = { class: "sk-page-content" };
|
|
17061
|
+
const _hoisted_6$3 = {
|
|
17041
17062
|
key: 1,
|
|
17042
17063
|
class: "sk-page-footer"
|
|
17043
17064
|
};
|
|
@@ -17047,7 +17068,8 @@ Defaulting to \`null\`.`);
|
|
|
17047
17068
|
sidebarPosition: { default: "left" },
|
|
17048
17069
|
fixedHeader: { type: Boolean, default: false },
|
|
17049
17070
|
fixedFooter: { type: Boolean, default: false },
|
|
17050
|
-
sidebarWidth: { default: void 0 }
|
|
17071
|
+
sidebarWidth: { default: void 0 },
|
|
17072
|
+
theme: { default: void 0 }
|
|
17051
17073
|
},
|
|
17052
17074
|
setup(__props) {
|
|
17053
17075
|
const props = __props;
|
|
@@ -17065,30 +17087,40 @@ Defaulting to \`null\`.`);
|
|
|
17065
17087
|
"--sk-page-sidebar-width": props.sidebarWidth
|
|
17066
17088
|
};
|
|
17067
17089
|
});
|
|
17090
|
+
if (props.theme) {
|
|
17091
|
+
const { currentTheme, setTheme } = provideTheme(props.theme);
|
|
17092
|
+
vue.provide("sk-theme", currentTheme);
|
|
17093
|
+
vue.watch(() => props.theme, (newTheme) => {
|
|
17094
|
+
if (newTheme) {
|
|
17095
|
+
setTheme(newTheme);
|
|
17096
|
+
}
|
|
17097
|
+
});
|
|
17098
|
+
}
|
|
17068
17099
|
return (_ctx, _cache) => {
|
|
17069
17100
|
return vue.openBlock(), vue.createElementBlock("div", {
|
|
17070
17101
|
class: vue.normalizeClass(classes.value),
|
|
17071
|
-
style: vue.normalizeStyle(customStyles.value)
|
|
17102
|
+
style: vue.normalizeStyle(customStyles.value),
|
|
17103
|
+
"data-scheme": __props.theme
|
|
17072
17104
|
}, [
|
|
17073
|
-
_ctx.$slots.header ? (vue.openBlock(), vue.createElementBlock("header",
|
|
17105
|
+
_ctx.$slots.header ? (vue.openBlock(), vue.createElementBlock("header", _hoisted_2$8, [
|
|
17074
17106
|
vue.renderSlot(_ctx.$slots, "header", {}, void 0, true)
|
|
17075
17107
|
])) : vue.createCommentVNode("", true),
|
|
17076
|
-
vue.createElementVNode("div",
|
|
17077
|
-
_ctx.$slots.sidebar ? (vue.openBlock(), vue.createElementBlock("aside",
|
|
17108
|
+
vue.createElementVNode("div", _hoisted_3$6, [
|
|
17109
|
+
_ctx.$slots.sidebar ? (vue.openBlock(), vue.createElementBlock("aside", _hoisted_4$5, [
|
|
17078
17110
|
vue.renderSlot(_ctx.$slots, "sidebar", {}, void 0, true)
|
|
17079
17111
|
])) : vue.createCommentVNode("", true),
|
|
17080
|
-
vue.createElementVNode("main",
|
|
17112
|
+
vue.createElementVNode("main", _hoisted_5$3, [
|
|
17081
17113
|
vue.renderSlot(_ctx.$slots, "default", {}, void 0, true)
|
|
17082
17114
|
])
|
|
17083
17115
|
]),
|
|
17084
|
-
_ctx.$slots.footer ? (vue.openBlock(), vue.createElementBlock("footer",
|
|
17116
|
+
_ctx.$slots.footer ? (vue.openBlock(), vue.createElementBlock("footer", _hoisted_6$3, [
|
|
17085
17117
|
vue.renderSlot(_ctx.$slots, "footer", {}, void 0, true)
|
|
17086
17118
|
])) : vue.createCommentVNode("", true)
|
|
17087
|
-
],
|
|
17119
|
+
], 14, _hoisted_1$e);
|
|
17088
17120
|
};
|
|
17089
17121
|
}
|
|
17090
17122
|
});
|
|
17091
|
-
const SkPage = /* @__PURE__ */ _export_sfc(_sfc_main$r, [["__scopeId", "data-v-
|
|
17123
|
+
const SkPage = /* @__PURE__ */ _export_sfc(_sfc_main$r, [["__scopeId", "data-v-ad672949"]]);
|
|
17092
17124
|
const _hoisted_1$d = ["disabled", "aria-label", "aria-current"];
|
|
17093
17125
|
const _hoisted_2$7 = { key: 0 };
|
|
17094
17126
|
const _hoisted_3$5 = { key: 1 };
|
|
@@ -18896,26 +18928,6 @@ Defaulting to \`null\`.`);
|
|
|
18896
18928
|
};
|
|
18897
18929
|
}
|
|
18898
18930
|
});
|
|
18899
|
-
const ThemeSymbol = Symbol("SkTheme");
|
|
18900
|
-
function provideTheme(initialTheme = "greyscale") {
|
|
18901
|
-
const currentTheme = vue.ref(initialTheme);
|
|
18902
|
-
const setTheme = (theme) => {
|
|
18903
|
-
currentTheme.value = theme;
|
|
18904
|
-
};
|
|
18905
|
-
const context2 = {
|
|
18906
|
-
currentTheme,
|
|
18907
|
-
setTheme
|
|
18908
|
-
};
|
|
18909
|
-
vue.provide(ThemeSymbol, context2);
|
|
18910
|
-
return context2;
|
|
18911
|
-
}
|
|
18912
|
-
function useTheme() {
|
|
18913
|
-
const context2 = vue.inject(ThemeSymbol);
|
|
18914
|
-
if (!context2) {
|
|
18915
|
-
throw new Error("useTheme must be called within an SkTheme component");
|
|
18916
|
-
}
|
|
18917
|
-
return context2;
|
|
18918
|
-
}
|
|
18919
18931
|
const _hoisted_1 = ["data-scheme"];
|
|
18920
18932
|
const _sfc_main = /* @__PURE__ */ vue.defineComponent({
|
|
18921
18933
|
__name: "SkTheme",
|
package/dist/tokens.css
CHANGED
|
@@ -158,6 +158,9 @@
|
|
|
158
158
|
--sk-opacity-medium: 0.40;
|
|
159
159
|
--sk-opacity-strong: 0.60;
|
|
160
160
|
--sk-opacity-opaque: 1;
|
|
161
|
+
/* Semantic opacity aliases */
|
|
162
|
+
--sk-opacity-disabled: 0.5;
|
|
163
|
+
--sk-opacity-loading: 0.6;
|
|
161
164
|
/* ===================================================================
|
|
162
165
|
* Color Mixing Percentages
|
|
163
166
|
* Tokenized mixing amounts for color-mix() function
|
|
@@ -351,6 +354,12 @@
|
|
|
351
354
|
--sk-transition-easing-ease-in: ease-in;
|
|
352
355
|
--sk-transition-easing-ease-out: ease-out;
|
|
353
356
|
--sk-transition-easing-ease-in-out: ease-in-out;
|
|
357
|
+
/* ===================================================================
|
|
358
|
+
* Default Aliases
|
|
359
|
+
* Generic names that resolve to the most common values
|
|
360
|
+
* =================================================================== */
|
|
361
|
+
--sk-transition-duration-base: var(--sk-transition-duration-normal);
|
|
362
|
+
--sk-transition-easing: var(--sk-transition-easing-ease-out);
|
|
354
363
|
/* ===================================================================
|
|
355
364
|
* Common Transition Combinations
|
|
356
365
|
* Convenience tokens for frequently used transitions
|
|
@@ -652,6 +661,10 @@
|
|
|
652
661
|
*
|
|
653
662
|
* Background and text colors for surfaces and general use.
|
|
654
663
|
* These provide a consistent color system independent of component kinds.
|
|
664
|
+
*
|
|
665
|
+
* Defaults are defined on :root as fallbacks. Themes can override any of these
|
|
666
|
+
* via [data-scheme] selectors. The [data-scheme] rule also applies background
|
|
667
|
+
* and text color so that any themed element gets the correct surface treatment.
|
|
655
668
|
*/
|
|
656
669
|
:root {
|
|
657
670
|
/* ===================================================================
|
|
@@ -677,6 +690,16 @@
|
|
|
677
690
|
--sk-border-subtle: var(--sk-color-gray-80); /* Subtle borders/dividers */
|
|
678
691
|
}
|
|
679
692
|
|
|
693
|
+
/**
|
|
694
|
+
* Apply text color to any themed element so descendants inherit the correct
|
|
695
|
+
* color without needing to set it themselves. Background is intentionally NOT
|
|
696
|
+
* set here — page-level containers like SkPage handle their own background
|
|
697
|
+
* via the surface tokens.
|
|
698
|
+
*/
|
|
699
|
+
[data-scheme] {
|
|
700
|
+
color: var(--sk-text-primary);
|
|
701
|
+
}
|
|
702
|
+
|
|
680
703
|
/**
|
|
681
704
|
* Semantic Tokens - Interactive
|
|
682
705
|
*
|
|
@@ -33,9 +33,22 @@ Beyond colors, foundation tokens cover spacing, borders, typography, transitions
|
|
|
33
33
|
--sk-font-size-lg: 1.125rem
|
|
34
34
|
--sk-font-size-xl: 1.25rem
|
|
35
35
|
|
|
36
|
-
/*
|
|
36
|
+
/* Transition Durations */
|
|
37
37
|
--sk-transition-duration-instant: 0ms
|
|
38
38
|
--sk-transition-duration-fast: 150ms
|
|
39
|
-
--sk-transition-duration-normal:
|
|
40
|
-
--sk-transition-duration-slow:
|
|
39
|
+
--sk-transition-duration-normal: 250ms
|
|
40
|
+
--sk-transition-duration-slow: 350ms
|
|
41
|
+
--sk-transition-duration-slower: 500ms
|
|
42
|
+
|
|
43
|
+
/* Transition Easing */
|
|
44
|
+
--sk-transition-easing-linear: linear
|
|
45
|
+
--sk-transition-easing-ease: ease
|
|
46
|
+
--sk-transition-easing-ease-in: ease-in
|
|
47
|
+
--sk-transition-easing-ease-out: ease-out
|
|
48
|
+
--sk-transition-easing-ease-in-out: ease-in-out
|
|
49
|
+
|
|
50
|
+
/* Common Transition Combinations */
|
|
51
|
+
--sk-transition-fast: all 150ms ease-out
|
|
52
|
+
--sk-transition-normal: all 250ms ease-out
|
|
53
|
+
--sk-transition-slow: all 350ms ease-out
|
|
41
54
|
```
|
|
@@ -24,19 +24,32 @@ Hover and active states are automatically calculated using CSS `color-mix()`:
|
|
|
24
24
|
|
|
25
25
|
### Surface & Text Semantics
|
|
26
26
|
|
|
27
|
-
Background and text colors for layouts and content, separate from interactive component colors.
|
|
27
|
+
Background and text colors for layouts and content, separate from interactive component colors. Any element with a `data-scheme` attribute (set by `SkTheme` or `SkPage`'s `theme` prop) automatically inherits `color: var(--sk-text-primary)`. Page-level containers like `SkPage` set their own `background: var(--sk-surface-base)`.
|
|
28
28
|
|
|
29
29
|
```css
|
|
30
30
|
/* Surface Colors */
|
|
31
|
-
--sk-surface-base:
|
|
32
|
-
--sk-surface-raised:
|
|
33
|
-
--sk-surface-overlay: var(--sk-color-gray-
|
|
31
|
+
--sk-surface-base: var(--sk-color-gray-90) /* Main background */
|
|
32
|
+
--sk-surface-raised: var(--sk-color-gray-95) /* Elevated surfaces (cards, panels) */
|
|
33
|
+
--sk-surface-overlay: var(--sk-color-gray-80) /* Overlays (modals, dropdowns) */
|
|
34
34
|
|
|
35
35
|
/* Text Colors */
|
|
36
|
-
--sk-text-primary:
|
|
37
|
-
--sk-text-secondary: var(--sk-color-gray-
|
|
38
|
-
--sk-text-tertiary:
|
|
39
|
-
--sk-text-disabled:
|
|
36
|
+
--sk-text-primary: oklch(1 0 0) /* Primary body text (white) */
|
|
37
|
+
--sk-text-secondary: var(--sk-color-gray-30) /* Secondary/muted text */
|
|
38
|
+
--sk-text-tertiary: var(--sk-color-gray-50) /* Tertiary/placeholder text */
|
|
39
|
+
--sk-text-disabled: var(--sk-color-gray-60) /* Disabled text */
|
|
40
|
+
|
|
41
|
+
/* Border Colors */
|
|
42
|
+
--sk-border-normal: var(--sk-color-gray-70) /* Standard borders */
|
|
43
|
+
--sk-border-subtle: var(--sk-color-gray-80) /* Subtle borders/dividers */
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Custom themes can override any of these surface tokens to change the overall look:
|
|
47
|
+
|
|
48
|
+
```css
|
|
49
|
+
[data-scheme='my-theme'] {
|
|
50
|
+
--sk-surface-base: var(--sk-color-purple-90);
|
|
51
|
+
--sk-text-primary: oklch(0.95 0.02 300);
|
|
52
|
+
}
|
|
40
53
|
```
|
|
41
54
|
|
|
42
55
|
### Interactive State Semantics
|
|
@@ -45,11 +58,13 @@ Unified focus and selection states across all interactive components.
|
|
|
45
58
|
|
|
46
59
|
```css
|
|
47
60
|
/* Focus Ring */
|
|
48
|
-
--sk-focus-ring-color:
|
|
49
|
-
--sk-focus-ring-width:
|
|
61
|
+
--sk-focus-ring-color: var(--sk-primary-base)
|
|
62
|
+
--sk-focus-ring-width: var(--sk-border-width-normal)
|
|
50
63
|
--sk-focus-ring-offset: 2px
|
|
64
|
+
--sk-focus-ring-style: var(--sk-border-style-solid)
|
|
65
|
+
--sk-focus-ring: var(--sk-focus-ring-width) var(--sk-focus-ring-style) var(--sk-focus-ring-color)
|
|
51
66
|
|
|
52
67
|
/* Selection */
|
|
53
68
|
--sk-selection-background: var(--sk-primary-base)
|
|
54
|
-
--sk-selection-text:
|
|
69
|
+
--sk-selection-text: var(--sk-primary-text)
|
|
55
70
|
```
|
|
@@ -4,7 +4,7 @@ section: themes
|
|
|
4
4
|
|
|
5
5
|
## Themes
|
|
6
6
|
|
|
7
|
-
Themes map foundation colors to semantic kinds. Each theme is defined as a CSS attribute selector that overrides semantic tokens.
|
|
7
|
+
Themes map foundation colors to semantic kinds. Each theme is defined as a CSS attribute selector that overrides semantic tokens. `SkPage` automatically applies the theme's surface background; all themed elements inherit the correct text color.
|
|
8
8
|
|
|
9
9
|
### Available Themes
|
|
10
10
|
|
|
@@ -24,15 +24,26 @@ Themes are defined in `src/styles/themes/`. Each theme file exports a `[data-sch
|
|
|
24
24
|
--sk-primary-base: var(--sk-color-mint-50);
|
|
25
25
|
--sk-accent-base: var(--sk-color-orange-50);
|
|
26
26
|
/* ... define all 7 semantic kinds */
|
|
27
|
+
|
|
28
|
+
/* Optional: override surface tokens */
|
|
29
|
+
--sk-surface-base: var(--sk-color-purple-90);
|
|
27
30
|
}
|
|
28
31
|
```
|
|
29
32
|
|
|
30
33
|
### Using Themes
|
|
31
34
|
|
|
32
|
-
|
|
35
|
+
Use `SkPage` with a `theme` prop (recommended) or wrap content in `SkTheme`:
|
|
33
36
|
|
|
34
37
|
```vue
|
|
38
|
+
<!-- Recommended: SkPage acts as theme provider -->
|
|
39
|
+
<SkPage theme="colorful">
|
|
40
|
+
<YourApp />
|
|
41
|
+
</SkPage>
|
|
42
|
+
|
|
43
|
+
<!-- Alternative: standalone theme wrapper -->
|
|
35
44
|
<SkTheme theme="greyscale">
|
|
36
45
|
<YourApp />
|
|
37
46
|
</SkTheme>
|
|
38
47
|
```
|
|
48
|
+
|
|
49
|
+
See the [Theming Guide](/docs/guides/theming) for creating custom themes.
|
|
@@ -10,7 +10,7 @@ SleekSpace UI is a Vue 3 component library with a cyberpunk aesthetic. It provid
|
|
|
10
10
|
|
|
11
11
|
### Minimal Example
|
|
12
12
|
|
|
13
|
-
The only requirement is
|
|
13
|
+
The only requirement is establishing a theme context. The simplest way is with `SkTheme`:
|
|
14
14
|
|
|
15
15
|
```vue
|
|
16
16
|
<template>
|
|
@@ -26,49 +26,50 @@ The only requirement is wrapping your app in `SkTheme`. Here is the simplest set
|
|
|
26
26
|
</template>
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
That's it. You can start using any SleekSpace component inside `SkTheme
|
|
29
|
+
That's it. You can start using any SleekSpace component inside the theme context. If you're using `SkPage`, you can skip `SkTheme` entirely — see the next section.
|
|
30
30
|
|
|
31
31
|
### Recommended Setup with SkPage
|
|
32
32
|
|
|
33
|
-
For most applications, you will want a proper page layout with a header, sidebar, and content area. `SkPage` provides this structure:
|
|
33
|
+
For most applications, you will want a proper page layout with a header, sidebar, and content area. `SkPage` provides this structure and can act as a theme provider directly via its `theme` prop — no `SkTheme` wrapper needed:
|
|
34
34
|
|
|
35
35
|
```vue
|
|
36
36
|
<template>
|
|
37
|
-
<
|
|
38
|
-
<
|
|
39
|
-
<
|
|
40
|
-
<
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
<
|
|
46
|
-
<
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
<
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
<
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
</SkPage>
|
|
63
|
-
</SkTheme>
|
|
37
|
+
<SkPage theme="colorful" fixed-header>
|
|
38
|
+
<template #header>
|
|
39
|
+
<SkNavBar kind="primary">
|
|
40
|
+
<template #brand>My App</template>
|
|
41
|
+
</SkNavBar>
|
|
42
|
+
</template>
|
|
43
|
+
|
|
44
|
+
<template #sidebar>
|
|
45
|
+
<SkSidebar>
|
|
46
|
+
<SkSidebarItem href="/">Home</SkSidebarItem>
|
|
47
|
+
<SkSidebarItem href="/settings">Settings</SkSidebarItem>
|
|
48
|
+
</SkSidebar>
|
|
49
|
+
</template>
|
|
50
|
+
|
|
51
|
+
<SkPanel kind="neutral">
|
|
52
|
+
<h2>Welcome to SleekSpace UI</h2>
|
|
53
|
+
<SkButton kind="accent" variant="solid">
|
|
54
|
+
Get Started
|
|
55
|
+
</SkButton>
|
|
56
|
+
</SkPanel>
|
|
57
|
+
|
|
58
|
+
<template #footer>
|
|
59
|
+
<p>Footer content goes here</p>
|
|
60
|
+
</template>
|
|
61
|
+
</SkPage>
|
|
64
62
|
</template>
|
|
65
63
|
```
|
|
66
64
|
|
|
65
|
+
> **Note:** When `theme` is provided, `SkPage` sets `data-scheme` on its root element and provides theme context to all descendants — including portal components like dropdowns and modals. If you omit the `theme` prop, `SkPage` behaves as a pure layout component and you'll need an `SkTheme` wrapper instead.
|
|
66
|
+
|
|
67
67
|
### Why Use SkPage?
|
|
68
68
|
|
|
69
69
|
`SkPage` is optional, but most applications will benefit from it:
|
|
70
70
|
|
|
71
71
|
- **Full page layout structure** -- Provides header, sidebar, content, and footer regions in a single component.
|
|
72
|
+
- **Built-in theme provider** -- Pass a `theme` prop to eliminate the `SkTheme` wrapper entirely.
|
|
72
73
|
- **Semantic HTML** -- Uses `<main>`, `<header>`, `<footer>`, and `<aside>` elements for better accessibility and SEO.
|
|
73
74
|
- **Fixed headers and footers** -- Keep navigation visible while the content area scrolls independently.
|
|
74
75
|
- **Flexible slots** -- All slots are optional. Use just a header, just a sidebar, or any combination. The layout adapts automatically.
|
package/docs/guides/theming.md
CHANGED
|
@@ -42,9 +42,29 @@ const { currentTheme, setTheme } = useTheme();
|
|
|
42
42
|
</template>
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
+
## SkPage as Theme Provider
|
|
46
|
+
|
|
47
|
+
If your app already uses `SkPage`, you can skip the `SkTheme` wrapper and pass a `theme` prop directly:
|
|
48
|
+
|
|
49
|
+
```vue
|
|
50
|
+
<template>
|
|
51
|
+
<SkPage theme="colorful" fixed-header>
|
|
52
|
+
<template #header>
|
|
53
|
+
<SkNavBar kind="primary">
|
|
54
|
+
<template #brand>My App</template>
|
|
55
|
+
</SkNavBar>
|
|
56
|
+
</template>
|
|
57
|
+
|
|
58
|
+
<SkPanel kind="accent">Fully themed — no SkTheme wrapper needed.</SkPanel>
|
|
59
|
+
</SkPage>
|
|
60
|
+
</template>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
This establishes the same theme context that `SkTheme` does (including portal component support). The `useTheme` composable works identically inside a themed `SkPage`.
|
|
64
|
+
|
|
45
65
|
## How It Works
|
|
46
66
|
|
|
47
|
-
SkTheme sets a `data-scheme` attribute on its wrapper element. CSS rules scoped to each scheme override semantic token values:
|
|
67
|
+
SkTheme (or SkPage with a `theme` prop) sets a `data-scheme` attribute on its wrapper element. This cascades the correct text color (`--sk-text-primary`) to all descendants. SkPage also sets the page background (`--sk-surface-base`). CSS rules scoped to each scheme override semantic token values:
|
|
48
68
|
|
|
49
69
|
```css
|
|
50
70
|
[data-scheme="greyscale"] {
|
|
@@ -60,30 +80,264 @@ All components reference these semantic tokens, so switching the scheme instantl
|
|
|
60
80
|
|
|
61
81
|
## Creating Custom Themes
|
|
62
82
|
|
|
63
|
-
|
|
83
|
+
Themes are pure CSS. You define a `[data-scheme="name"]` block with 35 custom properties (7 semantic kinds × 5 tokens each) and you're done. No library modifications, no build steps — just a stylesheet.
|
|
84
|
+
|
|
85
|
+
> See the [SkTheme component page](/components/theme) for live demos of custom themes compared side-by-side with the built-in ones.
|
|
86
|
+
|
|
87
|
+
### Token Structure
|
|
88
|
+
|
|
89
|
+
Each of the 7 semantic kinds requires 5 tokens:
|
|
90
|
+
|
|
91
|
+
| Token | Purpose |
|
|
92
|
+
|-------|---------|
|
|
93
|
+
| `--sk-{kind}-base` | Main background color |
|
|
94
|
+
| `--sk-{kind}-hover` | Hover state background |
|
|
95
|
+
| `--sk-{kind}-active` | Active/pressed state background |
|
|
96
|
+
| `--sk-{kind}-text` | Text color on the base background |
|
|
97
|
+
| `--sk-{kind}-text-contrast` | Alternative text for subtle/ghost variants |
|
|
98
|
+
|
|
99
|
+
The 7 kinds are: `neutral`, `primary`, `accent`, `success`, `warning`, `danger`, `info`.
|
|
100
|
+
|
|
101
|
+
### Surface Tokens (Optional)
|
|
102
|
+
|
|
103
|
+
Themes can also override the page surface tokens. These have sensible defaults (dark gray background, white text) so you only need to override them if your theme wants a different page feel:
|
|
104
|
+
|
|
105
|
+
| Token | Default | Purpose |
|
|
106
|
+
|-------|---------|---------|
|
|
107
|
+
| `--sk-surface-base` | `--sk-color-gray-90` | Page/app background |
|
|
108
|
+
| `--sk-surface-raised` | `--sk-color-gray-95` | Elevated surfaces (cards, panels) |
|
|
109
|
+
| `--sk-surface-overlay` | `--sk-color-gray-80` | Overlays (modals, dropdowns) |
|
|
110
|
+
| `--sk-text-primary` | white | Primary body text |
|
|
111
|
+
|
|
112
|
+
`SkPage` applies `--sk-surface-base` as its background automatically. If you use `SkTheme` without `SkPage`, set your body background to `var(--sk-surface-base)` for the dark page feel.
|
|
113
|
+
|
|
114
|
+
### Deriving Hover and Active States
|
|
115
|
+
|
|
116
|
+
You don't need to hand-pick hover/active colors. The `color-mix()` function lightens the base color automatically, which is how the built-in themes do it:
|
|
64
117
|
|
|
65
118
|
```css
|
|
119
|
+
--sk-primary-hover: color-mix(
|
|
120
|
+
in oklch,
|
|
121
|
+
var(--sk-primary-base),
|
|
122
|
+
var(--sk-color-gray-10) var(--sk-mix-amount-moderate) /* 15% lighter */
|
|
123
|
+
);
|
|
124
|
+
--sk-primary-active: color-mix(
|
|
125
|
+
in oklch,
|
|
126
|
+
var(--sk-primary-base),
|
|
127
|
+
var(--sk-color-gray-10) var(--sk-mix-amount-strong) /* 20% lighter */
|
|
128
|
+
);
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
This pattern references the `--sk-color-gray-10` foundation token (a light gray) and mixes it in at either 15% (`moderate`) or 20% (`strong`). You can also use hardcoded OKLCH values if you prefer full control.
|
|
132
|
+
|
|
133
|
+
### Complete Example: "Ocean" Theme
|
|
134
|
+
|
|
135
|
+
Here's a full theme definition using OKLCH values. This theme uses deep blues for neutral elements, teal for primary, coral for accent, and keeps the standard semantic colors for success/warning/danger/info:
|
|
136
|
+
|
|
137
|
+
```css
|
|
138
|
+
/* ocean-theme.css — import this after SleekSpace UI styles */
|
|
139
|
+
|
|
66
140
|
[data-scheme="ocean"] {
|
|
67
|
-
|
|
141
|
+
/* Neutral — deep slate blue */
|
|
142
|
+
--sk-neutral-base: oklch(0.35 0.04 250);
|
|
143
|
+
--sk-neutral-hover: color-mix(in oklch, var(--sk-neutral-base), var(--sk-color-gray-10) var(--sk-mix-amount-moderate));
|
|
144
|
+
--sk-neutral-active: color-mix(in oklch, var(--sk-neutral-base), var(--sk-color-gray-10) var(--sk-mix-amount-strong));
|
|
145
|
+
--sk-neutral-text: oklch(1 0 0);
|
|
146
|
+
--sk-neutral-text-contrast: oklch(0.15 0.02 250);
|
|
147
|
+
|
|
148
|
+
/* Primary — bright teal */
|
|
149
|
+
--sk-primary-base: oklch(0.72 0.15 195);
|
|
150
|
+
--sk-primary-hover: color-mix(in oklch, var(--sk-primary-base), var(--sk-color-gray-10) var(--sk-mix-amount-moderate));
|
|
151
|
+
--sk-primary-active: color-mix(in oklch, var(--sk-primary-base), var(--sk-color-gray-10) var(--sk-mix-amount-strong));
|
|
68
152
|
--sk-primary-text: oklch(1 0 0);
|
|
69
|
-
--sk-primary-
|
|
153
|
+
--sk-primary-text-contrast: oklch(0.15 0.02 195);
|
|
70
154
|
|
|
71
|
-
|
|
155
|
+
/* Accent — warm coral */
|
|
156
|
+
--sk-accent-base: oklch(0.68 0.18 25);
|
|
157
|
+
--sk-accent-hover: color-mix(in oklch, var(--sk-accent-base), var(--sk-color-gray-10) var(--sk-mix-amount-moderate));
|
|
158
|
+
--sk-accent-active: color-mix(in oklch, var(--sk-accent-base), var(--sk-color-gray-10) var(--sk-mix-amount-strong));
|
|
72
159
|
--sk-accent-text: oklch(1 0 0);
|
|
73
|
-
--sk-accent-
|
|
160
|
+
--sk-accent-text-contrast: oklch(0.15 0.02 25);
|
|
74
161
|
|
|
75
|
-
/*
|
|
162
|
+
/* Success — emerald green */
|
|
163
|
+
--sk-success-base: oklch(0.70 0.18 155);
|
|
164
|
+
--sk-success-hover: color-mix(in oklch, var(--sk-success-base), var(--sk-color-gray-10) var(--sk-mix-amount-moderate));
|
|
165
|
+
--sk-success-active: color-mix(in oklch, var(--sk-success-base), var(--sk-color-gray-10) var(--sk-mix-amount-strong));
|
|
166
|
+
--sk-success-text: oklch(1 0 0);
|
|
167
|
+
--sk-success-text-contrast: oklch(0.15 0.02 155);
|
|
168
|
+
|
|
169
|
+
/* Warning — amber */
|
|
170
|
+
--sk-warning-base: oklch(0.85 0.16 85);
|
|
171
|
+
--sk-warning-hover: color-mix(in oklch, var(--sk-warning-base), var(--sk-color-gray-10) var(--sk-mix-amount-moderate));
|
|
172
|
+
--sk-warning-active: color-mix(in oklch, var(--sk-warning-base), var(--sk-color-gray-10) var(--sk-mix-amount-strong));
|
|
173
|
+
--sk-warning-text: oklch(1 0 0);
|
|
174
|
+
--sk-warning-text-contrast: oklch(0.15 0.02 85);
|
|
175
|
+
|
|
176
|
+
/* Danger — crimson red */
|
|
177
|
+
--sk-danger-base: oklch(0.60 0.22 25);
|
|
178
|
+
--sk-danger-hover: color-mix(in oklch, var(--sk-danger-base), var(--sk-color-gray-10) var(--sk-mix-amount-moderate));
|
|
179
|
+
--sk-danger-active: color-mix(in oklch, var(--sk-danger-base), var(--sk-color-gray-10) var(--sk-mix-amount-strong));
|
|
180
|
+
--sk-danger-text: oklch(1 0 0);
|
|
181
|
+
--sk-danger-text-contrast: oklch(0.15 0.02 25);
|
|
182
|
+
|
|
183
|
+
/* Info — sky blue */
|
|
184
|
+
--sk-info-base: oklch(0.75 0.12 230);
|
|
185
|
+
--sk-info-hover: color-mix(in oklch, var(--sk-info-base), var(--sk-color-gray-10) var(--sk-mix-amount-moderate));
|
|
186
|
+
--sk-info-active: color-mix(in oklch, var(--sk-info-base), var(--sk-color-gray-10) var(--sk-mix-amount-strong));
|
|
187
|
+
--sk-info-text: oklch(1 0 0);
|
|
188
|
+
--sk-info-text-contrast: oklch(0.15 0.02 230);
|
|
76
189
|
}
|
|
77
190
|
```
|
|
78
191
|
|
|
79
|
-
|
|
192
|
+
### Complete Example: "Cyberpunk" Theme
|
|
193
|
+
|
|
194
|
+
Neon pink primary, electric cyan accent, deep violet neutrals, and screaming neon green for success. High chroma across the board.
|
|
195
|
+
|
|
196
|
+
```css
|
|
197
|
+
/* cyberpunk-theme.css */
|
|
198
|
+
|
|
199
|
+
[data-scheme="cyberpunk"] {
|
|
200
|
+
/* Neutral — deep violet */
|
|
201
|
+
--sk-neutral-base: oklch(0.25 0.08 300);
|
|
202
|
+
--sk-neutral-hover: color-mix(in oklch, var(--sk-neutral-base), var(--sk-color-gray-10) var(--sk-mix-amount-moderate));
|
|
203
|
+
--sk-neutral-active: color-mix(in oklch, var(--sk-neutral-base), var(--sk-color-gray-10) var(--sk-mix-amount-strong));
|
|
204
|
+
--sk-neutral-text: oklch(1 0 0);
|
|
205
|
+
--sk-neutral-text-contrast: oklch(0.12 0.04 300);
|
|
206
|
+
|
|
207
|
+
/* Primary — hot pink */
|
|
208
|
+
--sk-primary-base: oklch(0.65 0.27 355);
|
|
209
|
+
--sk-primary-hover: color-mix(in oklch, var(--sk-primary-base), var(--sk-color-gray-10) var(--sk-mix-amount-moderate));
|
|
210
|
+
--sk-primary-active: color-mix(in oklch, var(--sk-primary-base), var(--sk-color-gray-10) var(--sk-mix-amount-strong));
|
|
211
|
+
--sk-primary-text: oklch(1 0 0);
|
|
212
|
+
--sk-primary-text-contrast: oklch(0.12 0.04 355);
|
|
213
|
+
|
|
214
|
+
/* Accent — electric cyan */
|
|
215
|
+
--sk-accent-base: oklch(0.78 0.15 195);
|
|
216
|
+
--sk-accent-hover: color-mix(in oklch, var(--sk-accent-base), var(--sk-color-gray-10) var(--sk-mix-amount-moderate));
|
|
217
|
+
--sk-accent-active: color-mix(in oklch, var(--sk-accent-base), var(--sk-color-gray-10) var(--sk-mix-amount-strong));
|
|
218
|
+
--sk-accent-text: oklch(1 0 0);
|
|
219
|
+
--sk-accent-text-contrast: oklch(0.12 0.04 195);
|
|
220
|
+
|
|
221
|
+
/* Success — neon green */
|
|
222
|
+
--sk-success-base: oklch(0.82 0.25 145);
|
|
223
|
+
--sk-success-hover: color-mix(in oklch, var(--sk-success-base), var(--sk-color-gray-10) var(--sk-mix-amount-moderate));
|
|
224
|
+
--sk-success-active: color-mix(in oklch, var(--sk-success-base), var(--sk-color-gray-10) var(--sk-mix-amount-strong));
|
|
225
|
+
--sk-success-text: oklch(1 0 0);
|
|
226
|
+
--sk-success-text-contrast: oklch(0.12 0.04 145);
|
|
227
|
+
|
|
228
|
+
/* Warning — electric yellow */
|
|
229
|
+
--sk-warning-base: oklch(0.90 0.18 100);
|
|
230
|
+
--sk-warning-hover: color-mix(in oklch, var(--sk-warning-base), var(--sk-color-gray-10) var(--sk-mix-amount-moderate));
|
|
231
|
+
--sk-warning-active: color-mix(in oklch, var(--sk-warning-base), var(--sk-color-gray-10) var(--sk-mix-amount-strong));
|
|
232
|
+
--sk-warning-text: oklch(1 0 0);
|
|
233
|
+
--sk-warning-text-contrast: oklch(0.12 0.04 100);
|
|
234
|
+
|
|
235
|
+
/* Danger — hot red */
|
|
236
|
+
--sk-danger-base: oklch(0.62 0.25 30);
|
|
237
|
+
--sk-danger-hover: color-mix(in oklch, var(--sk-danger-base), var(--sk-color-gray-10) var(--sk-mix-amount-moderate));
|
|
238
|
+
--sk-danger-active: color-mix(in oklch, var(--sk-danger-base), var(--sk-color-gray-10) var(--sk-mix-amount-strong));
|
|
239
|
+
--sk-danger-text: oklch(1 0 0);
|
|
240
|
+
--sk-danger-text-contrast: oklch(0.12 0.04 30);
|
|
241
|
+
|
|
242
|
+
/* Info — neon purple */
|
|
243
|
+
--sk-info-base: oklch(0.60 0.25 305);
|
|
244
|
+
--sk-info-hover: color-mix(in oklch, var(--sk-info-base), var(--sk-color-gray-10) var(--sk-mix-amount-moderate));
|
|
245
|
+
--sk-info-active: color-mix(in oklch, var(--sk-info-base), var(--sk-color-gray-10) var(--sk-mix-amount-strong));
|
|
246
|
+
--sk-info-text: oklch(1 0 0);
|
|
247
|
+
--sk-info-text-contrast: oklch(0.12 0.04 305);
|
|
248
|
+
}
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### Using a Custom Theme
|
|
252
|
+
|
|
253
|
+
Apply it with `SkTheme` or `SkPage`:
|
|
80
254
|
|
|
81
255
|
```vue
|
|
256
|
+
<!-- With SkTheme -->
|
|
82
257
|
<SkTheme theme="ocean">
|
|
83
258
|
<YourContent />
|
|
84
259
|
</SkTheme>
|
|
260
|
+
|
|
261
|
+
<!-- Or directly on SkPage -->
|
|
262
|
+
<SkPage theme="ocean" fixed-header>
|
|
263
|
+
<template #header>...</template>
|
|
264
|
+
<YourContent />
|
|
265
|
+
</SkPage>
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
> **TypeScript note:** The `theme` prop is typed as `SkThemeName` which is `'greyscale' | 'colorful'`. For custom theme names, cast the value: `:theme="'ocean' as any"`. If you're building a library that adds themes, you can augment the type via module declaration.
|
|
269
|
+
|
|
270
|
+
### Using Foundation Colors
|
|
271
|
+
|
|
272
|
+
Instead of raw OKLCH values, you can reference the built-in foundation color palette. Each color family has 11 shades (05 through 95, where 50 is the most saturated):
|
|
273
|
+
|
|
274
|
+
```css
|
|
275
|
+
[data-scheme="mytheme"] {
|
|
276
|
+
/* Reference foundation palette variables */
|
|
277
|
+
--sk-primary-base: var(--sk-color-purple-50);
|
|
278
|
+
--sk-accent-base: var(--sk-color-pink-50);
|
|
279
|
+
--sk-neutral-base: var(--sk-color-gray-60);
|
|
280
|
+
|
|
281
|
+
/* hover/active states auto-derived the same way */
|
|
282
|
+
--sk-primary-hover: color-mix(in oklch, var(--sk-primary-base), var(--sk-color-gray-10) var(--sk-mix-amount-moderate));
|
|
283
|
+
/* ... */
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
Available foundation color families: `gray`, `blue`, `red`, `orange`, `yellow`, `green`, `mint`, `cyan`, `purple`, `pink`.
|
|
288
|
+
|
|
289
|
+
### Quick Reference: Minimal Theme
|
|
290
|
+
|
|
291
|
+
If you just want to remap which colors go where, copy this template and change the `-base` values. The `color-mix()` lines can be copied verbatim — they derive from the base automatically:
|
|
292
|
+
|
|
293
|
+
```css
|
|
294
|
+
[data-scheme="mytheme"] {
|
|
295
|
+
--sk-neutral-base: /* your color */;
|
|
296
|
+
--sk-neutral-hover: color-mix(in oklch, var(--sk-neutral-base), var(--sk-color-gray-10) var(--sk-mix-amount-moderate));
|
|
297
|
+
--sk-neutral-active: color-mix(in oklch, var(--sk-neutral-base), var(--sk-color-gray-10) var(--sk-mix-amount-strong));
|
|
298
|
+
--sk-neutral-text: oklch(1 0 0);
|
|
299
|
+
--sk-neutral-text-contrast: var(--sk-color-gray-95);
|
|
300
|
+
|
|
301
|
+
--sk-primary-base: /* your color */;
|
|
302
|
+
--sk-primary-hover: color-mix(in oklch, var(--sk-primary-base), var(--sk-color-gray-10) var(--sk-mix-amount-moderate));
|
|
303
|
+
--sk-primary-active: color-mix(in oklch, var(--sk-primary-base), var(--sk-color-gray-10) var(--sk-mix-amount-strong));
|
|
304
|
+
--sk-primary-text: oklch(1 0 0);
|
|
305
|
+
--sk-primary-text-contrast: var(--sk-color-gray-95);
|
|
306
|
+
|
|
307
|
+
--sk-accent-base: /* your color */;
|
|
308
|
+
--sk-accent-hover: color-mix(in oklch, var(--sk-accent-base), var(--sk-color-gray-10) var(--sk-mix-amount-moderate));
|
|
309
|
+
--sk-accent-active: color-mix(in oklch, var(--sk-accent-base), var(--sk-color-gray-10) var(--sk-mix-amount-strong));
|
|
310
|
+
--sk-accent-text: oklch(1 0 0);
|
|
311
|
+
--sk-accent-text-contrast: var(--sk-color-gray-95);
|
|
312
|
+
|
|
313
|
+
--sk-success-base: /* your color */;
|
|
314
|
+
--sk-success-hover: color-mix(in oklch, var(--sk-success-base), var(--sk-color-gray-10) var(--sk-mix-amount-moderate));
|
|
315
|
+
--sk-success-active: color-mix(in oklch, var(--sk-success-base), var(--sk-color-gray-10) var(--sk-mix-amount-strong));
|
|
316
|
+
--sk-success-text: oklch(1 0 0);
|
|
317
|
+
--sk-success-text-contrast: var(--sk-color-gray-95);
|
|
318
|
+
|
|
319
|
+
--sk-warning-base: /* your color */;
|
|
320
|
+
--sk-warning-hover: color-mix(in oklch, var(--sk-warning-base), var(--sk-color-gray-10) var(--sk-mix-amount-moderate));
|
|
321
|
+
--sk-warning-active: color-mix(in oklch, var(--sk-warning-base), var(--sk-color-gray-10) var(--sk-mix-amount-strong));
|
|
322
|
+
--sk-warning-text: oklch(1 0 0);
|
|
323
|
+
--sk-warning-text-contrast: var(--sk-color-gray-95);
|
|
324
|
+
|
|
325
|
+
--sk-danger-base: /* your color */;
|
|
326
|
+
--sk-danger-hover: color-mix(in oklch, var(--sk-danger-base), var(--sk-color-gray-10) var(--sk-mix-amount-moderate));
|
|
327
|
+
--sk-danger-active: color-mix(in oklch, var(--sk-danger-base), var(--sk-color-gray-10) var(--sk-mix-amount-strong));
|
|
328
|
+
--sk-danger-text: oklch(1 0 0);
|
|
329
|
+
--sk-danger-text-contrast: var(--sk-color-gray-95);
|
|
330
|
+
|
|
331
|
+
--sk-info-base: /* your color */;
|
|
332
|
+
--sk-info-hover: color-mix(in oklch, var(--sk-info-base), var(--sk-color-gray-10) var(--sk-mix-amount-moderate));
|
|
333
|
+
--sk-info-active: color-mix(in oklch, var(--sk-info-base), var(--sk-color-gray-10) var(--sk-mix-amount-strong));
|
|
334
|
+
--sk-info-text: oklch(1 0 0);
|
|
335
|
+
--sk-info-text-contrast: var(--sk-color-gray-95);
|
|
336
|
+
}
|
|
85
337
|
```
|
|
86
338
|
|
|
339
|
+
Only the 7 `-base` values need to change. Everything else is boilerplate that can be copied as-is.
|
|
340
|
+
|
|
87
341
|
## Semantic Kinds
|
|
88
342
|
|
|
89
343
|
All themed components accept a `kind` prop with these values:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skewedaspect/sleekspace-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "A Vue 3 component library with a cyberpunk aesthetic, featuring OKLCH colors, beveled corners, and a powerful design token system",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/sleekspace-ui.umd.js",
|
|
@@ -49,10 +49,10 @@
|
|
|
49
49
|
"license": "MIT",
|
|
50
50
|
"repository": {
|
|
51
51
|
"type": "git",
|
|
52
|
-
"url": "git+https://gitlab.com/
|
|
52
|
+
"url": "git+https://gitlab.com/skewed-aspect/sleekspace-ui.git",
|
|
53
53
|
"directory": "packages/sleekspace-ui"
|
|
54
54
|
},
|
|
55
|
-
"bugs": "https://gitlab.com/
|
|
55
|
+
"bugs": "https://gitlab.com/skewed-aspect/sleekspace-ui/-/issues",
|
|
56
56
|
"homepage": "https://sleekspace.skewedaspect.com",
|
|
57
57
|
"peerDependencies": {
|
|
58
58
|
"vue": "^3.3.0"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div :class="classes" :style="customStyles">
|
|
2
|
+
<div :class="classes" :style="customStyles" :data-scheme="theme">
|
|
3
3
|
<header v-if="$slots.header" class="sk-page-header">
|
|
4
4
|
<slot name="header" />
|
|
5
5
|
</header>
|
|
@@ -62,11 +62,15 @@
|
|
|
62
62
|
* width below the sidebar and content areas.
|
|
63
63
|
*/
|
|
64
64
|
|
|
65
|
-
import { computed } from 'vue';
|
|
65
|
+
import { computed, provide, watch } from 'vue';
|
|
66
66
|
|
|
67
67
|
// Types
|
|
68
|
+
import type { SkThemeName } from '../Theme/types';
|
|
68
69
|
import type { SkPageSidebarPosition } from './types';
|
|
69
70
|
|
|
71
|
+
// Composables
|
|
72
|
+
import { provideTheme } from '../Theme/useTheme';
|
|
73
|
+
|
|
70
74
|
//------------------------------------------------------------------------------------------------------------------
|
|
71
75
|
|
|
72
76
|
export interface SkPageComponentProps
|
|
@@ -101,6 +105,14 @@
|
|
|
101
105
|
* Only applies when the sidebar slot is provided.
|
|
102
106
|
*/
|
|
103
107
|
sidebarWidth ?: string;
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Optional theme name. When provided, SkPage acts as a theme provider — setting
|
|
111
|
+
* `data-scheme` on the root element and providing theme context for descendant
|
|
112
|
+
* components (including portal components like dropdowns and modals).
|
|
113
|
+
* When omitted, SkPage has no theme behavior.
|
|
114
|
+
*/
|
|
115
|
+
theme ?: SkThemeName;
|
|
104
116
|
}
|
|
105
117
|
|
|
106
118
|
//------------------------------------------------------------------------------------------------------------------
|
|
@@ -110,6 +122,7 @@
|
|
|
110
122
|
fixedHeader: false,
|
|
111
123
|
fixedFooter: false,
|
|
112
124
|
sidebarWidth: undefined,
|
|
125
|
+
theme: undefined,
|
|
113
126
|
});
|
|
114
127
|
|
|
115
128
|
//------------------------------------------------------------------------------------------------------------------
|
|
@@ -138,6 +151,27 @@
|
|
|
138
151
|
'--sk-page-sidebar-width': props.sidebarWidth,
|
|
139
152
|
};
|
|
140
153
|
});
|
|
154
|
+
|
|
155
|
+
//------------------------------------------------------------------------------------------------------------------
|
|
156
|
+
// Theme Provider
|
|
157
|
+
//------------------------------------------------------------------------------------------------------------------
|
|
158
|
+
|
|
159
|
+
if(props.theme)
|
|
160
|
+
{
|
|
161
|
+
const { currentTheme, setTheme } = provideTheme(props.theme);
|
|
162
|
+
|
|
163
|
+
// Provide theme for portal components (dropdown, modal, tooltip, etc.)
|
|
164
|
+
provide('sk-theme', currentTheme);
|
|
165
|
+
|
|
166
|
+
// Watch for external theme prop changes
|
|
167
|
+
watch(() => props.theme, (newTheme) =>
|
|
168
|
+
{
|
|
169
|
+
if(newTheme)
|
|
170
|
+
{
|
|
171
|
+
setTheme(newTheme);
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
}
|
|
141
175
|
</script>
|
|
142
176
|
|
|
143
177
|
<!--------------------------------------------------------------------------------------------------------------------->
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
// Page Types
|
|
3
3
|
//----------------------------------------------------------------------------------------------------------------------
|
|
4
4
|
|
|
5
|
+
import type { SkThemeName } from '../Theme/types';
|
|
6
|
+
|
|
7
|
+
//----------------------------------------------------------------------------------------------------------------------
|
|
8
|
+
|
|
5
9
|
/** Sidebar position */
|
|
6
10
|
export type SkPageSidebarPosition = 'left' | 'right';
|
|
7
11
|
|
|
@@ -16,6 +20,8 @@ export interface SkPageProps
|
|
|
16
20
|
fixedFooter ?: boolean;
|
|
17
21
|
/** Custom sidebar width */
|
|
18
22
|
sidebarWidth ?: string;
|
|
23
|
+
/** Optional theme name — when provided, SkPage acts as a theme provider */
|
|
24
|
+
theme ?: SkThemeName;
|
|
19
25
|
}
|
|
20
26
|
|
|
21
27
|
//----------------------------------------------------------------------------------------------------------------------
|
|
@@ -56,8 +56,8 @@
|
|
|
56
56
|
|
|
57
57
|
/* Smooth transitions for interactive states */
|
|
58
58
|
transition:
|
|
59
|
-
background-color var(--sk-transition-duration-fast) var(--sk-transition-easing-
|
|
60
|
-
border-color var(--sk-transition-duration-fast) var(--sk-transition-easing-
|
|
59
|
+
background-color var(--sk-transition-duration-fast) var(--sk-transition-easing-ease-out),
|
|
60
|
+
border-color var(--sk-transition-duration-fast) var(--sk-transition-easing-ease-out);
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
/* Hover State */
|
|
@@ -21,7 +21,7 @@ body
|
|
|
21
21
|
{
|
|
22
22
|
margin: 0;
|
|
23
23
|
min-height: 100svh;
|
|
24
|
-
color: var(--sk-
|
|
24
|
+
color: var(--sk-text-primary);
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
img,
|
|
@@ -40,8 +40,8 @@ canvas
|
|
|
40
40
|
|
|
41
41
|
:focus-visible
|
|
42
42
|
{
|
|
43
|
-
outline: var(--sk-focus-
|
|
44
|
-
outline-offset: var(--sk-focus-
|
|
43
|
+
outline: var(--sk-focus-ring-width) solid currentColor;
|
|
44
|
+
outline-offset: var(--sk-focus-ring-offset);
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
//----------------------------------------------------------------------------------------------------------------------
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
display: flex;
|
|
13
13
|
flex-direction: column;
|
|
14
14
|
min-height: 100vh;
|
|
15
|
-
background: var(--sk-
|
|
16
|
-
color: var(--sk-
|
|
15
|
+
background: var(--sk-surface-base);
|
|
16
|
+
color: var(--sk-text-primary);
|
|
17
17
|
|
|
18
18
|
//------------------------------------------------------------------------------------------------------------------
|
|
19
19
|
// Header
|
|
@@ -156,6 +156,10 @@
|
|
|
156
156
|
--sk-opacity-strong: 0.60;
|
|
157
157
|
--sk-opacity-opaque: 1;
|
|
158
158
|
|
|
159
|
+
/* Semantic opacity aliases */
|
|
160
|
+
--sk-opacity-disabled: 0.5;
|
|
161
|
+
--sk-opacity-loading: 0.6;
|
|
162
|
+
|
|
159
163
|
/* ===================================================================
|
|
160
164
|
* Color Mixing Percentages
|
|
161
165
|
* Tokenized mixing amounts for color-mix() function
|
|
@@ -26,6 +26,14 @@
|
|
|
26
26
|
--sk-transition-easing-ease-out: ease-out;
|
|
27
27
|
--sk-transition-easing-ease-in-out: ease-in-out;
|
|
28
28
|
|
|
29
|
+
/* ===================================================================
|
|
30
|
+
* Default Aliases
|
|
31
|
+
* Generic names that resolve to the most common values
|
|
32
|
+
* =================================================================== */
|
|
33
|
+
|
|
34
|
+
--sk-transition-duration-base: var(--sk-transition-duration-normal);
|
|
35
|
+
--sk-transition-easing: var(--sk-transition-easing-ease-out);
|
|
36
|
+
|
|
29
37
|
/* ===================================================================
|
|
30
38
|
* Common Transition Combinations
|
|
31
39
|
* Convenience tokens for frequently used transitions
|
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Background and text colors for surfaces and general use.
|
|
5
5
|
* These provide a consistent color system independent of component kinds.
|
|
6
|
+
*
|
|
7
|
+
* Defaults are defined on :root as fallbacks. Themes can override any of these
|
|
8
|
+
* via [data-scheme] selectors. The [data-scheme] rule also applies background
|
|
9
|
+
* and text color so that any themed element gets the correct surface treatment.
|
|
6
10
|
*/
|
|
7
11
|
|
|
8
12
|
:root
|
|
@@ -34,3 +38,14 @@
|
|
|
34
38
|
--sk-border-normal: var(--sk-color-gray-70); /* Standard borders */
|
|
35
39
|
--sk-border-subtle: var(--sk-color-gray-80); /* Subtle borders/dividers */
|
|
36
40
|
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Apply text color to any themed element so descendants inherit the correct
|
|
44
|
+
* color without needing to set it themselves. Background is intentionally NOT
|
|
45
|
+
* set here — page-level containers like SkPage handle their own background
|
|
46
|
+
* via the surface tokens.
|
|
47
|
+
*/
|
|
48
|
+
[data-scheme]
|
|
49
|
+
{
|
|
50
|
+
color: var(--sk-text-primary);
|
|
51
|
+
}
|
package/web-types.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"framework": "vue",
|
|
3
3
|
"name": "@skewedaspect/sleekspace-ui",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.5.0",
|
|
5
5
|
"contributions": {
|
|
6
6
|
"html": {
|
|
7
7
|
"description-markup": "markdown",
|
|
@@ -1589,6 +1589,16 @@
|
|
|
1589
1589
|
"type": "string"
|
|
1590
1590
|
},
|
|
1591
1591
|
"default": "undefined"
|
|
1592
|
+
},
|
|
1593
|
+
{
|
|
1594
|
+
"name": "theme",
|
|
1595
|
+
"required": false,
|
|
1596
|
+
"description": "Optional theme name. When provided, SkPage acts as a theme provider — setting\n`data-scheme` on the root element and providing theme context for descendant\ncomponents (including portal components like dropdowns and modals).\nWhen omitted, SkPage has no theme behavior.",
|
|
1597
|
+
"value": {
|
|
1598
|
+
"kind": "expression",
|
|
1599
|
+
"type": "SkThemeName"
|
|
1600
|
+
},
|
|
1601
|
+
"default": "undefined"
|
|
1592
1602
|
}
|
|
1593
1603
|
],
|
|
1594
1604
|
"slots": [
|