diff --git a/src/lib/components/Button.module.scss b/src/lib/components/Button.module.scss
deleted file mode 100644
index 392e9fe9..00000000
--- a/src/lib/components/Button.module.scss
+++ /dev/null
@@ -1,144 +0,0 @@
-@use '../../themes/spacing';
-@use '../../themes/mixins';
-
-.button {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- gap: spacing.$unit;
- font-family: var(--font-family);
- font-weight: 500;
- border: none;
- border-radius: 6px;
- cursor: pointer;
- transition: all 0.2s ease;
- outline: none;
- position: relative;
- white-space: nowrap;
- text-decoration: none;
- line-height: 1;
-
- &:disabled {
- cursor: not-allowed;
- opacity: 0.5;
- }
-
- &:focus-visible {
- box-shadow: 0 0 0 2px var(--accent-blue-focus);
- }
-}
-
-// Variants
-.primary {
- background-color: var(--button-contained-bg);
- color: var(--button-text);
-
- &:hover:not(:disabled) {
- background-color: var(--button-contained-bg-hover);
- }
-
- &:active:not(:disabled) {
- transform: translateY(1px);
- }
-}
-
-.secondary {
- background-color: var(--button-bg);
- color: var(--button-text);
- border: 1px solid var(--separator-bg);
-
- &:hover:not(:disabled) {
- background-color: var(--button-bg-hover);
- color: var(--button-text-hover);
- }
-
- &:active:not(:disabled) {
- transform: translateY(1px);
- }
-}
-
-.ghost {
- background-color: transparent;
- color: var(--text-secondary);
-
- &:hover:not(:disabled) {
- background-color: var(--button-bg);
- color: var(--text-primary);
- }
-
- &:active:not(:disabled) {
- transform: translateY(1px);
- }
-}
-
-.text {
- background-color: transparent;
- color: var(--accent-blue);
- padding: 0;
- min-height: auto;
-
- &:hover:not(:disabled) {
- color: var(--accent-blue-focus);
- text-decoration: underline;
- }
-
- &:active:not(:disabled) {
- transform: none;
- }
-}
-
-// Sizes
-.small {
- padding: spacing.$unit spacing.$unit-2x;
- font-size: 1.2rem;
- min-height: 28px;
-
- &.iconOnly {
- padding: spacing.$unit;
- width: 28px;
- height: 28px;
- }
-}
-
-.medium {
- padding: spacing.$unit-2x spacing.$unit-3x;
- font-size: 1.4rem;
- min-height: 36px;
-
- &.iconOnly {
- padding: spacing.$unit-2x;
- width: 36px;
- height: 36px;
- }
-}
-
-.large {
- padding: spacing.$unit-2x spacing.$unit-4x;
- font-size: 1.6rem;
- min-height: 44px;
-
- &.iconOnly {
- padding: spacing.$unit-2x;
- width: 44px;
- height: 44px;
- }
-}
-
-// Icon positioning
-.iconLeft {
- flex-direction: row;
-}
-
-.iconRight {
- flex-direction: row-reverse;
-}
-
-.iconOnly {
- gap: 0;
- aspect-ratio: 1;
-}
-
-// Full width
-.fullWidth {
- width: 100%;
-}
\ No newline at end of file
diff --git a/src/lib/components/Button.svelte b/src/lib/components/Button.svelte
deleted file mode 100644
index 740d522f..00000000
--- a/src/lib/components/Button.svelte
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/src/lib/components/ui/ContextMenu.svelte b/src/lib/components/ui/ContextMenu.svelte
index e0cf1c34..d60559ef 100644
--- a/src/lib/components/ui/ContextMenu.svelte
+++ b/src/lib/components/ui/ContextMenu.svelte
@@ -30,6 +30,7 @@
@use '$src/themes/spacing' as *;
@use '$src/themes/layout' as *;
@use '$src/themes/typography' as *;
+ @use '$src/themes/effects' as *;
:global(.context-menu) {
background: var(--app-bg, white);
@@ -37,9 +38,9 @@
border-radius: $card-corner;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
padding: $unit-half;
- min-width: 180px;
+ min-width: calc($unit * 22.5);
z-index: 200;
- animation: slideIn 0.15s ease-out;
+ animation: slideIn $duration-quick ease-out;
}
:global(.context-menu-item) {
@@ -51,7 +52,7 @@
display: flex;
align-items: center;
gap: $unit;
- transition: background 0.2s;
+ @include smooth-transition($duration-standard, background);
&:hover {
background: var(--button-contained-bg-hover, #f5f5f5);
@@ -76,7 +77,7 @@
@keyframes slideIn {
from {
opacity: 0;
- transform: translateY(-2px);
+ transform: translateY(-$unit-fourth);
}
to {
opacity: 1;
diff --git a/src/lib/components/ui/Dialog.svelte b/src/lib/components/ui/Dialog.svelte
index dbae7579..938915b7 100644
--- a/src/lib/components/ui/Dialog.svelte
+++ b/src/lib/components/ui/Dialog.svelte
@@ -59,13 +59,14 @@
@use '$src/themes/spacing' as *;
@use '$src/themes/layout' as *;
@use '$src/themes/typography' as *;
+ @use '$src/themes/effects' as *;
:global(.dialog-overlay) {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 100;
- animation: fade-in 0.15s ease-out;
+ animation: fade-in $duration-quick ease-out;
}
:global(.dialog-content) {
@@ -80,7 +81,7 @@
max-height: 90vh;
width: 500px;
z-index: 101;
- animation: slide-up 0.2s ease-out;
+ animation: slide-up $duration-standard ease-out;
display: flex;
flex-direction: column;
}
@@ -105,18 +106,18 @@
position: absolute;
right: $unit;
top: $unit;
- width: 32px;
- height: 32px;
+ width: $unit-4x;
+ height: $unit-4x;
display: flex;
align-items: center;
justify-content: center;
border: none;
background: transparent;
- font-size: 24px;
+ font-size: $unit-3x;
color: var(--text-secondary);
cursor: pointer;
border-radius: $item-corner-small;
- transition: all 0.2s;
+ @include smooth-transition($duration-standard, all);
&:hover {
background: var(--button-contained-bg-hover);
diff --git a/src/lib/components/ui/Tooltip.svelte b/src/lib/components/ui/Tooltip.svelte
index 8c34c3cd..4ace8e0a 100644
--- a/src/lib/components/ui/Tooltip.svelte
+++ b/src/lib/components/ui/Tooltip.svelte
@@ -40,20 +40,20 @@
\ No newline at end of file
diff --git a/src/lib/components/ui/button/Button.svelte b/src/lib/components/ui/button/Button.svelte
index f745255b..72e0dfaa 100644
--- a/src/lib/components/ui/button/Button.svelte
+++ b/src/lib/components/ui/button/Button.svelte
@@ -1,57 +1,74 @@
+
+
-
- {#if effectiveLeftIcon}
-
-
-
- {/if}
- {#if !iconOnly && children}
-
- {@render children()}
-
- {/if}
- {#if effectiveRightIcon}
-
-
-
- {/if}
-
\ No newline at end of file
+{#if isLink}
+
+ {#if leftAccessory}
+
+ {@render leftAccessory()}
+
+ {:else if effectiveLeftIcon}
+
+
+
+ {/if}
+ {#if children && !iconOnly}
+
+ {@render children()}
+
+ {/if}
+ {#if rightAccessory}
+
+ {@render rightAccessory()}
+
+ {:else if effectiveRightIcon}
+
+
+
+ {/if}
+
+{:else}
+
+{/if}
+
+
\ No newline at end of file
diff --git a/src/lib/components/ui/button/button.module.scss b/src/lib/components/ui/button/button.module.scss
deleted file mode 100644
index 0ddcc273..00000000
--- a/src/lib/components/ui/button/button.module.scss
+++ /dev/null
@@ -1,453 +0,0 @@
-@use 'sass:color';
-@use 'themes/spacing';
-@use 'themes/mixins';
-@use 'themes/colors';
-@use 'themes/typography';
-@use 'themes/effects';
-@use 'themes/layout';
-
-.button {
- align-items: center;
- background: var(--button-bg);
- border: 2px solid transparent;
- border-radius: layout.$input-corner;
- color: var(--button-text);
- display: inline-flex;
- font-size: typography.$font-button;
- font-weight: typography.$normal;
- justify-content: center;
- gap: 6px;
- transition: 0.18s opacity ease-in-out;
- user-select: none;
- transition:
- background-color 0.18s ease-out,
- color 0.18s ease-out;
- cursor: pointer;
- outline: none;
- position: relative;
- white-space: nowrap;
- text-decoration: none;
- line-height: 1;
-
- .text {
- align-items: center;
- color: inherit;
- display: flex;
- }
-
- &:hover,
- &.blended:hover,
- &.blended.active {
- background: var(--button-bg-hover);
- cursor: pointer;
- color: var(--button-text-hover);
-
- .accessory svg {
- fill: var(--button-text-hover);
- }
-
- .accessory svg.stroke {
- fill: none;
- stroke: var(--button-text-hover);
- }
- }
-
- &:disabled {
- background-color: var(--button-bg-disabled);
- color: var(--button-text-disabled);
- cursor: not-allowed;
- opacity: 0.5;
-
- &:hover {
- background-color: var(--button-bg-disabled);
- color: var(--button-text-disabled);
- cursor: not-allowed;
- }
- }
-
- &:focus-visible {
- border: 2px solid colors.$blue;
- outline: none;
- }
-
- &:active:not(:disabled) {
- transform: translateY(1px);
- }
-}
-
-// Variants
-.primary {
- background-color: var(--button-contained-bg);
- color: var(--button-text);
-
- &:hover:not(:disabled) {
- background-color: var(--button-contained-bg-hover);
- }
-}
-
-.secondary {
- background-color: var(--button-bg);
- color: var(--button-text);
- border: 1px solid var(--separator-bg);
-
- &:hover:not(:disabled) {
- background-color: var(--button-bg-hover);
- color: var(--button-text-hover);
- }
-}
-
-.ghost {
- background-color: transparent;
- color: var(--text-secondary);
-
- &:hover:not(:disabled) {
- background-color: var(--button-bg);
- color: var(--text-primary);
- }
-}
-
-.text {
- background-color: transparent;
- color: var(--accent-blue);
- padding: 0;
- min-height: auto;
-
- &:hover:not(:disabled) {
- color: var(--accent-blue-focus);
- text-decoration: underline;
- }
-
- &:active:not(:disabled) {
- transform: none;
- }
-}
-
-.blended {
- background: transparent;
-
- &:hover:not(:disabled) {
- background: var(--button-bg-hover);
- }
-}
-
-.bound {
- background: var(--button-contained-bg);
-
- &:hover:not(:disabled) {
- background: var(--button-contained-bg-hover);
- }
-
- &.save:hover .accessory svg {
- fill: colors.$save-red;
- stroke: colors.$save-red;
- }
-
- &.save {
- color: colors.$save-red;
-
- &.active .accessory svg {
- fill: colors.$save-red;
- stroke: colors.$save-red;
- }
-
- &:hover {
- color: color.adjust(colors.$save-red, $lightness: -30%);
-
- .accessory svg {
- fill: color.adjust(colors.$save-red, $lightness: -30%);
- stroke: color.adjust(colors.$save-red, $lightness: -30%);
- }
- }
- }
-}
-
-.bound.blended {
- background: var(--dialog-bg);
-
- &:hover:not(:disabled) {
- background: var(--input-bound-bg);
- }
-}
-
-.floating {
- pointer-events: none;
- position: absolute;
- opacity: 0;
- z-index: 99;
-}
-
-.destructive {
- background: colors.$error;
- color: white;
-
- &:hover:not(:disabled) {
- background: color.adjust(colors.$error, $lightness: -15%);
- }
-
- @include mixins.breakpoint(phone) {
- background: colors.$error;
- color: colors.$grey-100;
-
- .accessory svg {
- fill: colors.$grey-100;
- }
- }
-}
-
-.notice {
- background-color: var(--notice-button-bg);
- color: var(--notice-button-text);
-
- &:hover:not(:disabled) {
- background-color: var(--notice-button-bg-hover);
- }
-}
-
-.modal {
- &:hover:not(:disabled) {
- background: colors.$grey-90;
- }
-
- &.destructive {
- color: colors.$error;
-
- &:hover:not(:disabled) {
- color: color.adjust(colors.$error, $lightness: -10%);
- }
- }
-}
-
-// Modifiers
-.full {
- width: 100%;
-}
-
-.fullWidth {
- width: 100%;
-}
-
-.grow {
- flex-grow: 1;
-}
-
-.no-shrink {
- flex-shrink: 0;
-}
-
-.active {
- background: var(--button-bg-hover);
- color: var(--button-text-hover);
-}
-
-// Sizes
-.icon {
- aspect-ratio: 1 / 1;
- padding: spacing.$unit * 1.5;
- height: 44px;
- width: 44px;
-
- .text {
- display: none;
-
- @include mixins.breakpoint(tablet) {
- display: block;
- }
-
- @include mixins.breakpoint(phone) {
- display: block;
- }
- }
-}
-
-.small {
- padding: spacing.$unit spacing.$unit-2x;
- font-size: typography.$font-small;
- min-height: 28px;
-
- &.iconOnly {
- padding: spacing.$unit;
- width: 28px;
- height: 28px;
- }
-}
-
-.medium {
- height: spacing.$unit * 5.5;
- padding: (spacing.$unit * 1.5) spacing.$unit-2x;
- font-size: typography.$font-regular;
-
- &.iconOnly {
- padding: spacing.$unit * 1.5;
- width: 44px;
- height: 44px;
- }
-}
-
-.large {
- font-size: typography.$font-large;
- padding: spacing.$unit-2x spacing.$unit-3x;
- min-height: 52px;
-
- &.iconOnly {
- padding: spacing.$unit-2x;
- width: 52px;
- height: 52px;
- }
-}
-
-// Special features
-.save {
- .accessory svg {
- fill: none;
- stroke: var(--button-text);
- }
-
- &.saved {
- color: colors.$save-red;
-
- .accessory svg {
- fill: colors.$save-red;
- stroke: colors.$save-red;
- }
-
- &:hover:not(:disabled) {
- color: colors.$save-red;
-
- .accessory svg {
- fill: none;
- stroke: colors.$save-red;
- }
- }
- }
-
- &:hover:not(:disabled) {
- color: colors.$save-red;
-
- .accessory svg {
- fill: colors.$save-red;
- stroke: colors.$save-red;
- }
- }
-}
-
-// Element colors
-.wind {
- background: var(--wind-bg);
- color: var(--wind-text-contrast);
-
- &:hover:not(:disabled) {
- background: var(--wind-bg-hover);
- color: var(--wind-text-hover);
- }
-}
-
-.fire {
- background: var(--fire-bg);
- color: var(--fire-text-contrast);
-
- &:hover:not(:disabled) {
- background: var(--fire-bg-hover);
- color: var(--fire-text-hover);
- }
-}
-
-.water {
- background: var(--water-bg);
- color: var(--water-text-contrast);
-
- &:hover:not(:disabled) {
- background: var(--water-bg-hover);
- color: var(--water-text-hover);
- }
-}
-
-.earth {
- background: var(--earth-bg);
- color: var(--earth-text-contrast);
-
- &:hover:not(:disabled) {
- background: var(--earth-bg-hover);
- color: var(--earth-text-hover);
- }
-}
-
-.dark {
- background: var(--dark-bg);
- color: var(--dark-text-contrast);
-
- &:hover:not(:disabled) {
- background: var(--dark-bg-hover);
- color: var(--dark-text-hover);
- }
-}
-
-.light {
- background: var(--light-bg);
- color: var(--light-text-contrast);
-
- &:hover:not(:disabled) {
- background: var(--light-bg-hover);
- color: var(--light-text-hover);
- }
-}
-
-// Icon-only specific
-.iconOnly {
- gap: 0;
- aspect-ratio: 1;
-}
-
-// Accessories
-.accessory {
- $dimension: spacing.$unit-2x;
-
- display: flex;
- align-items: center;
-
- &.arrow {
- margin-top: spacing.$unit-half;
- }
-
- &.flipped {
- transform: rotate(180deg);
- }
-
- svg {
- fill: var(--button-text);
- height: $dimension;
- width: $dimension;
-
- &.stroke {
- fill: none;
- stroke: var(--button-text);
- }
-
- &.Add {
- height: 18px;
- width: 18px;
- }
-
- &.Check {
- height: 22px;
- width: 22px;
- }
- }
-
- &.check svg {
- margin-top: 1px;
- height: 14px;
- width: auto;
- }
-
- &.settings svg {
- height: 13px;
- width: 13px;
- }
-}
-
-// CSS modules workaround for floating button behavior
-:global(.unit:hover) .floating,
-:global(.unit) .floating.active {
- pointer-events: initial;
- opacity: 1;
-}
diff --git a/src/lib/components/ui/checkbox/Checkbox.svelte b/src/lib/components/ui/checkbox/Checkbox.svelte
index c8ef5139..94a8155b 100644
--- a/src/lib/components/ui/checkbox/Checkbox.svelte
+++ b/src/lib/components/ui/checkbox/Checkbox.svelte
@@ -2,8 +2,6 @@
-
+
{#if checked === 'indeterminate'}
-
- {:else}
-
+ −
+ {:else if checked}
+ ✓
{/if}
-
\ No newline at end of file
+
+
+
\ No newline at end of file
diff --git a/src/lib/components/ui/checkbox/checkbox.module.scss b/src/lib/components/ui/checkbox/checkbox.module.scss
deleted file mode 100644
index fc1b9424..00000000
--- a/src/lib/components/ui/checkbox/checkbox.module.scss
+++ /dev/null
@@ -1,99 +0,0 @@
-@use 'themes/spacing';
-@use 'themes/colors';
-@use 'themes/layout';
-@use 'themes/typography';
-
-.checkbox {
- background-color: var(--input-bg);
- border: 2px solid var(--separator-bg);
- border-radius: layout.$item-corner-small;
- cursor: pointer;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- transition: all 0.18s ease-out;
-
- &:hover:not(:disabled) {
- background-color: var(--input-bg-hover);
- border-color: var(--separator-bg-hover);
- }
-
- &:focus,
- &:focus-visible {
- outline: none;
- border-color: colors.$blue;
- box-shadow: 0 0 0 2px rgba(colors.$blue, 0.2);
- }
-
- &[data-state='checked'],
- &[data-state='indeterminate'] {
- background-color: var(--accent-blue);
- border-color: var(--accent-blue);
-
- &:hover:not(:disabled) {
- background-color: var(--accent-blue-hover);
- border-color: var(--accent-blue-hover);
- }
- }
-
- &:disabled {
- cursor: not-allowed;
- opacity: 0.5;
- }
-
- &.bound {
- background-color: var(--input-bound-bg);
-
- &:hover:not(:disabled) {
- background-color: var(--input-bound-bg-hover);
- }
-
- &[data-state='checked'],
- &[data-state='indeterminate'] {
- background-color: var(--accent-blue);
- border-color: var(--accent-blue);
- }
- }
-}
-
-// Size variations
-.small {
- width: 16px;
- height: 16px;
-
- .icon {
- width: 12px;
- height: 12px;
- }
-}
-
-.medium {
- width: 20px;
- height: 20px;
-
- .icon {
- width: 14px;
- height: 14px;
- }
-}
-
-.large {
- width: 24px;
- height: 24px;
-
- .icon {
- width: 18px;
- height: 18px;
- }
-}
-
-.indicator {
- display: flex;
- align-items: center;
- justify-content: center;
- color: white;
-}
-
-.icon {
- stroke-width: 3;
-}
\ No newline at end of file
diff --git a/src/lib/components/ui/dropdown/DropdownItem.svelte b/src/lib/components/ui/dropdown/DropdownItem.svelte
new file mode 100644
index 00000000..5399dadb
--- /dev/null
+++ b/src/lib/components/ui/dropdown/DropdownItem.svelte
@@ -0,0 +1,101 @@
+
+
+
+
+{#if href}
+
+
+ {@render children()}
+
+
+{:else}
+
+ {@render children()}
+
+{/if}
+
+
diff --git a/src/lib/components/ui/input/Input.svelte b/src/lib/components/ui/input/Input.svelte
index 67995781..0a2b0078 100644
--- a/src/lib/components/ui/input/Input.svelte
+++ b/src/lib/components/ui/input/Input.svelte
@@ -1,132 +1,342 @@
\ No newline at end of file
+ {#if children}
+ {@render children()}
+ {/if}
+
+
+
\ No newline at end of file
diff --git a/src/lib/components/ui/segmented-control/rep-segment.module.scss b/src/lib/components/ui/segmented-control/rep-segment.module.scss
index e5f3b83c..e9b727ab 100644
--- a/src/lib/components/ui/segmented-control/rep-segment.module.scss
+++ b/src/lib/components/ui/segmented-control/rep-segment.module.scss
@@ -15,7 +15,7 @@
transition: all 0.2s ease;
&:hover {
- background: $grey-80; // Solid gray for hover state
+ background: $grey-100;
}
&:focus-visible {
@@ -36,7 +36,7 @@
.indicator {
position: absolute;
inset: 0;
- background: $grey-80;
+ background: $grey-100;
border-radius: $item-corner;
opacity: 0;
transition: opacity 0.2s ease;
diff --git a/src/lib/components/ui/select/Select.svelte b/src/lib/components/ui/select/Select.svelte
index b33877d7..e4f8fe02 100644
--- a/src/lib/components/ui/select/Select.svelte
+++ b/src/lib/components/ui/select/Select.svelte
@@ -1,7 +1,5 @@