@kine-design/core 0.0.1-beta.11 → 0.0.1-beta.13
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/components/base/image/__tests__/useImage.test.ts +61 -0
- package/components/base/image/api.ts +2 -2
- package/components/base/image/index.ts +2 -2
- package/components/base/image/props.d.ts +15 -4
- package/components/base/image/useImage.ts +27 -16
- package/components/base/tooltip/api.ts +3 -2
- package/components/base/tooltip/index.ts +3 -2
- package/components/base/tooltip/props.d.ts +12 -6
- package/components/base/tooltip/useTooltip.ts +175 -56
- package/compositions/commandPalette/index.ts +11 -0
- package/compositions/commandPalette/types.ts +29 -0
- package/compositions/commandPalette/useCommandPalette.ts +135 -0
- package/compositions/contextMenu/index.ts +10 -0
- package/compositions/contextMenu/types.ts +21 -0
- package/compositions/contextMenu/useContextMenu.ts +101 -0
- package/compositions/editor/index.ts +18 -0
- package/compositions/editor/types.ts +147 -0
- package/compositions/editor/useEditor.ts +224 -0
- package/compositions/index.ts +15 -0
- package/compositions/overlay/index.ts +14 -0
- package/compositions/overlay/useOverlayStack.ts +146 -0
- package/compositions/peekView/index.ts +10 -0
- package/compositions/peekView/usePeekView.ts +99 -0
- package/compositions/theme/index.ts +17 -0
- package/compositions/theme/presets/compact.ts +117 -0
- package/compositions/theme/presets/dark.ts +113 -0
- package/compositions/theme/presets/index.ts +11 -0
- package/compositions/theme/presets/light.ts +113 -0
- package/compositions/theme/types.ts +46 -0
- package/compositions/theme/useTheme.ts +269 -0
- package/compositions/toast/index.ts +10 -0
- package/compositions/toast/useToast.ts +176 -0
- package/compositions/tooltip/index.ts +9 -0
- package/compositions/tooltip/useTooltip.ts +10 -0
- package/dist/components/base/image/index.d.ts +2 -2
- package/dist/components/base/image/useImage.d.ts +7 -0
- package/dist/components/base/tooltip/index.d.ts +1 -0
- package/dist/components/base/tooltip/useTooltip.d.ts +20 -17
- package/dist/compositions/commandPalette/index.d.ts +11 -0
- package/dist/compositions/commandPalette/types.d.ts +20 -0
- package/dist/compositions/commandPalette/useCommandPalette.d.ts +32 -0
- package/dist/compositions/contextMenu/index.d.ts +10 -0
- package/dist/compositions/contextMenu/types.d.ts +12 -0
- package/dist/compositions/contextMenu/useContextMenu.d.ts +52 -0
- package/dist/compositions/editor/index.d.ts +10 -0
- package/dist/compositions/editor/types.d.ts +132 -0
- package/dist/compositions/editor/useEditor.d.ts +13 -0
- package/dist/compositions/index.d.ts +15 -0
- package/dist/compositions/overlay/index.d.ts +10 -0
- package/dist/compositions/overlay/useOverlayStack.d.ts +188 -0
- package/dist/compositions/peekView/index.d.ts +10 -0
- package/dist/compositions/peekView/usePeekView.d.ts +16 -0
- package/dist/compositions/theme/index.d.ts +11 -0
- package/dist/compositions/theme/presets/compact.d.ts +6 -0
- package/dist/compositions/theme/presets/dark.d.ts +2 -0
- package/dist/compositions/theme/presets/index.d.ts +11 -0
- package/dist/compositions/theme/presets/light.d.ts +2 -0
- package/dist/compositions/theme/types.d.ts +41 -0
- package/dist/compositions/theme/useTheme.d.ts +167 -0
- package/dist/compositions/toast/index.d.ts +10 -0
- package/dist/compositions/toast/useToast.d.ts +71 -0
- package/dist/compositions/tooltip/index.d.ts +9 -0
- package/dist/compositions/tooltip/useTooltip.d.ts +10 -0
- package/dist/core.js +836 -56
- package/dist/index.d.ts +1 -0
- package/index.ts +2 -0
- package/package.json +13 -2
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @description overlay stack manager — unified z-index and ESC handling for all popups
|
|
3
|
+
* @author kine-design
|
|
4
|
+
* @date 2026/5/22 00:00
|
|
5
|
+
* @version v1.0.0
|
|
6
|
+
*
|
|
7
|
+
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
8
|
+
*/
|
|
9
|
+
import { defineStore } from 'pinia';
|
|
10
|
+
import { computed, ref, onMounted, onBeforeUnmount } from 'vue';
|
|
11
|
+
|
|
12
|
+
export type OverlayType = 'popover' | 'alert-dialog' | 'context-menu' | 'command-palette';
|
|
13
|
+
|
|
14
|
+
export interface OverlayItem {
|
|
15
|
+
id: string;
|
|
16
|
+
type: OverlayType;
|
|
17
|
+
close: () => void;
|
|
18
|
+
zIndex: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const Z_INDEX_BASE = 100;
|
|
22
|
+
|
|
23
|
+
let idCounter = 0;
|
|
24
|
+
const generateId = (type: OverlayType) => `overlay-${type}-${++idCounter}`;
|
|
25
|
+
|
|
26
|
+
export const useOverlayStackStore = defineStore('overlayStack', () => {
|
|
27
|
+
const overlayStack = ref<OverlayItem[]>([]);
|
|
28
|
+
|
|
29
|
+
const isEmpty = computed(() => overlayStack.value.length === 0);
|
|
30
|
+
const topItem = computed(() =>
|
|
31
|
+
overlayStack.value.length > 0
|
|
32
|
+
? overlayStack.value[overlayStack.value.length - 1]
|
|
33
|
+
: undefined,
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const push = (item: Omit<OverlayItem, 'zIndex'>) => {
|
|
37
|
+
const zIndex = overlayStack.value.length + Z_INDEX_BASE;
|
|
38
|
+
const entry: OverlayItem = { ...item, zIndex };
|
|
39
|
+
overlayStack.value.push(entry);
|
|
40
|
+
return entry;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const pop = () => {
|
|
44
|
+
const item = overlayStack.value.pop();
|
|
45
|
+
if (item) {
|
|
46
|
+
item.close();
|
|
47
|
+
}
|
|
48
|
+
return item;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const remove = (id: string) => {
|
|
52
|
+
const index = overlayStack.value.findIndex(item => item.id === id);
|
|
53
|
+
if (index !== -1) {
|
|
54
|
+
overlayStack.value.splice(index, 1);
|
|
55
|
+
recalculateZIndices();
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const recalculateZIndices = () => {
|
|
60
|
+
overlayStack.value.forEach((item, index) => {
|
|
61
|
+
item.zIndex = index + Z_INDEX_BASE;
|
|
62
|
+
});
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const handleEsc = (e: KeyboardEvent) => {
|
|
66
|
+
if (e.key === 'Escape' && !isEmpty.value) {
|
|
67
|
+
pop();
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
let listenerAttached = false;
|
|
72
|
+
|
|
73
|
+
const attachEscListener = () => {
|
|
74
|
+
if (!listenerAttached) {
|
|
75
|
+
document.addEventListener('keydown', handleEsc);
|
|
76
|
+
listenerAttached = true;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const detachEscListener = () => {
|
|
81
|
+
if (listenerAttached) {
|
|
82
|
+
document.removeEventListener('keydown', handleEsc);
|
|
83
|
+
listenerAttached = false;
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
overlayStack,
|
|
89
|
+
isEmpty,
|
|
90
|
+
topItem,
|
|
91
|
+
push,
|
|
92
|
+
pop,
|
|
93
|
+
remove,
|
|
94
|
+
attachEscListener,
|
|
95
|
+
detachEscListener,
|
|
96
|
+
};
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
export function useOverlayStack() {
|
|
100
|
+
const store = useOverlayStackStore();
|
|
101
|
+
|
|
102
|
+
onMounted(() => {
|
|
103
|
+
store.attachEscListener();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
onBeforeUnmount(() => {
|
|
107
|
+
store.detachEscListener();
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
return store;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function useOverlayItem(type: OverlayType) {
|
|
114
|
+
const store = useOverlayStackStore();
|
|
115
|
+
let itemId: string | undefined;
|
|
116
|
+
|
|
117
|
+
const register = (closeFn: () => void) => {
|
|
118
|
+
const id = generateId(type);
|
|
119
|
+
const entry = store.push({ id, type, close: closeFn });
|
|
120
|
+
itemId = entry.id;
|
|
121
|
+
return entry;
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const unregister = () => {
|
|
125
|
+
if (itemId) {
|
|
126
|
+
store.remove(itemId);
|
|
127
|
+
itemId = undefined;
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const currentZIndex = computed(() => {
|
|
132
|
+
if (!itemId) return undefined;
|
|
133
|
+
const item = store.overlayStack.find((i: OverlayItem) => i.id === itemId);
|
|
134
|
+
return item?.zIndex;
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
onBeforeUnmount(() => {
|
|
138
|
+
unregister();
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
register,
|
|
143
|
+
unregister,
|
|
144
|
+
currentZIndex,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @description peekView composables barrel export
|
|
3
|
+
* @author kine-design
|
|
4
|
+
* @date 2026/5/22
|
|
5
|
+
* @version v1.0.0
|
|
6
|
+
*
|
|
7
|
+
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
8
|
+
*/
|
|
9
|
+
export { usePeekView } from './usePeekView';
|
|
10
|
+
export type { PeekViewMode, UsePeekViewOptions } from './usePeekView';
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @description PeekView composable — state management for non-modal peek panels
|
|
3
|
+
* @author kine-design
|
|
4
|
+
* @date 2026/5/22
|
|
5
|
+
* @version v1.0.0
|
|
6
|
+
*
|
|
7
|
+
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
8
|
+
*/
|
|
9
|
+
import { ref, onMounted } from 'vue';
|
|
10
|
+
import { useOverlayStackStore } from '../overlay/useOverlayStack';
|
|
11
|
+
|
|
12
|
+
export type PeekViewMode = 'side' | 'modal' | 'full';
|
|
13
|
+
|
|
14
|
+
export interface UsePeekViewOptions {
|
|
15
|
+
/** Default mode when opening without explicit mode */
|
|
16
|
+
defaultMode?: PeekViewMode;
|
|
17
|
+
/** Enable URL query param sync (?peek=<id>) */
|
|
18
|
+
urlSync?: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function usePeekView(options: UsePeekViewOptions = {}) {
|
|
22
|
+
const { defaultMode = 'side', urlSync = false } = options;
|
|
23
|
+
|
|
24
|
+
const isOpen = ref(false);
|
|
25
|
+
const mode = ref<PeekViewMode>(defaultMode);
|
|
26
|
+
const peekId = ref<string | undefined>(undefined);
|
|
27
|
+
|
|
28
|
+
// URL sync helpers
|
|
29
|
+
const readPeekFromUrl = (): string | undefined => {
|
|
30
|
+
if (typeof window === 'undefined') return undefined;
|
|
31
|
+
const params = new URLSearchParams(window.location.search);
|
|
32
|
+
return params.get('peek') || undefined;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const writePeekToUrl = (id: string | undefined) => {
|
|
36
|
+
if (typeof window === 'undefined') return;
|
|
37
|
+
const url = new URL(window.location.href);
|
|
38
|
+
if (id) {
|
|
39
|
+
url.searchParams.set('peek', id);
|
|
40
|
+
} else {
|
|
41
|
+
url.searchParams.delete('peek');
|
|
42
|
+
}
|
|
43
|
+
window.history.replaceState(window.history.state, '', url.toString());
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const open = (id: string, openMode?: PeekViewMode) => {
|
|
47
|
+
peekId.value = id;
|
|
48
|
+
mode.value = openMode ?? defaultMode;
|
|
49
|
+
isOpen.value = true;
|
|
50
|
+
if (urlSync) {
|
|
51
|
+
writePeekToUrl(id);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const close = () => {
|
|
56
|
+
isOpen.value = false;
|
|
57
|
+
peekId.value = undefined;
|
|
58
|
+
if (urlSync) {
|
|
59
|
+
writePeekToUrl(undefined);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const setMode = (newMode: PeekViewMode) => {
|
|
64
|
+
mode.value = newMode;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// Outside click handler: close only if overlay stack is empty
|
|
68
|
+
const handleOutsideClick = (event: MouseEvent, panelEl: HTMLElement | null) => {
|
|
69
|
+
if (!isOpen.value || !panelEl) return;
|
|
70
|
+
|
|
71
|
+
const overlayStore = useOverlayStackStore();
|
|
72
|
+
if (!overlayStore.isEmpty) return;
|
|
73
|
+
|
|
74
|
+
const target = event.target as Node;
|
|
75
|
+
if (!panelEl.contains(target)) {
|
|
76
|
+
close();
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
// Initialize from URL on mount (if urlSync is enabled)
|
|
81
|
+
onMounted(() => {
|
|
82
|
+
if (urlSync) {
|
|
83
|
+
const urlPeekId = readPeekFromUrl();
|
|
84
|
+
if (urlPeekId) {
|
|
85
|
+
open(urlPeekId);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
isOpen,
|
|
92
|
+
mode,
|
|
93
|
+
peekId,
|
|
94
|
+
open,
|
|
95
|
+
close,
|
|
96
|
+
setMode,
|
|
97
|
+
handleOutsideClick,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @description theme composables barrel export
|
|
3
|
+
* @author kine-design
|
|
4
|
+
* @date 2026/5/22
|
|
5
|
+
* @version v1.0.0
|
|
6
|
+
*
|
|
7
|
+
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
8
|
+
*/
|
|
9
|
+
export { useThemeStore } from './useTheme';
|
|
10
|
+
export type {
|
|
11
|
+
ThemeDefinition,
|
|
12
|
+
ThemeTokens,
|
|
13
|
+
ThemeTokenCategory,
|
|
14
|
+
ThemeOverrides,
|
|
15
|
+
PersistedThemeState,
|
|
16
|
+
} from './types';
|
|
17
|
+
export { lightTheme, darkTheme, compactTheme } from './presets';
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @description compact theme preset — denser layout with scaled-down spacing/font/radius
|
|
3
|
+
* @author kine-design
|
|
4
|
+
* @date 2026/5/22
|
|
5
|
+
* @version v1.0.0
|
|
6
|
+
*
|
|
7
|
+
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
8
|
+
*/
|
|
9
|
+
import type { ThemeDefinition } from '../types';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Compact theme inherits light colors but scales spacing/radius/font down by ~0.75.
|
|
13
|
+
* Shadow and motion stay unchanged.
|
|
14
|
+
*/
|
|
15
|
+
export const compactTheme: ThemeDefinition = {
|
|
16
|
+
id: 'compact',
|
|
17
|
+
name: 'Compact',
|
|
18
|
+
description: 'Denser layout — smaller spacing, font sizes, and radius (0.75x scale)',
|
|
19
|
+
tokens: {
|
|
20
|
+
color: {
|
|
21
|
+
'bg-primary': '#f5f5f5',
|
|
22
|
+
'bg-secondary': '#ebebeb',
|
|
23
|
+
'bg-tertiary': '#e0e0e0',
|
|
24
|
+
'bg-hover': '#d4d4d4',
|
|
25
|
+
'bg-inset': '#dcdcdc',
|
|
26
|
+
'neutral-1': '#f0f0f0',
|
|
27
|
+
'neutral-2': '#e5e5e5',
|
|
28
|
+
'neutral-3': '#d4d4d4',
|
|
29
|
+
'neutral-4': '#c0c0c0',
|
|
30
|
+
'neutral-5': '#a0a0a0',
|
|
31
|
+
'neutral-6': '#787878',
|
|
32
|
+
'accent-light': '#e8f5ef',
|
|
33
|
+
'accent-default': '#1ab873',
|
|
34
|
+
'accent-hover': '#1ec87d',
|
|
35
|
+
'accent-active': '#158f5a',
|
|
36
|
+
'accent-alt': '#168f5a',
|
|
37
|
+
'semantic-success': '#1ab873',
|
|
38
|
+
'semantic-success-hover': '#1ec87d',
|
|
39
|
+
'semantic-success-light': '#e8f5ef',
|
|
40
|
+
'semantic-warning': '#d4820a',
|
|
41
|
+
'semantic-warning-hover': '#e08f10',
|
|
42
|
+
'semantic-warning-light': '#fdf4e6',
|
|
43
|
+
'semantic-error': '#b03020',
|
|
44
|
+
'semantic-error-hover': '#c03828',
|
|
45
|
+
'semantic-error-light': '#fce8e6',
|
|
46
|
+
'semantic-info': '#4a6a9e',
|
|
47
|
+
'semantic-info-hover': '#3a558a',
|
|
48
|
+
'semantic-info-light': '#e8eef5',
|
|
49
|
+
'text-primary': '#1a1a1a',
|
|
50
|
+
'text-secondary': '#4a4f4c',
|
|
51
|
+
'text-muted': '#8a8a8a',
|
|
52
|
+
'text-inverse': '#ffffff',
|
|
53
|
+
'border-default': '#c8c9c3',
|
|
54
|
+
'border-subtle': '#e0e0dc',
|
|
55
|
+
'border-strong': '#1ab873',
|
|
56
|
+
},
|
|
57
|
+
interaction: {
|
|
58
|
+
'hover-intensity': '15%',
|
|
59
|
+
'active-intensity': '22%',
|
|
60
|
+
'focus-glow': '30%',
|
|
61
|
+
'focus-ring-width': '1px',
|
|
62
|
+
'focus-ring-offset': '1px',
|
|
63
|
+
'text-glow': '50%',
|
|
64
|
+
'transition-duration': '100ms',
|
|
65
|
+
},
|
|
66
|
+
spacing: {
|
|
67
|
+
'1': '1px',
|
|
68
|
+
'2': '3px',
|
|
69
|
+
'3': '4px',
|
|
70
|
+
'4': '6px',
|
|
71
|
+
'5': '8px',
|
|
72
|
+
'6': '9px',
|
|
73
|
+
'7': '10px',
|
|
74
|
+
'8': '12px',
|
|
75
|
+
'10': '15px',
|
|
76
|
+
'12': '18px',
|
|
77
|
+
'14': '21px',
|
|
78
|
+
'16': '24px',
|
|
79
|
+
'20': '30px',
|
|
80
|
+
'24': '36px',
|
|
81
|
+
},
|
|
82
|
+
radius: {
|
|
83
|
+
'xs': '1px',
|
|
84
|
+
'sm': '4px',
|
|
85
|
+
'md': '6px',
|
|
86
|
+
'lg': '9px',
|
|
87
|
+
},
|
|
88
|
+
font: {
|
|
89
|
+
'family-mono': "ui-monospace, 'SF Mono', 'Cascadia Code', 'Fira Code', monospace",
|
|
90
|
+
'family-system': 'system-ui, -apple-system, sans-serif',
|
|
91
|
+
'size-xs': '7px',
|
|
92
|
+
'size-sm': '8px',
|
|
93
|
+
'size-md': '10px',
|
|
94
|
+
'size-lg': '11px',
|
|
95
|
+
'size-xl': '12px',
|
|
96
|
+
'size-2xl': '13px',
|
|
97
|
+
'size-3xl': '16px',
|
|
98
|
+
'size-4xl': '20px',
|
|
99
|
+
'weight-thin': '100',
|
|
100
|
+
'weight-regular': '400',
|
|
101
|
+
'weight-medium': '500',
|
|
102
|
+
'weight-semibold': '600',
|
|
103
|
+
'weight-bold': '700',
|
|
104
|
+
},
|
|
105
|
+
shadow: {
|
|
106
|
+
'glow-radius': '8px',
|
|
107
|
+
'sm': '0px 1px 2px rgba(0,0,0,0.05)',
|
|
108
|
+
'md': '0px 4px 8px rgba(0,0,0,0.08), 0px 2px 4px rgba(0,0,0,0.04)',
|
|
109
|
+
'lg': '0px 4px 8px rgba(0,0,0,0.12), 0px 6px 12px rgba(16,24,40,0.12), 0px 1px 16px rgba(16,24,40,0.12)',
|
|
110
|
+
},
|
|
111
|
+
motion: {
|
|
112
|
+
'duration-fast': '200ms',
|
|
113
|
+
'duration-normal': '400ms',
|
|
114
|
+
'easing-default': 'ease-in-out',
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @description dark theme preset — Phosphor sci-fi terminal palette
|
|
3
|
+
* @author kine-design
|
|
4
|
+
* @date 2026/5/22
|
|
5
|
+
* @version v1.0.0
|
|
6
|
+
*
|
|
7
|
+
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
8
|
+
*/
|
|
9
|
+
import type { ThemeDefinition } from '../types';
|
|
10
|
+
|
|
11
|
+
export const darkTheme: ThemeDefinition = {
|
|
12
|
+
id: 'dark',
|
|
13
|
+
name: 'Dark',
|
|
14
|
+
description: 'Dark mode — Phosphor terminal aesthetic, inverted colors',
|
|
15
|
+
tokens: {
|
|
16
|
+
color: {
|
|
17
|
+
'bg-primary': '#000000',
|
|
18
|
+
'bg-secondary': '#0a0a0a',
|
|
19
|
+
'bg-tertiary': '#141414',
|
|
20
|
+
'bg-hover': '#1a1a1a',
|
|
21
|
+
'bg-inset': '#1e1e1e',
|
|
22
|
+
'neutral-1': '#0f0f0f',
|
|
23
|
+
'neutral-2': '#1a1a1a',
|
|
24
|
+
'neutral-3': '#262626',
|
|
25
|
+
'neutral-4': '#333333',
|
|
26
|
+
'neutral-5': '#4a4a4a',
|
|
27
|
+
'neutral-6': '#666666',
|
|
28
|
+
'accent-light': '#0d2e1f',
|
|
29
|
+
'accent-default': '#2ad98d',
|
|
30
|
+
'accent-hover': '#3ae29a',
|
|
31
|
+
'accent-active': '#22b072',
|
|
32
|
+
'accent-alt': '#1fa86b',
|
|
33
|
+
'semantic-success': '#2ad98d',
|
|
34
|
+
'semantic-success-hover': '#3ae29a',
|
|
35
|
+
'semantic-success-light': '#0d2e1f',
|
|
36
|
+
'semantic-warning': '#fab03d',
|
|
37
|
+
'semantic-warning-hover': '#fabb55',
|
|
38
|
+
'semantic-warning-light': '#2e2210',
|
|
39
|
+
'semantic-error': '#cb523e',
|
|
40
|
+
'semantic-error-hover': '#de5f48',
|
|
41
|
+
'semantic-error-light': '#2e1210',
|
|
42
|
+
'semantic-info': '#8ba3c7',
|
|
43
|
+
'semantic-info-hover': '#5976ba',
|
|
44
|
+
'semantic-info-light': '#10182e',
|
|
45
|
+
'text-primary': '#e8e8e8',
|
|
46
|
+
'text-secondary': '#86908a',
|
|
47
|
+
'text-muted': '#555555',
|
|
48
|
+
'text-inverse': '#0a0a0a',
|
|
49
|
+
'border-default': '#31322c',
|
|
50
|
+
'border-subtle': '#252520',
|
|
51
|
+
'border-strong': '#2ad98d',
|
|
52
|
+
},
|
|
53
|
+
interaction: {
|
|
54
|
+
'hover-intensity': '18%',
|
|
55
|
+
'active-intensity': '28%',
|
|
56
|
+
'focus-glow': '35%',
|
|
57
|
+
'focus-ring-width': '2px',
|
|
58
|
+
'focus-ring-offset': '2px',
|
|
59
|
+
'text-glow': '55%',
|
|
60
|
+
'transition-duration': '150ms',
|
|
61
|
+
},
|
|
62
|
+
spacing: {
|
|
63
|
+
'1': '2px',
|
|
64
|
+
'2': '4px',
|
|
65
|
+
'3': '6px',
|
|
66
|
+
'4': '8px',
|
|
67
|
+
'5': '10px',
|
|
68
|
+
'6': '12px',
|
|
69
|
+
'7': '14px',
|
|
70
|
+
'8': '16px',
|
|
71
|
+
'10': '20px',
|
|
72
|
+
'12': '24px',
|
|
73
|
+
'14': '28px',
|
|
74
|
+
'16': '32px',
|
|
75
|
+
'20': '40px',
|
|
76
|
+
'24': '48px',
|
|
77
|
+
},
|
|
78
|
+
radius: {
|
|
79
|
+
'xs': '2px',
|
|
80
|
+
'sm': '6px',
|
|
81
|
+
'md': '8px',
|
|
82
|
+
'lg': '12px',
|
|
83
|
+
},
|
|
84
|
+
font: {
|
|
85
|
+
'family-mono': "ui-monospace, 'SF Mono', 'Cascadia Code', 'Fira Code', monospace",
|
|
86
|
+
'family-system': 'system-ui, -apple-system, sans-serif',
|
|
87
|
+
'size-xs': '9px',
|
|
88
|
+
'size-sm': '10px',
|
|
89
|
+
'size-md': '12px',
|
|
90
|
+
'size-lg': '13px',
|
|
91
|
+
'size-xl': '14px',
|
|
92
|
+
'size-2xl': '16px',
|
|
93
|
+
'size-3xl': '20px',
|
|
94
|
+
'size-4xl': '24px',
|
|
95
|
+
'weight-thin': '100',
|
|
96
|
+
'weight-regular': '400',
|
|
97
|
+
'weight-medium': '500',
|
|
98
|
+
'weight-semibold': '600',
|
|
99
|
+
'weight-bold': '700',
|
|
100
|
+
},
|
|
101
|
+
shadow: {
|
|
102
|
+
'glow-radius': '8px',
|
|
103
|
+
'sm': '0px 1px 2px rgba(0,0,0,0.15)',
|
|
104
|
+
'md': '0px 4px 8px rgba(0,0,0,0.25), 0px 2px 4px rgba(0,0,0,0.15)',
|
|
105
|
+
'lg': '0px 4px 8px rgba(0,0,0,0.35), 0px 6px 12px rgba(0,0,0,0.25), 0px 1px 16px rgba(0,0,0,0.2)',
|
|
106
|
+
},
|
|
107
|
+
motion: {
|
|
108
|
+
'duration-fast': '200ms',
|
|
109
|
+
'duration-normal': '400ms',
|
|
110
|
+
'easing-default': 'ease-in-out',
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @description built-in theme presets barrel export
|
|
3
|
+
* @author kine-design
|
|
4
|
+
* @date 2026/5/22
|
|
5
|
+
* @version v1.0.0
|
|
6
|
+
*
|
|
7
|
+
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
8
|
+
*/
|
|
9
|
+
export { lightTheme } from './light';
|
|
10
|
+
export { darkTheme } from './dark';
|
|
11
|
+
export { compactTheme } from './compact';
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @description light theme preset — extracted from base.css :root values
|
|
3
|
+
* @author kine-design
|
|
4
|
+
* @date 2026/5/22
|
|
5
|
+
* @version v1.0.0
|
|
6
|
+
*
|
|
7
|
+
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
8
|
+
*/
|
|
9
|
+
import type { ThemeDefinition } from '../types';
|
|
10
|
+
|
|
11
|
+
export const lightTheme: ThemeDefinition = {
|
|
12
|
+
id: 'light',
|
|
13
|
+
name: 'Light',
|
|
14
|
+
description: 'Default light theme — neutral backgrounds, dark text, Phosphor accent',
|
|
15
|
+
tokens: {
|
|
16
|
+
color: {
|
|
17
|
+
'bg-primary': '#f5f5f5',
|
|
18
|
+
'bg-secondary': '#ebebeb',
|
|
19
|
+
'bg-tertiary': '#e0e0e0',
|
|
20
|
+
'bg-hover': '#d4d4d4',
|
|
21
|
+
'bg-inset': '#dcdcdc',
|
|
22
|
+
'neutral-1': '#f0f0f0',
|
|
23
|
+
'neutral-2': '#e5e5e5',
|
|
24
|
+
'neutral-3': '#d4d4d4',
|
|
25
|
+
'neutral-4': '#c0c0c0',
|
|
26
|
+
'neutral-5': '#a0a0a0',
|
|
27
|
+
'neutral-6': '#787878',
|
|
28
|
+
'accent-light': '#e8f5ef',
|
|
29
|
+
'accent-default': '#1ab873',
|
|
30
|
+
'accent-hover': '#1ec87d',
|
|
31
|
+
'accent-active': '#158f5a',
|
|
32
|
+
'accent-alt': '#168f5a',
|
|
33
|
+
'semantic-success': '#1ab873',
|
|
34
|
+
'semantic-success-hover': '#1ec87d',
|
|
35
|
+
'semantic-success-light': '#e8f5ef',
|
|
36
|
+
'semantic-warning': '#d4820a',
|
|
37
|
+
'semantic-warning-hover': '#e08f10',
|
|
38
|
+
'semantic-warning-light': '#fdf4e6',
|
|
39
|
+
'semantic-error': '#b03020',
|
|
40
|
+
'semantic-error-hover': '#c03828',
|
|
41
|
+
'semantic-error-light': '#fce8e6',
|
|
42
|
+
'semantic-info': '#4a6a9e',
|
|
43
|
+
'semantic-info-hover': '#3a558a',
|
|
44
|
+
'semantic-info-light': '#e8eef5',
|
|
45
|
+
'text-primary': '#1a1a1a',
|
|
46
|
+
'text-secondary': '#4a4f4c',
|
|
47
|
+
'text-muted': '#8a8a8a',
|
|
48
|
+
'text-inverse': '#ffffff',
|
|
49
|
+
'border-default': '#c8c9c3',
|
|
50
|
+
'border-subtle': '#e0e0dc',
|
|
51
|
+
'border-strong': '#1ab873',
|
|
52
|
+
},
|
|
53
|
+
interaction: {
|
|
54
|
+
'hover-intensity': '15%',
|
|
55
|
+
'active-intensity': '22%',
|
|
56
|
+
'focus-glow': '30%',
|
|
57
|
+
'focus-ring-width': '2px',
|
|
58
|
+
'focus-ring-offset': '2px',
|
|
59
|
+
'text-glow': '50%',
|
|
60
|
+
'transition-duration': '150ms',
|
|
61
|
+
},
|
|
62
|
+
spacing: {
|
|
63
|
+
'1': '2px',
|
|
64
|
+
'2': '4px',
|
|
65
|
+
'3': '6px',
|
|
66
|
+
'4': '8px',
|
|
67
|
+
'5': '10px',
|
|
68
|
+
'6': '12px',
|
|
69
|
+
'7': '14px',
|
|
70
|
+
'8': '16px',
|
|
71
|
+
'10': '20px',
|
|
72
|
+
'12': '24px',
|
|
73
|
+
'14': '28px',
|
|
74
|
+
'16': '32px',
|
|
75
|
+
'20': '40px',
|
|
76
|
+
'24': '48px',
|
|
77
|
+
},
|
|
78
|
+
radius: {
|
|
79
|
+
'xs': '2px',
|
|
80
|
+
'sm': '6px',
|
|
81
|
+
'md': '8px',
|
|
82
|
+
'lg': '12px',
|
|
83
|
+
},
|
|
84
|
+
font: {
|
|
85
|
+
'family-mono': "ui-monospace, 'SF Mono', 'Cascadia Code', 'Fira Code', monospace",
|
|
86
|
+
'family-system': 'system-ui, -apple-system, sans-serif',
|
|
87
|
+
'size-xs': '9px',
|
|
88
|
+
'size-sm': '10px',
|
|
89
|
+
'size-md': '12px',
|
|
90
|
+
'size-lg': '13px',
|
|
91
|
+
'size-xl': '14px',
|
|
92
|
+
'size-2xl': '16px',
|
|
93
|
+
'size-3xl': '20px',
|
|
94
|
+
'size-4xl': '24px',
|
|
95
|
+
'weight-thin': '100',
|
|
96
|
+
'weight-regular': '400',
|
|
97
|
+
'weight-medium': '500',
|
|
98
|
+
'weight-semibold': '600',
|
|
99
|
+
'weight-bold': '700',
|
|
100
|
+
},
|
|
101
|
+
shadow: {
|
|
102
|
+
'glow-radius': '8px',
|
|
103
|
+
'sm': '0px 1px 2px rgba(0,0,0,0.05)',
|
|
104
|
+
'md': '0px 4px 8px rgba(0,0,0,0.08), 0px 2px 4px rgba(0,0,0,0.04)',
|
|
105
|
+
'lg': '0px 4px 8px rgba(0,0,0,0.12), 0px 6px 12px rgba(16,24,40,0.12), 0px 1px 16px rgba(16,24,40,0.12)',
|
|
106
|
+
},
|
|
107
|
+
motion: {
|
|
108
|
+
'duration-fast': '200ms',
|
|
109
|
+
'duration-normal': '400ms',
|
|
110
|
+
'easing-default': 'ease-in-out',
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @description theme system type definitions
|
|
3
|
+
* @author kine-design
|
|
4
|
+
* @date 2026/5/22
|
|
5
|
+
* @version v1.0.0
|
|
6
|
+
*
|
|
7
|
+
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/** Token category map: flat key-value pairs per category */
|
|
11
|
+
export interface ThemeTokens {
|
|
12
|
+
/** e.g. 'bg-primary': '#f5f5f5', 'neutral-3': '#d4d4d4', 'accent-light': '#e8f5ef' */
|
|
13
|
+
color: Record<string, string>
|
|
14
|
+
/** e.g. '1': '2px', '2': '4px' */
|
|
15
|
+
spacing: Record<string, string>
|
|
16
|
+
/** e.g. 'xs': '2px', 'sm': '6px' */
|
|
17
|
+
radius: Record<string, string>
|
|
18
|
+
/** e.g. 'size-sm': '12px', 'family-system': 'system-ui, ...' */
|
|
19
|
+
font: Record<string, string>
|
|
20
|
+
/** e.g. 'sm': '0px 1px 2px ...', 'glow-radius': '8px' */
|
|
21
|
+
shadow: Record<string, string>
|
|
22
|
+
/** e.g. 'duration-fast': '200ms', 'easing-default': 'ease-in-out' */
|
|
23
|
+
motion: Record<string, string>
|
|
24
|
+
/** e.g. 'hover-intensity': '15%', 'transition-duration': '150ms' */
|
|
25
|
+
interaction: Record<string, string>
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** All supported token category names */
|
|
29
|
+
export type ThemeTokenCategory = keyof ThemeTokens
|
|
30
|
+
|
|
31
|
+
/** A registered theme definition */
|
|
32
|
+
export interface ThemeDefinition {
|
|
33
|
+
id: string
|
|
34
|
+
name: string
|
|
35
|
+
description?: string
|
|
36
|
+
tokens: Partial<ThemeTokens>
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** User-level per-token overrides (sparse) */
|
|
40
|
+
export type ThemeOverrides = Partial<ThemeTokens>
|
|
41
|
+
|
|
42
|
+
/** Serialized state persisted to localStorage */
|
|
43
|
+
export interface PersistedThemeState {
|
|
44
|
+
currentTheme: string
|
|
45
|
+
overrides: ThemeOverrides
|
|
46
|
+
}
|