@damillora/iuno 0.2.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.
Files changed (47) hide show
  1. package/README.md +44 -0
  2. package/dist/app.css +12 -0
  3. package/dist/components/form/Button.svelte +21 -0
  4. package/dist/components/form/Button.svelte.d.ts +8 -0
  5. package/dist/components/form/Input.svelte +10 -0
  6. package/dist/components/form/Input.svelte.d.ts +13 -0
  7. package/dist/components/form/InputButton.svelte +18 -0
  8. package/dist/components/form/InputButton.svelte.d.ts +7 -0
  9. package/dist/components/form/Label.svelte +12 -0
  10. package/dist/components/form/Label.svelte.d.ts +7 -0
  11. package/dist/components/form/LinkButton.svelte +20 -0
  12. package/dist/components/form/LinkButton.svelte.d.ts +8 -0
  13. package/dist/components/form/TagsInput.svelte +141 -0
  14. package/dist/components/form/TagsInput.svelte.d.ts +9 -0
  15. package/dist/components/form/TextInput.svelte +15 -0
  16. package/dist/components/form/TextInput.svelte.d.ts +7 -0
  17. package/dist/components/image/Image.svelte +31 -0
  18. package/dist/components/image/Image.svelte.d.ts +15 -0
  19. package/dist/components/image/LocalImage.svelte +7 -0
  20. package/dist/components/image/LocalImage.svelte.d.ts +15 -0
  21. package/dist/components/layout/Container.svelte +9 -0
  22. package/dist/components/layout/Container.svelte.d.ts +6 -0
  23. package/dist/components/layout/ContainerWithSidebar.svelte +25 -0
  24. package/dist/components/layout/ContainerWithSidebar.svelte.d.ts +8 -0
  25. package/dist/components/layout/Footer.svelte +9 -0
  26. package/dist/components/layout/Footer.svelte.d.ts +6 -0
  27. package/dist/components/layout/ScreenCenteredContainer.svelte +11 -0
  28. package/dist/components/layout/ScreenCenteredContainer.svelte.d.ts +6 -0
  29. package/dist/components/layout/Tabs.svelte +29 -0
  30. package/dist/components/layout/Tabs.svelte.d.ts +8 -0
  31. package/dist/components/nav/Nav.svelte +62 -0
  32. package/dist/components/nav/Nav.svelte.d.ts +7 -0
  33. package/dist/components/nav/NavButton.svelte +27 -0
  34. package/dist/components/nav/NavButton.svelte.d.ts +10 -0
  35. package/dist/components/nav/NavDropdown.svelte +46 -0
  36. package/dist/components/nav/NavDropdown.svelte.d.ts +7 -0
  37. package/dist/components/nav/NavHeader.svelte +9 -0
  38. package/dist/components/nav/NavHeader.svelte.d.ts +5 -0
  39. package/dist/components/nav/NavLink.svelte +24 -0
  40. package/dist/components/nav/NavLink.svelte.d.ts +9 -0
  41. package/dist/components/nav/Pagination.svelte +48 -0
  42. package/dist/components/nav/Pagination.svelte.d.ts +7 -0
  43. package/dist/index.d.ts +21 -0
  44. package/dist/index.js +34 -0
  45. package/dist/utils/simple-pagination.d.ts +2 -0
  46. package/dist/utils/simple-pagination.js +53 -0
  47. package/package.json +72 -0
package/README.md ADDED
@@ -0,0 +1,44 @@
1
+ # iuno
2
+
3
+ Damillora's next-generation component library and design system.
4
+
5
+ ## Developing
6
+
7
+ Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
8
+
9
+ ```sh
10
+ npm run dev
11
+
12
+ # or start the server and open the app in a new browser tab
13
+ npm run dev -- --open
14
+ ```
15
+
16
+ Everything inside `src/lib` is part of your library, everything inside `src/routes` can be used as a showcase or preview app.
17
+
18
+ ## Building
19
+
20
+ To build your library:
21
+
22
+ ```sh
23
+ npm pack
24
+ ```
25
+
26
+ To create a production version of your showcase app:
27
+
28
+ ```sh
29
+ npm run build
30
+ ```
31
+
32
+ You can preview the production build with `npm run preview`.
33
+
34
+ > To deploy your app, you may need to install an [adapter](https://svelte.dev/docs/kit/adapters) for your target environment.
35
+
36
+ ## Publishing
37
+
38
+ Go into the `package.json` and give your package the desired name through the `"name"` option. Also consider adding a `"license"` field and point it to a `LICENSE` file which you can create from a template (one popular option is the [MIT license](https://opensource.org/license/mit/)).
39
+
40
+ To publish your library to [npm](https://www.npmjs.com):
41
+
42
+ ```sh
43
+ npm publish
44
+ ```
package/dist/app.css ADDED
@@ -0,0 +1,12 @@
1
+ @import url('https://fonts.googleapis.com/css2?family=Sen:wght@400..800&display=swap');
2
+ @import "tailwindcss";
3
+
4
+ @theme {
5
+ --font-sans: "Sen", sans-serif;
6
+ }
7
+
8
+ @theme inline {
9
+ --color-primary: var(--color-blue-800);
10
+ --color-primary-content: var(--color-blue-100);
11
+ --color-primary-hover: var(--color-blue-200);
12
+ }
@@ -0,0 +1,21 @@
1
+ <script lang="ts">
2
+ import type { MouseEventHandler } from "svelte/elements";
3
+
4
+ let {
5
+ children,
6
+ primary = false,
7
+ large = false,
8
+ class: className = "",
9
+ ...restProps
10
+ } = $props();
11
+ </script>
12
+
13
+ <button
14
+ class={[
15
+ "py-1 px-4 rounded-lg text-blue-800 border border-blue-800 transition-colors cursor-pointer hover:bg-blue-100",
16
+ primary && "bg-blue-800 text-white hover:bg-blue-700",
17
+ large && "text-xl py-2 px-8",
18
+ className,
19
+ ]}
20
+ {...restProps}>{@render children?.()}</button
21
+ >
@@ -0,0 +1,8 @@
1
+ declare const Button: import("svelte").Component<{
2
+ children: any;
3
+ primary?: boolean;
4
+ large?: boolean;
5
+ class?: string;
6
+ } & Record<string, any>, {}, "">;
7
+ type Button = ReturnType<typeof Button>;
8
+ export default Button;
@@ -0,0 +1,10 @@
1
+ <script>
2
+ let { children, class: className = "", ...restProps } = $props();
3
+ </script>
4
+
5
+ <div
6
+ class="group rounded-lg bg-gray-100 focus-within:bg-blue-100 focus-within:ring focus-within:ring-blue-800 transition-all flex flex-row cursor-text {className}"
7
+ {...restProps}
8
+ >
9
+ {@render children?.()}
10
+ </div>
@@ -0,0 +1,13 @@
1
+ export default Input;
2
+ type Input = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ declare const Input: import("svelte").Component<{
7
+ children: any;
8
+ class?: string;
9
+ } & Record<string, any>, {}, "">;
10
+ type $$ComponentProps = {
11
+ children: any;
12
+ class?: string;
13
+ } & Record<string, any>;
@@ -0,0 +1,18 @@
1
+ <script lang="ts">
2
+ let {
3
+ primary = false,
4
+ children,
5
+ class: className = "",
6
+ ...restProps
7
+ } = $props();
8
+ </script>
9
+
10
+ <button
11
+ class="cursor-pointer hover:bg-blue-100 rounded-r-lg transition-colors px-2 {className}"
12
+ class:bg-blue-800={primary}
13
+ class:hover:bg-blue-700={primary}
14
+ class:text-white={primary}
15
+ {...restProps}
16
+ >
17
+ {@render children?.()}
18
+ </button>
@@ -0,0 +1,7 @@
1
+ declare const InputButton: import("svelte").Component<{
2
+ primary?: boolean;
3
+ children: any;
4
+ class?: string;
5
+ } & Record<string, any>, {}, "">;
6
+ type InputButton = ReturnType<typeof InputButton>;
7
+ export default InputButton;
@@ -0,0 +1,12 @@
1
+ <script lang="ts">
2
+ let {
3
+ children,
4
+ for: forName = "",
5
+ class: className = "",
6
+ ...restProps
7
+ } = $props();
8
+ </script>
9
+
10
+ <div class="font-medium mb-2 text-base text-left {className}" {...restProps}>
11
+ <label for={forName}>{@render children?.()}</label>
12
+ </div>
@@ -0,0 +1,7 @@
1
+ declare const Label: import("svelte").Component<{
2
+ children: any;
3
+ for?: string;
4
+ class?: string;
5
+ } & Record<string, any>, {}, "">;
6
+ type Label = ReturnType<typeof Label>;
7
+ export default Label;
@@ -0,0 +1,20 @@
1
+ <script lang="ts">
2
+ import type { MouseEventHandler } from "svelte/elements";
3
+
4
+ let {
5
+ href,
6
+ children,
7
+ primary = false,
8
+ class: className = "",
9
+ ...restProps
10
+ } = $props();
11
+ </script>
12
+
13
+ <a
14
+ class="inline-block py-1 px-4 rounded-lg border border-blue-800 font-bold transition-colors cursor-pointer hover:bg-blue-100 {className}"
15
+ class:bg-blue-800={primary}
16
+ class:text-white={primary}
17
+ class:hover:bg-blue-700={primary}
18
+ {href}
19
+ {...restProps}>{@render children?.()}</a
20
+ >
@@ -0,0 +1,8 @@
1
+ declare const LinkButton: import("svelte").Component<{
2
+ href: any;
3
+ children: any;
4
+ primary?: boolean;
5
+ class?: string;
6
+ } & Record<string, any>, {}, "">;
7
+ type LinkButton = ReturnType<typeof LinkButton>;
8
+ export default LinkButton;
@@ -0,0 +1,141 @@
1
+ <script lang="ts">
2
+ import type { KeyboardEventHandler } from "svelte/elements";
3
+ import NavButton from "../nav/NavButton.svelte";
4
+
5
+ let {
6
+ value = [],
7
+ class: className = "",
8
+ ontagchange,
9
+ name = "",
10
+ onautocomplete = undefined,
11
+ ...restProps
12
+ } = $props();
13
+ let textValue = $state("");
14
+ let id = $state(0);
15
+
16
+ let timer: Timeout | undefined = $state();
17
+
18
+ let autocompleteEntries: string[] = $state([]);
19
+ let selectedAutocomplete: number | undefined = $state();
20
+
21
+ const appendTextValue = (textValue: string) => {
22
+ let newValue = value.concat(textValue);
23
+ if (ontagchange) {
24
+ ontagchange(newValue);
25
+ }
26
+ id += 1;
27
+ };
28
+ const onKeyDown: KeyboardEventHandler<HTMLInputElement> = (e) => {
29
+ if (e.key === "ArrowUp") {
30
+ e.preventDefault();
31
+ let len = autocompleteEntries.length;
32
+ if (selectedAutocomplete === undefined) {
33
+ selectedAutocomplete = (len + len - 1) % len;
34
+ } else {
35
+ selectedAutocomplete = (selectedAutocomplete + len - 1) % len;
36
+ }
37
+ return;
38
+ } else if (e.key === "ArrowDown") {
39
+ e.preventDefault();
40
+ let len = autocompleteEntries.length;
41
+ if (selectedAutocomplete === undefined) {
42
+ console.log("up");
43
+ selectedAutocomplete = 0;
44
+ } else {
45
+ console.log("up");
46
+ selectedAutocomplete = (selectedAutocomplete + 1) % len;
47
+ }
48
+ return;
49
+ }
50
+ if (e.key === " ") {
51
+ e.preventDefault();
52
+ if (selectedAutocomplete !== undefined) {
53
+ console.log(autocompleteEntries[selectedAutocomplete]);
54
+ autocompleteSelect(autocompleteEntries[selectedAutocomplete]);
55
+ return;
56
+ }
57
+ if (textValue !== "") {
58
+ const exist = value.find((x) => x === textValue);
59
+ if (!exist) {
60
+ appendTextValue(textValue);
61
+ textValue = "";
62
+ id += 1;
63
+ }
64
+ } else {
65
+ textValue = "";
66
+ }
67
+ } else if (
68
+ e.key === "Backspace" &&
69
+ textValue === "" &&
70
+ value.length > 0
71
+ ) {
72
+ removeTag(value[value.length - 1]);
73
+ } else if (onautocomplete) {
74
+ clearTimeout(timer);
75
+ timer = setTimeout(() => {
76
+ invokeAutocomplete(textValue);
77
+ }, 400);
78
+ }
79
+ autocompleteEntries = [];
80
+ };
81
+ const invokeAutocomplete = async (str: string) => {
82
+ let autocomplete: string[] = await onautocomplete(str);
83
+ autocomplete = autocomplete.filter((x) => !value.includes(x));
84
+ autocompleteEntries = autocomplete.slice(0, 5);
85
+ };
86
+ const removeTag = (i: string) => {
87
+ let newValue = value.filter((x) => x != i);
88
+ console.log(newValue);
89
+ if (ontagchange) {
90
+ ontagchange(newValue);
91
+ }
92
+ };
93
+ const autocompleteSelect = (str: string) => {
94
+ appendTextValue(str);
95
+ autocompleteEntries = [];
96
+ selectedAutocomplete = undefined;
97
+ textValue = "";
98
+ id += 1;
99
+ };
100
+ </script>
101
+
102
+ <div
103
+ class="relative group py-2 px-2 w-full rounded-lg transition-shadow {className} flex flex-row flex-wrap cursor-text"
104
+ {...restProps}
105
+ >
106
+ {#each value as item, i}
107
+ <div
108
+ class="text-sm mr-1 rounded-lg bg-blue-100 group-focus-within:bg-blue-200 transition-colors px-2 my-1 cursor-default flex flex-row items-center justify-center"
109
+ >
110
+ <span class="mr-1">{item}</span>
111
+ <button
112
+ class="cursor-pointer hover:text-red-800 rounded-full transition-colors"
113
+ type="button"
114
+ onclick={() => removeTag(item)}>✕</button
115
+ >
116
+ </div>
117
+ {/each}
118
+ <input
119
+ type="text"
120
+ autocomplete="off"
121
+ {name}
122
+ class="outline-none focus-within:outline-none grow min-w-32"
123
+ bind:value={textValue}
124
+ onkeydown={onKeyDown}
125
+ {...restProps}
126
+ />
127
+ <div
128
+ class="hidden group-focus-within:flex absolute left-0 top-full bg-gray-100 flex-col rounded-lg *:w-full transition-all"
129
+ >
130
+ {#each autocompleteEntries as autocomplete, i}
131
+ <NavButton
132
+ active={selectedAutocomplete === i}
133
+ class="text-left"
134
+ type="button"
135
+ onclick={() => autocompleteSelect(autocomplete)}
136
+ >
137
+ {autocomplete}
138
+ </NavButton>
139
+ {/each}
140
+ </div>
141
+ </div>
@@ -0,0 +1,9 @@
1
+ declare const TagsInput: import("svelte").Component<{
2
+ value?: any[];
3
+ class?: string;
4
+ ontagchange: any;
5
+ name?: string;
6
+ onautocomplete?: any;
7
+ } & Record<string, any>, {}, "">;
8
+ type TagsInput = ReturnType<typeof TagsInput>;
9
+ export default TagsInput;
@@ -0,0 +1,15 @@
1
+ <script lang="ts">
2
+ let {
3
+ type: typeName = "text",
4
+ value = $bindable(),
5
+ class: className = "",
6
+ ...restProps
7
+ } = $props();
8
+ </script>
9
+
10
+ <input
11
+ type={typeName}
12
+ class="py-2 px-2 rounded-lg outline-none focus-within:outline-none transition-shadow w-full {className}"
13
+ bind:value
14
+ {...restProps}
15
+ />
@@ -0,0 +1,7 @@
1
+ declare const TextInput: import("svelte").Component<{
2
+ type?: string;
3
+ value?: any;
4
+ class?: string;
5
+ } & Record<string, any>, {}, "value">;
6
+ type TextInput = ReturnType<typeof TextInput>;
7
+ export default TextInput;
@@ -0,0 +1,31 @@
1
+ <script>
2
+ import { onMount } from "svelte";
3
+ import { get } from "svelte/store";
4
+
5
+ let { alt, src, class: className = "" } = $props();
6
+ let loading = $state(false);
7
+ let failed = $state(false);
8
+
9
+ onMount(() => {
10
+ const img = new Image();
11
+ img.src = src;
12
+ loading = true;
13
+
14
+ img.onload = () => {
15
+ loading = false;
16
+ failed = false;
17
+ };
18
+ img.onerror = () => {
19
+ loading = true;
20
+ failed = true;
21
+ };
22
+ });
23
+ </script>
24
+
25
+ {#if !failed}
26
+ <figure class={className} class:bg-gray-300={loading}>
27
+ <img class="w-full" {src} {alt} />
28
+ </figure>
29
+ {:else}
30
+ <div class="bg-red-300">There was an error loading this image.</div>
31
+ {/if}
@@ -0,0 +1,15 @@
1
+ export default Image;
2
+ type Image = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ declare const Image: import("svelte").Component<{
7
+ alt: any;
8
+ src: any;
9
+ class?: string;
10
+ }, {}, "">;
11
+ type $$ComponentProps = {
12
+ alt: any;
13
+ src: any;
14
+ class?: string;
15
+ };
@@ -0,0 +1,7 @@
1
+ <script>
2
+ let { alt, src, class: className = "" } = $props();
3
+ </script>
4
+
5
+ <figure>
6
+ <img class={className} {src} {alt} />
7
+ </figure>
@@ -0,0 +1,15 @@
1
+ export default LocalImage;
2
+ type LocalImage = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ declare const LocalImage: import("svelte").Component<{
7
+ alt: any;
8
+ src: any;
9
+ class?: string;
10
+ }, {}, "">;
11
+ type $$ComponentProps = {
12
+ alt: any;
13
+ src: any;
14
+ class?: string;
15
+ };
@@ -0,0 +1,9 @@
1
+ <script lang="ts">
2
+ let { children, class: className = "" } = $props();
3
+ </script>
4
+
5
+ <div
6
+ class="min-h-[calc(100vh-4rem)] container mx-auto {className}"
7
+ >
8
+ {@render children?.()}
9
+ </div>
@@ -0,0 +1,6 @@
1
+ declare const Container: import("svelte").Component<{
2
+ children: any;
3
+ class?: string;
4
+ }, {}, "">;
5
+ type Container = ReturnType<typeof Container>;
6
+ export default Container;
@@ -0,0 +1,25 @@
1
+ <script lang="ts">
2
+ let {
3
+ sidebar = undefined,
4
+ contents = undefined,
5
+ reverse = false,
6
+ class: className = "",
7
+ } = $props();
8
+ </script>
9
+
10
+ <div
11
+ class="flex lg:flex-row {className}"
12
+ class:flex-col-reverse={reverse}
13
+ class:flex-col={!reverse}
14
+ >
15
+ <div
16
+ class="relative w-full lg:w-1/3 2xl:w-1/4 flex flex-col min-h-[calc(100vh-4rem)] pb-8"
17
+ >
18
+ {@render sidebar?.()}
19
+ </div>
20
+ <div
21
+ class="relative w-full lg:w-2/3 2xl:w-3/4 flex flex-col min-h-[calc(100vh-4rem)] pb-8"
22
+ >
23
+ {@render contents?.()}
24
+ </div>
25
+ </div>
@@ -0,0 +1,8 @@
1
+ declare const ContainerWithSidebar: import("svelte").Component<{
2
+ sidebar?: any;
3
+ contents?: any;
4
+ reverse?: boolean;
5
+ class?: string;
6
+ }, {}, "">;
7
+ type ContainerWithSidebar = ReturnType<typeof ContainerWithSidebar>;
8
+ export default ContainerWithSidebar;
@@ -0,0 +1,9 @@
1
+ <script lang="ts">
2
+ let { children, class: className = "", ...restProps } = $props();
3
+ </script>
4
+
5
+ <footer
6
+ class="min-h-16 text-center bg-blue-50 py-4 my-auto flex flex-col justify-center {className}"
7
+ >
8
+ {@render children?.()}
9
+ </footer>
@@ -0,0 +1,6 @@
1
+ declare const Footer: import("svelte").Component<{
2
+ children: any;
3
+ class?: string;
4
+ } & Record<string, any>, {}, "">;
5
+ type Footer = ReturnType<typeof Footer>;
6
+ export default Footer;
@@ -0,0 +1,11 @@
1
+ <script lang="ts">
2
+ let { children, class: className = "" } = $props();
3
+ </script>
4
+
5
+ <div
6
+ class="min-h-[calc(100vh-4rem)] w-full flex flex-col items-center justify-center p-8 {className}"
7
+ >
8
+ <div class="text-center lg:w-3/4 xl:w-1/2">
9
+ {@render children?.()}
10
+ </div>
11
+ </div>
@@ -0,0 +1,6 @@
1
+ declare const ScreenCenteredContainer: import("svelte").Component<{
2
+ children: any;
3
+ class?: string;
4
+ }, {}, "">;
5
+ type ScreenCenteredContainer = ReturnType<typeof ScreenCenteredContainer>;
6
+ export default ScreenCenteredContainer;
@@ -0,0 +1,29 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from "svelte";
3
+ import NavButton from "../nav/NavButton.svelte";
4
+
5
+ let { margin = true, tabs, contents, class: className = "" } = $props();
6
+
7
+ let currentTab = $state(0);
8
+ const changeTab = (tab: number) => {
9
+ currentTab = tab;
10
+ };
11
+ </script>
12
+
13
+ <div class="flex flex-row mx-4 my-2">
14
+ <div class="bg-gray-100 rounded-lg">
15
+ {#each tabs as tab, i}
16
+ <NavButton
17
+ active={currentTab === i}
18
+ onclick={() => changeTab(i)}
19
+ class={i > 0 ? "ml-1" : ""}
20
+ >
21
+ {tab}
22
+ </NavButton>
23
+ {/each}
24
+ </div>
25
+ </div>
26
+
27
+ <div class:mx-4={margin} class:my-2={margin} class={className}>
28
+ {@render contents?.(currentTab)}
29
+ </div>
@@ -0,0 +1,8 @@
1
+ declare const Tabs: import("svelte").Component<{
2
+ margin?: boolean;
3
+ tabs: any;
4
+ contents: any;
5
+ class?: string;
6
+ }, {}, "">;
7
+ type Tabs = ReturnType<typeof Tabs>;
8
+ export default Tabs;
@@ -0,0 +1,62 @@
1
+ <script lang="ts">
2
+ let menuVisible = $state(false);
3
+ let {
4
+ logoItem = undefined,
5
+ centerItems = undefined,
6
+ rightItems = undefined,
7
+ } = $props();
8
+ </script>
9
+
10
+ <nav class="w-full bg-blue-50">
11
+ <div class="relative container mx-auto h-16 py-2 px-4 flex flex-row items-center z-30">
12
+ <a
13
+ href="/"
14
+ class="text-white font-bold hover:bg-blue-100 py-2 px-4 rounded-lg transition-colors md:mr-1"
15
+ >
16
+ <div class="flex flex-row items-center text-blue-800">
17
+ {@render logoItem?.()}
18
+ </div>
19
+ </a>
20
+ <div
21
+ class="flex flex-row md:flex-row items-end md:items-start justify-end w-full"
22
+ >
23
+ <button
24
+ aria-label="Menu"
25
+ class="md:hidden py-2 px-2 hover:bg-blue-100 rounded-lg cursor-pointer transition-colors"
26
+ class:bg-blue-200={menuVisible}
27
+ class:text-blue-800={menuVisible}
28
+ class:hover:bg-blue-200={menuVisible}
29
+ class:hover:text-blue-800={menuVisible}
30
+ onclick={() => {
31
+ menuVisible = !menuVisible;
32
+ }}
33
+ >
34
+ <svg
35
+ xmlns="http://www.w3.org/2000/svg"
36
+ fill="none"
37
+ viewBox="0 0 24 24"
38
+ stroke-width="1.5"
39
+ stroke="currentColor"
40
+ class="size-6"
41
+ >
42
+ <path
43
+ stroke-linecap="round"
44
+ stroke-linejoin="round"
45
+ d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5"
46
+ />
47
+ </svg>
48
+ </button>
49
+ <div
50
+ class="absolute top-16 left-0 right-0 px-2 md:px-0 md:static flex flex-col md:flex-row md:flex md:grow bg-blue-50 md:bg-transparent pb-2 md:pb-0"
51
+ class:hidden={!menuVisible}
52
+ >
53
+ <div class="flex flex-col md:flex-row grow *:md:mr-1">
54
+ {@render centerItems?.()}
55
+ </div>
56
+ <div class="flex flex-col md:flex-row *:md:mr-1">
57
+ {@render rightItems?.()}
58
+ </div>
59
+ </div>
60
+ </div>
61
+ </div>
62
+ </nav>
@@ -0,0 +1,7 @@
1
+ declare const Nav: import("svelte").Component<{
2
+ logoItem?: any;
3
+ centerItems?: any;
4
+ rightItems?: any;
5
+ }, {}, "">;
6
+ type Nav = ReturnType<typeof Nav>;
7
+ export default Nav;
@@ -0,0 +1,27 @@
1
+ <script lang="ts">
2
+ let {
3
+ onclick = undefined,
4
+ active = false,
5
+ class: className = "",
6
+ children,
7
+ disabled = false,
8
+ danger = false,
9
+ ...restProps
10
+ } = $props();
11
+ </script>
12
+
13
+ <button
14
+ class={[
15
+ "inline-block py-2 px-4 rounded-lg transition-colors cursor-pointer",
16
+ "hover:bg-blue-100",
17
+ active && "bg-blue-100 text-blue-800",
18
+ disabled && "bg-gray-200 text-gray-700 hover:bg-gray-100 cursor-default",
19
+ danger && "text-red-800 hover:bg-red-200",
20
+ className,
21
+ ]}
22
+ {disabled}
23
+ {onclick}
24
+ {...restProps}
25
+ >
26
+ {@render children?.()}
27
+ </button>
@@ -0,0 +1,10 @@
1
+ declare const NavButton: import("svelte").Component<{
2
+ onclick?: any;
3
+ active?: boolean;
4
+ class?: string;
5
+ children: any;
6
+ disabled?: boolean;
7
+ danger?: boolean;
8
+ } & Record<string, any>, {}, "">;
9
+ type NavButton = ReturnType<typeof NavButton>;
10
+ export default NavButton;
@@ -0,0 +1,46 @@
1
+ <script lang="ts">
2
+ let { class: className = "", children, dropdownList } = $props();
3
+ import { fade, fly } from "svelte/transition";
4
+ let isDropdownVisible = $state(false);
5
+ </script>
6
+
7
+ <div class="relative">
8
+ <button
9
+ class="group w-full py-2 px-4 rounded-lg hover:bg-blue-100 cursor-pointer text-left flex flex-row items-center transition-colors {className}"
10
+ class:bg-blue-200={isDropdownVisible}
11
+ class:text-blue-800={isDropdownVisible}
12
+ class:hover:bg-blue-200={isDropdownVisible}
13
+ class:hover:text-blue-800={isDropdownVisible}
14
+ onclick={() => {
15
+ isDropdownVisible = !isDropdownVisible;
16
+ }}
17
+ >
18
+ <span class="w-full ">
19
+ {@render children?.()}
20
+ </span>
21
+ <svg
22
+ xmlns="http://www.w3.org/2000/svg"
23
+ fill="none"
24
+ viewBox="0 0 24 24"
25
+ stroke-width="1.5"
26
+ stroke="currentColor"
27
+ class="size-6 ml-2"
28
+ >
29
+ <path
30
+ stroke-linecap="round"
31
+ stroke-linejoin="round"
32
+ d="m19.5 8.25-7.5 7.5-7.5-7.5"
33
+ />
34
+ </svg>
35
+ </button>
36
+ {#if isDropdownVisible}
37
+ <div
38
+ class="absolute top-10 w-full md:min-w-64 right-0 md:px-0 flex flex-col bg-blue-50 rounded-lg *:w-full transition-all"
39
+ transition:fade={{
40
+ duration: 50,
41
+ }}
42
+ >
43
+ {@render dropdownList?.()}
44
+ </div>
45
+ {/if}
46
+ </div>
@@ -0,0 +1,7 @@
1
+ declare const NavDropdown: import("svelte").Component<{
2
+ class?: string;
3
+ children: any;
4
+ dropdownList: any;
5
+ }, {}, "">;
6
+ type NavDropdown = ReturnType<typeof NavDropdown>;
7
+ export default NavDropdown;
@@ -0,0 +1,9 @@
1
+ <script lang="ts">
2
+ let { children } = $props();
3
+ </script>
4
+
5
+ <div class="mx-4 my-2 flex flex-col items-center">
6
+ <div class="rounded-lg bg-gray-100">
7
+ {@render children?.()}
8
+ </div>
9
+ </div>
@@ -0,0 +1,5 @@
1
+ declare const NavHeader: import("svelte").Component<{
2
+ children: any;
3
+ }, {}, "">;
4
+ type NavHeader = ReturnType<typeof NavHeader>;
5
+ export default NavHeader;
@@ -0,0 +1,24 @@
1
+ <script lang="ts">
2
+ let {
3
+ href,
4
+ class: className = "",
5
+ active = false,
6
+ primary = false,
7
+ children,
8
+ ...restProps
9
+ } = $props();
10
+ </script>
11
+
12
+ <a
13
+ {href}
14
+ class={[
15
+ "inline-block py-2 px-4 rounded-lg transition-colors",
16
+ " hover:bg-blue-100",
17
+ primary && "bg-blue-800 text-white hover:bg-blue-700 hover:text-white",
18
+ active && "bg-blue-200 text-blue-800",
19
+ className,
20
+ ]}
21
+ {...restProps}
22
+ >
23
+ {@render children?.()}
24
+ </a>
@@ -0,0 +1,9 @@
1
+ declare const NavLink: import("svelte").Component<{
2
+ href: any;
3
+ class?: string;
4
+ active?: boolean;
5
+ primary?: boolean;
6
+ children: any;
7
+ } & Record<string, any>, {}, "">;
8
+ type NavLink = ReturnType<typeof NavLink>;
9
+ export default NavLink;
@@ -0,0 +1,48 @@
1
+ <script lang="ts">
2
+ import { paginate } from "../../utils/simple-pagination.js";
3
+ import NavButton from "./NavButton.svelte";
4
+
5
+ let { page, changePage, totalPages } = $props();
6
+
7
+ let pagination = $derived(paginate(page, totalPages));
8
+ </script>
9
+
10
+ <nav class="flex flex-row justify-center" aria-label="pagination">
11
+ <div class="flex flex-row justify-center bg-gray-100 rounded-lg">
12
+ {#if page > 1}
13
+ <NavButton
14
+ onclick={() => changePage(page - 1)}
15
+ disabled={page <= 1}
16
+ class="mr-1">Previous</NavButton
17
+ >
18
+ {/if}
19
+ <ul class="flex flex-row">
20
+ {#each pagination as pageEntry, i}
21
+ {#if pageEntry == "..."}
22
+ <li>
23
+ <span
24
+ class="inline-block py-2 px-4 rounded-lg font-medium"
25
+ >&hellip;</span
26
+ >
27
+ </li>
28
+ {:else}
29
+ <li>
30
+ <NavButton
31
+ class={i < pagination.length - 2 ? "mr-1" : ""}
32
+ onclick={() => changePage(pageEntry)}
33
+ aria-label="Go to page {pageEntry}"
34
+ active={page === pageEntry}>{pageEntry}</NavButton
35
+ >
36
+ </li>
37
+ {/if}
38
+ {/each}
39
+ </ul>
40
+ {#if page < totalPages}
41
+ <NavButton
42
+ class="ml-1"
43
+ onclick={() => changePage(page + 1)}
44
+ disabled={page >= totalPages}>Next</NavButton
45
+ >
46
+ {/if}
47
+ </div>
48
+ </nav>
@@ -0,0 +1,7 @@
1
+ declare const Pagination: import("svelte").Component<{
2
+ page: any;
3
+ changePage: any;
4
+ totalPages: any;
5
+ }, {}, "">;
6
+ type Pagination = ReturnType<typeof Pagination>;
7
+ export default Pagination;
@@ -0,0 +1,21 @@
1
+ import Button from "./components/form/Button.svelte";
2
+ import Input from "./components/form/Input.svelte";
3
+ import InputButton from "./components/form/InputButton.svelte";
4
+ import Label from "./components/form/Label.svelte";
5
+ import LinkButton from "./components/form/LinkButton.svelte";
6
+ import TagsInput from "./components/form/TagsInput.svelte";
7
+ import TextInput from "./components/form/TextInput.svelte";
8
+ import Image from "./components/image/Image.svelte";
9
+ import LocalImage from "./components/image/LocalImage.svelte";
10
+ import Container from "./components/layout/Container.svelte";
11
+ import ContainerWithSidebar from "./components/layout/ContainerWithSidebar.svelte";
12
+ import Footer from "./components/layout/Footer.svelte";
13
+ import ScreenCenteredContainer from "./components/layout/ScreenCenteredContainer.svelte";
14
+ import Tabs from "./components/layout/Tabs.svelte";
15
+ import Nav from "./components/nav/Nav.svelte";
16
+ import NavButton from "./components/nav/NavButton.svelte";
17
+ import NavDropdown from "./components/nav/NavDropdown.svelte";
18
+ import NavHeader from "./components/nav/NavHeader.svelte";
19
+ import NavLink from "./components/nav/NavLink.svelte";
20
+ import Pagination from "./components/nav/Pagination.svelte";
21
+ export { Button, Input, InputButton, Label, LinkButton, TagsInput, TextInput, Image, LocalImage, Container, ContainerWithSidebar, Footer, ScreenCenteredContainer, Tabs, Nav, NavButton, NavDropdown, NavHeader, NavLink, Pagination, };
package/dist/index.js ADDED
@@ -0,0 +1,34 @@
1
+ // Reexport your entry components here
2
+ // Form
3
+ import Button from "./components/form/Button.svelte";
4
+ import Input from "./components/form/Input.svelte";
5
+ import InputButton from "./components/form/InputButton.svelte";
6
+ import Label from "./components/form/Label.svelte";
7
+ import LinkButton from "./components/form/LinkButton.svelte";
8
+ import TagsInput from "./components/form/TagsInput.svelte";
9
+ import TextInput from "./components/form/TextInput.svelte";
10
+ // Image
11
+ import Image from "./components/image/Image.svelte";
12
+ import LocalImage from "./components/image/LocalImage.svelte";
13
+ // Layout
14
+ import Container from "./components/layout/Container.svelte";
15
+ import ContainerWithSidebar from "./components/layout/ContainerWithSidebar.svelte";
16
+ import Footer from "./components/layout/Footer.svelte";
17
+ import ScreenCenteredContainer from "./components/layout/ScreenCenteredContainer.svelte";
18
+ import Tabs from "./components/layout/Tabs.svelte";
19
+ // Nav
20
+ import Nav from "./components/nav/Nav.svelte";
21
+ import NavButton from "./components/nav/NavButton.svelte";
22
+ import NavDropdown from "./components/nav/NavDropdown.svelte";
23
+ import NavHeader from "./components/nav/NavHeader.svelte";
24
+ import NavLink from "./components/nav/NavLink.svelte";
25
+ import Pagination from "./components/nav/Pagination.svelte";
26
+ export {
27
+ // Form
28
+ Button, Input, InputButton, Label, LinkButton, TagsInput, TextInput,
29
+ // Image
30
+ Image, LocalImage,
31
+ // Layout
32
+ Container, ContainerWithSidebar, Footer, ScreenCenteredContainer, Tabs,
33
+ // Nav
34
+ Nav, NavButton, NavDropdown, NavHeader, NavLink, Pagination, };
@@ -0,0 +1,2 @@
1
+ declare const paginate: (c: number, m: number) => (string | number)[];
2
+ export { paginate };
@@ -0,0 +1,53 @@
1
+ // Implementation in ES6
2
+ // https://gist.github.com/kottenator/9d936eb3e4e3c3e02598
3
+ const paginate = (c, m) => {
4
+ let current = c, last = m, delta = 1, left = current - delta, right = current + delta + 1, range = [], rangeWithDots = [], l;
5
+ for (let i = 1; i <= last; i++) {
6
+ if (i == 1 || i == last || (i >= left && i < right)) {
7
+ range.push(i);
8
+ }
9
+ }
10
+ for (let i of range) {
11
+ if (l) {
12
+ if (i - l === 2) {
13
+ rangeWithDots.push(l + 1);
14
+ }
15
+ else if (i - l !== 1) {
16
+ rangeWithDots.push("...");
17
+ }
18
+ }
19
+ rangeWithDots.push(i);
20
+ l = i;
21
+ }
22
+ return rangeWithDots;
23
+ };
24
+ export { paginate };
25
+ /*
26
+ Test it:
27
+
28
+ for (let i = 1, l = 20; i <= l; i++)
29
+ console.log(`Selected page ${i}:`, pagination(i, l));
30
+
31
+ Expected output:
32
+
33
+ Selected page 1: [1, 2, 3, "...", 20]
34
+ Selected page 2: [1, 2, 3, 4, "...", 20]
35
+ Selected page 3: [1, 2, 3, 4, 5, "...", 20]
36
+ Selected page 4: [1, 2, 3, 4, 5, 6, "...", 20]
37
+ Selected page 5: [1, 2, 3, 4, 5, 6, 7, "...", 20]
38
+ Selected page 6: [1, "...", 4, 5, 6, 7, 8, "...", 20]
39
+ Selected page 7: [1, "...", 5, 6, 7, 8, 9, "...", 20]
40
+ Selected page 8: [1, "...", 6, 7, 8, 9, 10, "...", 20]
41
+ Selected page 9: [1, "...", 7, 8, 9, 10, 11, "...", 20]
42
+ Selected page 10: [1, "...", 8, 9, 10, 11, 12, "...", 20]
43
+ Selected page 11: [1, "...", 9, 10, 11, 12, 13, "...", 20]
44
+ Selected page 12: [1, "...", 10, 11, 12, 13, 14, "...", 20]
45
+ Selected page 13: [1, "...", 11, 12, 13, 14, 15, "...", 20]
46
+ Selected page 14: [1, "...", 12, 13, 14, 15, 16, "...", 20]
47
+ Selected page 15: [1, "...", 13, 14, 15, 16, 17, "...", 20]
48
+ Selected page 16: [1, "...", 14, 15, 16, 17, 18, 19, 20]
49
+ Selected page 17: [1, "...", 15, 16, 17, 18, 19, 20]
50
+ Selected page 18: [1, "...", 16, 17, 18, 19, 20]
51
+ Selected page 19: [1, "...", 17, 18, 19, 20]
52
+ Selected page 20: [1, "...", 18, 19, 20]
53
+ */
package/package.json ADDED
@@ -0,0 +1,72 @@
1
+ {
2
+ "name": "@damillora/iuno",
3
+ "version": "0.2.0",
4
+ "scripts": {
5
+ "dev": "vite dev",
6
+ "build": "vite build && npm run prepack",
7
+ "preview": "vite preview",
8
+ "prepare": "svelte-kit sync || echo ''",
9
+ "prepack": "svelte-kit sync && svelte-package && publint",
10
+ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
11
+ "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
12
+ "lint": "eslint .",
13
+ "storybook": "storybook dev -p 6006",
14
+ "build-storybook": "storybook build"
15
+ },
16
+ "files": [
17
+ "dist",
18
+ "!dist/**/*.test.*",
19
+ "!dist/**/*.spec.*"
20
+ ],
21
+ "sideEffects": [
22
+ "**/*.css"
23
+ ],
24
+ "svelte": "./dist/index.js",
25
+ "types": "./dist/index.d.ts",
26
+ "type": "module",
27
+ "exports": {
28
+ ".": {
29
+ "types": "./dist/index.d.ts",
30
+ "svelte": "./dist/index.js"
31
+ },
32
+ "./app.css": "./dist/app.css"
33
+ },
34
+ "peerDependencies": {
35
+ "svelte": "^5.0.0"
36
+ },
37
+ "devDependencies": {
38
+ "@chromatic-com/storybook": "^5.0.1",
39
+ "@eslint/compat": "^2.0.2",
40
+ "@eslint/js": "^9.39.2",
41
+ "@storybook/addon-a11y": "^10.2.10",
42
+ "@storybook/addon-docs": "^10.2.10",
43
+ "@storybook/addon-svelte-csf": "^5.0.11",
44
+ "@storybook/addon-vitest": "^10.2.10",
45
+ "@storybook/sveltekit": "^10.2.10",
46
+ "@sveltejs/adapter-auto": "^7.0.0",
47
+ "@sveltejs/kit": "^2.50.2",
48
+ "@sveltejs/package": "^2.5.7",
49
+ "@sveltejs/vite-plugin-svelte": "^6.2.4",
50
+ "@types/node": "^24",
51
+ "@vitest/browser-playwright": "^4.0.18",
52
+ "@vitest/coverage-v8": "^4.0.18",
53
+ "eslint": "^9.39.2",
54
+ "eslint-plugin-storybook": "^10.2.10",
55
+ "eslint-plugin-svelte": "^3.14.0",
56
+ "globals": "^17.3.0",
57
+ "playwright": "^1.58.2",
58
+ "publint": "^0.3.17",
59
+ "storybook": "^10.2.10",
60
+ "svelte": "^5.49.2",
61
+ "svelte-check": "^4.3.6",
62
+ "typescript": "^5.9.3",
63
+ "typescript-eslint": "^8.54.0",
64
+ "vite": "^7.3.1",
65
+ "vitest": "^4.0.18",
66
+ "@tailwindcss/vite": "^4.1.14",
67
+ "tailwindcss": "^4.1.14"
68
+ },
69
+ "keywords": [
70
+ "svelte"
71
+ ]
72
+ }