(nouns) use same styling on <NounsTemplatesTable>, extract <NounsTable> to not repeat styling

This commit is contained in:
Valentyne Stigloher 2025-01-17 13:35:41 +01:00
parent 7870951f49
commit 9d4900fde8
5 changed files with 156 additions and 163 deletions

View File

@ -1,12 +1,8 @@
<script setup lang="ts">
import type { ComponentExposed } from 'vue-component-type-helpers';
import type Table from '~/components/Table.vue';
import type NounsSubmitForm from '~/components/nouns/NounsSubmitForm.vue';
import { Noun } from '~/src/classes.ts';
import type { NounRaw } from '~/src/classes.ts';
import { buildDict } from '~/src/helpers.ts';
import { availableGenders } from '~/src/nouns.ts';
const props = defineProps<{
load?: boolean;
@ -16,7 +12,7 @@ const { $translator: translator } = useNuxtApp();
const config = useConfig();
const filter = useFilterWithCategory();
const dictionarytable = useTemplateRef<ComponentExposed<typeof Table>>('dictionarytable');
const dictionarytable = useTemplateRef('dictionarytable');
watch(filter, () => {
if (dictionarytable.value) {
dictionarytable.value.reset();
@ -114,90 +110,71 @@ defineExpose({ loadNouns });
@submit-clicked="form?.focus()"
/>
<Table
<NounsTable
ref="dictionarytable"
:class="[config.nouns.nonbinary ? 'nouns-table-nonbinary' : '']"
:data="visibleNouns"
:nouns="visibleNouns"
:marked="(el) => !el.approved"
fixed
>
<template #header>
<div v-for="gender in availableGenders(config)" :key="gender" class="d-none d-md-block bold">
<NounsGenderLabel :gender="gender" />
</div>
</template>
<template #row="{ el: noun }">
<NounsDictionaryEntry
:noun="noun"
:base="noun.base && nouns[noun.base] ? nouns[noun.base] : undefined"
>
<template #buttons>
<ul class="d-flex flex-wrap flex-md-column list-unstyled list-btn-concise mb-0">
<template v-if="$isGranted('nouns')">
<li v-if="noun.author" class="small">
<nuxt-link
:to="`/@${noun.author}`"
class="btn btn-concise btn-outline-dark btn-sm m-1"
>
<Icon v="user" />
<span class="btn-label">
<T>crud.author</T><T>quotation.colon</T>
@{{ noun.author }}
</span>
</nuxt-link>
</li>
<li v-if="!noun.approved">
<button class="btn btn-concise btn-success btn-sm m-1" @click="approve(noun)">
<Icon v="check" />
<span class="btn-label"><T>crud.approve</T></span>
</button>
</li>
<li v-else @click="hide(noun)">
<button class="btn btn-concise btn-outline-secondary btn-sm m-1">
<Icon v="times" />
<span class="btn-label"><T>crud.hide</T></span>
</button>
</li>
<li>
<button class="btn btn-concise btn-outline-danger btn-sm m-1" @click="remove(noun)">
<Icon v="trash" />
<span class="btn-label"><T>crud.remove</T></span>
</button>
</li>
</template>
<li>
<button class="btn btn-concise btn-outline-primary btn-sm m-1" @click="edit(noun)">
<Icon v="pen" />
<span class="btn-label">
<T v-if="$isGranted('nouns')">crud.edit</T>
<T v-else>nouns.edit</T>
</span>
</button>
</li>
<li>
<a
:href="`/api/nouns/${noun.id}.png`"
target="_blank"
rel="noopener"
class="btn btn-concise btn-outline-primary btn-sm m-1"
>
<Icon v="image" />
<span class="btn-label">
<T>nouns.image</T>
</span>
</a>
</li>
</ul>
<template #buttons="{ noun }">
<ul class="d-flex flex-wrap flex-md-column list-unstyled list-btn-concise mb-0">
<template v-if="$isGranted('nouns')">
<li v-if="noun.author" class="small">
<nuxt-link
:to="`/@${noun.author}`"
class="btn btn-concise btn-outline-dark btn-sm m-1"
>
<Icon v="user" />
<span class="btn-label">
<T>crud.author</T><T>quotation.colon</T>
@{{ noun.author }}
</span>
</nuxt-link>
</li>
<li v-if="!noun.approved">
<button class="btn btn-concise btn-success btn-sm m-1" @click="approve(noun)">
<Icon v="check" />
<span class="btn-label"><T>crud.approve</T></span>
</button>
</li>
<li v-else @click="hide(noun)">
<button class="btn btn-concise btn-outline-secondary btn-sm m-1">
<Icon v="times" />
<span class="btn-label"><T>crud.hide</T></span>
</button>
</li>
<li>
<button class="btn btn-concise btn-outline-danger btn-sm m-1" @click="remove(noun)">
<Icon v="trash" />
<span class="btn-label"><T>crud.remove</T></span>
</button>
</li>
</template>
</NounsDictionaryEntry>
<li>
<button class="btn btn-concise btn-outline-primary btn-sm m-1" @click="edit(noun)">
<Icon v="pen" />
<span class="btn-label">
<T v-if="$isGranted('nouns')">crud.edit</T>
<T v-else>nouns.edit</T>
</span>
</button>
</li>
<li>
<a
:href="`/api/nouns/${noun.id}.png`"
target="_blank"
rel="noopener"
class="btn btn-concise btn-outline-primary btn-sm m-1"
>
<Icon v="image" />
<span class="btn-label">
<T>nouns.image</T>
</span>
</a>
</li>
</ul>
</template>
<template #empty>
<Icon v="search" />
<T>nouns.empty</T>
</template>
</Table>
</NounsTable>
<AdPlaceholder :phkey="['content-1', 'content-mobile-1']" />
@ -208,42 +185,3 @@ defineExpose({ loadNouns });
</template>
</Loading>
</template>
<style scoped lang="scss">
@import "assets/variables";
:deep(.row-header) {
grid-template-columns: 1fr 1fr 1fr 3em;
.nouns-table-nonbinary & {
grid-template-columns: 1fr 1fr 1fr 1fr 3em;
}
}
:deep(.row-content) {
grid:
"mascLabel masc mascPl"
"femLabel fem femPl"
"neutrLabel neutr neutrPl"
"nbLabel nb nbPl"
"sources sources sources"
"buttons buttons buttons"
/ auto 1fr 1fr;
@include media-breakpoint-up('md', $grid-breakpoints) {
grid:
"masc fem neutr buttons"
"mascPl femPl neutrPl buttons"
"sources sources sources buttons"
/ 1fr 1fr 1fr 3em;
.nouns-table-nonbinary & {
grid:
"masc fem neutr nb buttons"
"mascPl femPl neutrPl nbPl buttons"
"sources sources sources sources buttons"
/ 1fr 1fr 1fr 1fr 3em;
}
}
}
</style>

View File

@ -0,0 +1,84 @@
<script setup lang="ts" generic="T extends Partial<Noun> & MinimalNoun & { id: string }">
import type { MinimalNoun, Noun } from '~/src/classes.ts';
import { availableGenders } from '~/src/nouns.ts';
defineProps<{
nouns: T[];
marked?: (element: T) => boolean;
}>();
const config = useConfig();
const table = useTemplateRef('table');
defineExpose({
reset() {
table.value?.reset();
},
focus() {
table.value?.focus();
},
});
</script>
<template>
<Table ref="table" :data="nouns" :marked fixed>
<template #header>
<div v-for="gender in availableGenders(config)" :key="gender" class="d-none d-md-block bold">
<NounsGenderLabel :gender="gender" />
</div>
</template>
<template #row="{ el: noun }">
<NounsTableEntry :noun>
<template #buttons>
<ul class="list-unstyled list-btn-concise">
<slot name="buttons" :noun="noun"></slot>
</ul>
</template>
</NounsTableEntry>
</template>
<template #empty>
<Icon v="search" />
<T>nouns.empty</T>
</template>
</Table>
</template>
<style scoped lang="scss">
@import "assets/variables";
:deep(.row-header) {
grid-template-columns: 1fr 1fr 1fr 3em;
.nouns-table-nonbinary & {
grid-template-columns: 1fr 1fr 1fr 1fr 3em;
}
}
:deep(.row-content) {
grid:
"mascLabel masc mascPl"
"femLabel fem femPl"
"neutrLabel neutr neutrPl"
"nbLabel nb nbPl"
"sources sources sources"
"buttons buttons buttons"
/ auto 1fr 1fr;
@include media-breakpoint-up('md', $grid-breakpoints) {
grid:
"masc fem neutr buttons"
"mascPl femPl neutrPl buttons"
"sources sources sources buttons"
/ 1fr 1fr 1fr 3em;
.nouns-table-nonbinary & {
grid:
"masc fem neutr nb buttons"
"mascPl femPl neutrPl nbPl buttons"
"sources sources sources sources buttons"
/ 1fr 1fr 1fr 1fr 3em;
}
}
}
</style>

View File

@ -1,9 +1,9 @@
<script setup lang="ts">
import type { Noun } from '~/src/classes.ts';
import type { MinimalNoun, Noun } from '~/src/classes.ts';
import { genders } from '~/src/nouns.ts';
const props = defineProps<{
noun: Noun;
noun: Partial<Noun> & MinimalNoun;
base?: Noun;
}>();
@ -44,7 +44,7 @@ const numerus = computed(() => {
</small>
</div>
</template>
<div v-if="noun.sourcesData.length" style="grid-area: sources">
<div v-if="noun.sourcesData?.length" style="grid-area: sources">
<p><strong><T>sources.referenced</T><T>quotation.colon</T></strong></p>
<ul class="list-unstyled mb-0">
<li v-for="source in noun.sourcesData" :key="source.id">

View File

@ -1,7 +1,7 @@
<script setup lang="ts">
import type { MinimalNoun } from '~/src/classes.ts';
import { nounTemplates } from '~/src/data.ts';
import { availableGenders, gendersWithNumerus } from '~/src/nouns.ts';
import { gendersWithNumerus } from '~/src/nouns.ts';
const props = withDefaults(defineProps<{
templateBase?: string;
@ -11,15 +11,6 @@ const props = withDefaults(defineProps<{
filter: '',
});
const config = useConfig();
const numerus = computed(() => {
if (config.nouns.plurals) {
return [false, true];
}
return [false];
});
const templates = computed((): (MinimalNoun & { id: string })[] => {
return nounTemplates.filter((template) => {
for (const field of gendersWithNumerus) {
@ -39,33 +30,11 @@ const templates = computed((): (MinimalNoun & { id: string })[] => {
</script>
<template>
<Table :data="templates" fixed>
<template #header>
<th v-for="gender in availableGenders(config)" :key="gender" class="text-nowrap">
<NounsGenderLabel :gender="gender" />
</th>
<th></th>
<NounsTable :nouns="templates">
<template #buttons="{ noun }">
<ul class="list-unstyled list-btn-concise">
<slot name="buttons" :template="noun"></slot>
</ul>
</template>
<template #row="{ el: template }">
<td v-for="gender in availableGenders(config)" :key="gender">
<NounsItem
v-for="plural in numerus"
:key="plural ? 'plural' : 'singular'"
:noun="template"
:gender
:plural
/>
</td>
<td>
<ul class="list-unstyled list-btn-concise">
<slot name="buttons" :template="template"></slot>
</ul>
</td>
</template>
<template #empty>
<Icon v="search" />
<T>nouns.empty</T>
</template>
</Table>
</NounsTable>
</template>

View File

@ -13,6 +13,8 @@ definePageMeta({
},
});
const NounsNav = useLocaleComponent('nouns', 'NounsNav');
const { $translator: translator } = useNuxtApp();
useSimpleHead({
title: translator.translate('nouns.headerLonger'),