duckylib 0.1.2 → 0.1.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.
Files changed (32) hide show
  1. package/dist/components/buttons/Button.svelte +109 -0
  2. package/dist/components/buttons/Button.svelte.d.ts +10 -0
  3. package/dist/components/containers/AgeConfirm.svelte +100 -0
  4. package/dist/components/containers/AgeConfirm.svelte.d.ts +7 -0
  5. package/dist/components/containers/Column.svelte +3 -2
  6. package/dist/components/containers/Column.svelte.d.ts +1 -1
  7. package/dist/components/containers/HorizontalRule.svelte +39 -0
  8. package/dist/components/containers/HorizontalRule.svelte.d.ts +13 -0
  9. package/dist/components/containers/Loading.svelte +62 -0
  10. package/dist/components/containers/Loading.svelte.d.ts +3 -0
  11. package/dist/components/containers/Row.svelte +1 -0
  12. package/dist/components/containers/cards/{LinkCard.svelte → ButtonCard.svelte} +18 -10
  13. package/dist/components/containers/cards/ButtonCard.svelte.d.ts +15 -0
  14. package/dist/components/containers/navigation/Header.svelte +40 -4
  15. package/dist/components/containers/navigation/Header.svelte.d.ts +11 -2
  16. package/dist/components/containers/navigation/SearchBar.svelte +539 -0
  17. package/dist/components/containers/navigation/SearchBar.svelte.d.ts +22 -0
  18. package/dist/components/text/Code.svelte +19 -0
  19. package/dist/components/text/Code.svelte.d.ts +11 -0
  20. package/dist/components/text/Markdown.svelte +62 -8
  21. package/dist/components/text/Markdown.svelte.d.ts +8 -3
  22. package/dist/components/text/Text.svelte +40 -0
  23. package/dist/components/text/Text.svelte.d.ts +15 -0
  24. package/dist/components/text/Typewriter.svelte +3 -3
  25. package/dist/index.d.ts +0 -24
  26. package/dist/index.js +49 -2
  27. package/dist/styles/fonts.css +1 -0
  28. package/dist/styles/theme.css +4 -0
  29. package/package.json +4 -3
  30. package/dist/components/containers/cards/LinkCard.svelte.d.ts +0 -14
  31. package/dist/components/index.d.ts +0 -1
  32. package/dist/components/index.js +0 -2
@@ -0,0 +1,539 @@
1
+ <script lang="ts">
2
+ import { browser } from "$app/environment";
3
+ import { goto } from "$app/navigation";
4
+ import {
5
+ PUBLIC_MOBILE_SIZE_PX,
6
+ PUBLIC_TABLET_SIZE_PX,
7
+ } from "$env/static/public";
8
+ import Heading from "../../text/Heading.svelte";
9
+ import Symbol from "../../text/Symbol.svelte";
10
+ import Text from "../../text/Text.svelte";
11
+ import { onMount } from "svelte";
12
+ import { MediaQuery } from "svelte/reactivity";
13
+ import Column from "../Column.svelte";
14
+ import Row from "../Row.svelte";
15
+
16
+ export interface SearchResult {
17
+ query?: string | null;
18
+ href?: string | null;
19
+
20
+ iconUrl?: string | null;
21
+
22
+ name: string;
23
+ description?: string | null;
24
+
25
+ onclick?: (e: MouseEvent) => Promise<void>;
26
+ }
27
+
28
+ export type QueryMapKeys = keyof SearchResult;
29
+
30
+ interface SearchBarProps {
31
+ queryUrl?: string;
32
+ queryObjMap?: { [key in QueryMapKeys]: string | null };
33
+ queryDataKey?: string;
34
+
35
+ options: SearchResult[];
36
+ onsearch: ((query: string) => Promise<void>) | null;
37
+ onresult: (result: SearchResult) => Promise<void>;
38
+ }
39
+
40
+ let {
41
+ onsearch,
42
+ onresult,
43
+ options = [],
44
+ queryUrl,
45
+ queryObjMap,
46
+ queryDataKey,
47
+ }: SearchBarProps = $props();
48
+
49
+ let searching = $state(false);
50
+
51
+ let showBar = $state(false);
52
+ let showInput = $state(false);
53
+
54
+ let showContextMenu = $state(false);
55
+
56
+ let closing = $state(false);
57
+
58
+ let query = $state("");
59
+ let results: SearchResult[] = $state([]);
60
+
61
+ const mobileQuery = new MediaQuery(`max-width: ${PUBLIC_MOBILE_SIZE_PX}px`);
62
+ const tabletQuery = new MediaQuery(`max-width: ${PUBLIC_TABLET_SIZE_PX}px`);
63
+
64
+ onMount(() => {
65
+ query = "";
66
+ searching = false;
67
+ showBar = false;
68
+ showInput = false;
69
+ closeResults();
70
+ });
71
+
72
+ function submitSearch() {
73
+ if (onsearch) onsearch(query);
74
+ query = "";
75
+ showBar = false;
76
+ showInput = false;
77
+ searching = false;
78
+ }
79
+
80
+ function searchWithQuery(q: string): SearchResult[] {
81
+ let MAX = 3;
82
+ let re: SearchResult[] = [];
83
+
84
+ if (!queryUrl || !queryObjMap) {
85
+ options.forEach((o) => {
86
+ let pass = false;
87
+ if (o.name.toLowerCase().includes(q.toLowerCase())) pass = true;
88
+ if (
89
+ o?.description &&
90
+ o.description.toLowerCase().includes(q.toLowerCase())
91
+ )
92
+ pass = true;
93
+
94
+ if (pass && re.length < MAX) re.push(o);
95
+ });
96
+
97
+ if (re.length > 1) showContextMenu = true;
98
+
99
+ console.log("RESULTS", re);
100
+
101
+ results = re;
102
+ } else if (queryUrl && queryObjMap) {
103
+ let url = queryUrl.replace("%s", q);
104
+ if (!queryDataKey) {
105
+ results = [];
106
+ return [];
107
+ }
108
+
109
+ if (!queryObjMap.name || queryObjMap.name === null) {
110
+ results = [];
111
+ return [];
112
+ }
113
+
114
+ console.log(new URL(url).hostname)
115
+
116
+ fetch(url)
117
+ .then((r) =>
118
+ r.json().then((r: Record<string, any>) => {
119
+ console.log(r)
120
+ let obj: any = null;
121
+
122
+ if (queryObjMap.name !== null) {
123
+ if (!queryDataKey) {
124
+ if (!r[queryObjMap.name as string]) {
125
+ results = [];
126
+ return [];
127
+ } else {
128
+ obj = r;
129
+ }
130
+ } else if (queryDataKey) {
131
+ if (!r[queryDataKey]) {
132
+ results = [];
133
+ return [];
134
+ } else {
135
+ obj = r[queryDataKey];
136
+ }
137
+ } else {
138
+ results = [];
139
+ return [];
140
+ }
141
+ }
142
+
143
+ console.log(obj)
144
+
145
+ if (obj !== null && queryObjMap.name) {
146
+ if (!obj?.length || obj?.length === undefined) {
147
+ console.log("obj is not array")
148
+ let result: SearchResult = {
149
+ name: obj[queryObjMap.name],
150
+ query: q,
151
+ };
152
+
153
+ if (
154
+ queryObjMap.description &&
155
+ obj[queryObjMap.description]
156
+ )
157
+ result.description =
158
+ obj[queryObjMap.description];
159
+ if (queryObjMap.href && obj[queryObjMap.href])
160
+ result.href = obj[queryObjMap.href];
161
+ if (
162
+ queryObjMap.iconUrl &&
163
+ obj[queryObjMap.iconUrl]
164
+ )
165
+ result.iconUrl = obj[queryObjMap.iconUrl];
166
+
167
+ if(re.length < MAX) re.push(result);
168
+
169
+ results = re;
170
+ return re;
171
+ } else {
172
+ console.log("obj is array");
173
+ (obj as any[]).forEach((e: any) => {
174
+ let result: SearchResult = {
175
+ name: e[queryObjMap.name as string],
176
+ query: q,
177
+ };
178
+
179
+ if (
180
+ queryObjMap.description &&
181
+ e[queryObjMap.description]
182
+ )
183
+ result.description =
184
+ e[queryObjMap.description];
185
+ if (queryObjMap.href && e[queryObjMap.href])
186
+ result.href = e[queryObjMap.href];
187
+ if (
188
+ queryObjMap.iconUrl &&
189
+ e[queryObjMap.iconUrl]
190
+ )
191
+ result.iconUrl = e[queryObjMap.iconUrl];
192
+
193
+ if(re.length < MAX) re.push(result);
194
+ });
195
+
196
+ if (re.length > 1) showContextMenu = true;
197
+ results = re;
198
+ return re;
199
+ }
200
+ } else {
201
+ results = [];
202
+ return [];
203
+ }
204
+ }),
205
+ )
206
+ .catch((r) => {
207
+ results = [];
208
+ return [];
209
+ });
210
+ } else {
211
+ options.forEach((o) => {
212
+ let pass = false;
213
+ if (o.name.toLowerCase().includes(q.toLowerCase())) pass = true;
214
+ if (
215
+ o?.description &&
216
+ o.description.toLowerCase().includes(q.toLowerCase())
217
+ )
218
+ pass = true;
219
+
220
+ if (pass && re.length < MAX) re.push(o);
221
+ });
222
+
223
+ if (re.length > 1) showContextMenu = true;
224
+
225
+ console.log("RESULTS", re);
226
+
227
+ results = re;
228
+ }
229
+
230
+ return re;
231
+ }
232
+
233
+ function closeResults() {
234
+ results = [];
235
+ showContextMenu = false;
236
+ }
237
+ </script>
238
+
239
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
240
+ <!-- svelte-ignore a11y_click_events_have_key_events -->
241
+ <div
242
+ id="outer"
243
+ onclick={async () => {
244
+ console.log("click");
245
+ if (!closing) {
246
+ if (query !== "") {
247
+ submitSearch();
248
+ } else if (!showBar && !searching) {
249
+ showBar = true;
250
+ showInput = true;
251
+ }
252
+ } else {
253
+ closing = false;
254
+ }
255
+
256
+ console.log(showBar);
257
+ }}
258
+ >
259
+ <Symbol name="search" />
260
+ <!-- {#if showInput} -->
261
+ <input
262
+ data-show={showInput}
263
+ class="font-semibold"
264
+ type="text"
265
+ name="query"
266
+ id="query"
267
+ placeholder="Search Query..."
268
+ onclick={() => {
269
+ showInput = true;
270
+ showBar = true;
271
+ }}
272
+ onkeypress={(e) => {
273
+ if (e.key === "Enter" && query !== "") {
274
+ submitSearch();
275
+ }
276
+ }}
277
+ bind:value={
278
+ () => query,
279
+ (v) => {
280
+ query = v.trimStart();
281
+ searching = query.length > 0;
282
+ if (searching) searchWithQuery(query);
283
+ if (!searching) closeResults();
284
+ }
285
+ }
286
+ />
287
+ {#if showInput}
288
+ <div
289
+ id="close"
290
+ onclick={() => {
291
+ if (showInput && !closing) {
292
+ closing = true;
293
+ query = "";
294
+ showBar = false;
295
+ showInput = false;
296
+ searching = false;
297
+ }
298
+ }}
299
+ >
300
+ <Symbol name="close" sizePx={18} />
301
+ </div>
302
+ {/if}
303
+ <contextmenu
304
+ style="visibility:{showContextMenu ? 'visible' : 'hidden'};"
305
+ class={showContextMenu ? "show" : "hide"}
306
+ >
307
+ {#each results as result}
308
+ <!-- svelte-ignore a11y_click_events_have_key_events -->
309
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
310
+ <contextentry
311
+ data-disabled="false"
312
+ onclick={async (e: any) => {
313
+ if (result.onclick && !result.href) {
314
+ await result.onclick(e);
315
+ } else if (result.href) {
316
+ if (window.location.href.startsWith("/")) {
317
+ if (browser) goto(result.href);
318
+ return;
319
+ } else {
320
+ if (browser) window.open(result.href);
321
+ }
322
+ }
323
+ }}
324
+ >
325
+ <Row
326
+ justifyContent="flex-start"
327
+ alignItems="flex-start"
328
+ heightPx="fit"
329
+ >
330
+ {#if result.iconUrl}
331
+ <img src={result.iconUrl} alt="{result.name} icon" />
332
+ {/if}
333
+ <Column
334
+ justifyContent="flex-end"
335
+ alignItems="flex-start"
336
+ heightPx="fit"
337
+ textWrap={true}
338
+ textAlign="left"
339
+ gapEm={0.2}
340
+ >
341
+ <Text sizeEm={1} weight="bolder" maxLines={1}
342
+ >{result.name}</Text
343
+ >
344
+ {#if result.description}
345
+ <Text
346
+ classList={["italic"]}
347
+ sizeEm={0.8}
348
+ maxLines={1}
349
+ weight="semibold">{result.description}</Text
350
+ >
351
+ {/if}
352
+ </Column>
353
+ </Row>
354
+ </contextentry>
355
+ {/each}
356
+ </contextmenu>
357
+ </div>
358
+
359
+ <style>
360
+ @import url("$lib/styles/globals.css");
361
+
362
+ @keyframes input_focus {
363
+ 0% {
364
+ opacity: 0;
365
+ display: none;
366
+ width: 0%;
367
+ }
368
+
369
+ 1% {
370
+ opacity: 1;
371
+ display: flex;
372
+ width: 0%;
373
+ }
374
+
375
+ 100% {
376
+ width: 100%;
377
+ opacity: 1;
378
+ /* display: flex; */
379
+ }
380
+ }
381
+
382
+ @keyframes fade_in {
383
+ from {
384
+ display: none;
385
+ opacity: 0;
386
+ }
387
+
388
+ to {
389
+ display: flex;
390
+ opacity: 1;
391
+ }
392
+ }
393
+
394
+ @keyframes show {
395
+ from {
396
+ display: none;
397
+ opacity: 0;
398
+ top: 3em;
399
+ right: 0.33em;
400
+ }
401
+ to {
402
+ display: flex;
403
+ opacity: 1;
404
+ top: 3.33em;
405
+ right: 3.66em;
406
+ }
407
+ }
408
+
409
+ @keyframes hide {
410
+ from {
411
+ display: flex;
412
+ opacity: 1;
413
+ top: 3.66em;
414
+ right: 0.66em;
415
+ }
416
+ to {
417
+ display: none;
418
+ opacity: 0;
419
+ top: 3em;
420
+ right: 0.33em;
421
+ }
422
+ }
423
+
424
+ .show {
425
+ animation: show 0.1s ease-in forwards;
426
+ }
427
+
428
+ .hide {
429
+ animation: hide 0.1s ease-in forwards;
430
+ }
431
+
432
+ contextmenu {
433
+ /* display: flex; */
434
+ flex-direction: column;
435
+ align-items: flex-start;
436
+ justify-content: flex-start;
437
+ width: 300px;
438
+
439
+ position: absolute;
440
+ top: 0;
441
+ right: 0;
442
+
443
+ user-select: none;
444
+ background-color: var(--surface-0);
445
+ filter: drop-shadow(0 3px 5px 1px var(--crust));
446
+
447
+ padding: 0.33em 0.33em;
448
+
449
+ border-radius: 8px;
450
+
451
+ /* animation: ; */
452
+ }
453
+
454
+ #outer {
455
+ width: auto;
456
+ display: flex;
457
+ flex-direction: row;
458
+ justify-content: flex-start;
459
+ align-items: center;
460
+
461
+ gap: 0.66em;
462
+ padding: 0.05em 0.66em;
463
+
464
+ border: 2px solid var(--base);
465
+ border-radius: var(--border-md);
466
+
467
+ background-color: var(--mantle);
468
+
469
+ cursor: pointer;
470
+ }
471
+
472
+ input {
473
+ min-width: 150px;
474
+ background-color: transparent;
475
+ border: none;
476
+ outline: none;
477
+ color: var(--text);
478
+ }
479
+
480
+ input[data-show="false"] {
481
+ width: 0px;
482
+ display: none;
483
+ }
484
+
485
+ input[data-show="true"] {
486
+ border-bottom: 2px solid var(--surface-0);
487
+ animation: 0.2s linear forwards input_focus;
488
+ }
489
+
490
+ #close {
491
+ animation: 0.5s fade_in forwards linear;
492
+ z-index: 5000;
493
+ }
494
+
495
+ contextentry {
496
+ transition: opacity 10s ease-out;
497
+ display: flex;
498
+ /* flex-direction: row;
499
+ align-items: center;
500
+ justify-content: flex-start; */
501
+
502
+ gap: 0.66em;
503
+
504
+ width: 95%;
505
+ cursor: pointer;
506
+ padding: 0.33em 0.33em;
507
+ margin: 0.1em 0em;
508
+
509
+ border-radius: 8px;
510
+ }
511
+
512
+ contextentry[data-disabled="true"]:not(:hover) {
513
+ transition: all 0.5s;
514
+ opacity: 0.5;
515
+ }
516
+
517
+ contextentry[data-disabled="true"]:hover {
518
+ transition: all 0.5s;
519
+ background: var(--overlay-0);
520
+ cursor: not-allowed;
521
+ opacity: 0.3;
522
+ }
523
+
524
+ contextentry:not([data-disabled="true"]):hover {
525
+ transition: all 0.5s;
526
+ background: var(--overlay-0);
527
+ }
528
+
529
+ contextentry:not([data-disabled="true"]):not(:hover) {
530
+ transition: all 0.5s;
531
+ background: transparent;
532
+ }
533
+
534
+ img {
535
+ width: 2.33em;
536
+ aspect-ratio: 1/1;
537
+ border-radius: var(--border-md);
538
+ }
539
+ </style>
@@ -0,0 +1,22 @@
1
+ export interface SearchResult {
2
+ query?: string | null;
3
+ href?: string | null;
4
+ iconUrl?: string | null;
5
+ name: string;
6
+ description?: string | null;
7
+ onclick?: (e: MouseEvent) => Promise<void>;
8
+ }
9
+ export type QueryMapKeys = keyof SearchResult;
10
+ interface SearchBarProps {
11
+ queryUrl?: string;
12
+ queryObjMap?: {
13
+ [key in QueryMapKeys]: string | null;
14
+ };
15
+ queryDataKey?: string;
16
+ options: SearchResult[];
17
+ onsearch: ((query: string) => Promise<void>) | null;
18
+ onresult: (result: SearchResult) => Promise<void>;
19
+ }
20
+ declare const SearchBar: import("svelte").Component<SearchBarProps, {}, "">;
21
+ type SearchBar = ReturnType<typeof SearchBar>;
22
+ export default SearchBar;
@@ -0,0 +1,19 @@
1
+ <script lang="ts">
2
+ import Markdown from "./Markdown.svelte";
3
+
4
+ interface CodeBlockProps {
5
+ content: string[];
6
+ language: "ts" | "js" | "diff" | "txt" | "svelte";
7
+
8
+ widthPx?: number | "fill" | "fit";
9
+ heightPx?: number | "fill" | "fit";
10
+ widthPercent?: number;
11
+ heightPercent?: number;
12
+ }
13
+
14
+ let { language, content, widthPx = "fill", heightPx = "fill", widthPercent = 0, heightPercent = 0 }: CodeBlockProps = $props();
15
+ </script>
16
+
17
+ <Markdown {widthPx} {widthPercent} {heightPx} {heightPercent} content={`\`\`\`${language}
18
+ ${content.map(c => c.trimEnd()).join('\n').trimEnd()}
19
+ \`\`\``} />
@@ -0,0 +1,11 @@
1
+ interface CodeBlockProps {
2
+ content: string[];
3
+ language: "ts" | "js" | "diff" | "txt" | "svelte";
4
+ widthPx?: number | "fill" | "fit";
5
+ heightPx?: number | "fill" | "fit";
6
+ widthPercent?: number;
7
+ heightPercent?: number;
8
+ }
9
+ declare const Code: import("svelte").Component<CodeBlockProps, {}, "">;
10
+ type Code = ReturnType<typeof Code>;
11
+ export default Code;