diff --git a/apps/todo/apps/web/src/lib/components/TaskEditModal.svelte b/apps/todo/apps/web/src/lib/components/TaskEditModal.svelte index 2ed79e38b..b41d6999a 100644 --- a/apps/todo/apps/web/src/lib/components/TaskEditModal.svelte +++ b/apps/todo/apps/web/src/lib/components/TaskEditModal.svelte @@ -1,16 +1,15 @@ @@ -304,20 +213,7 @@
-
- {#each priorities as p} - - {/each} -
+ (priority = p)} />
@@ -346,68 +242,10 @@
-
- - - {#if showLabelDropdown} -
- {#each labelsStore.labels as label} - - {/each} - {#if labelsStore.labels.length === 0} -
Keine Labels vorhanden
- {/if} -
- {/if} -
+ (selectedLabelIds = ids)} + />
@@ -441,140 +279,22 @@
-
- {#each storyPointOptions as sp} - - {/each} - {#if storyPoints !== null} - - {/if} -
+ (storyPoints = v)} />
-
- {#each durationOptions as opt} - - {/each} - - {#if effectiveDurationValue !== null} - - {/if} -
- {#if showCustomDuration} -
- - -
- {/if} + (effectiveDuration = v)} />
-
- {#each Array(10) as _, i} - {@const rating = i + 1} - - {/each} - {#if funRating !== null} - - {/if} -
-
- 1 - 5 - 10 -
+ (funRating = v)} />
@@ -788,184 +508,6 @@ min-height: 80px; } - /* Priority buttons */ - .priority-buttons { - display: flex; - gap: 0.5rem; - flex-wrap: wrap; - } - - .priority-btn { - display: flex; - align-items: center; - gap: 0.375rem; - padding: 0.5rem 0.875rem; - border: 1px solid rgba(0, 0, 0, 0.1); - border-radius: 9999px; - background: rgba(255, 255, 255, 0.8); - font-size: 0.8125rem; - color: #374151; - cursor: pointer; - transition: all 0.15s; - } - - :global(.dark) .priority-btn { - background: rgba(255, 255, 255, 0.1); - border-color: rgba(255, 255, 255, 0.15); - color: #e5e7eb; - } - - .priority-btn:hover { - border-color: var(--priority-color); - } - - .priority-btn.selected { - background: color-mix(in srgb, var(--priority-color) 15%, transparent); - border-color: var(--priority-color); - color: var(--priority-color); - } - - .priority-dot { - width: 0.5rem; - height: 0.5rem; - border-radius: 9999px; - } - - /* Label selector */ - .label-selector { - position: relative; - } - - .label-trigger { - width: 100%; - display: flex; - align-items: center; - justify-content: space-between; - padding: 0.625rem 0.875rem; - border: 1px solid rgba(0, 0, 0, 0.15); - border-radius: 0.75rem; - background: rgba(255, 255, 255, 0.8); - cursor: pointer; - transition: all 0.15s; - } - - :global(.dark) .label-trigger { - background: rgba(255, 255, 255, 0.1); - border-color: rgba(255, 255, 255, 0.15); - } - - .label-trigger:hover { - border-color: rgba(0, 0, 0, 0.25); - } - - .text-muted { - color: #9ca3af; - font-size: 0.875rem; - } - - .selected-labels { - display: flex; - flex-wrap: wrap; - gap: 0.375rem; - } - - .label-tag { - font-size: 0.75rem; - padding: 0.125rem 0.5rem; - border-radius: 9999px; - background: color-mix(in srgb, var(--label-color) 15%, transparent); - color: var(--label-color); - font-weight: 500; - } - - .label-more { - font-size: 0.75rem; - color: #6b7280; - } - - .dropdown-arrow { - width: 1rem; - height: 1rem; - color: #9ca3af; - } - - .label-dropdown { - position: absolute; - top: calc(100% + 0.5rem); - left: 0; - right: 0; - max-height: 200px; - overflow-y: auto; - padding: 0.375rem; - border-radius: 0.75rem; - background: rgba(255, 255, 255, 0.95); - backdrop-filter: blur(12px); - border: 1px solid rgba(0, 0, 0, 0.1); - box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1); - z-index: 10; - } - - :global(.dark) .label-dropdown { - background: rgba(40, 40, 40, 0.95); - border-color: rgba(255, 255, 255, 0.15); - } - - .label-option { - display: flex; - align-items: center; - gap: 0.5rem; - width: 100%; - padding: 0.5rem 0.75rem; - border: none; - background: transparent; - border-radius: 0.5rem; - cursor: pointer; - transition: background 0.15s; - text-align: left; - } - - .label-option:hover { - background: rgba(0, 0, 0, 0.05); - } - - :global(.dark) .label-option:hover { - background: rgba(255, 255, 255, 0.1); - } - - .label-option.selected { - background: rgba(139, 92, 246, 0.1); - } - - .label-dot { - width: 0.625rem; - height: 0.625rem; - border-radius: 9999px; - flex-shrink: 0; - } - - .label-name { - flex: 1; - font-size: 0.875rem; - color: #374151; - } - - :global(.dark) .label-name { - color: #e5e7eb; - } - - .check-icon { - width: 1rem; - height: 1rem; - color: #8b5cf6; - } - - .no-labels { - padding: 0.75rem; - text-align: center; - font-size: 0.875rem; - color: #9ca3af; - } - /* Footer */ .modal-footer { display: flex; @@ -1056,164 +598,6 @@ } } - /* Storypoints */ - .storypoint-buttons { - display: flex; - gap: 0.375rem; - flex-wrap: wrap; - align-items: center; - } - - .storypoint-btn { - min-width: 2.25rem; - height: 2.25rem; - display: flex; - align-items: center; - justify-content: center; - padding: 0 0.5rem; - border: 1px solid rgba(0, 0, 0, 0.1); - border-radius: 9999px; - background: rgba(255, 255, 255, 0.8); - font-size: 0.8125rem; - font-weight: 500; - color: #374151; - cursor: pointer; - transition: all 0.15s; - } - - :global(.dark) .storypoint-btn { - background: rgba(255, 255, 255, 0.1); - border-color: rgba(255, 255, 255, 0.15); - color: #e5e7eb; - } - - .storypoint-btn:hover { - border-color: #8b5cf6; - } - - .storypoint-btn.selected { - background: rgba(139, 92, 246, 0.15); - border-color: #8b5cf6; - color: #8b5cf6; - } - - .storypoint-clear, - .duration-clear, - .fun-rating-clear { - width: 2rem; - height: 2rem; - display: flex; - align-items: center; - justify-content: center; - padding: 0; - border: none; - border-radius: 9999px; - background: rgba(239, 68, 68, 0.1); - color: #ef4444; - cursor: pointer; - transition: all 0.15s; - } - - .storypoint-clear:hover, - .duration-clear:hover, - .fun-rating-clear:hover { - background: rgba(239, 68, 68, 0.2); - } - - /* Duration */ - .duration-buttons { - display: flex; - gap: 0.375rem; - flex-wrap: wrap; - align-items: center; - } - - .duration-btn { - padding: 0.5rem 0.75rem; - border: 1px solid rgba(0, 0, 0, 0.1); - border-radius: 9999px; - background: rgba(255, 255, 255, 0.8); - font-size: 0.8125rem; - color: #374151; - cursor: pointer; - transition: all 0.15s; - } - - :global(.dark) .duration-btn { - background: rgba(255, 255, 255, 0.1); - border-color: rgba(255, 255, 255, 0.15); - color: #e5e7eb; - } - - .duration-btn:hover { - border-color: #8b5cf6; - } - - .duration-btn.selected { - background: rgba(139, 92, 246, 0.15); - border-color: #8b5cf6; - color: #8b5cf6; - } - - .duration-custom { - display: flex; - gap: 0.5rem; - margin-top: 0.75rem; - } - - .duration-input { - width: 80px; - } - - .duration-unit { - width: 120px; - } - - /* Fun Rating */ - .fun-rating { - display: flex; - gap: 0.25rem; - align-items: center; - } - - .fun-rating-dot { - padding: 0.25rem; - border: none; - background: transparent; - cursor: pointer; - transition: transform 0.15s; - } - - .fun-rating-dot:hover { - transform: scale(1.2); - } - - .fun-rating-dot .dot { - display: block; - width: 1.25rem; - height: 1.25rem; - border-radius: 9999px; - background: rgba(0, 0, 0, 0.1); - transition: all 0.15s; - } - - :global(.dark) .fun-rating-dot .dot { - background: rgba(255, 255, 255, 0.15); - } - - .fun-rating-dot.filled .dot { - background: var(--dot-color); - } - - .fun-rating-labels { - display: flex; - justify-content: space-between; - padding: 0 0.25rem; - margin-top: 0.25rem; - font-size: 0.6875rem; - color: #9ca3af; - } - .fun-rating-value { font-weight: 600; } diff --git a/apps/todo/apps/web/src/lib/components/form/DurationPicker.svelte b/apps/todo/apps/web/src/lib/components/form/DurationPicker.svelte new file mode 100644 index 000000000..c0be0f92a --- /dev/null +++ b/apps/todo/apps/web/src/lib/components/form/DurationPicker.svelte @@ -0,0 +1,238 @@ + + +
+
+ {#each quickOptions as opt} + + {/each} + + {#if value !== null} + + {/if} +
+ + {#if showCustom} +
+ + +
+ {/if} +
+ + diff --git a/apps/todo/apps/web/src/lib/components/form/FunRatingPicker.svelte b/apps/todo/apps/web/src/lib/components/form/FunRatingPicker.svelte new file mode 100644 index 000000000..2d2fbbbd6 --- /dev/null +++ b/apps/todo/apps/web/src/lib/components/form/FunRatingPicker.svelte @@ -0,0 +1,127 @@ + + +
+
+ {#each Array(10) as _, i} + {@const rating = i + 1} + + {/each} + {#if value !== null} + + {/if} +
+
+ 1 + 5 + 10 +
+
+ + diff --git a/apps/todo/apps/web/src/lib/components/form/LabelSelector.svelte b/apps/todo/apps/web/src/lib/components/form/LabelSelector.svelte new file mode 100644 index 000000000..86d8d644c --- /dev/null +++ b/apps/todo/apps/web/src/lib/components/form/LabelSelector.svelte @@ -0,0 +1,223 @@ + + + + +
+ + + {#if showDropdown} +
e.stopPropagation()} role="listbox"> + {#each labelsStore.labels as label} + + {/each} + {#if labelsStore.labels.length === 0} +
Keine Labels vorhanden
+ {/if} +
+ {/if} +
+ + diff --git a/apps/todo/apps/web/src/lib/components/form/PrioritySelector.svelte b/apps/todo/apps/web/src/lib/components/form/PrioritySelector.svelte new file mode 100644 index 000000000..429081926 --- /dev/null +++ b/apps/todo/apps/web/src/lib/components/form/PrioritySelector.svelte @@ -0,0 +1,76 @@ + + +
+ {#each priorities as p} + + {/each} +
+ + diff --git a/apps/todo/apps/web/src/lib/components/form/StorypointsSelector.svelte b/apps/todo/apps/web/src/lib/components/form/StorypointsSelector.svelte new file mode 100644 index 000000000..553bc7305 --- /dev/null +++ b/apps/todo/apps/web/src/lib/components/form/StorypointsSelector.svelte @@ -0,0 +1,105 @@ + + +
+ {#each options as sp} + + {/each} + {#if value !== null} + + {/if} +
+ + diff --git a/apps/todo/apps/web/src/lib/components/form/index.ts b/apps/todo/apps/web/src/lib/components/form/index.ts new file mode 100644 index 000000000..cd7e13ded --- /dev/null +++ b/apps/todo/apps/web/src/lib/components/form/index.ts @@ -0,0 +1,5 @@ +export { default as PrioritySelector } from './PrioritySelector.svelte'; +export { default as StorypointsSelector } from './StorypointsSelector.svelte'; +export { default as DurationPicker } from './DurationPicker.svelte'; +export { default as FunRatingPicker } from './FunRatingPicker.svelte'; +export { default as LabelSelector } from './LabelSelector.svelte';