ankiutils 0.0.2 → 0.0.4

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.
@@ -0,0 +1,199 @@
1
+ <script lang="ts">
2
+ import { tick } from 'svelte';
3
+ import SelectOptions, { type SelectOption } from './SelectOptions.svelte';
4
+
5
+ interface Props {
6
+ id?: string;
7
+ options: SelectOption[];
8
+ selectedOptions: string[];
9
+ placeholder?: string;
10
+ searchPlaceholder?: string;
11
+ disabled?: boolean;
12
+ clearable?: boolean;
13
+ multiple?: boolean;
14
+ onSelected?: (value: string[]) => void;
15
+ }
16
+
17
+ let {
18
+ id,
19
+ options,
20
+ selectedOptions = $bindable<string[]>([]),
21
+ placeholder = 'Select an option...',
22
+ searchPlaceholder = 'Search...',
23
+ disabled = false,
24
+ clearable = false,
25
+ multiple = false,
26
+ onSelected = () => {}
27
+ }: Props = $props();
28
+
29
+ let searchTerm = $state('');
30
+ let isOpen = $state(false);
31
+ let highlightedIndex = $state(-1);
32
+
33
+ let containerElement: HTMLDivElement;
34
+ let inputElement: HTMLInputElement;
35
+ let optionElements: (HTMLButtonElement | HTMLInputElement)[] = $state([]);
36
+
37
+ let filteredOptions = $derived(
38
+ searchTerm
39
+ ? options.filter((option) => option.label.toLowerCase().includes(searchTerm.toLowerCase()))
40
+ : options
41
+ );
42
+
43
+ let displayValue = $derived(
44
+ isOpen
45
+ ? searchTerm
46
+ : selectedOptions
47
+ .map((option) => options.find((o) => o.value === option)?.label)
48
+ .filter((o) => o?.trim())
49
+ .join(', ') || ''
50
+ );
51
+
52
+ let selectOptionsComponent: SelectOptions | undefined = $state();
53
+
54
+ async function onOpenDropdown() {
55
+ searchTerm = '';
56
+ await tick();
57
+ inputElement?.focus();
58
+ if (highlightedIndex >= 0) {
59
+ scrollHighlightedIntoView();
60
+ }
61
+ }
62
+
63
+ function onCloseDropdown() {
64
+ searchTerm = '';
65
+ }
66
+
67
+ function clearSelection() {
68
+ if (multiple) {
69
+ selectedOptions = [];
70
+ } else {
71
+ selectedOptions = [''];
72
+ }
73
+ searchTerm = '';
74
+ inputElement?.focus();
75
+ onSelected(selectedOptions);
76
+ }
77
+
78
+ async function scrollHighlightedIntoView() {
79
+ await tick();
80
+ if (highlightedIndex >= 0 && optionElements[highlightedIndex]) {
81
+ optionElements[highlightedIndex].scrollIntoView({
82
+ behavior: 'smooth',
83
+ block: 'nearest'
84
+ });
85
+ }
86
+ }
87
+
88
+ function handleKeydown(event: KeyboardEvent) {
89
+ if (!isOpen) {
90
+ if (event.key === 'Enter' || event.key === ' ' || event.key === 'ArrowDown') {
91
+ event.preventDefault();
92
+ selectOptionsComponent?.openDropdown();
93
+ }
94
+ return;
95
+ }
96
+
97
+ switch (event.key) {
98
+ case 'Escape':
99
+ event.preventDefault();
100
+ selectOptionsComponent?.closeDropdown();
101
+ break;
102
+ case 'ArrowDown':
103
+ event.preventDefault();
104
+ highlightedIndex = Math.min(highlightedIndex + 1, filteredOptions.length - 1);
105
+ scrollHighlightedIntoView();
106
+ break;
107
+ case 'ArrowUp':
108
+ event.preventDefault();
109
+ highlightedIndex = Math.max(highlightedIndex - 1, -1);
110
+ scrollHighlightedIntoView();
111
+ break;
112
+ case 'Enter':
113
+ event.preventDefault();
114
+ if (highlightedIndex >= 0 && filteredOptions[highlightedIndex]) {
115
+ selectOptionsComponent?.selectOption(filteredOptions[highlightedIndex]);
116
+ }
117
+ break;
118
+ case 'Tab':
119
+ selectOptionsComponent?.closeDropdown();
120
+ break;
121
+ }
122
+ }
123
+
124
+ function handleClickOutside(event: MouseEvent) {
125
+ if (containerElement && !containerElement.contains(event.target as Node)) {
126
+ selectOptionsComponent?.closeDropdown();
127
+ }
128
+ }
129
+
130
+ $effect(() => {
131
+ if (isOpen) {
132
+ document.addEventListener('click', handleClickOutside);
133
+ return () => document.removeEventListener('click', handleClickOutside);
134
+ }
135
+ });
136
+ </script>
137
+
138
+ <div class="dropdown" bind:this={containerElement}>
139
+ <div class="flex gap-2">
140
+ <input
141
+ bind:this={inputElement}
142
+ {id}
143
+ class="input select-input"
144
+ type="text"
145
+ value={displayValue}
146
+ placeholder={isOpen ? searchPlaceholder : placeholder}
147
+ readonly={!isOpen}
148
+ {disabled}
149
+ oninput={(e) => {
150
+ if (isOpen) {
151
+ searchTerm = e.currentTarget.value;
152
+ highlightedIndex = -1;
153
+ optionElements = [];
154
+ }
155
+ }}
156
+ onclick={() => (isOpen = true)}
157
+ onkeydown={handleKeydown}
158
+ />
159
+
160
+ <div class="join gap-1" role="group">
161
+ {#if clearable && isOpen && selectedOptions.length > 0 && !disabled}
162
+ <button
163
+ type="button"
164
+ class="join-item btn btn-soft btn-primary clear-btn"
165
+ onclick={clearSelection}
166
+ aria-label="Clear selection"
167
+ >
168
+ <i class="bi bi-x"></i>
169
+ </button>
170
+ {/if}
171
+ <button
172
+ type="button"
173
+ class="join-item btn btn-soft btn-primary"
174
+ class:disabled
175
+ onclick={() => (isOpen = !isOpen)}
176
+ aria-label="Toggle dropdown"
177
+ >
178
+ <i class="bi bi-chevron-{isOpen ? 'up' : 'down'}"></i>
179
+ </button>
180
+ </div>
181
+ </div>
182
+
183
+ {#if isOpen}
184
+ <SelectOptions
185
+ bind:this={selectOptionsComponent}
186
+ bind:isOpen
187
+ options={filteredOptions}
188
+ bind:selectedOptions
189
+ {multiple}
190
+ {onSelected}
191
+ {onOpenDropdown}
192
+ {onCloseDropdown}
193
+ />
194
+ {/if}
195
+ </div>
196
+
197
+ <style>.select-input:focus, .select-input:focus-within {
198
+ outline: none;
199
+ }</style>
@@ -0,0 +1,15 @@
1
+ import { type SelectOption } from './SelectOptions.svelte';
2
+ interface Props {
3
+ id?: string;
4
+ options: SelectOption[];
5
+ selectedOptions: string[];
6
+ placeholder?: string;
7
+ searchPlaceholder?: string;
8
+ disabled?: boolean;
9
+ clearable?: boolean;
10
+ multiple?: boolean;
11
+ onSelected?: (value: string[]) => void;
12
+ }
13
+ declare const BaseSelect: import("svelte").Component<Props, {}, "selectedOptions">;
14
+ type BaseSelect = ReturnType<typeof BaseSelect>;
15
+ export default BaseSelect;
@@ -0,0 +1,53 @@
1
+ <script lang="ts">
2
+ import SelectOptions, { type SelectOption } from './SelectOptions.svelte';
3
+
4
+ interface Props {
5
+ label: string;
6
+ options: SelectOption[];
7
+ selectedOptions: string[];
8
+ multiple?: boolean;
9
+ onSelected?: (value: string[]) => void;
10
+ }
11
+
12
+ let {
13
+ label,
14
+ options,
15
+ selectedOptions = $bindable<string[]>([]),
16
+ multiple = false,
17
+ onSelected = () => {}
18
+ }: Props = $props();
19
+
20
+ let isOpen = $state(false);
21
+ let containerElement: HTMLDivElement;
22
+ let selectOptionsComponent: SelectOptions | undefined = $state();
23
+
24
+ function handleClickOutside(event: MouseEvent) {
25
+ if (containerElement && !containerElement.contains(event.target as Node)) {
26
+ selectOptionsComponent?.closeDropdown();
27
+ }
28
+ }
29
+
30
+ $effect(() => {
31
+ if (isOpen) {
32
+ document.addEventListener('click', handleClickOutside);
33
+ return () => document.removeEventListener('click', handleClickOutside);
34
+ }
35
+ });
36
+ </script>
37
+
38
+ <div class="dropdown" bind:this={containerElement}>
39
+ <button class="btn" onclick={() => (isOpen = !isOpen)}>
40
+ <span>{label}</span>
41
+ <i class="bi bi-chevron-{isOpen ? 'up' : 'down'}"></i>
42
+ </button>
43
+ {#if isOpen}
44
+ <SelectOptions
45
+ bind:this={selectOptionsComponent}
46
+ {options}
47
+ bind:selectedOptions
48
+ {multiple}
49
+ {onSelected}
50
+ bind:isOpen
51
+ />
52
+ {/if}
53
+ </div>
@@ -0,0 +1,11 @@
1
+ import { type SelectOption } from './SelectOptions.svelte';
2
+ interface Props {
3
+ label: string;
4
+ options: SelectOption[];
5
+ selectedOptions: string[];
6
+ multiple?: boolean;
7
+ onSelected?: (value: string[]) => void;
8
+ }
9
+ declare const Dropdown: import("svelte").Component<Props, {}, "selectedOptions">;
10
+ type Dropdown = ReturnType<typeof Dropdown>;
11
+ export default Dropdown;
@@ -0,0 +1,43 @@
1
+ <script lang="ts">
2
+ interface Props {
3
+ keys: string[];
4
+ }
5
+
6
+ let { keys = $bindable([]) }: Props = $props();
7
+ let keysDisplay = $derived.by(() => {
8
+ let components = [];
9
+ for (let key of keys) {
10
+ if (key === ' ') {
11
+ key = 'space';
12
+ }
13
+ components.push(key[0].toUpperCase() + key.slice(1));
14
+ }
15
+ return components.join(',');
16
+ });
17
+
18
+ function onKeydown(event: Event) {
19
+ keys = [...keys, (event as KeyboardEvent).key];
20
+ event.preventDefault();
21
+ }
22
+
23
+ function clearKeys() {
24
+ keys = [];
25
+ }
26
+ </script>
27
+
28
+ <div class="join">
29
+ <input
30
+ class="join-item input"
31
+ type="text"
32
+ value={keysDisplay}
33
+ onkeydown={onKeydown}
34
+ placeholder="Press shortcut"
35
+ />
36
+ <button class="join-item btn btn-primary btn-soft" aria-label="Clear" onclick={clearKeys}>
37
+ <i class="bi bi-x"></i>
38
+ </button>
39
+ </div>
40
+
41
+ <style>input:focus, input:focus-within {
42
+ outline: none;
43
+ }</style>
@@ -0,0 +1,6 @@
1
+ interface Props {
2
+ keys: string[];
3
+ }
4
+ declare const KeyboardInput: import("svelte").Component<Props, {}, "keys">;
5
+ type KeyboardInput = ReturnType<typeof KeyboardInput>;
6
+ export default KeyboardInput;
@@ -0,0 +1,91 @@
1
+ <script lang="ts">
2
+ export interface Option {
3
+ value: string;
4
+ label: string;
5
+ }
6
+
7
+ interface Props {
8
+ selectedOption: string;
9
+ options: Option[];
10
+ placeholder?: string;
11
+ onSelected?: () => void;
12
+ }
13
+
14
+ let {
15
+ selectedOption = $bindable(),
16
+ onSelected,
17
+ options,
18
+ placeholder = 'Search...'
19
+ }: Props = $props();
20
+ let search = $state('');
21
+ let filteredOptions = $derived.by(() =>
22
+ search
23
+ ? options.filter(
24
+ (opt) =>
25
+ opt.value.toLowerCase().includes(search.toLowerCase()) ||
26
+ opt.label.toLowerCase().includes(search.toLowerCase())
27
+ )
28
+ : options
29
+ );
30
+ let selectedIndex = $derived.by(() => {
31
+ for (let i = 0; i < filteredOptions.length; i++) {
32
+ if (isOptionSelected(filteredOptions[i])) return i;
33
+ }
34
+ return -1;
35
+ });
36
+
37
+ let inputElement: HTMLInputElement;
38
+ let modalElement: HTMLDialogElement;
39
+ let optionElements: HTMLButtonElement[] = $state([]);
40
+
41
+ function isOptionSelected(option: Option) {
42
+ return option.value.toLowerCase() === selectedOption.toLowerCase();
43
+ }
44
+
45
+ function selectOption(language: Option) {
46
+ selectedOption = language.value;
47
+ modalElement.close();
48
+ onSelected?.();
49
+ }
50
+
51
+ export function show() {
52
+ modalElement.showModal();
53
+ inputElement.focus();
54
+ if (selectedIndex >= 0) {
55
+ optionElements[selectedIndex].scrollIntoView({
56
+ block: 'center'
57
+ });
58
+ }
59
+ }
60
+ </script>
61
+
62
+ <dialog class="modal" aria-hidden="true" bind:this={modalElement}>
63
+ <div class="modal-box max-w-5xl pt-1">
64
+ <input
65
+ bind:this={inputElement}
66
+ class="search-input input w-full sticky mb-2 top-0"
67
+ type="text"
68
+ bind:value={search}
69
+ {placeholder}
70
+ />
71
+ <div class="grid grid-cols-[repeat(auto-fill,minmax(25ch,1fr))] gap-2">
72
+ {#each filteredOptions as option, i (option.value)}
73
+ <button
74
+ bind:this={optionElements[i]}
75
+ class="btn"
76
+ class:btn-primary={isOptionSelected(option)}
77
+ onclick={() => selectOption(option)}
78
+ >
79
+ {option.label}
80
+ </button>
81
+ {/each}
82
+ </div>
83
+ </div>
84
+ <form method="dialog" class="modal-backdrop">
85
+ <button>close</button>
86
+ </form>
87
+ </dialog>
88
+
89
+ <style>.search-input:focus, .search-input:focus-within {
90
+ outline: none;
91
+ }</style>
@@ -0,0 +1,15 @@
1
+ export interface Option {
2
+ value: string;
3
+ label: string;
4
+ }
5
+ interface Props {
6
+ selectedOption: string;
7
+ options: Option[];
8
+ placeholder?: string;
9
+ onSelected?: () => void;
10
+ }
11
+ declare const ModalSelector: import("svelte").Component<Props, {
12
+ show: () => void;
13
+ }, "selectedOption">;
14
+ type ModalSelector = ReturnType<typeof ModalSelector>;
15
+ export default ModalSelector;
@@ -0,0 +1,38 @@
1
+ <script lang="ts">
2
+ import BaseSelect from './BaseSelect.svelte';
3
+ import { type SelectOption } from './SelectOptions.svelte';
4
+
5
+ interface Props {
6
+ id?: string;
7
+ options: SelectOption[];
8
+ selectedOptions: string[];
9
+ placeholder?: string;
10
+ searchPlaceholder?: string;
11
+ disabled?: boolean;
12
+ clearable?: boolean;
13
+ onSelected?: (options: string[]) => void;
14
+ }
15
+
16
+ let {
17
+ id,
18
+ options,
19
+ selectedOptions = $bindable<string[]>([]),
20
+ placeholder,
21
+ searchPlaceholder,
22
+ disabled = false,
23
+ clearable = true,
24
+ onSelected = () => {}
25
+ }: Props = $props();
26
+ </script>
27
+
28
+ <BaseSelect
29
+ {id}
30
+ {options}
31
+ bind:selectedOptions
32
+ {placeholder}
33
+ {searchPlaceholder}
34
+ {disabled}
35
+ {clearable}
36
+ multiple={true}
37
+ {onSelected}
38
+ />
@@ -0,0 +1,14 @@
1
+ import { type SelectOption } from './SelectOptions.svelte';
2
+ interface Props {
3
+ id?: string;
4
+ options: SelectOption[];
5
+ selectedOptions: string[];
6
+ placeholder?: string;
7
+ searchPlaceholder?: string;
8
+ disabled?: boolean;
9
+ clearable?: boolean;
10
+ onSelected?: (options: string[]) => void;
11
+ }
12
+ declare const MultiSelect: import("svelte").Component<Props, {}, "selectedOptions">;
13
+ type MultiSelect = ReturnType<typeof MultiSelect>;
14
+ export default MultiSelect;
@@ -0,0 +1,43 @@
1
+ <script lang="ts">
2
+ import BaseSelect from './BaseSelect.svelte';
3
+ import { type SelectOption } from './SelectOptions.svelte';
4
+ interface Props {
5
+ id?: string;
6
+ options: SelectOption[];
7
+ value?: string;
8
+ placeholder?: string;
9
+ searchPlaceholder?: string;
10
+ disabled?: boolean;
11
+ clearable?: boolean;
12
+ onSelected?: (value: string) => void;
13
+ }
14
+
15
+ let {
16
+ id,
17
+ options,
18
+ value = $bindable(''),
19
+ placeholder,
20
+ searchPlaceholder,
21
+ disabled = false,
22
+ clearable = false,
23
+ onSelected = () => {}
24
+ }: Props = $props();
25
+
26
+ let selectedOptions = $state<string[]>([value]);
27
+
28
+ $effect(() => {
29
+ value = selectedOptions[0] || '';
30
+ });
31
+ </script>
32
+
33
+ <BaseSelect
34
+ {id}
35
+ {options}
36
+ bind:selectedOptions
37
+ {placeholder}
38
+ {searchPlaceholder}
39
+ {disabled}
40
+ {clearable}
41
+ multiple={false}
42
+ onSelected={(options) => onSelected(options[0])}
43
+ />
@@ -0,0 +1,14 @@
1
+ import { type SelectOption } from './SelectOptions.svelte';
2
+ interface Props {
3
+ id?: string;
4
+ options: SelectOption[];
5
+ value?: string;
6
+ placeholder?: string;
7
+ searchPlaceholder?: string;
8
+ disabled?: boolean;
9
+ clearable?: boolean;
10
+ onSelected?: (value: string) => void;
11
+ }
12
+ declare const Select: import("svelte").Component<Props, {}, "value">;
13
+ type Select = ReturnType<typeof Select>;
14
+ export default Select;
@@ -0,0 +1,86 @@
1
+ <script lang="ts">
2
+ export interface SelectOption {
3
+ value: string;
4
+ label: string;
5
+ }
6
+
7
+ interface Props {
8
+ options: SelectOption[];
9
+ selectedOptions: string[];
10
+ multiple?: boolean;
11
+ isOpen?: boolean;
12
+ onSelected?: (value: string[]) => void;
13
+ onOpenDropdown?: () => void;
14
+ onCloseDropdown?: () => void;
15
+ }
16
+
17
+ let {
18
+ options,
19
+ selectedOptions = $bindable<string[]>([]),
20
+ multiple = false,
21
+ isOpen = $bindable(false),
22
+ onSelected,
23
+ onOpenDropdown,
24
+ onCloseDropdown
25
+ }: Props = $props();
26
+
27
+ let optionElements: (HTMLButtonElement | HTMLInputElement)[] = $state([]);
28
+
29
+ export async function openDropdown() {
30
+ isOpen = true;
31
+ optionElements = [];
32
+ onOpenDropdown?.();
33
+ }
34
+
35
+ export function closeDropdown() {
36
+ isOpen = false;
37
+ optionElements = [];
38
+ onCloseDropdown?.();
39
+ }
40
+
41
+ export function selectOption(option: SelectOption) {
42
+ if (multiple) {
43
+ if (selectedOptions.includes(option.value)) {
44
+ selectedOptions = selectedOptions.filter((o) => o !== option.value);
45
+ } else {
46
+ selectedOptions.push(option.value);
47
+ }
48
+ } else {
49
+ selectedOptions = [option.value];
50
+ closeDropdown();
51
+ }
52
+ onSelected?.(selectedOptions);
53
+ }
54
+ </script>
55
+
56
+ <div class="menu dropdown-content bg-base-100 rounded-box z-1 w-52 p-2 shadow-sm gap-1">
57
+ {#if options.length === 0}
58
+ <div class="text-gray-400">No options found</div>
59
+ {:else}
60
+ {#each options as option, index (option.value)}
61
+ {@const checked = selectedOptions.includes(option.value)}
62
+
63
+ {#if multiple}
64
+ <input
65
+ bind:this={optionElements[index]}
66
+ type="checkbox"
67
+ class="btn"
68
+ class:btn-primary={checked}
69
+ {checked}
70
+ aria-label={option.label}
71
+ onclick={() => selectOption(option)}
72
+ />
73
+ {:else}
74
+ <button
75
+ bind:this={optionElements[index]}
76
+ type="button"
77
+ class="btn"
78
+ class:btn-primary={checked}
79
+ onclick={() => selectOption(option)}
80
+ >
81
+ {option.label}
82
+ </button>
83
+ {/if}
84
+ {/each}
85
+ {/if}
86
+ </div>
@@ -0,0 +1,20 @@
1
+ export interface SelectOption {
2
+ value: string;
3
+ label: string;
4
+ }
5
+ interface Props {
6
+ options: SelectOption[];
7
+ selectedOptions: string[];
8
+ multiple?: boolean;
9
+ isOpen?: boolean;
10
+ onSelected?: (value: string[]) => void;
11
+ onOpenDropdown?: () => void;
12
+ onCloseDropdown?: () => void;
13
+ }
14
+ declare const SelectOptions: import("svelte").Component<Props, {
15
+ openDropdown: () => Promise<void>;
16
+ closeDropdown: () => void;
17
+ selectOption: (option: SelectOption) => void;
18
+ }, "selectedOptions" | "isOpen">;
19
+ type SelectOptions = ReturnType<typeof SelectOptions>;
20
+ export default SelectOptions;
@@ -1,2 +1,8 @@
1
- import Spinner from "./Spinner.svelte";
2
- export { Spinner };
1
+ import Spinner from './Spinner.svelte';
2
+ import type { SelectOption } from './SelectOptions.svelte';
3
+ import Select from './Select.svelte';
4
+ import MultiSelect from './MultiSelect.svelte';
5
+ import Dropdown from './Dropdown.svelte';
6
+ import ModalSelector from './ModalSelector.svelte';
7
+ import KeyboardInput from './KeyboardInput.svelte';
8
+ export { Spinner, type SelectOption, Select, MultiSelect, Dropdown, ModalSelector, KeyboardInput };
@@ -1,2 +1,7 @@
1
- import Spinner from "./Spinner.svelte";
2
- export { Spinner };
1
+ import Spinner from './Spinner.svelte';
2
+ import Select from './Select.svelte';
3
+ import MultiSelect from './MultiSelect.svelte';
4
+ import Dropdown from './Dropdown.svelte';
5
+ import ModalSelector from './ModalSelector.svelte';
6
+ import KeyboardInput from './KeyboardInput.svelte';
7
+ export { Spinner, Select, MultiSelect, Dropdown, ModalSelector, KeyboardInput };
package/dist/index.d.ts CHANGED
@@ -2,4 +2,4 @@ export * from "./bridgecommand";
2
2
  export * from "./promise";
3
3
  export * from "./proto";
4
4
  export * from "./theme.svelte";
5
- export * from "./components/index";
5
+ export * from "./components";
package/dist/index.js CHANGED
@@ -2,4 +2,4 @@ export * from "./bridgecommand";
2
2
  export * from "./promise";
3
3
  export * from "./proto";
4
4
  export * from "./theme.svelte";
5
- export * from "./components/index";
5
+ export * from "./components";
package/dist/promise.d.ts CHANGED
@@ -1 +1 @@
1
- export declare function promiseWithResolver<T>(): [Promise<T>, (value: T) => void];
1
+ export declare function promiseWithResolver<T>(): [Promise<T>, (value: T) => void, (error: unknown) => void];
package/dist/promise.js CHANGED
@@ -1,5 +1,6 @@
1
1
  export function promiseWithResolver() {
2
2
  let resolve;
3
- const promise = new Promise((res) => (resolve = res));
4
- return [promise, resolve];
3
+ let reject;
4
+ const promise = new Promise((res, rej) => (resolve = res, reject = rej));
5
+ return [promise, resolve, reject];
5
6
  }
package/dist/style.css ADDED
@@ -0,0 +1,4 @@
1
+ @import 'tailwindcss';
2
+ @plugin "daisyui";
3
+
4
+ @import 'bootstrap-icons/font/bootstrap-icons';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ankiutils",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "license": "AGPL-3.0-or-later",
5
5
  "scripts": {
6
6
  "dev": "vite dev",
@@ -31,16 +31,27 @@
31
31
  }
32
32
  },
33
33
  "peerDependencies": {
34
- "svelte": "^5.0.0"
34
+ "bootstrap-icons": "^1.13.1",
35
+ "svelte": "^5.0.0",
36
+ "@bufbuild/protobuf": "^2.7.0",
37
+ "@connectrpc/connect": "^2.1.0",
38
+ "@connectrpc/connect-web": "^2.1.0"
35
39
  },
36
40
  "devDependencies": {
41
+ "@bufbuild/buf": "^1.57.0",
42
+ "@bufbuild/protobuf": "^2.7.0",
43
+ "@connectrpc/connect": "^2.1.0",
44
+ "@connectrpc/connect-web": "^2.1.0",
37
45
  "@eslint/compat": "^1.4.0",
38
46
  "@eslint/js": "^9.39.1",
39
- "@sveltejs/adapter-auto": "^7.0.0",
47
+ "@sveltejs/adapter-static": "^3.0.10",
40
48
  "@sveltejs/kit": "^2.49.1",
41
49
  "@sveltejs/package": "^2.5.7",
42
50
  "@sveltejs/vite-plugin-svelte": "^6.2.1",
51
+ "@tailwindcss/vite": "^4.1.18",
43
52
  "@types/node": "^24",
53
+ "bootstrap-icons": "^1.13.1",
54
+ "daisyui": "^5.5.14",
44
55
  "eslint": "^9.39.1",
45
56
  "eslint-config-prettier": "^10.1.8",
46
57
  "eslint-plugin-svelte": "^3.13.1",
@@ -51,6 +62,7 @@
51
62
  "sass": "^1.97.2",
52
63
  "svelte": "^5.45.6",
53
64
  "svelte-check": "^4.3.4",
65
+ "tailwindcss": "^4.1.18",
54
66
  "typescript": "^5.9.3",
55
67
  "typescript-eslint": "^8.48.1",
56
68
  "vite": "^7.2.6"