@katlux/preset-modern 0.1.0-beta.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/LICENSE +21 -0
- package/README.md +133 -0
- package/build.config.ts +3 -0
- package/package.json +25 -0
- package/src/module.ts +48 -0
- package/src/runtime/assets/scss/css-variables.scss +175 -0
- package/src/runtime/assets/scss/index.scss +3 -0
- package/src/runtime/components/KBulkActions/KBulkActions.vue +72 -0
- package/src/runtime/components/KButton/KButton.vue +227 -0
- package/src/runtime/components/KCheckbox/KCheckbox.vue +136 -0
- package/src/runtime/components/KDatatable/KDatatable.vue +216 -0
- package/src/runtime/components/KMaskTextbox/KMaskTextbox.vue +126 -0
- package/src/runtime/components/KPagination/KPagination.vue +96 -0
- package/src/runtime/components/KRangeSlider/KRangeSlider.vue +201 -0
- package/src/runtime/components/KSlider/KSlider.vue +156 -0
- package/src/runtime/components/KTextarea/KTextarea.vue +52 -0
- package/src/runtime/components/KTextbox/KTextbox.vue +87 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026-present, The Katlux Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Modern Template - Component Summary
|
|
2
|
+
|
|
3
|
+
The modern template provides a fresh, contemporary design for KatluxToolkit components with gradients, smooth animations, and enhanced visual feedback.
|
|
4
|
+
|
|
5
|
+
## Supported Components
|
|
6
|
+
|
|
7
|
+
### ✅ KButton
|
|
8
|
+
- Gradient backgrounds for all button types
|
|
9
|
+
- Smooth hover lift animation
|
|
10
|
+
- Enhanced shadows for depth
|
|
11
|
+
- Icon slot support
|
|
12
|
+
- Custom animated loading spinner
|
|
13
|
+
|
|
14
|
+
### ✅ KCheckbox
|
|
15
|
+
- Gradient-filled checkmark on selection
|
|
16
|
+
- Smooth check animation with pop effect
|
|
17
|
+
- Hover glow effect
|
|
18
|
+
- Rounded corners
|
|
19
|
+
- Disabled state styling
|
|
20
|
+
|
|
21
|
+
### ✅ KTextbox
|
|
22
|
+
- Clean, minimal design
|
|
23
|
+
- Focus ring with brand color
|
|
24
|
+
- Animated clear button
|
|
25
|
+
- Smooth transitions
|
|
26
|
+
- Enhanced placeholder styling
|
|
27
|
+
|
|
28
|
+
### ✅ KTextarea
|
|
29
|
+
- Consistent styling with KTextbox
|
|
30
|
+
- Focus ring animation
|
|
31
|
+
- Smooth border transitions
|
|
32
|
+
- Comfortable padding
|
|
33
|
+
- Disabled state support
|
|
34
|
+
|
|
35
|
+
## Design Features
|
|
36
|
+
|
|
37
|
+
### Color Palette
|
|
38
|
+
- Primary: `#667eea` → `#764ba2` (gradient)
|
|
39
|
+
- Focus ring: `rgba(102, 126, 234, 0.1)`
|
|
40
|
+
- Borders: `#e5e7eb` (default), `#667eea` (focus)
|
|
41
|
+
- Text: `#1f2937` (primary), `#9ca3af` (placeholder)
|
|
42
|
+
|
|
43
|
+
### Animations
|
|
44
|
+
- Cubic-bezier easing: `cubic-bezier(0.4, 0, 0.2, 1)`
|
|
45
|
+
- Transition duration: `0.3s` (standard), `0.2s` (quick)
|
|
46
|
+
- Transform effects: lift, scale, pop
|
|
47
|
+
|
|
48
|
+
### Spacing
|
|
49
|
+
- Border radius: `10-14px` (depending on component)
|
|
50
|
+
- Padding: `12-16px`
|
|
51
|
+
- Focus ring: `3px` offset
|
|
52
|
+
- Gaps: `8-12px`
|
|
53
|
+
|
|
54
|
+
## Usage Examples
|
|
55
|
+
|
|
56
|
+
### KButton with Icon
|
|
57
|
+
```vue
|
|
58
|
+
<KButton type="primary">
|
|
59
|
+
<template #icon>
|
|
60
|
+
<Icon name="mdi:check" />
|
|
61
|
+
</template>
|
|
62
|
+
Save Changes
|
|
63
|
+
</KButton>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### KCheckbox
|
|
67
|
+
```vue
|
|
68
|
+
<KCheckbox v-model="accepted">
|
|
69
|
+
I accept the terms and conditions
|
|
70
|
+
</KCheckbox>
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### KTextbox with Clear
|
|
74
|
+
```vue
|
|
75
|
+
<KTextbox
|
|
76
|
+
v-model="searchQuery"
|
|
77
|
+
placeholder="Search..."
|
|
78
|
+
:showClear="true"
|
|
79
|
+
/>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### KTextarea
|
|
83
|
+
```vue
|
|
84
|
+
<KTextarea
|
|
85
|
+
v-model="description"
|
|
86
|
+
placeholder="Enter description..."
|
|
87
|
+
:rows="6"
|
|
88
|
+
/>
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Installation
|
|
92
|
+
|
|
93
|
+
Katlux is a zero-configuration Nuxt module. When you install this preset, the core `@katlux/toolkit` is automatically provisioned for you.
|
|
94
|
+
|
|
95
|
+
### Option 1: Using Nuxt CLI (Recommended)
|
|
96
|
+
```bash
|
|
97
|
+
npx nuxi module add @katlux/preset-modern
|
|
98
|
+
```
|
|
99
|
+
This single command installs the package and adds it to your `nuxt.config.ts`.
|
|
100
|
+
|
|
101
|
+
### Option 2: Manual Installation
|
|
102
|
+
1. Install via NPM:
|
|
103
|
+
```bash
|
|
104
|
+
npm install @katlux/preset-modern
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
2. Register the module in `nuxt.config.ts`:
|
|
108
|
+
```ts
|
|
109
|
+
export default defineNuxtConfig({
|
|
110
|
+
modules: [
|
|
111
|
+
'@katlux/preset-modern'
|
|
112
|
+
]
|
|
113
|
+
})
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
That's all! Start using Katlux components like `<KButton>` in your Vue files immediately. No imports required.
|
|
117
|
+
|
|
118
|
+
## Next Components
|
|
119
|
+
|
|
120
|
+
Coming soon:
|
|
121
|
+
- KRadiobox
|
|
122
|
+
- KCombobox
|
|
123
|
+
- KDatatable
|
|
124
|
+
- KModal
|
|
125
|
+
- KPanel
|
|
126
|
+
- And more...
|
|
127
|
+
|
|
128
|
+
## Trademark Policy
|
|
129
|
+
|
|
130
|
+
The code in this repository is completely free and open-source under the MIT License.
|
|
131
|
+
However, **Katlux™** and the Katlux logo are unregistered trademarks of the Katlux project.
|
|
132
|
+
|
|
133
|
+
To protect our users from fraud, you may not use the "Katlux" name or logo to brand your own modified forks, derivative works, or malicious distributions without explicit permission. You are, however, completely free to state "Built with Katlux" in your projects!
|
package/build.config.ts
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@katlux/preset-modern",
|
|
3
|
+
"version": "0.1.0-beta.0",
|
|
4
|
+
"description": "Modern default design preset and styling variables for Katlux components",
|
|
5
|
+
"author": "Katlux",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"access": "public"
|
|
9
|
+
},
|
|
10
|
+
"main": "./dist/module.mjs",
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "nuxt-module-build build",
|
|
13
|
+
"dev": "nuxt-module-build build --stub"
|
|
14
|
+
},
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"import": "./dist/module.mjs"
|
|
18
|
+
},
|
|
19
|
+
"./dist/runtime/assets/*": "./dist/runtime/assets/*"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@katlux/toolkit": "*",
|
|
23
|
+
"@nuxt/kit": "^3.20.1"
|
|
24
|
+
}
|
|
25
|
+
}
|
package/src/module.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { defineNuxtModule, addComponentsDir, createResolver, installModule } from '@nuxt/kit'
|
|
2
|
+
import { createRequire } from 'node:module'
|
|
3
|
+
|
|
4
|
+
export default defineNuxtModule({
|
|
5
|
+
meta: {
|
|
6
|
+
name: '@katlux/preset-modern',
|
|
7
|
+
configKey: 'katluxTemplateModern'
|
|
8
|
+
},
|
|
9
|
+
async setup(options, nuxt) {
|
|
10
|
+
const { resolve } = createResolver(import.meta.url)
|
|
11
|
+
const _require = createRequire(import.meta.url)
|
|
12
|
+
|
|
13
|
+
// 0. Auto-install the base toolkit dependency!
|
|
14
|
+
await installModule('@katlux/toolkit')
|
|
15
|
+
|
|
16
|
+
// 1. Auto-import components
|
|
17
|
+
addComponentsDir({
|
|
18
|
+
path: resolve('./runtime/components'),
|
|
19
|
+
pathPrefix: false,
|
|
20
|
+
extensions: ['vue'],
|
|
21
|
+
global: true
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
// 2. Inject SCSS variables globally via Vite
|
|
25
|
+
nuxt.options.vite.css = nuxt.options.vite.css || {}
|
|
26
|
+
nuxt.options.vite.css.preprocessorOptions = nuxt.options.vite.css.preprocessorOptions || {}
|
|
27
|
+
nuxt.options.vite.css.preprocessorOptions.scss = nuxt.options.vite.css.preprocessorOptions.scss || {}
|
|
28
|
+
|
|
29
|
+
const currentAdditionalData = nuxt.options.vite.css.preprocessorOptions.scss.additionalData || ''
|
|
30
|
+
|
|
31
|
+
// Resolve toolkit SCSS: find package root via package.json (exposed in exports)
|
|
32
|
+
const toolkitPkgJson = _require.resolve('@katlux/toolkit/package.json')
|
|
33
|
+
const toolkitPkgDir = toolkitPkgJson.replace(/[\\/]package\.json$/, '')
|
|
34
|
+
|
|
35
|
+
const toolkitScssPath = nuxt.options.dev
|
|
36
|
+
? `${toolkitPkgDir}/src/runtime/presets/default/assets/scss/index.scss`
|
|
37
|
+
: `${toolkitPkgDir}/dist/runtime/presets/default/assets/scss/index.css`
|
|
38
|
+
|
|
39
|
+
const presetScssPath = nuxt.options.dev
|
|
40
|
+
? resolve('./runtime/assets/scss/index.scss')
|
|
41
|
+
: resolve('../dist/runtime/assets/scss/index.css')
|
|
42
|
+
|
|
43
|
+
const toolkitScss = `@use "${toolkitScssPath}" as *;`
|
|
44
|
+
const presetScssImport = `@use "${presetScssPath}" as *;`
|
|
45
|
+
|
|
46
|
+
nuxt.options.vite.css.preprocessorOptions.scss.additionalData = `${toolkitScss}\n${presetScssImport}\n${currentAdditionalData}`
|
|
47
|
+
}
|
|
48
|
+
})
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
// Modern Template - CSS Custom Properties
|
|
2
|
+
// Vibrant gradients and modern aesthetics
|
|
3
|
+
// Applied when data-template="modern" is set on the root element
|
|
4
|
+
|
|
5
|
+
[data-template="modern"] {
|
|
6
|
+
// Primary Colors - Purple-blue gradient palette
|
|
7
|
+
--primary-100: #ede9fe;
|
|
8
|
+
--primary-300: #c4b5fd;
|
|
9
|
+
--primary-500: #8b5cf6;
|
|
10
|
+
--primary-700: #7c3aed;
|
|
11
|
+
--primary-900: #5b21b6;
|
|
12
|
+
|
|
13
|
+
// Accent Colors - Cyan/teal
|
|
14
|
+
--accent-100: #cffafe;
|
|
15
|
+
--accent-300: #67e8f9;
|
|
16
|
+
--accent-500: #06b6d4;
|
|
17
|
+
--accent-700: #0891b2;
|
|
18
|
+
--accent-900: #155e75;
|
|
19
|
+
|
|
20
|
+
// Neutral Colors - Slate tones
|
|
21
|
+
--neutral-50: #f8fafc;
|
|
22
|
+
--neutral-100: #f1f5f9;
|
|
23
|
+
--neutral-200: #e2e8f0;
|
|
24
|
+
--neutral-300: #cbd5e1;
|
|
25
|
+
--neutral-400: #94a3b8;
|
|
26
|
+
--neutral-500: #64748b;
|
|
27
|
+
--neutral-600: #475569;
|
|
28
|
+
--neutral-700: #334155;
|
|
29
|
+
--neutral-800: #1e293b;
|
|
30
|
+
--neutral-900: #0f172a;
|
|
31
|
+
|
|
32
|
+
// Semantic Colors
|
|
33
|
+
--success-color: #10b981;
|
|
34
|
+
--success-color-light: #ecfdf5;
|
|
35
|
+
--warning-color: #f59e0b;
|
|
36
|
+
--warning-color-light: #fffbeb;
|
|
37
|
+
--error-color: #ef4444;
|
|
38
|
+
--error-color-light: #fef2f2;
|
|
39
|
+
--info-color: #3b82f6;
|
|
40
|
+
--info-color-light: #eff6ff;
|
|
41
|
+
|
|
42
|
+
// Font Colors
|
|
43
|
+
--font-color-primary: var(--neutral-700);
|
|
44
|
+
--font-color-secondary: var(--neutral-500);
|
|
45
|
+
--font-color-heading: var(--neutral-900);
|
|
46
|
+
--font-color-light: #ffffff;
|
|
47
|
+
|
|
48
|
+
// Background Colors
|
|
49
|
+
--background-color: #ffffff;
|
|
50
|
+
--background-color-light: var(--neutral-50);
|
|
51
|
+
--background-color-medium: var(--neutral-100);
|
|
52
|
+
--background-color-dark: var(--neutral-800);
|
|
53
|
+
|
|
54
|
+
// Border Colors
|
|
55
|
+
--border-color-light: var(--neutral-200);
|
|
56
|
+
--border-color-medium: var(--neutral-300);
|
|
57
|
+
--border-color-dark: var(--neutral-500);
|
|
58
|
+
|
|
59
|
+
// Spacing
|
|
60
|
+
--gap-sm: 8px;
|
|
61
|
+
--gap-md: 16px;
|
|
62
|
+
--gap-lg: 24px;
|
|
63
|
+
--gap-xl: 32px;
|
|
64
|
+
|
|
65
|
+
// Border Radius - More rounded for modern look
|
|
66
|
+
--border-radius-sm: 8px;
|
|
67
|
+
--border-radius-md: 12px;
|
|
68
|
+
--border-radius-lg: 16px;
|
|
69
|
+
--border-radius-xl: 24px;
|
|
70
|
+
--border-radius-full: 9999px;
|
|
71
|
+
|
|
72
|
+
// Shadows - Modern elevated shadows
|
|
73
|
+
--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
|
74
|
+
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
|
75
|
+
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
|
76
|
+
--shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
|
77
|
+
|
|
78
|
+
// Glow shadows for buttons
|
|
79
|
+
--shadow-glow-primary: 0 10px 15px -3px rgba(102, 126, 234, 0.4), 0 4px 6px -2px rgba(102, 126, 234, 0.2);
|
|
80
|
+
--shadow-glow-danger: 0 10px 15px -3px rgba(245, 87, 108, 0.4), 0 4px 6px -2px rgba(245, 87, 108, 0.2);
|
|
81
|
+
--shadow-glow-success: 0 10px 15px -3px rgba(79, 172, 254, 0.4), 0 4px 6px -2px rgba(79, 172, 254, 0.2);
|
|
82
|
+
|
|
83
|
+
// Typography
|
|
84
|
+
--font-size-xs: 12px;
|
|
85
|
+
--font-size-sm: 14px;
|
|
86
|
+
--font-size-md: 16px;
|
|
87
|
+
--font-size-lg: 18px;
|
|
88
|
+
--font-size-xl: 20px;
|
|
89
|
+
--font-weight-normal: 400;
|
|
90
|
+
--font-weight-medium: 500;
|
|
91
|
+
--font-weight-semibold: 600;
|
|
92
|
+
--font-weight-bold: 700;
|
|
93
|
+
--font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
94
|
+
--font-family-mono: 'Fira Code', 'Roboto Mono', monospace;
|
|
95
|
+
|
|
96
|
+
// Transitions
|
|
97
|
+
--transition-fast: 0.15s ease;
|
|
98
|
+
--transition-normal: 0.3s ease;
|
|
99
|
+
--transition-slow: 0.5s ease;
|
|
100
|
+
--transition-bounce: 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
101
|
+
|
|
102
|
+
// Button-specific
|
|
103
|
+
--button-border-radius: var(--border-radius-md);
|
|
104
|
+
--button-font-size-sm: var(--font-size-sm);
|
|
105
|
+
--button-font-size-md: var(--font-size-md);
|
|
106
|
+
--button-font-size-lg: var(--font-size-lg);
|
|
107
|
+
|
|
108
|
+
// Button Gradients
|
|
109
|
+
--button-gradient-primary: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
110
|
+
--button-gradient-danger: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
|
|
111
|
+
--button-gradient-success: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
|
|
112
|
+
--button-gradient-warning: linear-gradient(135deg, #fa709a 0%, #fee140 100%);
|
|
113
|
+
--button-gradient-info: linear-gradient(135deg, #30cfd0 0%, #330867 100%);
|
|
114
|
+
--button-gradient-light: linear-gradient(135deg, #fdfbfb 0%, #ebedee 100%);
|
|
115
|
+
--button-gradient-dark: linear-gradient(135deg, #434343 0%, #000000 100%);
|
|
116
|
+
|
|
117
|
+
// Button Colors (using gradients as backgrounds)
|
|
118
|
+
--button-bg-default: var(--button-gradient-primary);
|
|
119
|
+
--button-text-default: var(--font-color-light);
|
|
120
|
+
--button-hover-bg-default: var(--button-gradient-primary);
|
|
121
|
+
|
|
122
|
+
--button-bg-primary: var(--button-gradient-primary);
|
|
123
|
+
--button-text-primary: var(--font-color-light);
|
|
124
|
+
--button-hover-bg-primary: var(--button-gradient-primary);
|
|
125
|
+
|
|
126
|
+
--button-bg-success: var(--button-gradient-success);
|
|
127
|
+
--button-text-success: var(--font-color-light);
|
|
128
|
+
--button-hover-bg-success: var(--button-gradient-success);
|
|
129
|
+
|
|
130
|
+
--button-bg-warning: var(--button-gradient-warning);
|
|
131
|
+
--button-text-warning: var(--neutral-800);
|
|
132
|
+
--button-hover-bg-warning: var(--button-gradient-warning);
|
|
133
|
+
|
|
134
|
+
--button-bg-danger: var(--button-gradient-danger);
|
|
135
|
+
--button-text-danger: var(--font-color-light);
|
|
136
|
+
--button-hover-bg-danger: var(--button-gradient-danger);
|
|
137
|
+
|
|
138
|
+
--button-bg-info: var(--button-gradient-info);
|
|
139
|
+
--button-text-info: var(--font-color-light);
|
|
140
|
+
--button-hover-bg-info: var(--button-gradient-info);
|
|
141
|
+
|
|
142
|
+
--button-bg-light: var(--button-gradient-light);
|
|
143
|
+
--button-text-light: var(--neutral-800);
|
|
144
|
+
--button-hover-bg-light: var(--button-gradient-light);
|
|
145
|
+
|
|
146
|
+
--button-bg-dark: var(--button-gradient-dark);
|
|
147
|
+
--button-text-dark: var(--font-color-light);
|
|
148
|
+
--button-hover-bg-dark: var(--button-gradient-dark);
|
|
149
|
+
|
|
150
|
+
// Input
|
|
151
|
+
--input-border-radius: var(--border-radius-sm);
|
|
152
|
+
--input-border-color: var(--border-color-medium);
|
|
153
|
+
--input-focus-border-color: var(--primary-500);
|
|
154
|
+
--input-focus-shadow: 0 0 0 3px rgba(139, 92, 246, 0.2);
|
|
155
|
+
|
|
156
|
+
// Table
|
|
157
|
+
--table-header-bg: var(--neutral-100);
|
|
158
|
+
--table-header-color: var(--neutral-600);
|
|
159
|
+
--table-border-color: var(--neutral-200);
|
|
160
|
+
--table-row-hover: var(--neutral-100);
|
|
161
|
+
--table-row-selected: #eff6ff;
|
|
162
|
+
|
|
163
|
+
// Checkbox
|
|
164
|
+
--checkbox-bg: var(--background-color);
|
|
165
|
+
--checkbox-checked-bg: var(--button-gradient-primary);
|
|
166
|
+
--checkbox-border-color: var(--neutral-400);
|
|
167
|
+
--modal-overlay-bg: rgba(15, 23, 42, 0.6);
|
|
168
|
+
|
|
169
|
+
// Layout Variables
|
|
170
|
+
--layout-header-height: 70px;
|
|
171
|
+
--layout-header-bg: var(--background-color);
|
|
172
|
+
--layout-sidebar-width: 240px;
|
|
173
|
+
--layout-sidebar-bg: var(--neutral-50);
|
|
174
|
+
--layout-content-bg: #ffffff;
|
|
175
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
<template lang="pug">
|
|
2
|
+
.k-bulk-actions-modern
|
|
3
|
+
.actions-wrapper
|
|
4
|
+
//- Display actions as buttons if few, or dropdown if many
|
|
5
|
+
template(v-if="bulkActions.length > 3")
|
|
6
|
+
KCombobox(
|
|
7
|
+
:dataProvider="dp"
|
|
8
|
+
v-model="selected"
|
|
9
|
+
labelField="label"
|
|
10
|
+
closeOnSelect
|
|
11
|
+
:disabled="selectedRows.length === 0"
|
|
12
|
+
placeholder="Select Action"
|
|
13
|
+
class="action-select"
|
|
14
|
+
)
|
|
15
|
+
KButton(
|
|
16
|
+
@click="doAction(selected)"
|
|
17
|
+
size="small"
|
|
18
|
+
:disabled="selectedRows.length === 0 || selected == undefined"
|
|
19
|
+
class="execute-btn"
|
|
20
|
+
) Go
|
|
21
|
+
|
|
22
|
+
template(v-else v-for="action in bulkActions" :key="action.label")
|
|
23
|
+
KButton(
|
|
24
|
+
@click="doAction(action)"
|
|
25
|
+
size="small"
|
|
26
|
+
variant="outline"
|
|
27
|
+
class="action-btn"
|
|
28
|
+
) {{ action.label }}
|
|
29
|
+
</template>
|
|
30
|
+
|
|
31
|
+
<script setup lang="ts">
|
|
32
|
+
import { CFlatClientDataProvider } from '@katlux/providers'
|
|
33
|
+
import type { IKDatatableAction } from '@katlux/providers'
|
|
34
|
+
|
|
35
|
+
// Use defineModel for simpler two-way binding
|
|
36
|
+
const selected = defineModel<any>('selected')
|
|
37
|
+
|
|
38
|
+
defineProps<{
|
|
39
|
+
bulkActions: IKDatatableAction[]
|
|
40
|
+
selectedRows: any[]
|
|
41
|
+
selectAll: boolean
|
|
42
|
+
dp: CFlatClientDataProvider
|
|
43
|
+
doAction: (action: any) => void
|
|
44
|
+
}>()
|
|
45
|
+
</script>
|
|
46
|
+
|
|
47
|
+
<style lang="scss" scoped>
|
|
48
|
+
.k-bulk-actions-modern {
|
|
49
|
+
display: flex;
|
|
50
|
+
align-items: center;
|
|
51
|
+
|
|
52
|
+
.actions-wrapper {
|
|
53
|
+
display: flex;
|
|
54
|
+
gap: var(--gap-sm);
|
|
55
|
+
align-items: center;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.action-btn {
|
|
59
|
+
border-radius: var(--border-radius-sm);
|
|
60
|
+
font-weight: var(--font-weight-medium);
|
|
61
|
+
transition: all var(--transition-fast);
|
|
62
|
+
|
|
63
|
+
&:hover {
|
|
64
|
+
transform: translateY(-1px);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.execute-btn {
|
|
69
|
+
border-radius: var(--border-radius-sm);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
</style>
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
<template lang="pug">
|
|
2
|
+
NuxtLink.KButton.modern-button(v-if="isLink" :to="href" @click.prevent="onClick" :class="buttonClasses")
|
|
3
|
+
.button-content
|
|
4
|
+
.button-icon(v-if="$slots.icon")
|
|
5
|
+
slot(name="icon")
|
|
6
|
+
.button-text
|
|
7
|
+
slot
|
|
8
|
+
.button-loader(v-if="loading")
|
|
9
|
+
.spinner
|
|
10
|
+
button.KButton.modern-button(v-else @click="onClick" :class="buttonClasses" :disabled="isDisabled")
|
|
11
|
+
.button-content
|
|
12
|
+
.button-icon(v-if="$slots.icon")
|
|
13
|
+
slot(name="icon")
|
|
14
|
+
.button-text
|
|
15
|
+
slot
|
|
16
|
+
.button-loader(v-if="loading")
|
|
17
|
+
.spinner
|
|
18
|
+
</template>
|
|
19
|
+
|
|
20
|
+
<script lang="ts" setup>
|
|
21
|
+
// Modern template for KButton
|
|
22
|
+
defineProps<{
|
|
23
|
+
isLink: boolean
|
|
24
|
+
isDisabled: boolean
|
|
25
|
+
buttonClasses: any
|
|
26
|
+
onClick: () => void
|
|
27
|
+
href?: string
|
|
28
|
+
loading?: boolean
|
|
29
|
+
}>()
|
|
30
|
+
</script>
|
|
31
|
+
|
|
32
|
+
<style lang="scss" scoped>
|
|
33
|
+
.KButton.modern-button {
|
|
34
|
+
border-radius: var(--button-border-radius);
|
|
35
|
+
font-weight: var(--font-weight-semibold);
|
|
36
|
+
cursor: pointer;
|
|
37
|
+
transition: all var(--transition-bounce);
|
|
38
|
+
border: 2px solid transparent;
|
|
39
|
+
position: relative;
|
|
40
|
+
overflow: hidden;
|
|
41
|
+
text-decoration: none;
|
|
42
|
+
box-shadow: var(--shadow-md);
|
|
43
|
+
|
|
44
|
+
.button-content {
|
|
45
|
+
display: flex;
|
|
46
|
+
align-items: center;
|
|
47
|
+
justify-content: center;
|
|
48
|
+
gap: var(--gap-sm);
|
|
49
|
+
position: relative;
|
|
50
|
+
z-index: 1;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.button-icon {
|
|
54
|
+
display: flex;
|
|
55
|
+
align-items: center;
|
|
56
|
+
font-size: 1.2em;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.button-text {
|
|
60
|
+
display: flex;
|
|
61
|
+
align-items: center;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.button-loader {
|
|
65
|
+
position: absolute;
|
|
66
|
+
right: 12px;
|
|
67
|
+
top: 50%;
|
|
68
|
+
transform: translateY(-50%);
|
|
69
|
+
|
|
70
|
+
.spinner {
|
|
71
|
+
width: 16px;
|
|
72
|
+
height: 16px;
|
|
73
|
+
border: 2px solid rgba(255, 255, 255, 0.3);
|
|
74
|
+
border-top-color: white;
|
|
75
|
+
border-radius: 50%;
|
|
76
|
+
animation: spin 0.6s linear infinite;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
&::before {
|
|
81
|
+
content: '';
|
|
82
|
+
position: absolute;
|
|
83
|
+
top: 0;
|
|
84
|
+
left: 0;
|
|
85
|
+
right: 0;
|
|
86
|
+
bottom: 0;
|
|
87
|
+
background: linear-gradient(135deg, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0) 100%);
|
|
88
|
+
opacity: 0;
|
|
89
|
+
transition: opacity var(--transition-normal);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
&:hover::before {
|
|
93
|
+
opacity: 1;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
&:disabled {
|
|
97
|
+
opacity: 0.6;
|
|
98
|
+
cursor: not-allowed;
|
|
99
|
+
pointer-events: none;
|
|
100
|
+
box-shadow: none;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Color variants
|
|
104
|
+
&.default, &.primary {
|
|
105
|
+
background: var(--button-bg-primary);
|
|
106
|
+
color: var(--button-text-primary);
|
|
107
|
+
|
|
108
|
+
&:hover {
|
|
109
|
+
transform: translateY(-2px);
|
|
110
|
+
box-shadow: var(--shadow-glow-primary, var(--shadow-lg));
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
&.danger {
|
|
115
|
+
background: var(--button-bg-danger);
|
|
116
|
+
color: var(--button-text-danger);
|
|
117
|
+
|
|
118
|
+
&:hover {
|
|
119
|
+
transform: translateY(-2px);
|
|
120
|
+
box-shadow: var(--shadow-glow-danger, var(--shadow-lg));
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
&.success {
|
|
125
|
+
background: var(--button-bg-success);
|
|
126
|
+
color: var(--button-text-success);
|
|
127
|
+
|
|
128
|
+
&:hover {
|
|
129
|
+
transform: translateY(-2px);
|
|
130
|
+
box-shadow: var(--shadow-glow-success, var(--shadow-lg));
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
&.warning {
|
|
135
|
+
background: var(--button-bg-warning);
|
|
136
|
+
color: var(--button-text-warning);
|
|
137
|
+
|
|
138
|
+
&:hover {
|
|
139
|
+
transform: translateY(-2px);
|
|
140
|
+
box-shadow: var(--shadow-lg);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.spinner {
|
|
144
|
+
border-color: rgba(51, 51, 51, 0.3);
|
|
145
|
+
border-top-color: #333;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
&.info {
|
|
150
|
+
background: var(--button-bg-info);
|
|
151
|
+
color: var(--button-text-info);
|
|
152
|
+
|
|
153
|
+
&:hover {
|
|
154
|
+
transform: translateY(-2px);
|
|
155
|
+
box-shadow: var(--shadow-lg);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
&.light {
|
|
160
|
+
background: var(--button-bg-light);
|
|
161
|
+
color: var(--button-text-light);
|
|
162
|
+
border-color: var(--border-color-medium);
|
|
163
|
+
|
|
164
|
+
&:hover {
|
|
165
|
+
transform: translateY(-2px);
|
|
166
|
+
box-shadow: var(--shadow-lg);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.spinner {
|
|
170
|
+
border-color: rgba(51, 51, 51, 0.3);
|
|
171
|
+
border-top-color: #333;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
&.dark {
|
|
176
|
+
background: var(--button-bg-dark);
|
|
177
|
+
color: var(--button-text-dark);
|
|
178
|
+
|
|
179
|
+
&:hover {
|
|
180
|
+
transform: translateY(-2px);
|
|
181
|
+
box-shadow: var(--shadow-lg);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Size variants
|
|
186
|
+
&.large {
|
|
187
|
+
font-size: var(--font-size-lg);
|
|
188
|
+
padding: var(--gap-md) var(--gap-xl);
|
|
189
|
+
border-radius: var(--border-radius-lg);
|
|
190
|
+
|
|
191
|
+
.button-icon {
|
|
192
|
+
font-size: 1.3em;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
&.medium {
|
|
197
|
+
font-size: var(--font-size-md);
|
|
198
|
+
padding: var(--gap-sm) var(--gap-lg);
|
|
199
|
+
border-radius: var(--button-border-radius);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
&.small {
|
|
203
|
+
font-size: var(--font-size-sm);
|
|
204
|
+
padding: var(--gap-sm) var(--gap-md);
|
|
205
|
+
border-radius: var(--border-radius-sm);
|
|
206
|
+
|
|
207
|
+
.button-icon {
|
|
208
|
+
font-size: 1.1em;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.spinner {
|
|
212
|
+
width: 12px;
|
|
213
|
+
height: 12px;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
&:active {
|
|
218
|
+
transform: translateY(0);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
@keyframes spin {
|
|
223
|
+
to {
|
|
224
|
+
transform: rotate(360deg);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
</style>
|