diff --git a/fe/src/assets/valerie-ui.scss b/fe/src/assets/valerie-ui.scss
index 79ba0d8..b13bafd 100644
--- a/fe/src/assets/valerie-ui.scss
+++ b/fe/src/assets/valerie-ui.scss
@@ -37,13 +37,11 @@
/* Textures */
--paper-texture: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='60' height='60' viewBox='0 0 60 60'%3E%3Cg fill-rule='evenodd'%3E%3Cg fill='%23a59a8a' fill-opacity='0.15'%3E%3Cpath opacity='.5' d='M36 60v-6h6v6h-6zm18-12v-6h6v6h-6zM6 0v6H0V0h6zM6 12v6H0v-6h6zM18 0v6h-6V0h6zM18 12v6h-6v-6h6zM30 0v6h-6V0h6zM30 12v6h-6v-6h6zM42 0v6h-6V0h6zM42 12v6h-6v-6h6zM54 0v6h-6V0h6zM54 12v6h-6v-6h6zM6 24v6H0v-6h6zM6 36v6H0v-6h6zM6 48v6H0v-6h6zM18 24v6h-6v-6h6zM18 36v6h-6v-6h6zM18 48v6h-6v-6h6zM30 24v6h-6v-6h6zM30 36v6h-6v-6h6zM30 48v6h-6v-6h6zM42 24v6h-6v-6h6zM42 36v6h-6v-6h6zM42 48v6h-6v-6h6zM54 24v6h-6v-6h6zM54 36v6h-6v-6h6zM54 48v6h-6v-6h6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E");
- --progress-texture: repeating-linear-gradient(
- 45deg,
- rgba(0, 0, 0, 0.05),
- rgba(0, 0, 0, 0.05) 5px,
- transparent 5px,
- transparent 10px
- );
+ --progress-texture: repeating-linear-gradient(45deg,
+ rgba(0, 0, 0, 0.05),
+ rgba(0, 0, 0, 0.05) 5px,
+ transparent 5px,
+ transparent 10px);
}
/* Accessibility Helpers */
@@ -61,6 +59,7 @@
/* Reduced Motion Preference */
@media (prefers-reduced-motion: reduce) {
+
*,
*::before,
*::after {
@@ -133,8 +132,8 @@ body {
/* Higher than non-focused tabs */
}
-.checkbox-label input:focus-visible ~ .checkmark,
-.radio-label input:focus-visible ~ .checkmark {
+.checkbox-label input:focus-visible~.checkmark,
+.radio-label input:focus-visible~.checkmark {
outline: var(--focus-outline);
outline-offset: var(--focus-outline-offset);
box-shadow:
@@ -142,7 +141,7 @@ body {
0 0 0 var(--focus-outline-width) var(--focus-outline-color);
}
-.switch-container input:focus-visible + .switch {
+.switch-container input:focus-visible+.switch {
outline: var(--focus-outline);
outline-offset: var(--focus-outline-offset);
}
@@ -211,7 +210,7 @@ h3 {
margin-right: 0.5em;
}
-button > .icon:last-child {
+button>.icon:last-child {
margin-right: 0;
}
@@ -300,6 +299,7 @@ button > .icon:last-child {
}
@keyframes jiggle-subtle {
+
0%,
100% {
transform: translate(2px, 2px) scale(0.98) rotate(0deg);
@@ -340,7 +340,7 @@ button > .icon:last-child {
/* Prevent texture from interfering */
}
-.card > * {
+.card>* {
position: relative;
z-index: 1;
/* Ensure content is above texture */
@@ -513,8 +513,8 @@ select.form-input {
border-radius: 50%;
}
-.checkbox-label input:checked ~ .checkmark:after,
-.radio-label input:checked ~ .checkmark:after {
+.checkbox-label input:checked~.checkmark:after,
+.radio-label input:checked~.checkmark:after {
content: '';
position: absolute;
display: block;
@@ -723,12 +723,12 @@ select.form-input {
/* Push to the right on larger screens */
}
-.list-item-details > * {
+.list-item-details>* {
margin-left: 0.5rem;
}
/* Spacing between items in details */
-.list-item-details > :first-child {
+.list-item-details> :first-child {
margin-left: 0;
}
@@ -908,7 +908,7 @@ select.form-input {
pointer-events: none;
}
-.tab-content > * {
+.tab-content>* {
position: relative;
z-index: 1;
}
@@ -1073,7 +1073,7 @@ select.form-input {
pointer-events: none;
}
-.alert > .alert-content {
+.alert>.alert-content {
/* Wrap main content */
display: flex;
align-items: center;
@@ -1241,11 +1241,11 @@ select.form-input {
/* Vertical centering */
}
-.switch-container input:checked + .switch {
+.switch-container input:checked+.switch {
background-color: var(--secondary-accent);
}
-.switch-container input:checked + .switch:before {
+.switch-container input:checked+.switch:before {
background-color: var(--light);
border-color: var(--dark);
/* Width (64) - border*2 (6) - left (2) - width (24) = 32 */
@@ -1497,8 +1497,8 @@ select.form-input {
border-color: var(--dark) transparent transparent transparent;
}
-.tooltip .tooltip-trigger:hover + .tooltip-text,
-.tooltip .tooltip-trigger:focus-visible + .tooltip-text,
+.tooltip .tooltip-trigger:hover+.tooltip-text,
+.tooltip .tooltip-trigger:focus-visible+.tooltip-text,
.tooltip-text.visible {
visibility: visible;
opacity: 1;
@@ -1544,6 +1544,7 @@ select.form-input {
}
@keyframes pulse-dot {
+
0%,
80%,
100% {
@@ -1678,7 +1679,7 @@ select.form-input {
/* Allow badges/avatar wrap on mobile */
}
- .list-item-details > * {
+ .list-item-details>* {
margin-left: 0;
margin-right: 0.5rem;
margin-bottom: 0.25rem;
@@ -1723,7 +1724,7 @@ select.form-input {
flex-direction: column;
}
- .flex-layout-stack-mobile > .card {
+ .flex-layout-stack-mobile>.card {
width: 100% !important;
margin: 0 0 1.5rem 0 !important;
flex-basis: auto !important;
@@ -1733,12 +1734,12 @@ select.form-input {
flex-direction: column;
}
- .form-row-wrap-mobile > .form-group {
+ .form-row-wrap-mobile>.form-group {
margin-right: 0 !important;
width: 100%;
}
- .form-row-wrap-mobile > .form-group:not(:last-child) {
+ .form-row-wrap-mobile>.form-group:not(:last-child) {
margin-bottom: 1.5rem;
}
-}
+}
\ No newline at end of file
diff --git a/fe/src/components/CreateListModal.vue b/fe/src/components/CreateListModal.vue
index c33d4dd..ab040ed 100644
--- a/fe/src/components/CreateListModal.vue
+++ b/fe/src/components/CreateListModal.vue
@@ -7,7 +7,7 @@
-
+
@@ -52,7 +52,8 @@ const emit = defineEmits<{
const isOpen = useVModel(props, 'modelValue', emit);
const listName = ref('');
const description = ref('');
-const selectedGroupId = ref(null); // Store only the ID
+const SENTINEL_NO_GROUP = 0; // Using 0 to represent 'None' or 'Personal List'
+const selectedGroupId = ref(SENTINEL_NO_GROUP); // Initialize with sentinel
const loading = ref(false);
const formErrors = ref<{ listName?: string }>({});
const notificationStore = useNotificationStore();
@@ -61,14 +62,8 @@ const listNameInput = ref | null>(null);
// const modalContainerRef = ref(null); // Removed
const groupOptionsForSelect = computed(() => {
- const options = props.groups ? props.groups.map(g => ({ label: g.label, value: g.value })) : [];
- // VSelect expects placeholder to be passed as a prop, not as an option for empty value usually
- // However, if 'None' is a valid selectable option representing null, this is okay.
- // The VSelect component's placeholder prop is typically for a non-selectable first option.
- // Let's adjust this to provide a clear "None" option if needed, or rely on VSelect's placeholder.
- // For now, assuming VSelect handles `null` modelValue with its placeholder prop.
- // If selectedGroupId can be explicitly null via selection:
- return [{ label: 'None (Personal List)', value: null }, ...options];
+ // VSelect's placeholder should work if selectedGroupId is the sentinel value
+ return props.groups ? props.groups.map(g => ({ label: g.label, value: g.value })) : [];
});
@@ -77,10 +72,15 @@ watch(isOpen, (newVal) => {
// Reset form when opening
listName.value = '';
description.value = '';
- selectedGroupId.value = null; // Default to 'None' or personal list
+ // If a single group is passed, pre-select it. Otherwise, default to sentinel
+ if (props.groups && props.groups.length === 1) {
+ selectedGroupId.value = props.groups[0].value;
+ } else {
+ selectedGroupId.value = SENTINEL_NO_GROUP; // Reset to sentinel
+ }
formErrors.value = {};
nextTick(() => {
- listNameInput.value?.focus?.();
+ // listNameInput.value?.focus?.(); // This might still be an issue depending on VInput. Commenting out for now.
});
}
});
@@ -105,11 +105,12 @@ const onSubmit = async () => {
}
loading.value = true;
try {
- const response = await apiClient.post(API_ENDPOINTS.LISTS.BASE, {
+ const payload = {
name: listName.value,
description: description.value,
- group_id: selectedGroupId.value,
- });
+ group_id: selectedGroupId.value === SENTINEL_NO_GROUP ? null : selectedGroupId.value,
+ };
+ const response = await apiClient.post(API_ENDPOINTS.LISTS.BASE, payload);
notificationStore.addNotification({ message: 'List created successfully', type: 'success' });
@@ -125,7 +126,7 @@ const onSubmit = async () => {
};
-
diff --git a/fe/src/components/valerie/VTextarea.vue b/fe/src/components/valerie/VTextarea.vue
index daa795f..ef1113c 100644
--- a/fe/src/components/valerie/VTextarea.vue
+++ b/fe/src/components/valerie/VTextarea.vue
@@ -1,19 +1,10 @@
-
+