@celestia-island/hikari 0.4.4 → 0.4.5
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/README.md +1 -1
- package/package.json +16 -7
- package/src/DemoApp.vue +1 -1
- package/src/components/HkAdminHeader.tsx +205 -0
- package/src/components/HkAdminShell.tsx +85 -0
- package/src/components/HkAdminTablePage.tsx +70 -0
- package/src/components/HkAuthCard.tsx +36 -0
- package/src/components/HkAuthSubmitButton.scss +12 -0
- package/src/components/HkAuthSubmitButton.tsx +94 -0
- package/src/components/HkAvatar.scss +93 -0
- package/src/components/HkAvatar.tsx +1 -1
- package/src/components/HkBreadcrumb.scss +624 -0
- package/src/components/HkBreadcrumb.tsx +1 -1
- package/src/components/HkCard.scss +1 -1
- package/src/components/HkCheckbox.tsx +2 -1
- package/src/components/HkCollapse.scss +50 -0
- package/src/components/HkCollapse.tsx +1 -1
- package/src/components/HkColorSchemeDialog.scss +16 -0
- package/src/components/HkColorSchemeDialog.tsx +237 -0
- package/src/components/HkConnectionInfo.ts +80 -0
- package/src/components/HkConnectionStatus.tsx +133 -0
- package/src/components/HkCountdownDigit.tsx +97 -0
- package/src/components/HkDateTimePicker.tsx +7 -1
- package/src/components/HkErrorBoundary.tsx +4 -1
- package/src/components/HkIcon.scss +123 -0
- package/src/components/HkIcon.tsx +7 -23
- package/src/components/HkIconButton.scss +170 -0
- package/src/components/HkIconButton.tsx +2 -2
- package/src/components/HkIconButtonVars.scss +176 -0
- package/src/components/HkInput.scss +22 -3
- package/src/components/HkInput.tsx +41 -1
- package/src/components/HkKeywordSearchModal.tsx +10 -7
- package/src/components/HkLocalePicker.tsx +113 -0
- package/src/components/HkMediaControlBar.tsx +14 -7
- package/src/components/HkMinimap.tsx +10 -2
- package/src/components/HkModal.tsx +2 -23
- package/src/components/HkNavItem.tsx +2 -1
- package/src/components/HkNavSidebar.tsx +99 -0
- package/src/components/HkPageHeader.tsx +40 -0
- package/src/components/HkPasswordInput.scss +14 -12
- package/src/components/HkPasswordInput.test.ts +242 -0
- package/src/components/HkPasswordInput.tsx +236 -41
- package/src/components/HkPopupSelect.scss +3 -3
- package/src/components/HkPopupSelect.tsx +2 -1
- package/src/components/HkSearchInput.tsx +2 -2
- package/src/components/HkSecretRevealModal.scss +61 -0
- package/src/components/HkSecretRevealModal.tsx +91 -0
- package/src/components/HkSelect.scss +4 -4
- package/src/components/HkSelect.tsx +2 -0
- package/src/components/HkSelectionGrid.tsx +2 -1
- package/src/components/HkStatusBar.tsx +235 -0
- package/src/components/HkTag.tsx +2 -1
- package/src/components/HkThemeToggle.scss +130 -0
- package/src/components/HkThemeToggle.tsx +160 -0
- package/src/components/HkTimeline.tsx +2 -1
- package/src/components/HkToast.tsx +4 -1
- package/src/components/HkTrendChart.tsx +27 -16
- package/src/components/HkZoomToolbar.tsx +4 -1
- package/src/components/_hikari-vars.scss +4 -0
- package/src/composables/highlightLanguages.ts +109 -0
- package/src/composables/iconRegistry.ts +127 -0
- package/src/composables/messaging/browserTransport.ts +96 -0
- package/src/composables/messaging/index.ts +204 -0
- package/src/composables/messaging/messaging.test.ts +256 -0
- package/src/composables/messaging/toastTransport.ts +26 -0
- package/src/composables/messaging/types.ts +115 -0
- package/src/composables/useActionBar.ts +66 -0
- package/src/composables/useConnectionProbe.ts +126 -0
- package/src/composables/useDeferredTransition.ts +16 -0
- package/src/composables/useEngineHealth.ts +69 -0
- package/src/composables/useHighlight.ts +124 -0
- package/src/composables/usePageTitle.ts +37 -0
- package/src/composables/useReducedMotion.ts +34 -0
- package/src/composables/useResourceListModal.tsx +147 -0
- package/src/composables/useZoomPan.ts +192 -0
- package/src/i18n/locales/ar/components.json +12 -3
- package/src/i18n/locales/ar/components.toml +5 -0
- package/src/i18n/locales/ar/connection.json +25 -0
- package/src/i18n/locales/ar/platform.json +50 -0
- package/src/i18n/locales/de/components.json +12 -3
- package/src/i18n/locales/de/components.toml +5 -0
- package/src/i18n/locales/de/connection.json +25 -0
- package/src/i18n/locales/de/platform.json +50 -0
- package/src/i18n/locales/en/components.json +12 -3
- package/src/i18n/locales/en/components.toml +5 -0
- package/src/i18n/locales/en/connection.json +27 -0
- package/src/i18n/locales/en/platform.json +53 -0
- package/src/i18n/locales/es/components.json +12 -3
- package/src/i18n/locales/es/components.toml +5 -0
- package/src/i18n/locales/es/connection.json +25 -0
- package/src/i18n/locales/es/platform.json +50 -0
- package/src/i18n/locales/fr/components.json +12 -3
- package/src/i18n/locales/fr/components.toml +5 -0
- package/src/i18n/locales/fr/connection.json +25 -0
- package/src/i18n/locales/fr/platform.json +50 -0
- package/src/i18n/locales/ja/components.json +12 -3
- package/src/i18n/locales/ja/components.toml +5 -0
- package/src/i18n/locales/ja/connection.json +27 -0
- package/src/i18n/locales/ja/platform.json +53 -0
- package/src/i18n/locales/ko/components.json +12 -3
- package/src/i18n/locales/ko/components.toml +5 -0
- package/src/i18n/locales/ko/connection.json +27 -0
- package/src/i18n/locales/ko/platform.json +50 -0
- package/src/i18n/locales/pt/components.json +12 -3
- package/src/i18n/locales/pt/components.toml +5 -0
- package/src/i18n/locales/pt/connection.json +25 -0
- package/src/i18n/locales/pt/platform.json +50 -0
- package/src/i18n/locales/ru/components.json +12 -3
- package/src/i18n/locales/ru/components.toml +5 -0
- package/src/i18n/locales/ru/connection.json +25 -0
- package/src/i18n/locales/ru/platform.json +50 -0
- package/src/i18n/locales/zh-Hans/components.json +12 -3
- package/src/i18n/locales/zh-Hans/components.toml +5 -0
- package/src/i18n/locales/zh-Hans/connection.json +27 -0
- package/src/i18n/locales/zh-Hans/platform.json +53 -0
- package/src/i18n/locales/zh-Hant/components.json +12 -3
- package/src/i18n/locales/zh-Hant/components.toml +5 -0
- package/src/i18n/locales/zh-Hant/connection.json +27 -0
- package/src/i18n/locales/zh-Hant/platform.json +53 -0
- package/src/index.ts +67 -4
- package/src/plugins/bootScriptsPlugin.ts +47 -0
- package/src/plugins/buildHashPlugin.ts +67 -0
- package/src/plugins/index.ts +2 -0
- package/src/render.ts +1 -1
- package/src/runtime/env.ts +4 -0
- package/src/runtime/index.ts +0 -1
- package/src/runtime/useConfirm.ts +7 -1
- package/src/styles/admin-tokens.scss +634 -0
- package/src/styles/index.scss +1 -0
- package/src/theme/_field.scss +116 -0
- package/src/theme/index.ts +2 -0
- package/src/theme/presets.ts +11 -9
- package/src/theme/useTheme.ts +54 -5
- package/src/tokens.scss +76 -0
- package/src/utils/base64.ts +31 -0
- package/src/utils/connectivity.ts +51 -0
- package/src/utils/dom.ts +39 -0
- package/src/utils/download.ts +22 -0
- package/src/utils/fileType.ts +127 -0
- package/src/utils/fuzzy.ts +77 -0
- package/src/utils/fuzzySearch.test.ts +87 -0
- package/src/utils/objectPath.ts +59 -0
- package/src/utils/password.ts +53 -0
- package/src/utils/pow.test.ts +45 -0
- package/src/utils/pow.ts +226 -0
- package/src/utils/powNonce.ts +83 -0
- package/src/utils/validation.test.ts +78 -0
- package/src/composables/useBreakpoint.ts +0 -41
- package/src/composables/useClipboard.ts +0 -37
- package/src/composables/useConfirm.ts +0 -35
- package/src/composables/useToast.ts +0 -2
- package/src/runtime/useAsyncData.ts +0 -30
|
@@ -1,13 +1,6 @@
|
|
|
1
1
|
import { defineComponent, type PropType } from "vue";
|
|
2
|
-
import
|
|
3
|
-
import "
|
|
4
|
-
|
|
5
|
-
function pascalCase(str: string): string {
|
|
6
|
-
const camel = str.replace(/-([a-z])/g, (_: string, c: string) => c.toUpperCase());
|
|
7
|
-
return camel.charAt(0).toUpperCase() + camel.slice(1);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
const icons = LucideIcons as Record<string, any>;
|
|
2
|
+
import { iconByName } from "../composables/iconRegistry";
|
|
3
|
+
import "./HkIcon.scss";
|
|
11
4
|
|
|
12
5
|
export default defineComponent({
|
|
13
6
|
name: "HkIcon",
|
|
@@ -24,20 +17,11 @@ export default defineComponent({
|
|
|
24
17
|
props.color ? `hk-icon-${props.color}` : "",
|
|
25
18
|
];
|
|
26
19
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
return (
|
|
35
|
-
<span class={cls}>
|
|
36
|
-
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
37
|
-
<circle cx="12" cy="12" r="10" />
|
|
38
|
-
</svg>
|
|
39
|
-
</span>
|
|
40
|
-
);
|
|
20
|
+
// Resolve through the explicit registry: a wildcard import of
|
|
21
|
+
// lucide-vue-next here defeated tree-shaking and shipped the whole
|
|
22
|
+
// ~1500-icon library in the shared bundle of every consumer.
|
|
23
|
+
const IconComp = iconByName(props.name) as any;
|
|
24
|
+
return <span class={cls}><IconComp /></span>;
|
|
41
25
|
};
|
|
42
26
|
},
|
|
43
27
|
});
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
// Use theme variables with namespace to avoid conflicts
|
|
2
|
+
@use "./hikari-vars" as vars;
|
|
3
|
+
@use "./HkIconButtonVars.scss";
|
|
4
|
+
|
|
5
|
+
// ------
|
|
6
|
+
// Hikari IconButton Component - FUI Styling
|
|
7
|
+
// Three-layer CSS variable system:
|
|
8
|
+
// - Layer1: Foundation variables (foundation.scss)
|
|
9
|
+
// - Layer2: Component variables (icon-button-vars.scss)
|
|
10
|
+
// - Custom: Runtime overrides via AnimationBuilder
|
|
11
|
+
//
|
|
12
|
+
// NOTE: Hover effects are handled by Glow wrapper, not here
|
|
13
|
+
// ------
|
|
14
|
+
|
|
15
|
+
.hk-icon-button {
|
|
16
|
+
// Layer2 variables are defined in icon-button-vars.scss
|
|
17
|
+
|
|
18
|
+
// Layout
|
|
19
|
+
display: inline-flex;
|
|
20
|
+
align-items: center;
|
|
21
|
+
justify-content: center;
|
|
22
|
+
flex-shrink: 0;
|
|
23
|
+
padding: 0;
|
|
24
|
+
line-height: 0;
|
|
25
|
+
gap: 0;
|
|
26
|
+
|
|
27
|
+
// Size - use CSS variables
|
|
28
|
+
width: var(--hi-icon-button-size);
|
|
29
|
+
height: var(--hi-icon-button-size);
|
|
30
|
+
min-width: var(--hi-icon-button-size);
|
|
31
|
+
max-width: var(--hi-icon-button-size);
|
|
32
|
+
min-height: var(--hi-icon-button-size);
|
|
33
|
+
max-height: var(--hi-icon-button-size);
|
|
34
|
+
|
|
35
|
+
// Allow glow effect to show
|
|
36
|
+
overflow: visible;
|
|
37
|
+
|
|
38
|
+
// Remove default button styling
|
|
39
|
+
appearance: none;
|
|
40
|
+
-webkit-appearance: none;
|
|
41
|
+
-moz-appearance: none;
|
|
42
|
+
|
|
43
|
+
// Background - use CSS variables
|
|
44
|
+
background: var(--hi-icon-button-bg);
|
|
45
|
+
border: none;
|
|
46
|
+
border-radius: var(--hi-icon-button-radius);
|
|
47
|
+
|
|
48
|
+
// Typography
|
|
49
|
+
font-family: vars.$hikari-font-family-sans;
|
|
50
|
+
font-size: vars.$hikari-font-size-sm;
|
|
51
|
+
font-weight: 400;
|
|
52
|
+
color: var(--hi-icon-button-icon-color);
|
|
53
|
+
|
|
54
|
+
// Transitions - use CSS variables
|
|
55
|
+
transition: var(--hi-icon-button-transition);
|
|
56
|
+
|
|
57
|
+
// No transform - controlled by AnimationBuilder via Glow wrapper
|
|
58
|
+
|
|
59
|
+
// Cursor
|
|
60
|
+
cursor: pointer;
|
|
61
|
+
|
|
62
|
+
// Focus state - only outline, no color changes
|
|
63
|
+
&:focus-visible {
|
|
64
|
+
outline: 2px solid var(--hi-icon-button-border-color-focus);
|
|
65
|
+
outline-offset: 2px;
|
|
66
|
+
color: var(--hi-icon-button-icon-color);
|
|
67
|
+
|
|
68
|
+
.hk-icon-button-icon {
|
|
69
|
+
color: var(--hi-icon-button-icon-color);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Disabled state
|
|
74
|
+
&:disabled {
|
|
75
|
+
background: var(--hi-icon-button-bg-disabled);
|
|
76
|
+
color: var(--hi-icon-button-icon-color-disabled);
|
|
77
|
+
cursor: not-allowed;
|
|
78
|
+
pointer-events: none;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// No active state - controlled by AnimationBuilder via Glow wrapper
|
|
82
|
+
|
|
83
|
+
// ------
|
|
84
|
+
// Size Variants - Variables defined in icon-button-vars.scss
|
|
85
|
+
// ------
|
|
86
|
+
|
|
87
|
+
&.hk-icon-button-16,
|
|
88
|
+
&.hk-icon-button-24,
|
|
89
|
+
&.hk-icon-button-32,
|
|
90
|
+
&.hk-icon-button-36,
|
|
91
|
+
&.hk-icon-button-40 {
|
|
92
|
+
// Size variables are already set by the classes in icon-button-vars.scss
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// ------
|
|
96
|
+
// Variant: Ghost (default - transparent)
|
|
97
|
+
// ------
|
|
98
|
+
|
|
99
|
+
&.hk-icon-button-ghost,
|
|
100
|
+
&.hk-icon-button-borderless {
|
|
101
|
+
// Variables defined in icon-button-vars.scss
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// ------
|
|
105
|
+
// Variant: Primary (solid primary color)
|
|
106
|
+
// ------
|
|
107
|
+
|
|
108
|
+
&.hk-icon-button-primary {
|
|
109
|
+
// Variables defined in icon-button-vars.scss
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// ------
|
|
113
|
+
// Variant: Secondary (solid secondary color)
|
|
114
|
+
// ------
|
|
115
|
+
|
|
116
|
+
&.hk-icon-button-secondary {
|
|
117
|
+
// Variables defined in icon-button-vars.scss
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// ------
|
|
121
|
+
// Variant: Danger (solid danger color)
|
|
122
|
+
// ------
|
|
123
|
+
|
|
124
|
+
&.hk-icon-button-danger {
|
|
125
|
+
// Variables defined in icon-button-vars.scss
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// ------
|
|
129
|
+
// Variant: Success (solid success color)
|
|
130
|
+
// ------
|
|
131
|
+
|
|
132
|
+
&.hk-icon-button-success {
|
|
133
|
+
// Variables defined in icon-button-vars.scss
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// ------
|
|
137
|
+
// Icon Styles - Use CSS Variables
|
|
138
|
+
// ------
|
|
139
|
+
|
|
140
|
+
.hk-icon-button-icon {
|
|
141
|
+
width: var(--hi-icon-button-icon-size);
|
|
142
|
+
height: var(--hi-icon-button-icon-size);
|
|
143
|
+
display: inline-flex;
|
|
144
|
+
align-items: center;
|
|
145
|
+
justify-content: center;
|
|
146
|
+
line-height: 0;
|
|
147
|
+
color: var(--hi-icon-button-icon-color);
|
|
148
|
+
|
|
149
|
+
svg {
|
|
150
|
+
width: var(--hi-icon-button-icon-size);
|
|
151
|
+
height: var(--hi-icon-button-icon-size);
|
|
152
|
+
display: block;
|
|
153
|
+
fill: currentColor;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Active state for icon
|
|
158
|
+
&:active:not(:disabled) .hk-icon-button-icon {
|
|
159
|
+
color: var(--hi-icon-button-icon-color-active);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Disabled state for icon
|
|
163
|
+
&:disabled .hk-icon-button-icon {
|
|
164
|
+
color: var(--hi-icon-button-icon-color-disabled);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.hk-icon-button-disabled {
|
|
168
|
+
opacity: 0.3;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { computed, defineComponent, type PropType } from "vue";
|
|
2
|
-
import "
|
|
3
|
-
import "
|
|
2
|
+
import "./HkIconButton.scss";
|
|
3
|
+
import "./HkIconButtonVars.scss";
|
|
4
4
|
|
|
5
5
|
export default defineComponent({
|
|
6
6
|
name: "HkIconButton",
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
// HkIconButtonVars.scss
|
|
2
|
+
// Layer2 - IconButton Component Variables
|
|
3
|
+
//
|
|
4
|
+
// This file defines component-level CSS variables for the IconButton component.
|
|
5
|
+
// These variables can be overridden at runtime via AnimationBuilder.
|
|
6
|
+
//
|
|
7
|
+
// NOTE: Hover effects are handled by Glow wrapper, not here.
|
|
8
|
+
// Only base, active, and disabled states are defined.
|
|
9
|
+
|
|
10
|
+
// ------
|
|
11
|
+
// Base IconButton Variables
|
|
12
|
+
// ------
|
|
13
|
+
|
|
14
|
+
.hk-icon-button {
|
|
15
|
+
// ------
|
|
16
|
+
// 1. Color System
|
|
17
|
+
// ------
|
|
18
|
+
|
|
19
|
+
// Icon Colors
|
|
20
|
+
--hi-icon-button-icon-color: var(--hi-icon-color);
|
|
21
|
+
--hi-icon-button-icon-color-active: var(--hi-icon-color);
|
|
22
|
+
--hi-icon-button-icon-color-disabled: rgba(128, 128, 128, 0.5);
|
|
23
|
+
|
|
24
|
+
// Background Colors
|
|
25
|
+
--hi-icon-button-bg: transparent;
|
|
26
|
+
--hi-icon-button-bg-active: var(--hi-bg-surface-dark);
|
|
27
|
+
--hi-icon-button-bg-disabled: rgba(128, 128, 128, 0.1);
|
|
28
|
+
|
|
29
|
+
// Border Colors
|
|
30
|
+
--hi-icon-button-border-color: transparent;
|
|
31
|
+
--hi-icon-button-border-color-focus: var(--hi-border-color-focus);
|
|
32
|
+
|
|
33
|
+
// Shadow & Glow (used by Glow wrapper)
|
|
34
|
+
--hi-icon-button-glow: var(--hi-glow-color);
|
|
35
|
+
|
|
36
|
+
// ------
|
|
37
|
+
// 2. Border Radius System
|
|
38
|
+
// ------
|
|
39
|
+
|
|
40
|
+
--hi-icon-button-radius: 4px;
|
|
41
|
+
|
|
42
|
+
// ------
|
|
43
|
+
// 3. Animation System
|
|
44
|
+
// ------
|
|
45
|
+
|
|
46
|
+
// Duration
|
|
47
|
+
--hi-icon-button-duration: var(--hi-duration-fast);
|
|
48
|
+
--hi-icon-button-duration-active: var(--hi-duration-instant);
|
|
49
|
+
|
|
50
|
+
// Easing
|
|
51
|
+
--hi-icon-button-easing: var(--hi-ease-default);
|
|
52
|
+
|
|
53
|
+
// Transition
|
|
54
|
+
--hi-icon-button-transition:
|
|
55
|
+
background-color var(--hi-icon-button-duration) var(--hi-icon-button-easing),
|
|
56
|
+
transform var(--hi-icon-button-duration-active) var(--hi-icon-button-easing);
|
|
57
|
+
|
|
58
|
+
// ------
|
|
59
|
+
// 4. Size System
|
|
60
|
+
// ------
|
|
61
|
+
|
|
62
|
+
--hi-icon-button-size: 40px;
|
|
63
|
+
--hi-icon-button-icon-size: var(--hi-icon-size-sm);
|
|
64
|
+
|
|
65
|
+
// ------
|
|
66
|
+
// 5. Transform System
|
|
67
|
+
// ------
|
|
68
|
+
|
|
69
|
+
--hi-icon-button-transform: none;
|
|
70
|
+
--hi-icon-button-transform-active: scale(0.95);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// ------
|
|
74
|
+
// Size Variants
|
|
75
|
+
// ------
|
|
76
|
+
|
|
77
|
+
.hk-icon-button-16 {
|
|
78
|
+
--hi-icon-button-size: 16px;
|
|
79
|
+
--hi-icon-button-icon-size: var(--hi-icon-size-xs);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.hk-icon-button-24 {
|
|
83
|
+
--hi-icon-button-size: 24px;
|
|
84
|
+
--hi-icon-button-icon-size: var(--hi-icon-size-xs);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.hk-icon-button-32 {
|
|
88
|
+
--hi-icon-button-size: 32px;
|
|
89
|
+
--hi-icon-button-icon-size: var(--hi-icon-size-sm);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.hk-icon-button-36 {
|
|
93
|
+
--hi-icon-button-size: 36px;
|
|
94
|
+
--hi-icon-button-icon-size: var(--hi-icon-size-sm);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.hk-icon-button-40 {
|
|
98
|
+
--hi-icon-button-size: 40px;
|
|
99
|
+
--hi-icon-button-icon-size: var(--hi-icon-size-sm);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// ------
|
|
103
|
+
// Ghost Variant Variables
|
|
104
|
+
// ------
|
|
105
|
+
|
|
106
|
+
.hk-icon-button-ghost,
|
|
107
|
+
.hk-icon-button-borderless {
|
|
108
|
+
--hi-icon-button-icon-color: var(--hi-color-text-secondary);
|
|
109
|
+
--hi-icon-button-icon-color-active: var(--hi-color-text-secondary);
|
|
110
|
+
|
|
111
|
+
--hi-icon-button-bg: transparent;
|
|
112
|
+
--hi-icon-button-bg-active: var(--hi-color-gray-20, rgba(128, 128, 128, 0.2));
|
|
113
|
+
|
|
114
|
+
--hi-icon-button-border-color: transparent;
|
|
115
|
+
--hi-icon-button-glow: var(--hi-glow-color);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// ------
|
|
119
|
+
// Primary Variant Variables
|
|
120
|
+
// ------
|
|
121
|
+
|
|
122
|
+
.hk-icon-button-primary {
|
|
123
|
+
--hi-icon-button-icon-color: var(--hi-color-text-on-primary);
|
|
124
|
+
--hi-icon-button-icon-color-active: var(--hi-color-text-on-primary);
|
|
125
|
+
|
|
126
|
+
--hi-icon-button-bg: var(--hi-color-primary);
|
|
127
|
+
--hi-icon-button-bg-active: var(--hi-color-primary-dark);
|
|
128
|
+
|
|
129
|
+
--hi-icon-button-border-color-focus: var(--hi-color-primary);
|
|
130
|
+
--hi-icon-button-glow: var(--hi-glow-color);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// ------
|
|
134
|
+
// Secondary Variant Variables
|
|
135
|
+
// ------
|
|
136
|
+
|
|
137
|
+
.hk-icon-button-secondary {
|
|
138
|
+
--hi-icon-button-icon-color: var(--hi-color-text-on-secondary);
|
|
139
|
+
--hi-icon-button-icon-color-active: var(--hi-color-text-on-secondary);
|
|
140
|
+
|
|
141
|
+
--hi-icon-button-bg: var(--hi-color-secondary);
|
|
142
|
+
--hi-icon-button-bg-active: var(--hi-color-secondary-dark);
|
|
143
|
+
|
|
144
|
+
--hi-icon-button-border-color-focus: var(--hi-color-secondary);
|
|
145
|
+
--hi-icon-button-glow: var(--hi-glow-color);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// ------
|
|
149
|
+
// Danger Variant Variables
|
|
150
|
+
// ------
|
|
151
|
+
|
|
152
|
+
.hk-icon-button-danger {
|
|
153
|
+
--hi-icon-button-icon-color: var(--hi-color-text-on-danger, #ffffff);
|
|
154
|
+
--hi-icon-button-icon-color-active: var(--hi-color-text-on-danger, #ffffff);
|
|
155
|
+
|
|
156
|
+
--hi-icon-button-bg: var(--hi-color-danger);
|
|
157
|
+
--hi-icon-button-bg-active: var(--hi-color-danger-dark);
|
|
158
|
+
|
|
159
|
+
--hi-icon-button-border-color-focus: var(--hi-color-danger);
|
|
160
|
+
--hi-icon-button-glow: var(--hi-glow-color);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// ------
|
|
164
|
+
// Success Variant Variables
|
|
165
|
+
// ------
|
|
166
|
+
|
|
167
|
+
.hk-icon-button-success {
|
|
168
|
+
--hi-icon-button-icon-color: var(--hi-color-text-on-success, #ffffff);
|
|
169
|
+
--hi-icon-button-icon-color-active: var(--hi-color-text-on-success, #ffffff);
|
|
170
|
+
|
|
171
|
+
--hi-icon-button-bg: var(--hi-color-success);
|
|
172
|
+
--hi-icon-button-bg-active: var(--hi-color-success-dark);
|
|
173
|
+
|
|
174
|
+
--hi-icon-button-border-color-focus: var(--hi-color-success);
|
|
175
|
+
--hi-icon-button-glow: var(--hi-glow-color);
|
|
176
|
+
}
|
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
gap: var(--space-6);
|
|
26
26
|
padding: var(--space-8) var(--space-12);
|
|
27
27
|
min-height: 2.5rem;
|
|
28
|
-
background: rgb(var(--color-surface)
|
|
29
|
-
|
|
30
|
-
border: 1px solid var(--
|
|
28
|
+
background: color-mix(in srgb, rgb(var(--color-surface)) 55%, transparent);
|
|
29
|
+
|
|
30
|
+
border: 1px solid color-mix(in srgb, rgb(var(--color-text)) 14%, transparent);
|
|
31
31
|
border-radius: var(--radius-sm);
|
|
32
32
|
overflow: hidden;
|
|
33
33
|
transition: background-color, border-color, color, box-shadow, opacity, transform, filter var(--duration-normal) var(--ease-standard);
|
|
@@ -72,6 +72,9 @@
|
|
|
72
72
|
background: transparent;
|
|
73
73
|
border: none;
|
|
74
74
|
outline: none;
|
|
75
|
+
appearance: none;
|
|
76
|
+
-webkit-appearance: none;
|
|
77
|
+
border-radius: 0;
|
|
75
78
|
font-family: inherit;
|
|
76
79
|
font-size: var(--text-base);
|
|
77
80
|
line-height: 1.5;
|
|
@@ -170,3 +173,19 @@
|
|
|
170
173
|
-webkit-box-shadow: 0 0 0 1000px rgb(var(--color-surface)) inset !important;
|
|
171
174
|
caret-color: rgb(var(--color-text));
|
|
172
175
|
}
|
|
176
|
+
|
|
177
|
+
/* Password-variant visibility toggle */
|
|
178
|
+
.hk-input-password-toggle {
|
|
179
|
+
display: inline-flex;
|
|
180
|
+
align-items: center;
|
|
181
|
+
justify-content: center;
|
|
182
|
+
padding: 0;
|
|
183
|
+
border: none;
|
|
184
|
+
background: transparent;
|
|
185
|
+
color: var(--color-text-secondary, #888);
|
|
186
|
+
cursor: pointer;
|
|
187
|
+
|
|
188
|
+
&:hover {
|
|
189
|
+
color: var(--color-text-primary, #222);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
+
import { Eye, EyeOff } from "lucide-vue-next";
|
|
1
2
|
import { computed, defineComponent, nextTick, onBeforeUnmount, onMounted, ref, useAttrs, watch } from "vue";
|
|
3
|
+
|
|
4
|
+
import { useI18n } from "../i18n/context";
|
|
5
|
+
|
|
2
6
|
import "./HkInput.scss";
|
|
3
7
|
|
|
4
8
|
export default defineComponent({
|
|
@@ -19,6 +23,16 @@ export default defineComponent({
|
|
|
19
23
|
rows: { type: Number, default: 3 },
|
|
20
24
|
autoGrow: { type: Boolean, default: false },
|
|
21
25
|
size: { type: String as () => "sm" | "md" | "lg", default: "md" },
|
|
26
|
+
/**
|
|
27
|
+
* Input variant. `password` renders a password field with a built-in
|
|
28
|
+
* visibility toggle (HPasswordInput layers strength / caps-lock /
|
|
29
|
+
* full-width extras on top of this base behavior). `number` maps to the
|
|
30
|
+
* numeric input type. Defaults to "text".
|
|
31
|
+
*/
|
|
32
|
+
variant: {
|
|
33
|
+
type: String as () => "text" | "password" | "number",
|
|
34
|
+
default: "text",
|
|
35
|
+
},
|
|
22
36
|
},
|
|
23
37
|
emits: {
|
|
24
38
|
"update:modelValue": (_value: string) => true,
|
|
@@ -27,9 +41,19 @@ export default defineComponent({
|
|
|
27
41
|
keydown: (_e: KeyboardEvent) => true,
|
|
28
42
|
},
|
|
29
43
|
setup(props, { emit, slots }) {
|
|
44
|
+
const { t } = useI18n();
|
|
30
45
|
const attrs = useAttrs();
|
|
31
46
|
const inputRef = ref<HTMLElement>();
|
|
32
47
|
|
|
48
|
+
const revealing = ref(false);
|
|
49
|
+
const resolvedType = computed(() => {
|
|
50
|
+
if (props.variant === "password") {
|
|
51
|
+
return revealing.value ? "text" : "password";
|
|
52
|
+
}
|
|
53
|
+
if (props.variant === "number") return "number";
|
|
54
|
+
return props.type;
|
|
55
|
+
});
|
|
56
|
+
|
|
33
57
|
const filteredAttrs = computed(() => {
|
|
34
58
|
const { class: _, style: __, ...rest } = attrs as Record<string, unknown>;
|
|
35
59
|
return rest;
|
|
@@ -113,7 +137,7 @@ export default defineComponent({
|
|
|
113
137
|
{isText ? (
|
|
114
138
|
<input
|
|
115
139
|
ref={inputRef}
|
|
116
|
-
type={
|
|
140
|
+
type={resolvedType.value}
|
|
117
141
|
value={props.modelValue}
|
|
118
142
|
placeholder={props.placeholder}
|
|
119
143
|
disabled={props.disabled}
|
|
@@ -163,6 +187,22 @@ export default defineComponent({
|
|
|
163
187
|
{slots.suffixIcon()}
|
|
164
188
|
</span>
|
|
165
189
|
)}
|
|
190
|
+
{props.variant === "password" && !slots.suffix && !slots.suffixIcon && (
|
|
191
|
+
<span class="hk-input-affix hk-input-suffix">
|
|
192
|
+
<button
|
|
193
|
+
type="button"
|
|
194
|
+
class="hk-input-password-toggle"
|
|
195
|
+
aria-label={
|
|
196
|
+
revealing.value
|
|
197
|
+
? t("hikari::input.hidePassword", "Hide password")
|
|
198
|
+
: t("hikari::input.showPassword", "Show password")
|
|
199
|
+
}
|
|
200
|
+
onClick={() => { revealing.value = !revealing.value; }}
|
|
201
|
+
>
|
|
202
|
+
{revealing.value ? <EyeOff size={15} /> : <Eye size={15} />}
|
|
203
|
+
</button>
|
|
204
|
+
</span>
|
|
205
|
+
)}
|
|
166
206
|
</div>
|
|
167
207
|
{props.error ? (
|
|
168
208
|
<p class="hk-input-error-msg">{props.error}</p>
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { computed, defineComponent, ref, watch, type PropType } from "vue";
|
|
2
2
|
|
|
3
|
+
import { useI18n } from "../i18n/context";
|
|
4
|
+
|
|
3
5
|
import "./HkKeywordSearchModal.scss";
|
|
4
6
|
import HModal from "./HkModal";
|
|
5
7
|
import { scheduleCronAfter, type CronHandle } from "../runtime/cronBus";
|
|
@@ -115,6 +117,7 @@ export default defineComponent({
|
|
|
115
117
|
select: (_rec: unknown) => true,
|
|
116
118
|
},
|
|
117
119
|
setup(props, { slots, emit }) {
|
|
120
|
+
const { t } = useI18n();
|
|
118
121
|
const query = ref("");
|
|
119
122
|
let debounceTimer: CronHandle | null = null;
|
|
120
123
|
const debouncedQuery = ref("");
|
|
@@ -190,7 +193,7 @@ export default defineComponent({
|
|
|
190
193
|
<HModal
|
|
191
194
|
modelValue={props.modelValue}
|
|
192
195
|
onUpdate:modelValue={(v: boolean) => emit("update:modelValue", v)}
|
|
193
|
-
title={props.title ?? "Search"}
|
|
196
|
+
title={props.title ?? t("hk.keywordSearch.title", "Search")}
|
|
194
197
|
width="40rem"
|
|
195
198
|
>
|
|
196
199
|
<div class="hk-kw-search">
|
|
@@ -212,7 +215,7 @@ export default defineComponent({
|
|
|
212
215
|
class="hk-kw-search-input"
|
|
213
216
|
type="text"
|
|
214
217
|
value={query.value}
|
|
215
|
-
placeholder={props.placeholder ?? "Search…"}
|
|
218
|
+
placeholder={props.placeholder ?? t("hk.keywordSearch.placeholder", "Search…")}
|
|
216
219
|
onInput={(e: Event) => { query.value = (e.target as HTMLInputElement).value; }}
|
|
217
220
|
autofocus
|
|
218
221
|
/>
|
|
@@ -220,7 +223,7 @@ export default defineComponent({
|
|
|
220
223
|
<button
|
|
221
224
|
class="hk-kw-search-clear"
|
|
222
225
|
type="button"
|
|
223
|
-
aria-label="Clear"
|
|
226
|
+
aria-label={t("hk.keywordSearch.clear", "Clear")}
|
|
224
227
|
onClick={() => {
|
|
225
228
|
query.value = "";
|
|
226
229
|
debouncedQuery.value = "";
|
|
@@ -247,13 +250,13 @@ export default defineComponent({
|
|
|
247
250
|
{semanticActive.value ? (
|
|
248
251
|
semanticLoading.value && semanticResults.value.length === 0 ? (
|
|
249
252
|
<div class="hk-kw-search-empty">
|
|
250
|
-
{props.searchingText ?? "Searching…"}
|
|
253
|
+
{props.searchingText ?? t("hk.keywordSearch.searching", "Searching…")}
|
|
251
254
|
</div>
|
|
252
255
|
) : semanticResults.value.length === 0 ? (
|
|
253
256
|
<div class="hk-kw-search-empty">
|
|
254
257
|
{debouncedQuery.value
|
|
255
|
-
? (props.emptyText ?? "No matches")
|
|
256
|
-
: (props.placeholder ?? "Search…")}
|
|
258
|
+
? (props.emptyText ?? t("hk.keywordSearch.noMatches", "No matches"))
|
|
259
|
+
: (props.placeholder ?? t("hk.keywordSearch.placeholder", "Search…"))}
|
|
257
260
|
</div>
|
|
258
261
|
) : (
|
|
259
262
|
semanticResults.value.map((r) => (
|
|
@@ -286,7 +289,7 @@ export default defineComponent({
|
|
|
286
289
|
)
|
|
287
290
|
) : results.value.length === 0 ? (
|
|
288
291
|
<div class="hk-kw-search-empty">
|
|
289
|
-
{props.emptyText ?? "No matches"}
|
|
292
|
+
{props.emptyText ?? t("hk.keywordSearch.noMatches", "No matches")}
|
|
290
293
|
</div>
|
|
291
294
|
) : (
|
|
292
295
|
results.value.map((r) => (
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { defineComponent, ref, type PropType } from "vue";
|
|
2
|
+
|
|
3
|
+
export interface LocaleOption {
|
|
4
|
+
code: string;
|
|
5
|
+
label: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const HkLocalePicker = defineComponent({
|
|
9
|
+
name: "HkLocalePicker",
|
|
10
|
+
props: {
|
|
11
|
+
locales: {
|
|
12
|
+
type: Array as PropType<LocaleOption[]>,
|
|
13
|
+
default: () => [],
|
|
14
|
+
},
|
|
15
|
+
currentLocale: {
|
|
16
|
+
type: String,
|
|
17
|
+
default: "en",
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
emits: ["select"],
|
|
21
|
+
setup(props, { emit }) {
|
|
22
|
+
const open = ref(false);
|
|
23
|
+
|
|
24
|
+
function handleSelect(code: string) {
|
|
25
|
+
emit("select", code);
|
|
26
|
+
open.value = false;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return () => (
|
|
30
|
+
<div style={{ position: "relative" }}>
|
|
31
|
+
<button
|
|
32
|
+
type="button"
|
|
33
|
+
style={{
|
|
34
|
+
display: "inline-flex",
|
|
35
|
+
alignItems: "center",
|
|
36
|
+
gap: "0.25rem",
|
|
37
|
+
padding: "0.25rem 0.5rem",
|
|
38
|
+
border: "1px solid var(--border-faint, rgb(var(--color-border) / 10%))",
|
|
39
|
+
borderRadius: "var(--radius-sm, 4px)",
|
|
40
|
+
background: "transparent",
|
|
41
|
+
color: "rgb(var(--color-muted))",
|
|
42
|
+
fontSize: "0.75rem",
|
|
43
|
+
fontWeight: 500,
|
|
44
|
+
cursor: "pointer",
|
|
45
|
+
transition: "background 0.15s",
|
|
46
|
+
}}
|
|
47
|
+
onClick={() => (open.value = !open.value)}
|
|
48
|
+
onBlur={() => setTimeout(() => (open.value = false), 150)}
|
|
49
|
+
>
|
|
50
|
+
{props.currentLocale.toUpperCase()}
|
|
51
|
+
<svg width="10" height="10" viewBox="0 0 10 10" style={{ opacity: 0.5 }}>
|
|
52
|
+
<path d="M2 3.5l3 3 3-3" fill="none" stroke="currentColor" stroke-width="1.2" />
|
|
53
|
+
</svg>
|
|
54
|
+
</button>
|
|
55
|
+
{open.value && (
|
|
56
|
+
<div
|
|
57
|
+
style={{
|
|
58
|
+
position: "absolute",
|
|
59
|
+
top: "calc(100% + 4px)",
|
|
60
|
+
right: 0,
|
|
61
|
+
minWidth: "120px",
|
|
62
|
+
background: "rgb(var(--color-surface))",
|
|
63
|
+
border: "1px solid var(--border-faint, rgb(var(--color-border) / 10%))",
|
|
64
|
+
borderRadius: "var(--radius-md, 6px)",
|
|
65
|
+
boxShadow: "0 4px 16px rgb(0 0 0 / 12%)",
|
|
66
|
+
zIndex: 1000,
|
|
67
|
+
overflow: "hidden",
|
|
68
|
+
padding: "4px",
|
|
69
|
+
}}
|
|
70
|
+
>
|
|
71
|
+
{props.locales.map((loc) => (
|
|
72
|
+
<button
|
|
73
|
+
key={loc.code}
|
|
74
|
+
type="button"
|
|
75
|
+
style={{
|
|
76
|
+
display: "flex",
|
|
77
|
+
alignItems: "center",
|
|
78
|
+
width: "100%",
|
|
79
|
+
padding: "6px 10px",
|
|
80
|
+
border: "none",
|
|
81
|
+
borderRadius: "4px",
|
|
82
|
+
background: loc.code === props.currentLocale
|
|
83
|
+
? "var(--c-primary-subtle, rgb(var(--color-primary) / 8%))"
|
|
84
|
+
: "transparent",
|
|
85
|
+
color: loc.code === props.currentLocale
|
|
86
|
+
? "var(--c-primary, rgb(var(--color-primary)))"
|
|
87
|
+
: "rgb(var(--color-text))",
|
|
88
|
+
fontSize: "0.75rem",
|
|
89
|
+
cursor: "pointer",
|
|
90
|
+
textAlign: "left",
|
|
91
|
+
transition: "background 0.1s",
|
|
92
|
+
}}
|
|
93
|
+
onMouseenter={(e: MouseEvent) => {
|
|
94
|
+
if (loc.code !== props.currentLocale) {
|
|
95
|
+
(e.currentTarget as HTMLElement).style.background = "var(--c-primary-overlay, rgb(var(--color-primary) / 15%))";
|
|
96
|
+
}
|
|
97
|
+
}}
|
|
98
|
+
onMouseleave={(e: MouseEvent) => {
|
|
99
|
+
if (loc.code !== props.currentLocale) {
|
|
100
|
+
(e.currentTarget as HTMLElement).style.background = "transparent";
|
|
101
|
+
}
|
|
102
|
+
}}
|
|
103
|
+
onMousedown={() => handleSelect(loc.code)}
|
|
104
|
+
>
|
|
105
|
+
{loc.label}
|
|
106
|
+
</button>
|
|
107
|
+
))}
|
|
108
|
+
</div>
|
|
109
|
+
)}
|
|
110
|
+
</div>
|
|
111
|
+
);
|
|
112
|
+
},
|
|
113
|
+
});
|