implement fixes for review

This commit is contained in:
Kavin
2026-03-27 20:06:35 +05:30
parent 75201a8083
commit 1e9c5dff5d
10 changed files with 63 additions and 49 deletions

View File

@@ -3,12 +3,12 @@
<div class="flex min-w-[50vw] flex-col">
<div class="h-[70vh] overflow-y-scroll pr-4">
<span v-t="'actions.add_to_group'" class="mb-3 inline-block w-max text-2xl" />
<div v-for="(group, index) in channelGroups" :key="group.groupName" class="px-1">
<div v-for="group in channelGroups" :key="group.groupName" class="px-1">
<div class="flex items-center justify-between">
<span>{{ group.groupName }}</span>
<UiCheckbox
:model-value="group.channels.includes(channelId)"
@update:model-value="onCheckedChange(index, group)"
@update:model-value="onCheckedChange(group)"
/>
</div>
<hr class="h-1 w-full" />
@@ -56,9 +56,12 @@ onMounted(() => {
loadChannelGroups();
});
function onCheckedChange(index, group) {
function onCheckedChange(group) {
if (group.channels.includes(props.channelId)) {
group.channels.splice(index, 1);
const channelIndex = group.channels.indexOf(props.channelId);
if (channelIndex !== -1) {
group.channels.splice(channelIndex, 1);
}
} else {
group.channels.push(props.channelId);
}

View File

@@ -52,6 +52,7 @@
<a
:href="getRssUrl"
class="inline-block w-auto cursor-pointer rounded-sm bg-gray-300 py-2 text-gray-600 hover:bg-gray-500 hover:text-white max-md:px-2 md:px-4 dark:bg-dark-400 dark:text-gray-400 dark:hover:bg-dark-300"
:aria-label="$t('actions.rss_feed')"
>
<i-fa6-solid-rss />
</a>

View File

@@ -48,6 +48,7 @@
<a
class="mr-1 inline-block w-auto cursor-pointer rounded-sm bg-gray-300 py-2 text-gray-600 hover:bg-gray-500 hover:text-white focus:shadow-red-400 focus:outline-2 focus:outline-red-500 max-md:px-2 md:px-4 dark:bg-dark-400 dark:text-gray-400 dark:hover:bg-dark-300"
:href="getRssUrl"
:aria-label="$t('actions.playlist_rss_feed')"
>
<i-fa6-solid-rss />
</a>

View File

@@ -4,11 +4,11 @@
<div class="flex flex-wrap justify-between">
<div class="flex gap-1">
<!-- import json/csv -->
<button
<router-link
v-t="'actions.import_from_json_csv'"
to="/import"
class="inline-block w-auto cursor-pointer rounded-sm bg-gray-300 py-2 text-gray-600 hover:bg-gray-500 hover:text-white focus:shadow-red-400 focus:outline-2 focus:outline-red-500 max-md:px-2 md:px-4 dark:bg-dark-400 dark:text-gray-400 dark:hover:bg-dark-300"
>
<router-link v-t="'actions.import_from_json_csv'" to="/import" />
</button>
/>
<!-- export to json -->
<button
v-t="'actions.export_to_json'"

View File

@@ -2,8 +2,10 @@
<button
:type="type"
:class="[
'inline-block w-auto cursor-pointer rounded-sm py-2 text-gray-600 hover:bg-gray-500 hover:text-white focus:shadow-red-400 focus:outline-2 focus:outline-red-500 max-md:px-2 md:px-4 dark:text-gray-400 dark:hover:bg-dark-300',
variant === 'primary' ? 'bg-gray-300 dark:bg-dark-400' : 'bg-gray-300 dark:bg-dark-400',
'inline-block w-auto cursor-pointer rounded-sm py-2 text-gray-600 hover:bg-gray-500 hover:text-white focus:shadow-sm focus:shadow-red-400 focus:outline-2 focus:outline-red-500 max-md:px-2 md:px-4 dark:text-gray-400 dark:hover:bg-dark-300',
variant === 'primary'
? 'bg-gray-300 dark:bg-dark-400'
: 'border border-gray-500 bg-transparent dark:border-gray-400',
customClass,
]"
v-bind="$attrs"

View File

@@ -1,25 +1,7 @@
<template>
<CheckboxRoot
v-if="hasModelValue"
:id="id"
:model-value="modelValue"
:value="value"
:disabled="disabled"
:class="[
'inline-flex size-4 shrink-0 items-center justify-center rounded-sm border border-gray-500 bg-gray-300 text-white outline-none focus:shadow-red-400 focus:outline-2 focus:outline-red-500 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:border-red-500 data-[state=checked]:bg-red-500 dark:border-gray-400 dark:bg-dark-400 dark:data-[state=checked]:border-red-400 dark:data-[state=checked]:bg-red-400',
customClass,
]"
@update:model-value="handleUpdate"
>
<CheckboxIndicator class="inline-flex items-center justify-center text-current">
<i-fa6-solid-check class="size-3" />
</CheckboxIndicator>
</CheckboxRoot>
<CheckboxRoot
v-else
:id="id"
:value="value"
:disabled="disabled"
:class="[
'inline-flex size-4 shrink-0 items-center justify-center rounded-sm border border-gray-500 bg-gray-300 text-white outline-none focus:shadow-red-400 focus:outline-2 focus:outline-red-500 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:border-red-500 data-[state=checked]:bg-red-500 dark:border-gray-400 dark:bg-dark-400 dark:data-[state=checked]:border-red-400 dark:data-[state=checked]:bg-red-400',
@@ -34,25 +16,20 @@
</template>
<script setup>
import { computed } from "vue";
import { CheckboxRoot, CheckboxIndicator } from "reka-ui";
defineOptions({
name: "UiCheckbox",
});
const props = defineProps({
defineProps({
id: {
type: String,
default: undefined,
},
modelValue: {
type: [Boolean, String, Number, Array],
default: undefined,
},
value: {
type: [Boolean, String, Number],
default: true,
type: Boolean,
default: false,
},
disabled: {
type: Boolean,
@@ -66,10 +43,9 @@ const props = defineProps({
const emit = defineEmits(["update:modelValue", "change"]);
const hasModelValue = computed(() => props.modelValue !== undefined);
function handleUpdate(value) {
emit("update:modelValue", value);
emit("change", value);
const nextValue = value === true;
emit("update:modelValue", nextValue);
emit("change", nextValue);
}
</script>

View File

@@ -2,7 +2,7 @@
<button
type="button"
class="absolute right-3 size-4 cursor-pointer rounded-full bg-gray-300 text-center text-[10px] text-black opacity-50 hover:opacity-70 dark:bg-gray-400"
:aria-label="$t('actions.clear', { count: 0 }) || 'Clear'"
:aria-label="$t('actions.clear')"
@click="$emit('clear')"
>
@@ -10,8 +10,9 @@
</template>
<script setup>
import { useI18n } from "vue-i18n";
defineEmits(["clear"]);
import { useI18n } from "vue-i18n";
const { t: $t } = useI18n();
</script>

View File

@@ -2,6 +2,8 @@
<button
type="button"
class="ml-2 inline-block w-auto cursor-pointer rounded-sm bg-gray-300 py-2 text-gray-600 hover:bg-gray-500 hover:text-white focus:shadow-red-400 focus:outline-2 focus:outline-red-500 max-md:px-2 md:px-4 dark:bg-dark-400 dark:text-gray-400 dark:hover:bg-dark-300"
:aria-label="modelValue ? $t('actions.hide_password') : $t('actions.show_password')"
:aria-pressed="modelValue"
@click="$emit('update:modelValue', !modelValue)"
>
<i-fa6-solid-eye v-if="!modelValue" />
@@ -10,6 +12,8 @@
</template>
<script setup>
import { useI18n } from "vue-i18n";
defineProps({
modelValue: {
type: Boolean,
@@ -18,4 +22,6 @@ defineProps({
});
defineEmits(["update:modelValue"]);
const { t: $t } = useI18n();
</script>

View File

@@ -32,12 +32,19 @@ function createPreferenceRefForValue(key, valueForTypeInference) {
}
export function usePreferenceString(key, defaultVal) {
return getOrCreatePreferenceRef(key, () =>
const preferenceRef = getOrCreatePreferenceRef(key, () =>
useLocalStorage(key, defaultVal ?? null, {
serializer: StorageSerializers.any,
writeDefaults: false,
}),
);
const queryValue = getQueryPreference(key);
if (queryValue !== null && preferenceRef.value !== queryValue) {
preferenceRef.value = queryValue;
}
return preferenceRef;
}
export function usePreferenceBoolean(key, defaultVal = false) {
@@ -104,14 +111,20 @@ export function getPreferenceBoolean(key, defaultVal) {
}
export function getPreferenceString(key, defaultVal) {
const queryValue = getQueryPreference(key);
if (queryValue !== null) return queryValue;
if (testLocalStorage()) {
const value = usePreferenceString(key, defaultVal).value;
const preferenceRef = usePreferenceString(key, defaultVal);
const queryValue = getQueryPreference(key);
if (queryValue !== null && preferenceRef.value !== queryValue) {
preferenceRef.value = queryValue;
}
const value = preferenceRef.value;
return value ?? defaultVal;
}
const queryValue = getQueryPreference(key);
if (queryValue !== null) return queryValue;
return defaultVal;
}
@@ -133,7 +146,13 @@ export function getPreferenceNumber(key, defaultVal) {
export function getPreferenceJSON(key, defaultVal) {
const queryValue = getQueryPreference(key);
if (queryValue !== null) return JSON.parse(queryValue);
if (queryValue !== null) {
try {
return JSON.parse(queryValue);
} catch {
return defaultVal;
}
}
if (testLocalStorage()) {
const value = usePreferenceJSON(key, defaultVal).value;

View File

@@ -91,6 +91,7 @@
"search": "Search (Ctrl+K)",
"filter": "Filter",
"loading": "Loading…",
"clear": "Clear",
"clear_history": "Clear History",
"hide_replies": "Hide Replies",
"load_more_replies": "Load more Replies",
@@ -172,7 +173,11 @@
"export": "Export",
"never": "Never",
"playlists_only": "Playlists only",
"always": "Always"
"always": "Always",
"show_password": "Show password",
"hide_password": "Hide password",
"rss_feed": "RSS feed",
"playlist_rss_feed": "Playlist RSS feed"
},
"comment": {
"pinned_by": "Pinned by {author}",