@hkdigital/lib-core 0.4.6 → 0.4.8
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 +23 -2
- package/dist/design/README.md +120 -0
- package/dist/logging/README.md +5 -9
- package/dist/logging/internal/adapters/pino.d.ts +2 -1
- package/package.json +33 -31
- package/dist/ui/dev/explorer/Explorer.svelte +0 -300
- package/dist/ui/dev/explorer/Explorer.svelte.d.ts +0 -20
- package/dist/ui/dev/explorer/TopBar.svelte +0 -82
- package/dist/ui/dev/explorer/TopBar.svelte.d.ts +0 -14
- package/dist/ui/dev/explorer/index.d.ts +0 -2
- package/dist/ui/dev/explorer/index.js +0 -8
- package/dist/ui/dev/explorer/topbar.css +0 -30
package/README.md
CHANGED
|
@@ -21,12 +21,15 @@ pnpm add -D --save-peer @hkdigital/lib-core
|
|
|
21
21
|
|
|
22
22
|
### Peer Dependencies
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
**For projects/applications**, install peer dependencies:
|
|
25
25
|
```bash
|
|
26
26
|
# Core framework and utilities
|
|
27
27
|
pnpm add @sveltejs/kit svelte svelte-preprocess runed valibot
|
|
28
28
|
|
|
29
|
-
# UI
|
|
29
|
+
# UI framework and components
|
|
30
|
+
pnpm add @skeletonlabs/skeleton
|
|
31
|
+
|
|
32
|
+
# UI icons
|
|
30
33
|
pnpm add @steeze-ui/heroicons
|
|
31
34
|
|
|
32
35
|
# Logging
|
|
@@ -34,6 +37,15 @@ pnpm add pino pino-pretty
|
|
|
34
37
|
|
|
35
38
|
# Linting
|
|
36
39
|
pnpm add @eslint/js eslint-plugin-import
|
|
40
|
+
|
|
41
|
+
# Image processing
|
|
42
|
+
pnpm add vite-imagetools
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**For other libraries**, install as dev dependencies and declare as peer dependencies:
|
|
46
|
+
```bash
|
|
47
|
+
# Install as dev dependencies and peer dependencies
|
|
48
|
+
pnpm add -D --save-peer @sveltejs/kit svelte svelte-preprocess runed valibot @skeletonlabs/skeleton @steeze-ui/heroicons pino pino-pretty @eslint/js eslint-plugin-import vite-imagetools
|
|
37
49
|
```
|
|
38
50
|
|
|
39
51
|
### Design System & Configuration
|
|
@@ -120,9 +132,18 @@ This library includes a complete design system with Tailwind CSS integration. Ba
|
|
|
120
132
|
export default config;
|
|
121
133
|
```
|
|
122
134
|
|
|
135
|
+
### Logging System
|
|
136
|
+
|
|
137
|
+
The library includes a comprehensive logging system that provides:
|
|
138
|
+
|
|
139
|
+
- **Server-side**: Structured JSON logging with pino and beautiful terminal formatting via pino-pretty
|
|
140
|
+
- **Client-side**: Enhanced console logging with structured data display in browser inspector
|
|
141
|
+
- **Consistent API**: Same logging interface for both server and client environments
|
|
142
|
+
|
|
123
143
|
For detailed setup guides see:
|
|
124
144
|
- **Design system**: [src/lib/design/README.md](./src/lib/design/README.md)
|
|
125
145
|
- **Vite configuration**: [src/lib/config/README.md](./src/lib/config/README.md)
|
|
146
|
+
- **Logging system**: [src/lib/logging/README.md](./src/lib/logging/README.md)
|
|
126
147
|
|
|
127
148
|
### Update
|
|
128
149
|
|
package/dist/design/README.md
CHANGED
|
@@ -48,6 +48,126 @@ export default {
|
|
|
48
48
|
{@render children()}
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
+
## CSS Architecture & app.css
|
|
52
|
+
|
|
53
|
+
### Overview
|
|
54
|
+
|
|
55
|
+
The design system is orchestrated through `src/app.css`, which serves as the central CSS coordination file. Understanding its structure is essential for proper integration and troubleshooting.
|
|
56
|
+
|
|
57
|
+
### app.css Structure
|
|
58
|
+
|
|
59
|
+
When using this design system in your project, your `src/app.css` should follow this structure:
|
|
60
|
+
|
|
61
|
+
```css
|
|
62
|
+
/* your-project/src/app.css */
|
|
63
|
+
|
|
64
|
+
/* 1. CSS Layers - Controls style precedence */
|
|
65
|
+
@layer theme, base, utilities, components;
|
|
66
|
+
|
|
67
|
+
/* 2. Tailwind CSS Core */
|
|
68
|
+
@import 'tailwindcss';
|
|
69
|
+
|
|
70
|
+
/* 3. HKdigital Design System Theme */
|
|
71
|
+
@import '../node_modules/@hkdigital/lib-core/dist/design/themes/hkdev/theme.css' layer(theme);
|
|
72
|
+
/*@import '../node_modules/@hkdigital/lib-core/dist/design/themes/hkdev/debug.css';*/
|
|
73
|
+
@import '../node_modules/@hkdigital/lib-core/dist/design/themes/hkdev/globals.css';
|
|
74
|
+
@import '../node_modules/@hkdigital/lib-core/dist/design/themes/hkdev/components.css' layer(components);
|
|
75
|
+
@import '../node_modules/@hkdigital/lib-core/dist/design/themes/hkdev/responsive.css';
|
|
76
|
+
|
|
77
|
+
/* 4. Skeleton UI Framework */
|
|
78
|
+
@import '@skeletonlabs/skeleton' source('../node_modules/@skeletonlabs/skeleton-svelte/dist');
|
|
79
|
+
@import '@skeletonlabs/skeleton/optional/presets' source('../node_modules/@skeletonlabs/skeleton-svelte/dist');
|
|
80
|
+
|
|
81
|
+
/* 5. Tailwind Configuration Reference */
|
|
82
|
+
@config "../tailwind.config.js";
|
|
83
|
+
|
|
84
|
+
/* 6. Optional HKdigital Utilities */
|
|
85
|
+
/*@import '../node_modules/@hkdigital/lib-core/dist/css/utilities.css';*/
|
|
86
|
+
|
|
87
|
+
/* 7. Optional Project-specific CSS */
|
|
88
|
+
/*@import './css/custom.css';*/
|
|
89
|
+
|
|
90
|
+
/* 8. Optional Font Imports */
|
|
91
|
+
/*@import url(/fonts/unbounded/unbounded.css);
|
|
92
|
+
@import url(/fonts/mulish/mulish.css);*/
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**Available Optional Imports**:
|
|
96
|
+
- **Debug styles**: `debug.css` - Development debugging helpers
|
|
97
|
+
- **Additional utilities**: `utilities.css` - Extra utility classes beyond Tailwind
|
|
98
|
+
- **Custom fonts**: Project-specific typography files
|
|
99
|
+
|
|
100
|
+
**Path Structure**: All HKdigital lib-core imports use the `../node_modules/@hkdigital/lib-core/dist/` prefix for consuming projects.
|
|
101
|
+
|
|
102
|
+
### CSS Layer System
|
|
103
|
+
|
|
104
|
+
The `@layer` directive ensures proper style precedence:
|
|
105
|
+
|
|
106
|
+
1. **theme**: Design system color tokens and CSS variables
|
|
107
|
+
2. **base**: Reset styles, typography defaults
|
|
108
|
+
3. **utilities**: Tailwind utility classes (spacing, colors, etc.)
|
|
109
|
+
4. **components**: Component-specific styling
|
|
110
|
+
|
|
111
|
+
This layering prevents style conflicts and ensures predictable cascade behavior.
|
|
112
|
+
|
|
113
|
+
### Key Roles
|
|
114
|
+
|
|
115
|
+
**Central Reference Point**:
|
|
116
|
+
- External CSS files use `@reference '../../app.css'` to access design system utilities
|
|
117
|
+
- Provides single source of truth for all CSS dependencies
|
|
118
|
+
|
|
119
|
+
**Design System Integration**:
|
|
120
|
+
- Loads theme CSS files that define design tokens as CSS custom properties
|
|
121
|
+
- Integrates with `tailwind.config.js` via `@config` directive
|
|
122
|
+
- Enables responsive scaling system through imported theme files
|
|
123
|
+
|
|
124
|
+
**Framework Coordination**:
|
|
125
|
+
- Combines Tailwind CSS utilities with Skeleton UI components
|
|
126
|
+
- Manages style precedence through layer system
|
|
127
|
+
- Ensures consistent styling across the entire application
|
|
128
|
+
|
|
129
|
+
### Common Integration Points
|
|
130
|
+
|
|
131
|
+
**In SvelteKit Layout**:
|
|
132
|
+
```javascript
|
|
133
|
+
// src/routes/+layout.svelte
|
|
134
|
+
import '../app.css'; // Loads entire design system
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
**In Tailwind Config**:
|
|
138
|
+
```javascript
|
|
139
|
+
// tailwind.config.js
|
|
140
|
+
// References app.css through @config directive
|
|
141
|
+
export default {
|
|
142
|
+
content: ['./src/**/*.{html,js,svelte}'],
|
|
143
|
+
// ... theme extensions from design tokens
|
|
144
|
+
};
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**For External CSS**:
|
|
148
|
+
```css
|
|
149
|
+
/* any-external-file.css */
|
|
150
|
+
@reference '../../app.css'; /* Path to app.css */
|
|
151
|
+
|
|
152
|
+
.my-component {
|
|
153
|
+
@apply p-20up bg-surface-300; /* Now accessible */
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Troubleshooting
|
|
158
|
+
|
|
159
|
+
**Build Errors with External CSS**:
|
|
160
|
+
- Missing `@reference` directive → Add `@reference` with correct path to app.css
|
|
161
|
+
- Wrong path in `@reference` → Verify relative path from CSS file to `src/app.css`
|
|
162
|
+
|
|
163
|
+
**Style Precedence Issues**:
|
|
164
|
+
- Custom styles being overridden → Check CSS layer placement
|
|
165
|
+
- Theme variables not available → Ensure proper import order in app.css
|
|
166
|
+
|
|
167
|
+
**Design System Classes Not Working**:
|
|
168
|
+
- Classes not generated → Verify `tailwind.config.js` references correct design tokens
|
|
169
|
+
- CSS custom properties missing → Check theme files are properly imported
|
|
170
|
+
|
|
51
171
|
## Using Design System Classes in External CSS
|
|
52
172
|
|
|
53
173
|
When using design system utilities like `p-16up`, `bg-surface-300`, or `border-primary-500` in external CSS files (loaded via `<style src="./style.css"></style>`), you **must** include the `@reference` directive at the top of your CSS file.
|
package/dist/logging/README.md
CHANGED
|
@@ -12,8 +12,7 @@ pnpm add -D pino-pretty
|
|
|
12
12
|
|
|
13
13
|
```javascript
|
|
14
14
|
import { createServerLogger,
|
|
15
|
-
createClientLogger
|
|
16
|
-
createLogger } from '@hkdigital/lib-core/logging/index.js';
|
|
15
|
+
createClientLogger } from '@hkdigital/lib-core/logging/index.js';
|
|
17
16
|
|
|
18
17
|
// Server-side logging (uses pino)
|
|
19
18
|
const serverLogger = createServerLogger('app');
|
|
@@ -21,14 +20,11 @@ const serverLogger = createServerLogger('app');
|
|
|
21
20
|
// Client-side logging (uses console)
|
|
22
21
|
const clientLogger = createClientLogger('app');
|
|
23
22
|
|
|
24
|
-
// Universal logger (works on both server and client)
|
|
25
|
-
const logger = createLogger('app');
|
|
26
|
-
|
|
27
23
|
// Log at different levels
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
24
|
+
serverLogger.debug('Debug info', { data: 'details' });
|
|
25
|
+
serverLogger.info('Info message');
|
|
26
|
+
serverLogger.warn('Warning message');
|
|
27
|
+
serverLogger.error('Error message', { error: new Error('Something went wrong') });
|
|
32
28
|
```
|
|
33
29
|
|
|
34
30
|
## SvelteKit Integration
|
|
@@ -8,7 +8,7 @@ export class PinoAdapter {
|
|
|
8
8
|
* @param {Object} [options] - Pino configuration options
|
|
9
9
|
*/
|
|
10
10
|
constructor(options?: any);
|
|
11
|
-
pino:
|
|
11
|
+
pino: pino.Logger<never, boolean>;
|
|
12
12
|
/**
|
|
13
13
|
* Handle log events from Logger
|
|
14
14
|
*
|
|
@@ -24,3 +24,4 @@ export class PinoAdapter {
|
|
|
24
24
|
child(context: any): PinoAdapter;
|
|
25
25
|
#private;
|
|
26
26
|
}
|
|
27
|
+
import pino from 'pino';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hkdigital/lib-core",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.8",
|
|
4
4
|
"author": {
|
|
5
5
|
"name": "HKdigital",
|
|
6
6
|
"url": "https://hkdigital.nl"
|
|
@@ -73,6 +73,7 @@
|
|
|
73
73
|
},
|
|
74
74
|
"peerDependencies": {
|
|
75
75
|
"@eslint/js": "^9.28.0",
|
|
76
|
+
"@skeletonlabs/skeleton": "^3.1.7",
|
|
76
77
|
"@steeze-ui/heroicons": "^2.4.2",
|
|
77
78
|
"@sveltejs/kit": "^2.21.2",
|
|
78
79
|
"eslint-plugin-import": "^2.31.0",
|
|
@@ -81,49 +82,50 @@
|
|
|
81
82
|
"runed": "^0.23.1",
|
|
82
83
|
"svelte": "^5.33.16",
|
|
83
84
|
"svelte-preprocess": "^6.0.3",
|
|
84
|
-
"valibot": "^1.1.0"
|
|
85
|
+
"valibot": "^1.1.0",
|
|
86
|
+
"vite-imagetools": "^8.0.0"
|
|
85
87
|
},
|
|
86
88
|
"devDependencies": {
|
|
87
|
-
"@eslint/js": "^9.
|
|
88
|
-
"@playwright/test": "^1.
|
|
89
|
-
"@skeletonlabs/skeleton": "3.
|
|
90
|
-
"@skeletonlabs/skeleton-svelte": "1.
|
|
89
|
+
"@eslint/js": "^9.33.0",
|
|
90
|
+
"@playwright/test": "^1.54.2",
|
|
91
|
+
"@skeletonlabs/skeleton": "3.1.7",
|
|
92
|
+
"@skeletonlabs/skeleton-svelte": "1.3.1",
|
|
91
93
|
"@steeze-ui/heroicons": "^2.4.2",
|
|
92
|
-
"@sveltejs/adapter-auto": "^6.0
|
|
93
|
-
"@sveltejs/package": "^2.
|
|
94
|
-
"@sveltejs/vite-plugin-svelte": "^
|
|
94
|
+
"@sveltejs/adapter-auto": "^6.1.0",
|
|
95
|
+
"@sveltejs/package": "^2.4.1",
|
|
96
|
+
"@sveltejs/vite-plugin-svelte": "^6.1.1",
|
|
95
97
|
"@tailwindcss/typography": "^0.5.16",
|
|
96
|
-
"@testing-library/svelte": "^5.2.
|
|
98
|
+
"@testing-library/svelte": "^5.2.8",
|
|
97
99
|
"@testing-library/user-event": "^14.6.1",
|
|
98
100
|
"@types/eslint": "^9.6.1",
|
|
99
101
|
"@types/node": "^24.2.1",
|
|
100
102
|
"autoprefixer": "^10.4.21",
|
|
101
|
-
"eslint": "^9.
|
|
102
|
-
"eslint-config-prettier": "^10.1.
|
|
103
|
-
"eslint-plugin-import": "^2.
|
|
104
|
-
"eslint-plugin-svelte": "^3.
|
|
105
|
-
"fake-indexeddb": "^6.
|
|
106
|
-
"globals": "^16.
|
|
103
|
+
"eslint": "^9.33.0",
|
|
104
|
+
"eslint-config-prettier": "^10.1.8",
|
|
105
|
+
"eslint-plugin-import": "^2.32.0",
|
|
106
|
+
"eslint-plugin-svelte": "^3.11.0",
|
|
107
|
+
"fake-indexeddb": "^6.1.0",
|
|
108
|
+
"globals": "^16.3.0",
|
|
107
109
|
"jsdom": "^26.1.0",
|
|
108
|
-
"npm-check-updates": "^18.0.
|
|
110
|
+
"npm-check-updates": "^18.0.2",
|
|
109
111
|
"npm-run-all": "^4.1.5",
|
|
110
|
-
"pino": "^9.
|
|
111
|
-
"pino-pretty": "^13.
|
|
112
|
-
"postcss": "^8.5.
|
|
113
|
-
"postcss-mixins": "^
|
|
114
|
-
"prettier": "^3.
|
|
112
|
+
"pino": "^9.8.0",
|
|
113
|
+
"pino-pretty": "^13.1.1",
|
|
114
|
+
"postcss": "^8.5.6",
|
|
115
|
+
"postcss-mixins": "^12.1.2",
|
|
116
|
+
"prettier": "^3.6.2",
|
|
115
117
|
"prettier-plugin-svelte": "^3.4.0",
|
|
116
|
-
"prettier-plugin-tailwindcss": "^0.6.
|
|
118
|
+
"prettier-plugin-tailwindcss": "^0.6.14",
|
|
117
119
|
"publint": "^0.3.12",
|
|
118
|
-
"standardized-audio-context-mock": "^9.7.
|
|
119
|
-
"svelte": "^5.
|
|
120
|
-
"svelte-check": "^4.
|
|
120
|
+
"standardized-audio-context-mock": "^9.7.24",
|
|
121
|
+
"svelte": "^5.38.1",
|
|
122
|
+
"svelte-check": "^4.3.1",
|
|
121
123
|
"svelte-preprocess": "^6.0.3",
|
|
122
|
-
"tailwindcss": "^4.1.
|
|
123
|
-
"typescript": "^5.
|
|
124
|
-
"vite": "^
|
|
125
|
-
"vite-imagetools": "^
|
|
126
|
-
"vitest": "^3.2.
|
|
124
|
+
"tailwindcss": "^4.1.11",
|
|
125
|
+
"typescript": "^5.9.2",
|
|
126
|
+
"vite": "^7.1.2",
|
|
127
|
+
"vite-imagetools": "^8.0.0",
|
|
128
|
+
"vitest": "^3.2.4"
|
|
127
129
|
},
|
|
128
130
|
"dependencies": {
|
|
129
131
|
"@tailwindcss/postcss": "^4.1.11"
|
|
@@ -1,300 +0,0 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
import { goto } from '$app/navigation';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Reusable explorer component for navigating nested folder structures
|
|
6
|
-
* @type {{
|
|
7
|
-
* navigationData: Object,
|
|
8
|
-
* currentPath: string,
|
|
9
|
-
* getActiveSegments?: (segments: string[]) => void,
|
|
10
|
-
* getNavigateToLevelFunction?: (fn: Function) => void,
|
|
11
|
-
* rootName?: string,
|
|
12
|
-
* folderName?: string
|
|
13
|
-
* }}
|
|
14
|
-
*/
|
|
15
|
-
let {
|
|
16
|
-
navigationData,
|
|
17
|
-
currentPath = '',
|
|
18
|
-
getActiveSegments,
|
|
19
|
-
getNavigateToLevelFunction,
|
|
20
|
-
rootName = 'Categories',
|
|
21
|
-
folderName
|
|
22
|
-
} = $props();
|
|
23
|
-
|
|
24
|
-
/** @type {string[]} */
|
|
25
|
-
let pathSegments = $derived(
|
|
26
|
-
currentPath ? currentPath.split('/').filter(Boolean) : []
|
|
27
|
-
);
|
|
28
|
-
|
|
29
|
-
/** @type {string[]} */
|
|
30
|
-
let interactiveSegments = $state([]);
|
|
31
|
-
|
|
32
|
-
/** @type {string[]} */
|
|
33
|
-
let activeSegments = $derived(
|
|
34
|
-
interactiveSegments.length > 0 ? interactiveSegments : pathSegments
|
|
35
|
-
);
|
|
36
|
-
|
|
37
|
-
// Notify parent of active segments changes - only when they change
|
|
38
|
-
let lastActiveSegments = [];
|
|
39
|
-
$effect(() => {
|
|
40
|
-
if (
|
|
41
|
-
getActiveSegments &&
|
|
42
|
-
JSON.stringify(activeSegments) !== JSON.stringify(lastActiveSegments)
|
|
43
|
-
) {
|
|
44
|
-
lastActiveSegments = [...activeSegments];
|
|
45
|
-
getActiveSegments(activeSegments);
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
/** @type {Object[]} */
|
|
50
|
-
let breadcrumbColumns = $derived.by(() => {
|
|
51
|
-
const columns = [];
|
|
52
|
-
let current = navigationData;
|
|
53
|
-
|
|
54
|
-
// Root column with sorted items (folders first, then endpoints)
|
|
55
|
-
const rootItems = Object.values(current).map((item) => ({
|
|
56
|
-
name: item.name,
|
|
57
|
-
displayName: item.displayName || item.name,
|
|
58
|
-
isEndpoint: item.isEndpoint,
|
|
59
|
-
isSelected: activeSegments.length > 0 &&
|
|
60
|
-
activeSegments[0] === item.name
|
|
61
|
-
})).sort((a, b) => {
|
|
62
|
-
// Sort by type first (folders before endpoints)
|
|
63
|
-
if (a.isEndpoint !== b.isEndpoint) {
|
|
64
|
-
return a.isEndpoint ? 1 : -1;
|
|
65
|
-
}
|
|
66
|
-
// Then sort alphabetically by display name
|
|
67
|
-
return a.displayName.localeCompare(b.displayName);
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
columns.push({
|
|
71
|
-
title: rootName,
|
|
72
|
-
items: rootItems,
|
|
73
|
-
level: 0
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
// Build columns for each path segment
|
|
77
|
-
for (let i = 0; i < activeSegments.length; i++) {
|
|
78
|
-
const segment = activeSegments[i];
|
|
79
|
-
|
|
80
|
-
if (current[segment]) {
|
|
81
|
-
current = current[segment].children;
|
|
82
|
-
|
|
83
|
-
if (Object.keys(current).length > 0) {
|
|
84
|
-
const nextSegment = activeSegments[i + 1];
|
|
85
|
-
|
|
86
|
-
// Sort nested items (folders first, then endpoints)
|
|
87
|
-
const nestedItems = Object.values(current).map((item) => ({
|
|
88
|
-
name: item.name,
|
|
89
|
-
displayName: item.displayName || item.name,
|
|
90
|
-
isEndpoint: item.isEndpoint,
|
|
91
|
-
isSelected: nextSegment === item.name
|
|
92
|
-
})).sort((a, b) => {
|
|
93
|
-
// Sort by type first (folders before endpoints)
|
|
94
|
-
if (a.isEndpoint !== b.isEndpoint) {
|
|
95
|
-
return a.isEndpoint ? 1 : -1;
|
|
96
|
-
}
|
|
97
|
-
// Then sort alphabetically by display name
|
|
98
|
-
return a.displayName.localeCompare(b.displayName);
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
columns.push({
|
|
102
|
-
title: segment,
|
|
103
|
-
items: nestedItems,
|
|
104
|
-
level: i + 1
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
return columns;
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Handle navigation to a folder or endpoint
|
|
115
|
-
* @param {number} level - Column level
|
|
116
|
-
* @param {string} itemName - Item name
|
|
117
|
-
* @param {boolean} isEndpoint - Whether this is a final endpoint
|
|
118
|
-
*/
|
|
119
|
-
function handleNavigation(level, itemName, isEndpoint) {
|
|
120
|
-
// Build new path segments up to the selected level
|
|
121
|
-
const newSegments = [...activeSegments.slice(0, level), itemName];
|
|
122
|
-
const fullPath = newSegments.join('/');
|
|
123
|
-
|
|
124
|
-
// Always navigate to explorer URL - let the route system handle state
|
|
125
|
-
goto(`/explorer/${folderName}/${fullPath}`);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Handle breadcrumb navigation
|
|
130
|
-
* @param {number} level - Level to navigate back to
|
|
131
|
-
*/
|
|
132
|
-
function navigateToLevel(level) {
|
|
133
|
-
if (level === 0) {
|
|
134
|
-
// Navigate back to root explorer
|
|
135
|
-
goto('/explorer');
|
|
136
|
-
} else {
|
|
137
|
-
// Navigate to specific level
|
|
138
|
-
const currentSegments =
|
|
139
|
-
interactiveSegments.length > 0 ? interactiveSegments : pathSegments;
|
|
140
|
-
const newSegments = currentSegments.slice(0, level);
|
|
141
|
-
const explorerPath = newSegments.join('/');
|
|
142
|
-
goto(`/explorer/${folderName}/${explorerPath}`);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// Expose the navigate function to parent
|
|
147
|
-
if (getNavigateToLevelFunction) {
|
|
148
|
-
getNavigateToLevelFunction(navigateToLevel);
|
|
149
|
-
}
|
|
150
|
-
</script>
|
|
151
|
-
|
|
152
|
-
<div class="explorer-container">
|
|
153
|
-
<!-- Dynamic columns -->
|
|
154
|
-
<div class="navigation-columns">
|
|
155
|
-
{#each breadcrumbColumns as column, columnIndex}
|
|
156
|
-
<div class="column" data-column={`level-${column.level}`}>
|
|
157
|
-
<h2 class="type-heading-h2 mb-20up">{column.title}</h2>
|
|
158
|
-
<nav class="folder-list">
|
|
159
|
-
{#each column.items as item}
|
|
160
|
-
<button
|
|
161
|
-
class="folder-item"
|
|
162
|
-
class:active={item.isSelected}
|
|
163
|
-
class:endpoint={item.isEndpoint}
|
|
164
|
-
onclick={() =>
|
|
165
|
-
handleNavigation(column.level, item.name, item.isEndpoint)}
|
|
166
|
-
>
|
|
167
|
-
<div class="item-content">
|
|
168
|
-
<div class="item-icon">
|
|
169
|
-
{#if item.isEndpoint}
|
|
170
|
-
<svg
|
|
171
|
-
class="external-icon"
|
|
172
|
-
viewBox="0 0 16 16"
|
|
173
|
-
fill="currentColor"
|
|
174
|
-
aria-hidden="true"
|
|
175
|
-
>
|
|
176
|
-
<path d="M3.5 2A1.5 1.5 0 002 3.5v9A1.5 1.5 0 003.5 14h9a1.5 1.5 0 001.5-1.5V9.75a.75.75 0 00-1.5 0v2.75a.25.25 0 01-.25.25h-8.5a.25.25 0 01-.25-.25v-8.5a.25.25 0 01.25-.25H6.5a.75.75 0 000-1.5h-3z"/>
|
|
177
|
-
<path d="M15.25 1a.75.75 0 00-.75-.75h-4.5a.75.75 0 000 1.5h2.69l-6.22 6.22a.75.75 0 101.06 1.06L13.75 3.31v2.69a.75.75 0 001.5 0V1z"/>
|
|
178
|
-
</svg>
|
|
179
|
-
{:else}
|
|
180
|
-
<svg
|
|
181
|
-
class="folder-icon"
|
|
182
|
-
viewBox="0 0 16 16"
|
|
183
|
-
fill="currentColor"
|
|
184
|
-
aria-hidden="true"
|
|
185
|
-
>
|
|
186
|
-
<path d="M1.75 2A1.75 1.75 0 000 3.75v8.5C0 13.216.784 14 1.75 14h12.5A1.75 1.75 0 0016 12.25v-7.5A1.75 1.75 0 0014.25 3H7.5L6.25 1.75A.75.75 0 005.75 1.5h-4A1.75 1.75 0 000 3.25V3.75z"/>
|
|
187
|
-
</svg>
|
|
188
|
-
{/if}
|
|
189
|
-
</div>
|
|
190
|
-
<span class="item-name">{item.displayName}</span>
|
|
191
|
-
</div>
|
|
192
|
-
</button>
|
|
193
|
-
{/each}
|
|
194
|
-
|
|
195
|
-
{#if column.items.length === 0}
|
|
196
|
-
<div class="empty-state">
|
|
197
|
-
<p class="type-base-sm">No items found</p>
|
|
198
|
-
</div>
|
|
199
|
-
{/if}
|
|
200
|
-
</nav>
|
|
201
|
-
</div>
|
|
202
|
-
{/each}
|
|
203
|
-
</div>
|
|
204
|
-
</div>
|
|
205
|
-
|
|
206
|
-
<style>
|
|
207
|
-
.explorer-container {
|
|
208
|
-
padding: 20px;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
.navigation-columns {
|
|
212
|
-
display: grid;
|
|
213
|
-
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
|
214
|
-
gap: 30px;
|
|
215
|
-
align-items: start;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
.column {
|
|
219
|
-
min-height: 200px;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
.folder-list {
|
|
223
|
-
display: flex;
|
|
224
|
-
flex-direction: column;
|
|
225
|
-
gap: 4px;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
.folder-item {
|
|
229
|
-
display: block;
|
|
230
|
-
width: 100%;
|
|
231
|
-
padding: 12px 16px;
|
|
232
|
-
background: none;
|
|
233
|
-
border: none;
|
|
234
|
-
text-align: left;
|
|
235
|
-
cursor: pointer;
|
|
236
|
-
color: var(--color-surface-700);
|
|
237
|
-
transition: all 0.2s;
|
|
238
|
-
font-size: 14px;
|
|
239
|
-
line-height: 1.4;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
.folder-item:hover {
|
|
243
|
-
background-color: var(--color-surface-100);
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
.folder-item.active {
|
|
247
|
-
background-color: var(--color-primary-100);
|
|
248
|
-
color: var(--color-primary-700);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
.folder-item.endpoint:hover {
|
|
252
|
-
background-color: var(--color-primary-50);
|
|
253
|
-
color: var(--color-primary-600);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
.item-content {
|
|
257
|
-
display: flex;
|
|
258
|
-
align-items: center;
|
|
259
|
-
gap: 8px;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
.item-icon {
|
|
263
|
-
display: flex;
|
|
264
|
-
align-items: center;
|
|
265
|
-
width: 14px;
|
|
266
|
-
height: 14px;
|
|
267
|
-
flex-shrink: 0;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
.item-name {
|
|
271
|
-
flex: 1;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
.external-icon,
|
|
275
|
-
.folder-icon {
|
|
276
|
-
width: 14px;
|
|
277
|
-
height: 14px;
|
|
278
|
-
opacity: 0.6;
|
|
279
|
-
transition: opacity 0.2s;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
.folder-item:hover .external-icon,
|
|
283
|
-
.folder-item:hover .folder-icon {
|
|
284
|
-
opacity: 0.8;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
.folder-item.endpoint .external-icon {
|
|
288
|
-
color: var(--color-primary-600);
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
.folder-item .folder-icon {
|
|
292
|
-
color: var(--color-surface-500);
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
.empty-state {
|
|
296
|
-
padding: 20px;
|
|
297
|
-
text-align: center;
|
|
298
|
-
color: var(--color-surface-500);
|
|
299
|
-
}
|
|
300
|
-
</style>
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
export default Explorer;
|
|
2
|
-
type Explorer = {
|
|
3
|
-
$on?(type: string, callback: (e: any) => void): () => void;
|
|
4
|
-
$set?(props: Partial<{
|
|
5
|
-
navigationData: any;
|
|
6
|
-
currentPath: string;
|
|
7
|
-
getActiveSegments?: (segments: string[]) => void;
|
|
8
|
-
getNavigateToLevelFunction?: (fn: Function) => void;
|
|
9
|
-
rootName?: string;
|
|
10
|
-
folderName?: string;
|
|
11
|
-
}>): void;
|
|
12
|
-
};
|
|
13
|
-
declare const Explorer: import("svelte").Component<{
|
|
14
|
-
navigationData: any;
|
|
15
|
-
currentPath: string;
|
|
16
|
-
getActiveSegments?: (segments: string[]) => void;
|
|
17
|
-
getNavigateToLevelFunction?: (fn: Function) => void;
|
|
18
|
-
rootName?: string;
|
|
19
|
-
folderName?: string;
|
|
20
|
-
}, {}, "">;
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
import { enhance } from '$app/forms';
|
|
3
|
-
|
|
4
|
-
import { Panel } from '../../primitives.js';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* @type {{
|
|
8
|
-
* scalingEnabled: boolean,
|
|
9
|
-
* onchange?: (enabled: boolean) => void,
|
|
10
|
-
* crumblePath?: import('svelte').Snippet
|
|
11
|
-
* }}
|
|
12
|
-
*/
|
|
13
|
-
let { scalingEnabled = $bindable(), onchange, crumblePath } = $props();
|
|
14
|
-
</script>
|
|
15
|
-
|
|
16
|
-
<div class="examples-top-bar" data-component="top-bar">
|
|
17
|
-
<div class="container">
|
|
18
|
-
{#if crumblePath}
|
|
19
|
-
<div class="crumble-path">
|
|
20
|
-
{@render crumblePath()}
|
|
21
|
-
</div>
|
|
22
|
-
{/if}
|
|
23
|
-
|
|
24
|
-
<form
|
|
25
|
-
method="POST"
|
|
26
|
-
action="?/toggleScaling"
|
|
27
|
-
use:enhance={({ formData, cancel }) => {
|
|
28
|
-
const newValue = formData.get('scalingEnabled') === 'on';
|
|
29
|
-
scalingEnabled = newValue;
|
|
30
|
-
onchange?.(newValue);
|
|
31
|
-
|
|
32
|
-
return async ({ result }) => {
|
|
33
|
-
if (result.type === 'success') {
|
|
34
|
-
// Force page reload to apply scaling changes
|
|
35
|
-
window.location.reload();
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
}}
|
|
39
|
-
>
|
|
40
|
-
<label class="scaling-toggle">
|
|
41
|
-
<input
|
|
42
|
-
type="checkbox"
|
|
43
|
-
name="scalingEnabled"
|
|
44
|
-
bind:checked={scalingEnabled}
|
|
45
|
-
onchange={(e) => /** @type {HTMLInputElement} */ (e.target).form.requestSubmit()}
|
|
46
|
-
/>
|
|
47
|
-
<span class="type-ui-sm">Enable Design Scaling</span>
|
|
48
|
-
</label>
|
|
49
|
-
</form>
|
|
50
|
-
</div>
|
|
51
|
-
</div>
|
|
52
|
-
|
|
53
|
-
<style src="./topbar.css">@reference '../../../../app.css';
|
|
54
|
-
|
|
55
|
-
[data-component="top-bar"] {
|
|
56
|
-
@apply bg-surface-100 border-surface-300 sticky top-0 z-10;
|
|
57
|
-
@apply p-8ht;
|
|
58
|
-
|
|
59
|
-
& .container {
|
|
60
|
-
@apply max-w-screen-xl mx-auto flex justify-between items-center;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
& .scaling-toggle {
|
|
64
|
-
@apply flex items-center cursor-pointer;
|
|
65
|
-
@apply gap-8bt;
|
|
66
|
-
|
|
67
|
-
& input[type="checkbox"] {
|
|
68
|
-
@apply accent-primary-500;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
& .crumble-path {
|
|
73
|
-
@apply flex items-center;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/* Dark mode support */
|
|
78
|
-
@media (prefers-color-scheme: dark) {
|
|
79
|
-
[data-component="top-bar"] {
|
|
80
|
-
@apply bg-surface-800 border-surface-600;
|
|
81
|
-
}
|
|
82
|
-
}</style>
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export default TopBar;
|
|
2
|
-
type TopBar = {
|
|
3
|
-
$on?(type: string, callback: (e: any) => void): () => void;
|
|
4
|
-
$set?(props: Partial<{
|
|
5
|
-
scalingEnabled: boolean;
|
|
6
|
-
onchange?: (enabled: boolean) => void;
|
|
7
|
-
crumblePath?: Snippet<[]>;
|
|
8
|
-
}>): void;
|
|
9
|
-
};
|
|
10
|
-
declare const TopBar: import("svelte").Component<{
|
|
11
|
-
scalingEnabled: boolean;
|
|
12
|
-
onchange?: (enabled: boolean) => void;
|
|
13
|
-
crumblePath?: import("svelte").Snippet;
|
|
14
|
-
}, {}, "scalingEnabled">;
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
@reference '../../../../app.css';
|
|
2
|
-
|
|
3
|
-
[data-component="top-bar"] {
|
|
4
|
-
@apply bg-surface-100 border-surface-300 sticky top-0 z-10;
|
|
5
|
-
@apply p-8ht;
|
|
6
|
-
|
|
7
|
-
& .container {
|
|
8
|
-
@apply max-w-screen-xl mx-auto flex justify-between items-center;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
& .scaling-toggle {
|
|
12
|
-
@apply flex items-center cursor-pointer;
|
|
13
|
-
@apply gap-8bt;
|
|
14
|
-
|
|
15
|
-
& input[type="checkbox"] {
|
|
16
|
-
@apply accent-primary-500;
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
& .crumble-path {
|
|
21
|
-
@apply flex items-center;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/* Dark mode support */
|
|
26
|
-
@media (prefers-color-scheme: dark) {
|
|
27
|
-
[data-component="top-bar"] {
|
|
28
|
-
@apply bg-surface-800 border-surface-600;
|
|
29
|
-
}
|
|
30
|
-
}
|