Skip to content

Commit 22bb8aa

Browse files
committed
feat(list): first draft for lists
1 parent 9d69d2a commit 22bb8aa

21 files changed

+695
-94
lines changed

README.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ See examples in the demo (code [here](https://github.com/dvcol/neo-svelte/tree/f
5151
## TODO
5252
- [ ] @media any-pointer:coarse any-hover:none
5353
- [x] Buttons
54+
- [x] toggle
55+
- [x] groups
5456
- [x] Tabs
5557
- [x] Card
5658
- [x] Inputs
@@ -78,6 +80,7 @@ See examples in the demo (code [here](https://github.com/dvcol/neo-svelte/tree/f
7880
- [x] custom before-after
7981
- [x] steps
8082
- [ ] vertical
83+
- [ ] rating (stars)
8184
- [x] select
8285
- [x] native
8386
- [ ] custom
@@ -87,6 +90,19 @@ See examples in the demo (code [here](https://github.com/dvcol/neo-svelte/tree/f
8790
- [ ] nested menus
8891

8992
- [ ] list
93+
- [ ] snippets
94+
- [ ] children
95+
- [ ] header
96+
- [ ] footer
97+
- [ ] select
98+
- [ ] multiple
99+
- [ ] disabled
100+
- [ ] readonly
101+
- [ ] header (pills or item count)
102+
- [ ] separator
103+
- [ ] label (sections
104+
- [ ] keyboard navigation
105+
- [ ] scroll shadow
90106
- [ ] virtualized
91107
- [ ] infinite scroll
92108
- [ ] drag & drop
@@ -98,6 +114,27 @@ See examples in the demo (code [here](https://github.com/dvcol/neo-svelte/tree/f
98114
- [ ] select
99115
- [ ] tree
100116

117+
- [ ] Chat
118+
- [ ] infinite scroll
119+
- [ ] virtual scroll
120+
- [ ] async
121+
- [ ] stream
122+
- [ ] generative text animation
123+
- [ ] scroll to bottom
124+
- [ ] typing indicator
125+
- [ ] read indicator
126+
- [ ] reactions
127+
- [ ] threads
128+
- [ ] @ / # tags
129+
- [ ] mentions
130+
- [ ] attachments
131+
- [ ] gifs/images
132+
- [ ] videos
133+
- [ ] audio
134+
- [ ] custom cards (contact, etc.)
135+
- [ ] custom bubbles
136+
- [ ] custom input
137+
101138
- [ ] Modal/dialog
102139
- [ ] drawer/panel
103140
- [ ] collapsible

demo/App.svelte

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,15 @@
2424
in: fade,
2525
out: fade,
2626
params: { in: { delay: 200, duration: 200 }, out: { duration: 200 } },
27-
props: { container: { style: 'display: flex; justify-content: center; align-items: center;' } },
27+
props: {
28+
container: {
29+
style: {
30+
display: 'flex',
31+
justifyContent: 'center',
32+
alignItems: 'center',
33+
},
34+
},
35+
},
2836
skipFirst: true,
2937
};
3038

demo/components/DemoLists.svelte

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
<script lang="ts">
2+
import { fade } from 'svelte/transition';
3+
4+
import type { NeoListItem, NeoListProps } from '~/list/neo-list.model.js';
5+
6+
import NeoButton from '~/buttons/NeoButton.svelte';
7+
import NeoButtonGroup from '~/buttons/NeoButtonGroup.svelte';
8+
import NeoCard from '~/cards/NeoCard.svelte';
9+
import IconCircleLoading from '~/icons/IconCircleLoading.svelte';
10+
import NeoList from '~/list/NeoList.svelte';
11+
import { Colors } from '~/utils/colors.utils';
12+
import { enterTransitionProps } from '~/utils/transition.utils';
13+
14+
const options = $state<NeoListProps>({
15+
loading: false,
16+
skeleton: false,
17+
shadow: false,
18+
});
19+
20+
const list: NeoListItem[] = $state([
21+
{ value: 'Line item label 1', id: crypto.randomUUID() },
22+
{ value: 'Line item with longer label 2', id: crypto.randomUUID() },
23+
{ value: 'Line item error', color: Colors.Error, id: crypto.randomUUID() },
24+
{ value: 'Line item warning', color: Colors.Warning, id: crypto.randomUUID() },
25+
{ value: 'Line item success', color: Colors.Success, id: crypto.randomUUID() },
26+
{ value: 'Line item primary', color: Colors.Primary, id: crypto.randomUUID() },
27+
{ value: 'Line item secondary', color: Colors.Secondary, id: crypto.randomUUID() },
28+
]);
29+
30+
let isEmpty = $state(false);
31+
const items = $derived(isEmpty ? [] : list);
32+
33+
const onAdd = () => {
34+
list.push({ value: `Line item ${list.length + 1}`, id: crypto.randomUUID() });
35+
};
36+
37+
const onRemove = () => {
38+
// remove a random element form the list
39+
list.splice(Math.floor(Math.random() * list.length), 1);
40+
};
41+
</script>
42+
43+
<div class="row">
44+
<NeoButtonGroup rounded={options.rounded}>
45+
<NeoButton toggle bind:checked={isEmpty}>Empty</NeoButton>
46+
<NeoButton toggle bind:checked={options.shadow}>Shadow</NeoButton>
47+
<NeoButton toggle bind:checked={options.loading}>Loading</NeoButton>
48+
<NeoButton toggle bind:checked={options.skeleton}>Skeleton</NeoButton>
49+
<NeoButton onclick={onAdd}>Add</NeoButton>
50+
<NeoButton onclick={onRemove}>Remove</NeoButton>
51+
</NeoButtonGroup>
52+
</div>
53+
54+
<div class="row">
55+
<div class="column content">
56+
<span class="label">Card List</span>
57+
<NeoCard rounded elevation="0" hover="-2" flex="1 0 100%" width="min(80vw, 18rem)">
58+
<NeoList {items} {...options} />
59+
</NeoCard>
60+
</div>
61+
62+
<div class="column content">
63+
<span class="label">Multi-line loader</span>
64+
<NeoList {items} {...options} loading={options.loading ? 10 : false} />
65+
</div>
66+
67+
<div class="column content">
68+
<span class="label">Custom loader</span>
69+
<NeoList {items} {...options}>
70+
{#snippet loader()}
71+
<div class="custom-list-loader">
72+
<IconCircleLoading size="2rem" />
73+
</div>
74+
{/snippet}
75+
</NeoList>
76+
</div>
77+
78+
<div class="column content">
79+
<span class="label">Custom Empty</span>
80+
<NeoList {items} {...options}>
81+
{#snippet empty()}
82+
<div class="custom-list-loader" in:fade={enterTransitionProps}>
83+
<span> Custom empty snippet</span>
84+
</div>
85+
{/snippet}
86+
</NeoList>
87+
</div>
88+
89+
<!-- custom item-->
90+
91+
<!-- custom empty-->
92+
93+
<!-- buttons item -->
94+
95+
<!-- tooltip item (menu drawer) -->
96+
97+
<!-- select items -->
98+
99+
<!-- multi select items -->
100+
101+
<!-- search items -->
102+
103+
<!-- custom filter snippet -->
104+
</div>
105+
106+
<style lang="scss">
107+
@use 'src/lib/styles/common/flex' as flex;
108+
109+
.label {
110+
max-width: 80vw;
111+
white-space: pre-line;
112+
text-align: center;
113+
word-break: break-all;
114+
}
115+
116+
.custom-list-loader {
117+
display: flex;
118+
justify-content: center;
119+
padding: 0.5rem;
120+
}
121+
122+
.column {
123+
@include flex.column($gap: var(--neo-gap-lg), $flex: 0 1 auto);
124+
125+
&.content {
126+
width: min(80vw, 18rem);
127+
min-width: fit-content;
128+
height: min(80vh, 20rem);
129+
}
130+
}
131+
132+
.row {
133+
@include flex.row($center: true, $gap: var(--neo-gap-xl), $flex: 0 1 auto);
134+
135+
min-width: 80vw;
136+
margin: 2rem 0;
137+
}
138+
</style>

demo/router/routes.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export const Route = {
1111
Skeleton: 'skeleton' as const,
1212
Inputs: 'inputs' as const,
1313
Tooltips: 'tooltips' as const,
14+
Lists: 'lists' as const,
1415
} as const;
1516

1617
export type Routes = (typeof Route)[keyof typeof Route];
@@ -25,6 +26,7 @@ export const Path: Record<keyof typeof Route, string> = {
2526
Skeleton: '/skeleton' as const,
2627
Inputs: '/inputs' as const,
2728
Tooltips: '/tooltips' as const,
29+
Lists: '/lists' as const,
2830
Any: '*' as const,
2931
} as const;
3032

@@ -79,6 +81,11 @@ export const options: RouterOptions<Routes> = {
7981
path: Path.Tooltips,
8082
component: () => import('../components/DemoTooltips.svelte'),
8183
},
84+
{
85+
name: Route.Lists,
86+
path: Path.Lists,
87+
component: () => import('../components/DemoLists.svelte'),
88+
},
8289
{
8390
name: Route.Any,
8491
path: Path.Any,

package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,17 +110,17 @@
110110
"svelte": ">=5"
111111
},
112112
"dependencies": {
113-
"@dvcol/common-utils": "^1.20.0",
113+
"@dvcol/common-utils": "^1.21.2",
114114
"@dvcol/svelte-utils": "^1.6.1",
115115
"@skeletonlabs/floating-ui-svelte": "^0.3.9",
116-
"svelte": "^5.19.0"
116+
"svelte": "^5.19.3"
117117
},
118118
"devDependencies": {
119119
"@commitlint/cli": "^19.4.1",
120120
"@commitlint/config-conventional": "^19.4.1",
121121
"@dvcol/eslint-plugin-presets": "^1.3.11",
122122
"@dvcol/stylelint-plugin-presets": "^2.1.2",
123-
"@dvcol/svelte-simple-router": "^1.10.0",
123+
"@dvcol/svelte-simple-router": "^1.10.1",
124124
"@sveltejs/adapter-auto": "^4.0.0",
125125
"@sveltejs/kit": "^2.16.0",
126126
"@sveltejs/package": "^2.3.7",
@@ -162,7 +162,7 @@
162162
"sass": "^1.83.4",
163163
"standard-version": "^9.5.0",
164164
"stylelint": "^16.9.0",
165-
"svelte-check": "^4.1.1",
165+
"svelte-check": "^4.1.4",
166166
"svelte-preprocess": "^6.0.3",
167167
"typescript": "^5.5.4",
168168
"vite": "^6.0.7",

0 commit comments

Comments
 (0)