@salla.sa/twilight-bundles-starter-kit 0.1.1
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 +184 -0
- package/dist/advanced-inputs.js +54 -0
- package/dist/basic-inputs.js +54 -0
- package/dist/dropdown-list-source-input.js +54 -0
- package/dist/items-select-input.js +51 -0
- package/dist/product-card.js +160 -0
- package/dist/scroll-top.js +20 -0
- package/dist/table-list.js +66 -0
- package/package.json +45 -0
- package/src/components/advanced-inputs/index.ts +62 -0
- package/src/components/basic-inputs/index.ts +66 -0
- package/src/components/dropdown-list-source-input/index.ts +68 -0
- package/src/components/items-select-input/index.ts +59 -0
- package/src/components/product-card/index.ts +160 -0
- package/src/components/product-card/types.ts +43 -0
- package/src/components/scroll-top/index.ts +18 -0
- package/src/components/table-list/index.ts +60 -0
- package/src/types/salla.d.ts +11 -0
- package/tsconfig.json +16 -0
- package/twilight-bundle.json +580 -0
- package/vite.config.ts +21 -0
package/README.md
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# Salla Twilight Bundles Starter Kit
|
|
2
|
+
|
|
3
|
+
This starter kit provides a foundation for building custom Twilight components for Salla's e-commerce platform. It includes a pre-configured build setup and development environment to help you get started quickly.
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
1. Clone this repository
|
|
8
|
+
2. Remove the example components in `src/components/`
|
|
9
|
+
3. Create your own components using the component generator:
|
|
10
|
+
```
|
|
11
|
+
pnpm run create-component
|
|
12
|
+
```
|
|
13
|
+
4. Run `pnpm install` to install dependencies
|
|
14
|
+
5. Run `pnpm run dev` to start the development server
|
|
15
|
+
6. Run `pnpm run build` to build your components for production
|
|
16
|
+
|
|
17
|
+
## Project Structure
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
src/
|
|
21
|
+
components/
|
|
22
|
+
your-component-name/
|
|
23
|
+
index.ts # Main component file
|
|
24
|
+
styles.ts # Component styles (optional)
|
|
25
|
+
types.ts # Component types (optional)
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Built-in Plugins
|
|
29
|
+
|
|
30
|
+
This starter kit includes three Vite plugins that handle the build process:
|
|
31
|
+
|
|
32
|
+
### 1. Transform Plugin (`sallaTransformPlugin`)
|
|
33
|
+
- Transforms component files to ensure proper naming and registration
|
|
34
|
+
- Matches components in `src/components/*/index.ts`
|
|
35
|
+
- To disable: Remove from `vite.config.ts` plugins array
|
|
36
|
+
|
|
37
|
+
### 2. Build Plugin (`sallaBuildPlugin`)
|
|
38
|
+
- Handles component bundling and output
|
|
39
|
+
- Creates individual files for each component in `dist/`
|
|
40
|
+
- Configures external dependencies (lit libraries)
|
|
41
|
+
- To customize: Remove from plugins array and configure your own build settings:
|
|
42
|
+
```typescript
|
|
43
|
+
{
|
|
44
|
+
build: {
|
|
45
|
+
lib: {
|
|
46
|
+
entry: {/* your entries */},
|
|
47
|
+
formats: ['es'],
|
|
48
|
+
fileName: (format, entryName) => `${entryName}.js`
|
|
49
|
+
},
|
|
50
|
+
rollupOptions: {
|
|
51
|
+
external: [/^lit/],
|
|
52
|
+
output: {/* your output config */}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### 3. Demo Plugin (`sallaDemoPlugin`)
|
|
59
|
+
- Provides a development environment for testing components
|
|
60
|
+
- Creates a demo page with your components
|
|
61
|
+
- Configures hot module reloading
|
|
62
|
+
- To disable: Remove from plugins array and set up your own dev server
|
|
63
|
+
|
|
64
|
+
### Demo Plugin Options
|
|
65
|
+
|
|
66
|
+
The `sallaDemoPlugin` accepts the following configuration options:
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
{
|
|
70
|
+
// Optional: Show only specific components
|
|
71
|
+
components?: string[];
|
|
72
|
+
|
|
73
|
+
// Optional: Customize the demo grid layout
|
|
74
|
+
grid?: {
|
|
75
|
+
// CSS grid-template-columns value
|
|
76
|
+
columns?: string; // default: 'repeat(auto-fill, minmax(300px, 1fr))'
|
|
77
|
+
|
|
78
|
+
// Gap between components
|
|
79
|
+
gap?: string; // default: '1rem'
|
|
80
|
+
|
|
81
|
+
// Responsive breakpoint
|
|
82
|
+
minWidth?: string; // default: '300px'
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
// Optional: Add custom CSS
|
|
86
|
+
css?: string;
|
|
87
|
+
|
|
88
|
+
// Optional: Add custom JavaScript
|
|
89
|
+
js?: string;
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
#### Example Configuration
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
// vite.config.ts
|
|
97
|
+
export default defineConfig({
|
|
98
|
+
plugins: [
|
|
99
|
+
// ... other plugins
|
|
100
|
+
sallaDemoPlugin({
|
|
101
|
+
// Show only specific components
|
|
102
|
+
components: ['product-card', 'scroll-top'],
|
|
103
|
+
|
|
104
|
+
// Customize grid layout
|
|
105
|
+
grid: {
|
|
106
|
+
columns: 'repeat(3, 1fr)',
|
|
107
|
+
gap: '1.5rem',
|
|
108
|
+
minWidth: '768px'
|
|
109
|
+
},
|
|
110
|
+
|
|
111
|
+
// Add custom styles
|
|
112
|
+
css: `
|
|
113
|
+
.component-card {
|
|
114
|
+
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
115
|
+
transition: transform 0.2s;
|
|
116
|
+
}
|
|
117
|
+
.component-card:hover {
|
|
118
|
+
transform: translateY(-2px);
|
|
119
|
+
}
|
|
120
|
+
`,
|
|
121
|
+
|
|
122
|
+
// Add custom JavaScript
|
|
123
|
+
js: `
|
|
124
|
+
console.log('Demo page loaded!');
|
|
125
|
+
// Add your custom JavaScript here
|
|
126
|
+
`
|
|
127
|
+
})
|
|
128
|
+
]
|
|
129
|
+
});
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Creating New Components
|
|
133
|
+
|
|
134
|
+
This starter kit includes a component generator to help you create new components quickly. To use it, run:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
pnpm create-component
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
The generator will:
|
|
141
|
+
1. Prompt you for a component name (in kebab-case format)
|
|
142
|
+
2. Validate that the name is in kebab-case and doesn't already exist
|
|
143
|
+
3. Create a new component folder with an `index.ts` file
|
|
144
|
+
4. Add the component definition to `twilight-bundle.json`
|
|
145
|
+
|
|
146
|
+
## Component Requirements
|
|
147
|
+
|
|
148
|
+
Each component should:
|
|
149
|
+
1. Be a class that extends `LitElement`
|
|
150
|
+
2. Export the class as default
|
|
151
|
+
3. Be placed in its own directory under `src/components/`
|
|
152
|
+
4. Have an `index.ts` as the entry point
|
|
153
|
+
|
|
154
|
+
Example:
|
|
155
|
+
```typescript
|
|
156
|
+
import { css, html, LitElement } from 'lit';
|
|
157
|
+
import { property } from 'lit/decorators.js';
|
|
158
|
+
|
|
159
|
+
export default class MyComponent extends LitElement {
|
|
160
|
+
@property({ type: String })
|
|
161
|
+
name = 'World';
|
|
162
|
+
|
|
163
|
+
static styles = css`/* your styles */`;
|
|
164
|
+
|
|
165
|
+
render() {
|
|
166
|
+
return html`<div>Hello ${this.name}!</div>`;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Building for Production
|
|
172
|
+
|
|
173
|
+
Run `pnpm run build` to create production-ready bundles in the `dist/` directory. Each component will have its own file named after the component (e.g., `my-component.js`).
|
|
174
|
+
|
|
175
|
+
## Development
|
|
176
|
+
|
|
177
|
+
Run `pnpm run dev` to start the development server. This will:
|
|
178
|
+
1. Create a demo page with all your components
|
|
179
|
+
2. Enable hot module reloading
|
|
180
|
+
3. Provide a development environment for testing
|
|
181
|
+
|
|
182
|
+
## License
|
|
183
|
+
|
|
184
|
+
MIT
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { LitElement as a, css as f, html as d } from "lit";
|
|
2
|
+
import { property as p } from "lit/decorators.js";
|
|
3
|
+
var c = Object.defineProperty, m = (s, r, e, g) => {
|
|
4
|
+
for (var i = void 0, o = s.length - 1, n; o >= 0; o--)
|
|
5
|
+
(n = s[o]) && (i = n(r, e, i) || i);
|
|
6
|
+
return i && c(r, e, i), i;
|
|
7
|
+
};
|
|
8
|
+
const l = class l extends a {
|
|
9
|
+
render() {
|
|
10
|
+
return this.config ? d`
|
|
11
|
+
<div class="grid">
|
|
12
|
+
${Object.entries(this.config).map(([r, e]) => this.renderValue(r, e))}
|
|
13
|
+
</div>
|
|
14
|
+
` : d`<div style="color: red;">Configuration is required</div>`;
|
|
15
|
+
}
|
|
16
|
+
renderValue(r, e) {
|
|
17
|
+
return typeof e == "object" && (e = JSON.stringify(e)), d`
|
|
18
|
+
<div class="label">${r}</div>
|
|
19
|
+
<code class="value">${e}</code>
|
|
20
|
+
`;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
l.styles = f`
|
|
24
|
+
.grid {
|
|
25
|
+
display: grid;
|
|
26
|
+
grid-template-columns: 20% 75%;
|
|
27
|
+
gap: 0.5rem 1rem;
|
|
28
|
+
align-items: center;
|
|
29
|
+
}
|
|
30
|
+
.label {
|
|
31
|
+
font-weight: bold;
|
|
32
|
+
font-size: 0.9rem;
|
|
33
|
+
text-align: left;
|
|
34
|
+
}
|
|
35
|
+
.value {
|
|
36
|
+
background: #f5f5f5;
|
|
37
|
+
padding: 0.5rem;
|
|
38
|
+
border: 1px solid #ddd;
|
|
39
|
+
border-radius: 4px;
|
|
40
|
+
font-family: monospace;
|
|
41
|
+
white-space: nowrap;
|
|
42
|
+
overflow: hidden;
|
|
43
|
+
text-overflow: ellipsis;
|
|
44
|
+
direction: ltr;
|
|
45
|
+
}
|
|
46
|
+
`;
|
|
47
|
+
let t = l;
|
|
48
|
+
m([
|
|
49
|
+
p({ type: Object })
|
|
50
|
+
], t.prototype, "config");
|
|
51
|
+
typeof t < "u" && t.registerSallaComponent("salla-advanced-inputs");
|
|
52
|
+
export {
|
|
53
|
+
t as default
|
|
54
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { LitElement as a, css as f, html as d } from "lit";
|
|
2
|
+
import { property as p } from "lit/decorators.js";
|
|
3
|
+
var c = Object.defineProperty, m = (n, r, e, g) => {
|
|
4
|
+
for (var i = void 0, o = n.length - 1, s; o >= 0; o--)
|
|
5
|
+
(s = n[o]) && (i = s(r, e, i) || i);
|
|
6
|
+
return i && c(r, e, i), i;
|
|
7
|
+
};
|
|
8
|
+
const l = class l extends a {
|
|
9
|
+
render() {
|
|
10
|
+
return this.config ? d`
|
|
11
|
+
<div class="grid">
|
|
12
|
+
${Object.entries(this.config).map(([r, e]) => this.renderValue(r, e))}
|
|
13
|
+
</div>
|
|
14
|
+
` : d`<div style="color: red;">Configuration is required</div>`;
|
|
15
|
+
}
|
|
16
|
+
renderValue(r, e) {
|
|
17
|
+
return typeof e == "object" && (e = JSON.stringify(e)), d`
|
|
18
|
+
<div class="label">${r}</div>
|
|
19
|
+
<code class="value">${e}</code>
|
|
20
|
+
`;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
l.styles = f`
|
|
24
|
+
.grid {
|
|
25
|
+
display: grid;
|
|
26
|
+
grid-template-columns: 20% 75%;
|
|
27
|
+
gap: 0.5rem 1rem;
|
|
28
|
+
align-items: center;
|
|
29
|
+
}
|
|
30
|
+
.label {
|
|
31
|
+
font-weight: bold;
|
|
32
|
+
font-size: 0.9rem;
|
|
33
|
+
text-align: left;
|
|
34
|
+
}
|
|
35
|
+
.value {
|
|
36
|
+
background: #f5f5f5;
|
|
37
|
+
padding: 0.5rem;
|
|
38
|
+
border: 1px solid #ddd;
|
|
39
|
+
border-radius: 4px;
|
|
40
|
+
font-family: monospace;
|
|
41
|
+
white-space: nowrap;
|
|
42
|
+
overflow: hidden;
|
|
43
|
+
text-overflow: ellipsis;
|
|
44
|
+
direction: ltr;
|
|
45
|
+
}
|
|
46
|
+
`;
|
|
47
|
+
let t = l;
|
|
48
|
+
m([
|
|
49
|
+
p({ type: Object })
|
|
50
|
+
], t.prototype, "config");
|
|
51
|
+
typeof t < "u" && t.registerSallaComponent("salla-basic-inputs");
|
|
52
|
+
export {
|
|
53
|
+
t as default
|
|
54
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { LitElement as f, css as p, html as l } from "lit";
|
|
2
|
+
import { property as c } from "lit/decorators.js";
|
|
3
|
+
var m = Object.defineProperty, g = (s, r, e, n) => {
|
|
4
|
+
for (var i = void 0, d = s.length - 1, a; d >= 0; d--)
|
|
5
|
+
(a = s[d]) && (i = a(r, e, i) || i);
|
|
6
|
+
return i && m(r, e, i), i;
|
|
7
|
+
};
|
|
8
|
+
const o = class o extends f {
|
|
9
|
+
render() {
|
|
10
|
+
return this.config ? l`
|
|
11
|
+
<div class="grid">
|
|
12
|
+
${Object.entries(this.config).map(([r, e]) => this.renderValue(r, e))}
|
|
13
|
+
</div>
|
|
14
|
+
` : l`<div style="color: red;">Configuration is required</div>`;
|
|
15
|
+
}
|
|
16
|
+
renderValue(r, e) {
|
|
17
|
+
return e = typeof e == "object" ? e.map((n) => n.label).join(", ") : e, l`
|
|
18
|
+
<div class="label">${r}</div>
|
|
19
|
+
<code class="value">${e}</code>
|
|
20
|
+
`;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
o.styles = p`
|
|
24
|
+
.grid {
|
|
25
|
+
display: grid;
|
|
26
|
+
grid-template-columns: 30% 65%;
|
|
27
|
+
gap: 0.5rem 1rem;
|
|
28
|
+
align-items: center;
|
|
29
|
+
}
|
|
30
|
+
.label {
|
|
31
|
+
font-weight: bold;
|
|
32
|
+
font-size: 0.9rem;
|
|
33
|
+
text-align: left;
|
|
34
|
+
}
|
|
35
|
+
.value {
|
|
36
|
+
background: #f5f5f5;
|
|
37
|
+
padding: 0.5rem;
|
|
38
|
+
border: 1px solid #ddd;
|
|
39
|
+
border-radius: 4px;
|
|
40
|
+
font-family: monospace;
|
|
41
|
+
white-space: nowrap;
|
|
42
|
+
overflow: hidden;
|
|
43
|
+
text-overflow: ellipsis;
|
|
44
|
+
direction: ltr;
|
|
45
|
+
}
|
|
46
|
+
`;
|
|
47
|
+
let t = o;
|
|
48
|
+
g([
|
|
49
|
+
c({ type: Object })
|
|
50
|
+
], t.prototype, "config");
|
|
51
|
+
typeof t < "u" && t.registerSallaComponent("salla-dropdown-list-source-input");
|
|
52
|
+
export {
|
|
53
|
+
t as default
|
|
54
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { LitElement as f, css as p, html as d } from "lit";
|
|
2
|
+
import { property as c } from "lit/decorators.js";
|
|
3
|
+
var m = Object.defineProperty, g = (s, r, e, n) => {
|
|
4
|
+
for (var i = void 0, o = s.length - 1, a; o >= 0; o--)
|
|
5
|
+
(a = s[o]) && (i = a(r, e, i) || i);
|
|
6
|
+
return i && m(r, e, i), i;
|
|
7
|
+
};
|
|
8
|
+
const l = class l extends f {
|
|
9
|
+
render() {
|
|
10
|
+
return this.config ? d`
|
|
11
|
+
<div class="grid">
|
|
12
|
+
${Object.entries(this.config).map(([r, e]) => this.renderValue(r, e))}
|
|
13
|
+
</div>
|
|
14
|
+
` : d`<div style="color: red;">Configuration is required</div>`;
|
|
15
|
+
}
|
|
16
|
+
renderValue(r, e) {
|
|
17
|
+
return e = typeof e == "object" ? e.map((n) => n.label).join(", ") : e, d`<div class="label">${r}</div><code class="value">${e}</code>`;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
l.styles = p`
|
|
21
|
+
.grid {
|
|
22
|
+
display: grid;
|
|
23
|
+
grid-template-columns: 35% 60%;
|
|
24
|
+
gap: 0.5rem 1rem;
|
|
25
|
+
align-items: center;
|
|
26
|
+
}
|
|
27
|
+
.label {
|
|
28
|
+
font-weight: bold;
|
|
29
|
+
font-size: 0.9rem;
|
|
30
|
+
text-align: left;
|
|
31
|
+
}
|
|
32
|
+
.value {
|
|
33
|
+
background: #f5f5f5;
|
|
34
|
+
padding: 0.5rem;
|
|
35
|
+
border: 1px solid #ddd;
|
|
36
|
+
border-radius: 4px;
|
|
37
|
+
font-family: monospace;
|
|
38
|
+
white-space: nowrap;
|
|
39
|
+
overflow: hidden;
|
|
40
|
+
text-overflow: ellipsis;
|
|
41
|
+
direction: ltr;
|
|
42
|
+
}
|
|
43
|
+
`;
|
|
44
|
+
let t = l;
|
|
45
|
+
g([
|
|
46
|
+
c({ type: Object })
|
|
47
|
+
], t.prototype, "config");
|
|
48
|
+
typeof t < "u" && t.registerSallaComponent("salla-items-select-input");
|
|
49
|
+
export {
|
|
50
|
+
t as default
|
|
51
|
+
};
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { LitElement as u, css as m, html as d } from "lit";
|
|
2
|
+
import { property as l } from "lit/decorators.js";
|
|
3
|
+
var g = Object.defineProperty, p = (s, t, r, a) => {
|
|
4
|
+
for (var e = void 0, i = s.length - 1, c; i >= 0; i--)
|
|
5
|
+
(c = s[i]) && (e = c(t, r, e) || e);
|
|
6
|
+
return e && g(t, r, e), e;
|
|
7
|
+
};
|
|
8
|
+
const n = class n extends u {
|
|
9
|
+
async connectedCallback() {
|
|
10
|
+
var r, a, e;
|
|
11
|
+
super.connectedCallback();
|
|
12
|
+
const t = (e = (a = (r = this.config) == null ? void 0 : r.product) == null ? void 0 : a[0]) == null ? void 0 : e.value;
|
|
13
|
+
if (!t) {
|
|
14
|
+
console.error('Product card config is not valid, you must provide `config="{...}"!');
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
await window.Salla.onReady(), this.product = await window.Salla.product.api.getDetails(t).then((i) => i.data);
|
|
18
|
+
}
|
|
19
|
+
handleAddToCart() {
|
|
20
|
+
var t;
|
|
21
|
+
window.Salla.log("Adding to cart:", { product: this.product }), window.Salla.success(`Added ${(t = this.product) == null ? void 0 : t.name} to cart!`);
|
|
22
|
+
}
|
|
23
|
+
renderPlaceholder() {
|
|
24
|
+
return d`
|
|
25
|
+
<div class="product-card">
|
|
26
|
+
<div class="skeleton-image"></div>
|
|
27
|
+
<div class="skeleton-title"></div>
|
|
28
|
+
<div class="skeleton-price"></div>
|
|
29
|
+
<div class="skeleton-button"></div>
|
|
30
|
+
</div>
|
|
31
|
+
`;
|
|
32
|
+
}
|
|
33
|
+
render() {
|
|
34
|
+
var t, r;
|
|
35
|
+
return this.product ? d`
|
|
36
|
+
<div class="product-card">
|
|
37
|
+
<img
|
|
38
|
+
class="product-image"
|
|
39
|
+
src="${(t = this.product.image) == null ? void 0 : t.url}"
|
|
40
|
+
alt="${(r = this.product.image) == null ? void 0 : r.alt}"
|
|
41
|
+
/>
|
|
42
|
+
<h3 class="product-title">${this.product.name}</h3>
|
|
43
|
+
<div>
|
|
44
|
+
<span class="price-tag">${window.Salla.money(this.product.price)}</span>
|
|
45
|
+
${this.product.discount ? d`<span class="discount">${window.Salla.money(this.product.discount)}</span>` : ""}
|
|
46
|
+
</div>
|
|
47
|
+
<button class="add-to-cart" @click="${this.handleAddToCart}">
|
|
48
|
+
${window.Salla.lang.get("pages.cart.add_to_cart")}
|
|
49
|
+
</button>
|
|
50
|
+
</div>
|
|
51
|
+
` : this.renderPlaceholder();
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
n.styles = m`
|
|
55
|
+
.product-card {
|
|
56
|
+
width: 250px;
|
|
57
|
+
padding: 1rem;
|
|
58
|
+
border-radius: 8px;
|
|
59
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
60
|
+
transition: transform 0.2s;
|
|
61
|
+
background: white;
|
|
62
|
+
margin: 1rem;
|
|
63
|
+
}
|
|
64
|
+
.product-card:hover {
|
|
65
|
+
transform: translateY(-5px);
|
|
66
|
+
}
|
|
67
|
+
.product-image {
|
|
68
|
+
width: 100%;
|
|
69
|
+
height: 200px;
|
|
70
|
+
object-fit: cover;
|
|
71
|
+
border-radius: 4px;
|
|
72
|
+
}
|
|
73
|
+
.product-title {
|
|
74
|
+
margin: 0.5rem 0;
|
|
75
|
+
color: #333;
|
|
76
|
+
font-size: 1.1rem;
|
|
77
|
+
}
|
|
78
|
+
.price-tag {
|
|
79
|
+
font-size: 1.2rem;
|
|
80
|
+
color:var(--primary);
|
|
81
|
+
font-weight: bold;
|
|
82
|
+
}
|
|
83
|
+
.discount {
|
|
84
|
+
background: #ff4444;
|
|
85
|
+
color: white;
|
|
86
|
+
padding: 0.2rem 0.5rem;
|
|
87
|
+
border-radius: 4px;
|
|
88
|
+
font-size: 0.9rem;
|
|
89
|
+
margin-left: 0.5rem;
|
|
90
|
+
}
|
|
91
|
+
.add-to-cart {
|
|
92
|
+
width: 100%;
|
|
93
|
+
padding: 0.8rem;
|
|
94
|
+
margin-top: 1rem;
|
|
95
|
+
border: none;
|
|
96
|
+
border-radius: 4px;
|
|
97
|
+
background: var(--primary);
|
|
98
|
+
color: white;
|
|
99
|
+
font-weight: bold;
|
|
100
|
+
cursor: pointer;
|
|
101
|
+
transition: background 0.2s;
|
|
102
|
+
}
|
|
103
|
+
.add-to-cart:hover {
|
|
104
|
+
background: var(--primary-100);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/* Skeleton loading styles */
|
|
108
|
+
@keyframes pulse {
|
|
109
|
+
0% { opacity: 0.6; }
|
|
110
|
+
50% { opacity: 0.8; }
|
|
111
|
+
100% { opacity: 0.6; }
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.skeleton-image {
|
|
115
|
+
width: 100%;
|
|
116
|
+
height: 200px;
|
|
117
|
+
background-color: #e0e0e0;
|
|
118
|
+
border-radius: 4px;
|
|
119
|
+
margin-bottom: 0.5rem;
|
|
120
|
+
animation: pulse 1.5s infinite ease-in-out;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.skeleton-title {
|
|
124
|
+
width: 80%;
|
|
125
|
+
height: 20px;
|
|
126
|
+
background-color: #e0e0e0;
|
|
127
|
+
border-radius: 4px;
|
|
128
|
+
margin: 0.5rem 0;
|
|
129
|
+
animation: pulse 1.5s infinite ease-in-out;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.skeleton-price {
|
|
133
|
+
width: 40%;
|
|
134
|
+
height: 24px;
|
|
135
|
+
background-color: #e0e0e0;
|
|
136
|
+
border-radius: 4px;
|
|
137
|
+
margin: 0.5rem 0;
|
|
138
|
+
animation: pulse 1.5s infinite ease-in-out;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.skeleton-button {
|
|
142
|
+
width: 100%;
|
|
143
|
+
height: 40px;
|
|
144
|
+
background-color: #e0e0e0;
|
|
145
|
+
border-radius: 4px;
|
|
146
|
+
margin-top: 1rem;
|
|
147
|
+
animation: pulse 1.5s infinite ease-in-out;
|
|
148
|
+
}
|
|
149
|
+
`;
|
|
150
|
+
let o = n;
|
|
151
|
+
p([
|
|
152
|
+
l({ type: Object })
|
|
153
|
+
], o.prototype, "config");
|
|
154
|
+
p([
|
|
155
|
+
l({ type: Object })
|
|
156
|
+
], o.prototype, "product");
|
|
157
|
+
typeof o < "u" && o.registerSallaComponent("salla-product-card");
|
|
158
|
+
export {
|
|
159
|
+
o as default
|
|
160
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
class e extends HTMLElement {
|
|
2
|
+
connectedCallback() {
|
|
3
|
+
this.innerHTML = "↑", this.style.cssText = `
|
|
4
|
+
border-radius: 50%;
|
|
5
|
+
display: flex;
|
|
6
|
+
justify-content: center;
|
|
7
|
+
align-items: center;
|
|
8
|
+
width: 40px;
|
|
9
|
+
height: 40px;
|
|
10
|
+
background: hsl(var(--primary-400));
|
|
11
|
+
color: hsl(var(--primary-force));
|
|
12
|
+
cursor:pointer;
|
|
13
|
+
font-size: 24px;
|
|
14
|
+
`, this.onclick = () => window.scrollTo(0, 0);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
typeof e < "u" && e.registerSallaComponent("salla-scroll-top");
|
|
18
|
+
export {
|
|
19
|
+
e as default
|
|
20
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { LitElement as p, css as c, html as d } from "lit";
|
|
2
|
+
import { property as m } from "lit/decorators.js";
|
|
3
|
+
var f = Object.defineProperty, b = (a, t, i, o) => {
|
|
4
|
+
for (var e = void 0, s = a.length - 1, n; s >= 0; s--)
|
|
5
|
+
(n = a[s]) && (e = n(t, i, e) || e);
|
|
6
|
+
return e && f(t, i, e), e;
|
|
7
|
+
};
|
|
8
|
+
const l = class l extends p {
|
|
9
|
+
render() {
|
|
10
|
+
var t, i;
|
|
11
|
+
return d`
|
|
12
|
+
<div class="table-list">
|
|
13
|
+
${(i = (t = this.config) == null ? void 0 : t.items) == null ? void 0 : i.map(
|
|
14
|
+
(o) => d`
|
|
15
|
+
<div class="table-item">
|
|
16
|
+
<div class="item-content">
|
|
17
|
+
<h3 class="item-title">${o.title}</h3>
|
|
18
|
+
<p class="item-description">${o.description}</p>
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
21
|
+
`
|
|
22
|
+
)}
|
|
23
|
+
</div>
|
|
24
|
+
`;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
l.styles = c`
|
|
28
|
+
.table-list {
|
|
29
|
+
width: 100%;
|
|
30
|
+
border-radius: 8px;
|
|
31
|
+
overflow: hidden;
|
|
32
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
33
|
+
}
|
|
34
|
+
.table-item {
|
|
35
|
+
display: flex;
|
|
36
|
+
padding: 1rem;
|
|
37
|
+
background: white;
|
|
38
|
+
border-bottom: 1px solid #eee;
|
|
39
|
+
align-items: center;
|
|
40
|
+
transition: background 0.2s;
|
|
41
|
+
}
|
|
42
|
+
.table-item:hover {
|
|
43
|
+
background: #f8f9fa;
|
|
44
|
+
}
|
|
45
|
+
.item-content {
|
|
46
|
+
flex: 1;
|
|
47
|
+
}
|
|
48
|
+
.item-title {
|
|
49
|
+
font-weight: 500;
|
|
50
|
+
color: #2c3e50;
|
|
51
|
+
margin: 0;
|
|
52
|
+
}
|
|
53
|
+
.item-description {
|
|
54
|
+
color: #666;
|
|
55
|
+
font-size: 0.9rem;
|
|
56
|
+
margin: 4px 0 0;
|
|
57
|
+
}
|
|
58
|
+
`;
|
|
59
|
+
let r = l;
|
|
60
|
+
b([
|
|
61
|
+
m({ type: Object })
|
|
62
|
+
], r.prototype, "config");
|
|
63
|
+
typeof r < "u" && r.registerSallaComponent("salla-table-list");
|
|
64
|
+
export {
|
|
65
|
+
r as default
|
|
66
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@salla.sa/twilight-bundles-starter-kit",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Starter kit for building custom Salla components",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"salla",
|
|
8
|
+
"ecommerce",
|
|
9
|
+
"components",
|
|
10
|
+
"web-components",
|
|
11
|
+
"lit-element"
|
|
12
|
+
],
|
|
13
|
+
"author": "Salla",
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"@testing-library/dom": "^9.3.4",
|
|
17
|
+
"@testing-library/jest-dom": "^6.4.2",
|
|
18
|
+
"@types/node": "^22.13.1",
|
|
19
|
+
"@typescript-eslint/eslint-plugin": "^8.24.0",
|
|
20
|
+
"@typescript-eslint/parser": "^8.24.0",
|
|
21
|
+
"esbuild": "^0.25.0",
|
|
22
|
+
"eslint": "^9.20.1",
|
|
23
|
+
"glob": "^11.0.1",
|
|
24
|
+
"jsdom": "^24.0.0",
|
|
25
|
+
"prettier": "^3.5.0",
|
|
26
|
+
"typescript": "^5.7.3",
|
|
27
|
+
"vite": "^6.1.0",
|
|
28
|
+
"vitest": "^3.0.5"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"lit": "^3.2.1",
|
|
32
|
+
"@salla.sa/twilight-bundles": "0.1.1"
|
|
33
|
+
},
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=16.0.0",
|
|
36
|
+
"pnpm": ">=9.0.0"
|
|
37
|
+
},
|
|
38
|
+
"scripts": {
|
|
39
|
+
"dev": "vite",
|
|
40
|
+
"build": "vite build",
|
|
41
|
+
"preview": "vite preview",
|
|
42
|
+
"format": "prettier --write \"src/**/*.{ts,html,css}\"",
|
|
43
|
+
"create-component": "tw-component"
|
|
44
|
+
}
|
|
45
|
+
}
|