Skip to content

Commit

Permalink
refactor: Refactor readings page
Browse files Browse the repository at this point in the history
  • Loading branch information
botmaster committed Feb 7, 2024
1 parent a5f1068 commit d48249e
Show file tree
Hide file tree
Showing 17 changed files with 303 additions and 242 deletions.
14 changes: 0 additions & 14 deletions assets/scss/base/_forms.scss
Original file line number Diff line number Diff line change
@@ -1,14 +0,0 @@
// Select
select.form-select {
@apply block w-full rounded-md border-0 py-1.5 text-body-txt shadow-sm ring-1 ring-inset ring-polarnight-nord-3
focus:ring-2 focus:ring-inset focus:ring-accent sm:max-w-xs sm:text-sm sm:leading-6;
}

input[type="text"].form-input, .input-text {
@apply block w-full rounded-md border-0 py-1.5 text-body-txt shadow-sm ring-1 ring-inset ring-polarnight-nord-3
focus:ring-2 focus:ring-inset focus:ring-accent sm:max-w-xs sm:text-sm sm:leading-6;
}

input[type="checkbox"] {
@apply rounded border-b-polarnight-nord-0 text-body-txt shadow-sm focus:border-accent focus:ring focus:ring-offset-0 focus:ring-accent focus:ring-opacity-50;
}
2 changes: 2 additions & 0 deletions assets/scss/main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,5 @@
@layer components {
@import 'components/index';
}


2 changes: 2 additions & 0 deletions assets/scss/vendors/_index.scss
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@

@forward "lenis";
@forward "tailwindcss-form";

14 changes: 14 additions & 0 deletions assets/scss/vendors/_tailwindcss-form.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Select
.form-select, .form-multiselect {
@apply block w-full rounded-md border-0 py-1.5 text-body-txt shadow-sm ring-1 ring-inset ring-polarnight-nord-3
focus:ring-2 focus:ring-inset focus:ring-accent sm:max-w-xs sm:text-sm sm:leading-6;
}

input[type="text"].form-input, .input-text {
@apply block w-full rounded-md border-0 py-1.5 text-body-txt shadow-sm ring-1 ring-inset ring-polarnight-nord-3
focus:ring-2 focus:ring-inset focus:ring-accent sm:max-w-xs sm:text-sm sm:leading-6;
}

input[type="checkbox"] {
@apply rounded border-b-polarnight-nord-0 text-body-txt shadow-sm focus:border-accent focus:ring focus:ring-offset-0 focus:ring-accent focus:ring-opacity-50;
}
89 changes: 89 additions & 0 deletions components/ArticleListActionBar.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<script setup lang="ts">
// Define props
import type { IOption } from '~/components/MultiSelectTag.vue';
defineProps<{
tags: IOption[]
pending: boolean
}>();
// Define emits
const emit = defineEmits(['clearFilters']);
const { t } = useI18n();
// Define model
const selectedOptions = defineModel<IOption[]>('selectedOptions', { required: true });
const search = defineModel<string>('search', { required: true });
const status = defineModel<string>('status', { required: true });
const sort = defineModel<string>('sort', { required: true });
// Computed - Has any filters
const hasFilters = computed<boolean>(() => {
return status.value !== '' || search.value !== '';
});
</script>

<template>
<div class="flex flex-col flex-wrap gap-x-6 gap-y-1.5 lg:flex-row lg:items-end">
<div class="lg:mr-8">
<input
v-model.lazy="search" autocomplete="search" name="search" type="text"
placeholder="Search an article" class="form-input min-w-64"
>
</div>

<div>
<label class="mb-1 block" for="selectStatus">{{ t('pages.readings.filters.statusLabel') }}</label>
<select id="selectStatus" v-model="status" class="form-select">
<option value="">
{{ t('pages.readings.filters.status.all') }}
</option>
<option value="To read">
{{ t('pages.readings.filters.status.toRead') }}
</option>
<option value="Read">
{{ t('pages.readings.filters.status.read') }}
</option>
<option value="Reading">
{{ t('pages.readings.filters.status.inProgress') }}
</option>
<option value="Canceled">
{{ t('pages.readings.filters.status.canceled') }}
</option>
</select>
</div>

<div>
<MultiSelectTag v-model="selectedOptions" :options="tags" />
</div>

<div>
<label class="mb-1 block" for="selectSort">{{ t('pages.readings.sort.sortLabel') }}</label>
<select id="selectSort" v-model="sort" class="form-select">
<option value="Created time">
{{ t('pages.readings.sort.createdTime') }}
</option>
<option value="Last edited time">
{{ t('pages.readings.sort.lastEditedTime') }}
</option>
<option value="Name">
{{ t('pages.readings.sort.name') }}
</option>
<option value="Score">
{{ t('pages.readings.sort.score') }}
</option>
</select>
</div>

<div v-if="hasFilters" class="leading-none lg:mb-2">
<button class="inline-flex items-center" @click="emit('clearFilters')">
<Icon class="mr-1.5" name="material-symbols:cancel" />
{{ t('common.clearFilters') }}
</button>
</div>
<Transition name="fade">
<AppLoader v-if="pending" class="m-1 text-2xl" />
</Transition>
</div>
</template>
140 changes: 93 additions & 47 deletions components/MultiSelectTag.vue
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
<script lang="ts" setup>
import { Combobox, ComboboxButton, ComboboxInput, ComboboxOption, ComboboxOptions } from '@headlessui/vue';
import { Combobox, ComboboxButton, ComboboxInput, ComboboxLabel, ComboboxOption, ComboboxOptions } from '@headlessui/vue';
// Interfaces
export interface IOption {
id: string
name: string
color: 'blue' | 'brown' | 'default' | 'gray' | 'green' | 'orange' | 'pink' | 'purple' | 'red' | 'yellow'
}
// Props
const props = defineProps<{
options: { id: string, name: string }[]
options: IOption[]
}>();
const selectedOption = defineModel<string[]>({ required: true });
// Model
const selectedOptions = defineModel<IOption[]>({ required: true });
const query = ref('');
Expand All @@ -21,85 +29,123 @@ const filteredOption = computed(() =>
),
);
function displayValue(options: { id: string }[]) {
function displayValue(options: IOption[]) {
return options.map(option => option.name).join(', ');
}
</script>

<template>
<Combobox v-model="selectedOption" multiple nullable by="id">
<Combobox v-model="selectedOptions" as="div" multiple nullable by="id">
<ComboboxLabel class="mb-1 block">
Tags
</ComboboxLabel>
<div class="multi-select form-multiselect">
<div
class="multi-select__label-container"
class="multi-select__values-container"
>
<!-- <span v-if="selectedOption.length === 0" class="multi-select__label">Select an option</span> -->
<ComboboxInput
class="multi-select__label" :display-value="displayValue"
placeholder="Select an option"
@change="query = $event.target.value"
/>
<p class="multi-select__value">
<span v-if="selectedOptions.length === 0" class="multi-select__label">Select an option</span> <span
v-else
>{{ displayValue(selectedOptions) }}</span>
</p>
</div>

<ComboboxButton
class="ml-auto flex items-center"
>
<span>v</span>
</ComboboxButton>
class="multi-select__button" tabindex="0"
/>

<ComboboxOptions
class="multi-select__options"
as="div"
>
<div
v-if="filteredOption.length === 0 && query !== ''"
class="multi-select__nothing-found"
>
Nothing found.
<div class="multi-select__options-header">
<ComboboxInput
class="multi-select__search-input"
placeholder="Search..."
@change="query = $event.target.value"
/>
</div>
<ComboboxOption
v-for="option in filteredOption" :key="option.id" v-slot="{ active, selected }"
:value="option" as="template"
>
<ul class="multi-select__option-list" data-lenis-prevent>
<li
class="multi-select__option" :aria-selected="selected" :class="{ active }"
v-if="filteredOption.length === 0 && query !== ''"
class="multi-select__nothing-found"
>
<!-- <span class="block truncate" :class="[selected && 'font-semibold']">
{{ option.name }}
</span>
<span
v-if="selected" class="absolute inset-y-0 right-0 flex items-center pr-4"
:class="[active ? 'text-white' : 'text-accent']"
>
ok
</span> -->
<input class="form-checkbox" type="checkbox" :checked="selected"><span :class="[selected && 'font-semibold']">{{ option.name }}</span>
Nothing found.
</li>
</ComboboxOption>
<ComboboxOption
v-for="option in filteredOption" :key="option.id" v-slot="{ active, selected }"
:value="option" as="template"
>
<li
class="multi-select__option" :aria-selected="selected" :class="{ active }"
>
<input class="form-checkbox" type="checkbox" :checked="selected"><span
class="badge badge--is-small badge--is-neutral"
:class="[selected && 'font-semibold']"
>{{ option.name }}</span>
</li>
</ComboboxOption>
</ul>
<div class="multi-select__options-footer">
<div class="flex gap-1.5">
<span class="text-xs">
{{ selectedOptions.length }} / {{ props.options.length }} selected
</span>
<button v-if="selectedOptions.length > 0" class="ml-auto text-xs" @click="selectedOptions = []">
Clear selection
</button>
</div>
</div>
</ComboboxOptions>
</div>
</Combobox>
</template>

<style scoped lang="scss">
.multi-select {
@apply w-full relative flex items-center bg-white px-3
rounded-md border-0 py-1.5 text-body-txt shadow-sm ring-1 ring-inset ring-polarnight-nord-3
focus:ring-2 focus:ring-inset focus:ring-accent sm:max-w-xs sm:text-sm sm:leading-6;
@apply w-full relative flex items-center bg-white min-w-48 p-0;
&__label-container {
@apply flex items-center overflow-x-clip;
&__values-container {
@apply min-w-0 max-w-64 flex-grow;
padding-top: 0.375rem;
padding-bottom: 0.375rem;
padding-left: 0.75rem;
}
&__label {
color: red;
&__value {
@apply truncate;
}
&__button {
@apply ml-auto w-8 inline-block leading-none self-stretch;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");
background-position: right 0.5rem center;
background-repeat: no-repeat;
background-size: 1.5em 1.5em;
}
&__options {
@apply absolute left-0 top-[100%] z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm;
@apply absolute left-0 top-[100%] z-10 mt-1 w-full rounded-md bg-white text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm;
}
&__options-header {
@apply px-2 py-2;
}
&__search-input {
@apply w-full px-3 py-1.5 text-body-txt border-0 rounded-md shadow-sm;
}
&__option-list {
@apply relative overflow-auto max-h-60;
}
&__options-footer {
@apply px-2 py-2;
}
&__option {
@apply relative flex items-center gap-2 cursor-default select-none py-2 pl-3 pr-9;
@apply relative flex items-center gap-2 cursor-default select-none py-1.5 px-3;
&.active {
@apply bg-accent text-accent-content;
Expand Down
2 changes: 1 addition & 1 deletion components/ScrobbleListItem.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { Size, type Track } from '~/types/types';
import { Size, type Track } from '~/types/last-fm/types';
// Props type definition
interface Props {
Expand Down
2 changes: 2 additions & 0 deletions locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"languages": "Language",
"loadMore": "Load more",
"no": "No",
"noData": "No data",
"yes": "Yes"
},
"layouts": {
Expand Down Expand Up @@ -47,6 +48,7 @@
},
"statusLabel": "Status"
},
"filtersTooRestrictive": "🤔 Filters too restrictive ?",
"sort": {
"createdTime": "Created Time",
"lastEditedTime": "Last edited time",
Expand Down
2 changes: 2 additions & 0 deletions locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"languages": "Langue",
"loadMore": "Charger la suite",
"no": "Non",
"noData": "Pas de données",
"yes": "Oui"
},
"layouts": {
Expand Down Expand Up @@ -47,6 +48,7 @@
},
"statusLabel": "Statut"
},
"filtersTooRestrictive": "🤔 Filtres trop restrictifs ?",
"sort": {
"createdTime": "Date de création",
"lastEditedTime": "Date de dernière édition",
Expand Down
3 changes: 2 additions & 1 deletion pages/lab.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script setup lang="ts">
import { v4 as uuidv4 } from 'uuid';
import type { IPage, Recenttracks, Track } from '~/types/types';
import type { Recenttracks, Track } from '~/types/last-fm/types';
import type { IPage } from '~/types/types';
definePageMeta({
layout: false,
Expand Down
Loading

0 comments on commit d48249e

Please sign in to comment.