@valerius_petrini/corekit-ui 0.1.49 → 0.1.52

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 (54) hide show
  1. package/dist/components/Analytics.svelte.d.ts +1 -1
  2. package/dist/components/Button.svelte +35 -18
  3. package/dist/components/Button.svelte.d.ts +1 -1
  4. package/dist/components/Card.svelte +46 -6
  5. package/dist/components/Card.svelte.d.ts +1 -1
  6. package/dist/components/Checkbox.svelte +2 -1
  7. package/dist/components/Checkbox.svelte.d.ts +1 -1
  8. package/dist/components/FloatingInput.svelte +142 -30
  9. package/dist/components/FloatingInput.svelte.d.ts +3 -2
  10. package/dist/components/FloatingSelect.svelte +3 -2
  11. package/dist/components/FloatingSelect.svelte.d.ts +1 -1
  12. package/dist/components/Navbar.svelte +2 -2
  13. package/dist/components/Navbar.svelte.d.ts +1 -1
  14. package/dist/components/NavbarElement.svelte +1 -1
  15. package/dist/components/NavbarElement.svelte.d.ts +1 -1
  16. package/dist/components/Progress.svelte +69 -0
  17. package/dist/components/Progress.svelte.d.ts +4 -0
  18. package/dist/components/SEO.svelte.d.ts +1 -1
  19. package/dist/components/Text.svelte +6 -6
  20. package/dist/components/Text.svelte.d.ts +1 -1
  21. package/dist/components/Typewriter.svelte +1 -1
  22. package/dist/components/Typewriter.svelte.d.ts +1 -1
  23. package/dist/index.d.ts +2 -1
  24. package/dist/index.js +1 -0
  25. package/dist/styles/color.d.ts +2 -2
  26. package/dist/styles/color.js +148 -6
  27. package/dist/styles/layout.css +31 -23
  28. package/dist/styles/size.d.ts +4 -3
  29. package/dist/styles/size.js +72 -18
  30. package/dist/types/Analytics.d.ts +1 -1
  31. package/dist/types/Analytics.js +1 -0
  32. package/dist/types/Button.d.ts +2 -2
  33. package/dist/types/Button.js +1 -0
  34. package/dist/types/Card.d.ts +8 -1
  35. package/dist/types/Card.js +4 -0
  36. package/dist/types/Checkbox.d.ts +2 -1
  37. package/dist/types/Checkbox.js +2 -0
  38. package/dist/types/FloatingInput.d.ts +14 -4
  39. package/dist/types/FloatingInput.js +2 -0
  40. package/dist/types/FloatingSelect.d.ts +7 -3
  41. package/dist/types/FloatingSelect.js +2 -0
  42. package/dist/types/Navbar.d.ts +2 -3
  43. package/dist/types/Navbar.js +2 -0
  44. package/dist/types/Progress.d.ts +20 -0
  45. package/dist/types/Progress.js +2 -0
  46. package/dist/types/SEO.d.ts +1 -1
  47. package/dist/types/SEO.js +1 -0
  48. package/dist/types/Text.d.ts +5 -4
  49. package/dist/types/Text.js +2 -0
  50. package/dist/types/Typewriter.d.ts +24 -9
  51. package/dist/types/Typewriter.js +2 -0
  52. package/dist/utils/link.d.ts +9 -0
  53. package/dist/utils/link.js +9 -0
  54. package/package.json +3 -3
@@ -1,4 +1,4 @@
1
- import type { AnalyticsProps } from '../types/Analytics.js';
1
+ import type { AnalyticsProps } from '../types/Analytics.ts';
2
2
  declare const Analytics: import("svelte").Component<AnalyticsProps, {}, "">;
3
3
  type Analytics = ReturnType<typeof Analytics>;
4
4
  export default Analytics;
@@ -1,14 +1,16 @@
1
1
  <script lang="ts">
2
2
  import { generateColorStyle } from "../styles/color.js";
3
- import { sizeStyleParts, type SizeStyle } from "../styles/size.js";
3
+ import { sizeStyleParts, type SizeStyleTheme } from "../styles/size.js";
4
4
  import type { ButtonProps } from "../types/Button.js";
5
5
  import { twMerge } from "tailwind-merge";
6
+ import { getLinkProps } from "../utils/link.js";
6
7
 
7
8
  let {
8
9
  children = undefined,
9
10
  class: className = "",
10
11
  pill = false,
11
12
  icon = false,
13
+ square = false,
12
14
  href = undefined,
13
15
  color = "none",
14
16
  variant = "full",
@@ -20,21 +22,37 @@
20
22
  }: ButtonProps = $props();
21
23
 
22
24
  const sizeClasses = $derived.by(() => {
23
- if (typeof size === "string") {
24
- const parts = sizeStyleParts[size as SizeStyle];
25
- return icon ? parts.buttonIcon : parts.button;
26
- }
27
- return icon ? "p-0 flex-none" : "h-fit";
25
+ const parts = typeof size === "string" ? sizeStyleParts[size as SizeStyleTheme] : null;
26
+ const radiusParts = typeof radius === "string" ? sizeStyleParts[radius as SizeStyleTheme] : null;
27
+
28
+ return twMerge(
29
+ icon ? "p-0 flex-none" : "h-fit",
30
+ parts?.[icon ? "buttonIcon" : "button"],
31
+ radiusParts?.radius,
32
+ pill || icon ? "rounded-full" : "",
33
+ square ? "aspect-square rounded-none" : ""
34
+ );
28
35
  });
29
36
 
30
- const customStyle = $derived(
31
- typeof size === "number"
32
- ? `width: ${size}px; height: ${size}px; flex: none;`
33
- : ""
34
- );
37
+ const customStyle = $derived.by(() => {
38
+ const styles: string[] = [];
35
39
 
36
- const defaultClass = "inline-flex items-center justify-center gap-2 transition-colors duration-300 text-white whitespace-nowrap";
37
- const radiusClass = $derived(pill || icon ? "rounded-full" : sizeStyleParts[radius as SizeStyle].radius);
40
+ if (typeof size === "number") {
41
+ styles.push(`height: ${size}px`);
42
+ styles.push(icon
43
+ ? `width: ${size}px; padding: ${size / 8}px`
44
+ : `padding: ${size / 4}px ${size / 8}px`
45
+ );
46
+ }
47
+
48
+ if (typeof radius === "number") {
49
+ styles.push(`border-radius: ${radius}px`);
50
+ }
51
+
52
+ return styles.join("; ");
53
+ });
54
+
55
+ const defaultClass = "inline-flex items-center justify-center gap-2 transition-colors duration-300 ease-in-out text-white whitespace-nowrap";
38
56
  const disabledClass = $derived(disabled ? "opacity-50 pointer-events-none" : "cursor-pointer");
39
57
 
40
58
  const mergedClass = $derived(twMerge(
@@ -42,11 +60,12 @@
42
60
  generateColorStyle(color, variant),
43
61
  disabledClass,
44
62
  sizeClasses,
45
- radiusClass,
46
63
  className
47
64
  ));
48
65
 
49
66
  const mergedStyle = $derived([customStyle, restProps.style].filter(Boolean).join("; "));
67
+
68
+ const anchorProps = $derived(getLinkProps(href, external));
50
69
  </script>
51
70
 
52
71
  <svelte:element
@@ -56,9 +75,7 @@
56
75
  aria-disabled={disabled}
57
76
  type={href ? undefined : (restProps.type || "button")}
58
77
  style={mergedStyle}
59
- target={external ? "_blank" : undefined}
60
- rel={external ? "noopener noreferrer" : undefined}
61
- {...(href ? { href } : {})}
78
+ {...anchorProps}
62
79
  {...restProps}>
63
80
  {@render children?.()}
64
- </svelte:element>
81
+ </svelte:element>
@@ -1,4 +1,4 @@
1
- import type { ButtonProps } from "../types/Button.js";
1
+ import type { ButtonProps } from "../types/Button.ts";
2
2
  declare const Button: import("svelte").Component<ButtonProps, {}, "">;
3
3
  type Button = ReturnType<typeof Button>;
4
4
  export default Button;
@@ -1,24 +1,64 @@
1
1
  <script lang="ts">
2
- import type { CardProps } from "../types/Card.js";
3
- import type { SvelteComponent } from "svelte";
2
+ import { sizeStyleParts, type SizeStyleTheme } from "../styles/size.js";
3
+ import { cardVariantStyles, type CardProps } from "../types/Card.js";
4
4
  import { twMerge } from "tailwind-merge";
5
5
 
6
6
  let {
7
7
  children = undefined,
8
8
  class: className = "",
9
9
  href = undefined,
10
+ external = false,
11
+ variant = "bordered",
12
+ size = "md",
13
+ radius = "md",
10
14
  ...restProps
11
15
  }: CardProps = $props();
12
16
 
13
- let defaultClass = "text-main-text shadow-xl rounded-lg transition-colors bg-sub-background hover:bg-sub-background-hover p-4";
14
- let combinedClass = $derived(twMerge(defaultClass, className));
17
+ const sizeClasses = $derived.by(() => {
18
+ const parts = typeof size === "string" ? sizeStyleParts[size as SizeStyleTheme] : null;
19
+ const radiusParts = typeof radius === "string" ? sizeStyleParts[radius as SizeStyleTheme] : null;
20
+
21
+ return twMerge(
22
+ parts?.card,
23
+ radiusParts?.radius,
24
+ );
25
+ });
26
+
27
+ const customStyle = $derived.by(() => {
28
+ const styles: string[] = [];
29
+
30
+ if (typeof size === "number")
31
+ styles.push(`width: ${size}px`);
32
+
33
+ if (typeof radius === "number")
34
+ styles.push(`border-radius: ${radius}px`);
35
+
36
+ return styles.join("; ");
37
+ });
38
+
39
+ let defaultClass = "text-main-text rounded-lg transition-colors ease-in-out bg-sub-background p-4";
40
+ let linkClass = "hover:bg-sub-background-hover cursor-pointer";
41
+ let combinedClass = $derived(twMerge(
42
+ defaultClass,
43
+ href ? linkClass : "",
44
+ cardVariantStyles[variant],
45
+ sizeClasses,
46
+ className
47
+ ));
48
+
49
+ const anchorProps = $derived(href ? {
50
+ href,
51
+ target: external ? "_blank" : undefined,
52
+ rel: external ? "noopener noreferrer" : undefined,
53
+ } : {});
15
54
  </script>
16
55
 
17
56
  <svelte:element
18
57
  this={href ? "a" : "div"}
19
58
  class={combinedClass}
20
- {...(href ? { href } : {})}
59
+ style={customStyle}
60
+ {...anchorProps}
21
61
  {...restProps}
22
62
  >
23
63
  {@render children?.()}
24
- </svelte:element>
64
+ </svelte:element>
@@ -1,4 +1,4 @@
1
- import type { CardProps } from "../types/Card.js";
1
+ import { type CardProps } from "../types/Card.ts";
2
2
  declare const Card: import("svelte").Component<CardProps, {}, "">;
3
3
  type Card = ReturnType<typeof Card>;
4
4
  export default Card;
@@ -6,6 +6,7 @@
6
6
  let {
7
7
  children = undefined,
8
8
  class: className = "",
9
+ label = "",
9
10
  labelClass = "",
10
11
  divClass = "",
11
12
  checked = $bindable(),
@@ -30,6 +31,6 @@
30
31
  class={combinedClass}
31
32
  {...restProps}/>
32
33
  <Text tag="label" for={id} class={combinedLabelClass}>
33
- {@render children?.()}
34
+ {label}
34
35
  </Text>
35
36
  </div>
@@ -1,4 +1,4 @@
1
- import type { CheckboxProps } from "../types/Checkbox.js";
1
+ import type { CheckboxProps } from "../types/Checkbox.ts";
2
2
  declare const Checkbox: import("svelte").Component<CheckboxProps, {}, "checked">;
3
3
  type Checkbox = ReturnType<typeof Checkbox>;
4
4
  export default Checkbox;
@@ -2,43 +2,116 @@
2
2
  import type { FloatingInputProps } from "../types/FloatingInput.js";
3
3
  import { twMerge } from "tailwind-merge";
4
4
  import Text from "./Text.svelte";
5
+ import { sizeStyleParts, type SizeStyleTheme } from "../styles/size.js";
6
+ import { type Component } from "svelte";
7
+ import Button from "./Button.svelte";
8
+
9
+ import Mail from "@lucide/svelte/icons/mail";
10
+ import Lock from "@lucide/svelte/icons/lock";
11
+ import Phone from "@lucide/svelte/icons/phone";
12
+ import Eye from "@lucide/svelte/icons/eye";
13
+ import EyeOff from "@lucide/svelte/icons/eye-off";
5
14
 
6
15
  let {
7
16
  children = undefined,
8
17
  class: className = "",
18
+ label = "",
9
19
  labelClass = "",
10
20
  divClass = "",
21
+ icon = undefined,
22
+ variant = "default",
23
+ placeholder = "",
11
24
  value = $bindable(),
12
25
  onfocus = undefined,
13
26
  onblur = undefined,
14
- isTextArea = false,
27
+ required = false,
28
+ disabled = false,
15
29
  validInputRegex = undefined,
30
+ size = "md",
31
+ radius = "md",
16
32
  id = crypto.randomUUID(),
17
33
  ...restProps
18
34
  }: FloatingInputProps = $props();
19
35
 
36
+ const sizeParts = $derived(typeof size === "string" ? sizeStyleParts[size as SizeStyleTheme] : null);
37
+ const radiusParts = $derived(typeof radius === "string" ? sizeStyleParts[radius as SizeStyleTheme] : null);
38
+
39
+ const sizeClasses = $derived.by(() => {
40
+ const parts = typeof size === "string" ? sizeStyleParts[size as SizeStyleTheme] : null;
41
+
42
+ return twMerge(
43
+ parts?.form
44
+ );
45
+ });
46
+
47
+ const labelSizeClass = $derived.by(() => {
48
+ const parts = typeof size === "string" ? sizeStyleParts[size as SizeStyleTheme] : null;
49
+ return parts?.formLabel || "";
50
+ });
51
+
52
+ const divSizeClass = $derived.by(() => {
53
+ const radiusParts = typeof radius === "string" ? sizeStyleParts[radius as SizeStyleTheme] : null;
54
+ return twMerge(
55
+ radiusParts?.radius
56
+ );
57
+ });
58
+
59
+ const selectedLabelSizeClass = $derived.by(() => {
60
+ const parts = typeof size === "string" ? sizeStyleParts[size as SizeStyleTheme] : null;
61
+ return parts?.formLabelSelected || "";
62
+ });
63
+
64
+ const customStyle = $derived.by(() => {
65
+ const styles: string[] = [];
66
+
67
+ if (typeof size === "number")
68
+ styles.push(`width: ${size}px`);
69
+
70
+ if (typeof radius === "number")
71
+ styles.push(`border-radius: ${radius}px`);
72
+
73
+ return styles.join("; ");
74
+ });
75
+
76
+ const customLabelStyle = $derived.by(() => {
77
+ const styles: string[] = [];
78
+
79
+ if (typeof size === "number")
80
+ styles.push(`font-size: ${size / 4}px`);
81
+
82
+ return styles.join("; ");
83
+ });
84
+
20
85
  let isFocused = $state(false);
21
86
  let touched = $state(false);
22
87
 
23
- let hasContent = $derived(value !== undefined && value !== null && value.toString().length > 0);
24
- let isValid = $derived(!touched || !validInputRegex || validInputRegex.test(value || ""));
88
+ let canSeePassword = $state(false);
25
89
 
26
- let defaultClass = "z-20 bg-form-input-background text-main-text w-full rounded px-2 pt-4 pb-1 text-xs outline-none focus:ring-2 focus:ring-blue-500 transition-all";
27
- let defaultLabelClass = "block text-sub-text rounded-md text-sm font-medium mb-1 absolute transition-all duration-100 pointer-events-none";
28
- let defaultDivClass = "relative";
90
+ const isFloating = $derived(variant === "floating");
91
+ const hasContent = $derived(value !== undefined && value !== null && value.toString().length > 0);
92
+ const isValid = $derived(!touched || !validInputRegex || validInputRegex.test(value || ""));
93
+ const lifted = $derived(isFloating && (isFocused || hasContent));
29
94
 
30
- let originalLabelClass = "left-2 z-0";
31
- let originalLabelClassInput = "top-1/2 transform -translate-y-1/2";
32
- let originalLabelClassTextArea = "top-2";
33
- let selectedLabelClass = "left-2 z-30 top-0.5 text-[10px]!";
95
+ const Icon = $derived(icon ?? ({
96
+ mail: Mail, password: Lock, tel: Phone
97
+ }[restProps.type as string] as Component ?? null));
98
+
99
+ let defaultClass = "text-main-text w-full rounded outline-none px-1.5 w-full";
100
+ let defaultLabelClass = "block text-sub-text rounded-md font-medium mb-1 duration-100 pointer-events-none truncate w-fit";
101
+ let defaultDivClass = "relative *:transition-all flex-center bg-form-background border-[1px] border-form-border focus-within:ring-1 focus-within:ring-blue-500";
102
+ let iconContainerClass = "h-5 aspect-square px-1 py-0!";
103
+ let floatingLabelClass = "absolute w-full";
104
+ let iconClass = "h-full aspect-square text-sub-text";
34
105
 
35
- let invalidClass = "border border-red-500 focus:ring-red-500";
106
+ let originalLabelClass = "z-0";
107
+ let originalLabelClassInput = "top-1/2 transform -translate-y-1/2";
108
+ let originalSelectedLabelClass = "z-30";
36
109
 
37
- let labelClassFull = $derived(twMerge(isTextArea ? originalLabelClassTextArea : originalLabelClassInput, originalLabelClass));
110
+ let invalidClass = "border border-red-500 focus:ring-red-500 bg-[#2E1F1F]";
38
111
 
39
- let combinedLabelClass = $derived(twMerge(defaultLabelClass, isFocused || hasContent ? selectedLabelClass : labelClassFull, labelClass));
40
- let combinedClass = $derived(twMerge(defaultClass, className, isValid ? "" : invalidClass));
41
- let combinedDivClass = $derived(twMerge(defaultDivClass, divClass));
112
+ let floatingLabelClassFull = $derived(twMerge(originalLabelClassInput, originalLabelClass, floatingLabelClass));
113
+ let divFullClass = $derived(size === "full" ? "w-full" : "");
114
+ let disabledClass = $derived(disabled ? "opacity-50 pointer-events-none" : "cursor-pointer");
42
115
 
43
116
  function handleFocus(e: FocusEvent) {
44
117
  isFocused = true;
@@ -50,29 +123,68 @@
50
123
  touched = true;
51
124
  onblur?.(e);
52
125
  }
126
+
127
+ let labelClassIcon = $derived(Icon !== null ? "pl-[32px] pr-2" : "px-1.5");
128
+ let inputClassIcon = $derived(Icon !== null ? "pl-0 pr-1" : "");
129
+
130
+ let defaultInputClassCheck = $derived(variant !== "floating" ? "py-0" : "");
131
+ let floatingLabelClassCheck = $derived(variant === "floating" ? floatingLabelClassFull : "");
132
+ let defaultLabelClassCheck = $derived(variant !== "floating" ? "px-1.5" : "");
133
+ let selectedLabelClass = $derived(twMerge((isFocused || hasContent) && variant === "floating" ? `${originalSelectedLabelClass} ${selectedLabelSizeClass}` : ""));
134
+ let combinedLabelClass = $derived(twMerge(defaultLabelClass, floatingLabelClassCheck, labelSizeClass, selectedLabelClass, labelClassIcon, defaultLabelClassCheck, labelClass));
135
+ let combinedClass = $derived(twMerge(defaultClass, sizeClasses, defaultInputClassCheck, labelSizeClass, inputClassIcon, className, isValid ? "" : invalidClass));
136
+ let combinedDivClass = $derived(twMerge(defaultDivClass, divSizeClass, divFullClass, divClass, disabledClass));
137
+ let combinedOuterDivClass = $derived(twMerge("flex flex-col bg-transparent border-0 p-0", divSizeClass, divFullClass, divClass, disabledClass));
138
+
139
+ let EyeComponent = $derived(canSeePassword ? Eye : EyeOff);
53
140
  </script>
54
141
 
55
- <div class={combinedDivClass}>
56
- <Text tag="label" for={id} class={combinedLabelClass}>
57
- {@render children?.()}
142
+ {#snippet labelElement()}
143
+ <Text tag="label" for={id} class={combinedLabelClass} style={customLabelStyle}>
144
+ {label}
145
+ {#if required}
146
+ <span class="text-[#E05555]">*</span>
147
+ {/if}
58
148
  </Text>
59
- {#if isTextArea}
60
- <textarea
61
- {id}
62
- bind:value={value}
63
- onfocus={handleFocus}
64
- onblur={handleBlur}
65
- class={combinedClass}
66
- {...restProps}
67
- ></textarea>
68
- {:else}
149
+ {/snippet}
150
+
151
+ {#snippet innerDivElement()}
152
+ <div class={combinedDivClass}>
153
+ {#if Icon}
154
+ <div class={iconContainerClass}>
155
+ <Icon class={iconClass}></Icon>
156
+ </div>
157
+ {/if}
158
+ {#if variant === "floating"}
159
+ {@render labelElement()}
160
+ {/if}
69
161
  <input
70
162
  {id}
71
163
  bind:value={value}
72
164
  onfocus={handleFocus}
73
165
  onblur={handleBlur}
74
166
  class={combinedClass}
167
+ {required}
168
+ {disabled}
169
+ placeholder={variant === "floating" ? "" : placeholder}
170
+ aria-disabled={disabled}
171
+ style={customStyle}
75
172
  {...restProps}
173
+ type={canSeePassword ? "text" : restProps.type}
76
174
  />
77
- {/if}
78
- </div>
175
+ {#if restProps.type === "password"}
176
+ <Button class={iconContainerClass} onclick={() => { canSeePassword = !canSeePassword; }}>
177
+ <EyeComponent class={iconClass}></EyeComponent>
178
+ </Button>
179
+ {/if}
180
+ </div>
181
+ {/snippet}
182
+
183
+ {#if variant !== "floating"}
184
+ <div class={combinedOuterDivClass}>
185
+ {@render labelElement()}
186
+ {@render innerDivElement()}
187
+ </div>
188
+ {:else}
189
+ {@render innerDivElement()}
190
+ {/if}
@@ -1,4 +1,5 @@
1
- import type { FloatingInputProps } from "../types/FloatingInput.js";
2
- declare const FloatingInput: import("svelte").Component<FloatingInputProps, {}, "value">;
1
+ import type { FloatingInputProps } from "../types/FloatingInput.ts";
2
+ import { type Component } from "svelte";
3
+ declare const FloatingInput: Component<FloatingInputProps, {}, "value">;
3
4
  type FloatingInput = ReturnType<typeof FloatingInput>;
4
5
  export default FloatingInput;
@@ -6,6 +6,7 @@
6
6
  let {
7
7
  children = undefined,
8
8
  class: className = "",
9
+ label = "",
9
10
  divClass = "",
10
11
  optionClass = "",
11
12
  value = $bindable(),
@@ -14,7 +15,7 @@
14
15
  ...restProps
15
16
  }: FloatingSelectProps = $props();
16
17
 
17
- let defaultSelectClass = "cursor-pointer bg-form-input-background text-main-text z-20 w-full rounded px-1 pt-4 pb-1 text-xs outline-none focus:ring-2 focus:ring-blue-500 transition-all";
18
+ let defaultSelectClass = "cursor-pointer bg-form-background border-[1px] border-form-border text-main-text z-20 w-full rounded px-1 pt-4 pb-1 text-xs outline-none focus:ring-2 focus:ring-blue-500 transition-all";
18
19
  let defaultLabelClass = "block text-sub-text rounded-md text-sm font-medium mb-1 absolute transition-all duration-100 pointer-events-none";
19
20
  let defaultDivClass = "relative w-fit";
20
21
 
@@ -27,7 +28,7 @@
27
28
 
28
29
  <div class={combinedDivClass}>
29
30
  <Text tag="label" for={id} class={combinedLabelClass}>
30
- {@render children?.()}
31
+ {label}
31
32
  </Text>
32
33
  <select {id} class={combinedSelectClass} {...restProps} bind:value={value}>
33
34
  {#each options as option}
@@ -1,4 +1,4 @@
1
- import type { FloatingSelectProps } from "../types/FloatingSelect.js";
1
+ import type { FloatingSelectProps } from "../types/FloatingSelect.ts";
2
2
  declare const FloatingSelect: import("svelte").Component<FloatingSelectProps, {}, "value">;
3
3
  type FloatingSelect = ReturnType<typeof FloatingSelect>;
4
4
  export default FloatingSelect;
@@ -11,7 +11,7 @@
11
11
  ...restProps
12
12
  }: NavbarProps = $props();
13
13
 
14
- let defaultClass = "transition-colors duration-300 fixed top-0 left-0 w-full h-14 z-[100] flex items-center bg-main-background/99 border-b-sub-background border-box border-b";
14
+ let defaultClass = "transition-colors duration-300 fixed top-0 left-0 w-full h-14 z-[100] flex items-center bg-sub-background/99 border-b border-box border-b-sub-background-hover";
15
15
 
16
16
  let scrollY = $state(0);
17
17
  let isAtTop = $derived(scrollY <= threshold);
@@ -27,4 +27,4 @@
27
27
 
28
28
  <nav class={combinedClass} {...restProps}>
29
29
  {@render children?.()}
30
- </nav>
30
+ </nav>
@@ -1,4 +1,4 @@
1
- import type { NavbarProps } from "../types/Navbar.js";
1
+ import type { NavbarProps } from "../types/Navbar.ts";
2
2
  declare const Navbar: import("svelte").Component<NavbarProps, {}, "">;
3
3
  type Navbar = ReturnType<typeof Navbar>;
4
4
  export default Navbar;
@@ -30,6 +30,6 @@
30
30
 
31
31
  <svelte:window bind:scrollY={scrollY}/>
32
32
 
33
- <Button radius={0} {href} color="none" class={combinedClass} {...restProps} aria-current={isActive ? 'page' : undefined}>
33
+ <Button radius="none" {href} color="none" class={combinedClass} {...restProps} aria-current={isActive ? 'page' : undefined}>
34
34
  {@render children?.()}
35
35
  </Button>
@@ -1,4 +1,4 @@
1
- import type { NavbarElementProps } from "../types/Navbar.js";
1
+ import type { NavbarElementProps } from "../types/Navbar.ts";
2
2
  declare const NavbarElement: import("svelte").Component<NavbarElementProps, {}, "">;
3
3
  type NavbarElement = ReturnType<typeof NavbarElement>;
4
4
  export default NavbarElement;
@@ -0,0 +1,69 @@
1
+ <script lang="ts">
2
+ import { onMount } from "svelte";
3
+ import type { ProgressProps } from "../types/Progress.js";
4
+ import { twMerge } from "tailwind-merge";
5
+ import { colorStyleParts } from "../styles/color.js";
6
+ import { sizeStyleParts, type SizeStyleTheme } from "../styles/size.js";
7
+
8
+ let {
9
+ children = undefined,
10
+ class: className = "",
11
+ divClass = "",
12
+ progress = 100,
13
+ animate = undefined,
14
+ color = "blue",
15
+ size = "md",
16
+ radius = "full",
17
+ ...restProps
18
+ }: ProgressProps = $props();
19
+
20
+ let currentProgress = $state(0);
21
+
22
+ let defaultDivClass = "w-full bg-sub-background overflow-hidden";
23
+
24
+ const sizeClasses = $derived.by(() => {
25
+ const parts = typeof size === "string" ? sizeStyleParts[size as SizeStyleTheme] : null;
26
+ const radiusParts = typeof radius === "string" ? sizeStyleParts[radius as SizeStyleTheme] : null;
27
+
28
+ return twMerge(
29
+ parts?.progress,
30
+ radiusParts?.radius
31
+ );
32
+ });
33
+
34
+ const customStyle = $derived.by(() => {
35
+ const styles: string[] = [];
36
+
37
+ if (typeof size === "number")
38
+ styles.push(`height: ${size}px`);
39
+
40
+ if (typeof radius === "number")
41
+ styles.push(`border-radius: ${radius}px`);
42
+
43
+ return styles.join("; ");
44
+ });
45
+
46
+
47
+ let combinedDivClass = $derived(twMerge(
48
+ defaultDivClass,
49
+ sizeClasses,
50
+ divClass
51
+ ));
52
+
53
+ let combinedInnerClass = $derived(twMerge(
54
+ "h-full",
55
+ colorStyleParts[color]?.base,
56
+ className
57
+ ))
58
+
59
+ onMount(() => {
60
+ if (!animate) return;
61
+ currentProgress = animate.from;
62
+ requestAnimationFrame(() => currentProgress = animate.to);
63
+ if (animate.onend) setTimeout(animate.onend, animate.duration);
64
+ });
65
+ </script>
66
+
67
+ <div class={combinedDivClass} {...restProps} style={customStyle}>
68
+ <div class={combinedInnerClass} style="width: {animate ? currentProgress : progress}%; transition: width {animate?.duration ?? 500}ms ease;"></div>
69
+ </div>
@@ -0,0 +1,4 @@
1
+ import type { ProgressProps } from "../types/Progress.ts";
2
+ declare const Progress: import("svelte").Component<ProgressProps, {}, "">;
3
+ type Progress = ReturnType<typeof Progress>;
4
+ export default Progress;
@@ -1,4 +1,4 @@
1
- import type { SEOProps } from '../types/SEO.js';
1
+ import type { SEOProps } from '../types/SEO.ts';
2
2
  declare const SEO: import("svelte").Component<SEOProps, {}, "">;
3
3
  type SEO = ReturnType<typeof SEO>;
4
4
  export default SEO;
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">
2
- import { sizeStyleParts, textStyle, type SizeStyle } from "../styles/size.js";
2
+ import { sizeStyleParts, textStyle, type SizeStyle, type SizeStyleTheme } from "../styles/size.js";
3
3
  import type { TextProps } from "../types/Text.js";
4
4
  import { twMerge } from "tailwind-merge";
5
5
 
@@ -7,7 +7,7 @@
7
7
  children = undefined,
8
8
  class: className = "",
9
9
  tag = "p",
10
- shrink = false,
10
+ shrink = undefined,
11
11
  size = "none",
12
12
  ...restProps
13
13
  }: TextProps = $props();
@@ -16,7 +16,7 @@
16
16
  "p": { class: "", size: "text-base" },
17
17
  "div": { class: "", size: "text-base" },
18
18
  "span": { class: "", size: "text-base" },
19
- "label": { class: "", size: "text-sm" },
19
+ "label": { class: "text-sub-text font-semibold", size: "text-xs" },
20
20
  "strong": { class: "font-bold", size: "text-base" },
21
21
  "b": { class: "font-bold", size: "text-base" },
22
22
  "em": { class: "italic", size: "text-base" },
@@ -38,7 +38,7 @@
38
38
 
39
39
  function getTextSizeInRem(): string {
40
40
  if (size !== "none") {
41
- const sizeKey = (sizeStyleParts[size as SizeStyle]?.text ?? "text-base") as keyof typeof textStyle;
41
+ const sizeKey = (sizeStyleParts[size as SizeStyleTheme]?.text ?? "text-base") as keyof typeof textStyle;
42
42
  return textStyle[sizeKey] ?? textStyle["text-base"];
43
43
  }
44
44
 
@@ -46,7 +46,7 @@
46
46
  }
47
47
 
48
48
  let shrinkStyle = $derived(shrink
49
- ? `font-size: clamp(8px, 12cqi, ${getTextSizeInRem()}); white-space: nowrap; display: block; width: fit-content;`
49
+ ? `font-size: clamp(8px, ${shrink}cqi, ${getTextSizeInRem()}); white-space: nowrap; display: block; width: fit-content;`
50
50
  : ""
51
51
  );
52
52
 
@@ -55,7 +55,7 @@
55
55
  defaultClass,
56
56
  tagStyles[tag]?.class || "",
57
57
  tagStyles[tag]?.size || "",
58
- sizeStyleParts[size]?.text || "",
58
+ sizeStyleParts[size as SizeStyleTheme]?.text || "",
59
59
  className
60
60
  ));
61
61
  </script>
@@ -1,4 +1,4 @@
1
- import type { TextProps } from "../types/Text.js";
1
+ import type { TextProps } from "../types/Text.ts";
2
2
  declare const Text: import("svelte").Component<TextProps, {}, "">;
3
3
  type Text = ReturnType<typeof Text>;
4
4
  export default Text;
@@ -2,7 +2,7 @@
2
2
  import { twMerge } from "tailwind-merge";
3
3
  import { onMount } from "svelte";
4
4
 
5
- import type { DisplaySegment, TypewriterProps } from "../types/Typewriter.d.js";
5
+ import type { DisplaySegment, TypewriterProps } from "../types/Typewriter.js";
6
6
  import Text from "./Text.svelte";
7
7
 
8
8
  let {