mirror of
https://gitlab.com/PronounsPage/PronounsPage.git
synced 2025-09-23 12:43:48 -04:00
Merge branch 'a11y-p' into 'main'
some a11y tweaks See merge request PronounsPage/PronounsPage!618
This commit is contained in:
commit
2af5e6efaa
1
app.vue
1
app.vue
@ -56,6 +56,7 @@ useSeoMeta({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<NuxtRouteAnnouncer />
|
||||||
<NuxtPwaManifest />
|
<NuxtPwaManifest />
|
||||||
<NuxtLoadingIndicator color="#C71585" error-color="#dc3545" />
|
<NuxtLoadingIndicator color="#C71585" error-color="#dc3545" />
|
||||||
<NuxtLayout>
|
<NuxtLayout>
|
||||||
|
@ -75,15 +75,15 @@ selectPronounForExample(false);
|
|||||||
(<nuxt-link :to="`/${pronoun.canonicalName}`"><Spelling escape :text="pronoun.canonicalName" /></nuxt-link>)
|
(<nuxt-link :to="`/${pronoun.canonicalName}`"><Spelling escape :text="pronoun.canonicalName" /></nuxt-link>)
|
||||||
</small>
|
</small>
|
||||||
</ExampleItem>
|
</ExampleItem>
|
||||||
<Tooltip :text="tooltipText">
|
<Tooltip
|
||||||
<button
|
v-if="hasDifferentExample"
|
||||||
v-if="hasDifferentExample"
|
:text="tooltipText"
|
||||||
type="button"
|
tag="button"
|
||||||
class="btn btn-sm btn-link px-1 py-0"
|
type="button"
|
||||||
@click="selectDifferentExample()"
|
class="btn btn-sm btn-link px-1 py-0"
|
||||||
>
|
@click="selectDifferentExample()"
|
||||||
<Icon v="random" />
|
>
|
||||||
</button>
|
<Icon v="random" />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</li>
|
</li>
|
||||||
</template>
|
</template>
|
||||||
|
@ -4,7 +4,7 @@ import type { Category } from '~/src/classes.ts';
|
|||||||
const filter = defineModel<string>();
|
const filter = defineModel<string>();
|
||||||
const filterCategory = defineModel<string>('category');
|
const filterCategory = defineModel<string>('category');
|
||||||
|
|
||||||
defineProps<{
|
const props = defineProps<{
|
||||||
categories?: Category[] | undefined;
|
categories?: Category[] | undefined;
|
||||||
submitButton?: boolean;
|
submitButton?: boolean;
|
||||||
}>();
|
}>();
|
||||||
@ -17,10 +17,32 @@ const filterInput = useTemplateRef<HTMLInputElement>('filterInput');
|
|||||||
|
|
||||||
const { $translator: translator } = useNuxtApp();
|
const { $translator: translator } = useNuxtApp();
|
||||||
const allCategory: Category = { key: '', text: translator.translate('crud.all'), icon: 'clipboard-list' };
|
const allCategory: Category = { key: '', text: translator.translate('crud.all'), icon: 'clipboard-list' };
|
||||||
|
const categoriesWithAllCategory = computed(() => [allCategory, ...(props.categories ?? [])]);
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
focus: () => filterInput.value?.focus(),
|
focus: () => filterInput.value?.focus(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const categoryList = useTemplateRef('categoryList');
|
||||||
|
const categoryButtonKeydown = (event: KeyboardEvent) => {
|
||||||
|
if (filterCategory.value === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const activeIndex = categoriesWithAllCategory.value.map((category) => category.key).indexOf(filterCategory.value);
|
||||||
|
if (activeIndex === -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((event.key === 'ArrowUp' || event.key === 'ArrowLeft') &&
|
||||||
|
activeIndex > 0) {
|
||||||
|
filterCategory.value = categoriesWithAllCategory.value[activeIndex - 1].key;
|
||||||
|
(categoryList.value?.children[activeIndex - 1] as HTMLButtonElement | undefined)?.focus();
|
||||||
|
} else if ((event.key === 'ArrowDown' || event.key === 'ArrowRight') &&
|
||||||
|
activeIndex < categoriesWithAllCategory.value.length - 1) {
|
||||||
|
filterCategory.value = categoriesWithAllCategory.value[activeIndex + 1].key;
|
||||||
|
(categoryList.value?.children[activeIndex + 1] as HTMLButtonElement | undefined)?.focus();
|
||||||
|
}
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -36,7 +58,12 @@ defineExpose({
|
|||||||
class="form-control border-primary"
|
class="form-control border-primary"
|
||||||
:placeholder="$t('crud.filterLong')"
|
:placeholder="$t('crud.filterLong')"
|
||||||
>
|
>
|
||||||
<button v-if="filter" class="btn btn-outline-danger" @click="filter = ''; filterInput?.focus()">
|
<button
|
||||||
|
v-if="filter"
|
||||||
|
class="btn btn-outline-danger"
|
||||||
|
:title="$t('crud.resetFilter')"
|
||||||
|
@click="filter = ''; filterInput?.focus()"
|
||||||
|
>
|
||||||
<Icon v="times" />
|
<Icon v="times" />
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@ -50,17 +77,20 @@ defineExpose({
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="categories && categories.length > 0"
|
v-if="categories && categories.length > 0"
|
||||||
|
ref="categoryList"
|
||||||
class="d-flex flex-wrap mt-1 border border-primary rounded overflow-hidden"
|
class="d-flex flex-wrap mt-1 border border-primary rounded overflow-hidden"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
v-for="category of [allCategory, ...categories]"
|
v-for="category of categoriesWithAllCategory"
|
||||||
:key="category.text"
|
:key="category.text"
|
||||||
:class="[
|
:class="[
|
||||||
'btn btn-sm btn-wrapped',
|
'btn btn-sm btn-wrapped',
|
||||||
filterCategory === category.key ? 'btn-primary' : 'btn-outline-primary',
|
filterCategory === category.key ? 'btn-primary' : 'btn-outline-primary',
|
||||||
'flex-grow-1 d-flex justify-content-center align-items-center gap-1 rounded-0',
|
'flex-grow-1 d-flex justify-content-center align-items-center gap-1 rounded-0',
|
||||||
]"
|
]"
|
||||||
|
:tabindex="filterCategory === category.key ? 0 : -1"
|
||||||
@click="filterCategory = category.key"
|
@click="filterCategory = category.key"
|
||||||
|
@keydown="categoryButtonKeydown"
|
||||||
>
|
>
|
||||||
<Icon v-if="category.icon" :v="category.icon" />
|
<Icon v-if="category.icon" :v="category.icon" />
|
||||||
<Spelling :text="category.text" />
|
<Spelling :text="category.text" />
|
||||||
|
@ -1,12 +1,8 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { loadGrammarTableVariantsConverter } from '~/src/data.ts';
|
import { loadGrammarTableVariantsConverter } from '~/src/data.ts';
|
||||||
import type { Example, ExampleValues } from '~/src/language/examples.ts';
|
import type { Example, ExampleValues } from '~/src/language/examples.ts';
|
||||||
import {
|
import { expandVariantsForSection } from '~/src/language/grammarTables.ts';
|
||||||
type GrammarTableDefinition,
|
import type { GrammarTableDefinition, Variant, SectionDefinition } from '~/src/language/grammarTables.ts';
|
||||||
type Variant,
|
|
||||||
type SectionDefinition,
|
|
||||||
expandVariantsForSection,
|
|
||||||
} from '~/src/language/grammarTables.ts';
|
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
grammarTable: GrammarTableDefinition;
|
grammarTable: GrammarTableDefinition;
|
||||||
|
@ -286,6 +286,7 @@ const dismissCensus = (): void => {
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="config.header" class="mb-lg-4">
|
<div v-if="config.header" class="mb-lg-4">
|
||||||
<header @mouseleave="hoverItem = null">
|
<header @mouseleave="hoverItem = null">
|
||||||
|
<SkipLink />
|
||||||
<div class="d-none d-lg-flex justify-content-between align-items-center flex-row nav-custom btn-group mb-0">
|
<div class="d-none d-lg-flex justify-content-between align-items-center flex-row nav-custom btn-group mb-0">
|
||||||
<template v-for="link in links">
|
<template v-for="link in links">
|
||||||
<PotentiallyExternalLink
|
<PotentiallyExternalLink
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
:class="['icon', $attrs.class]"
|
:class="['icon', $attrs.class]"
|
||||||
@error="fallBack"
|
@error="fallBack"
|
||||||
>
|
>
|
||||||
<span v-else :class="[`fa${iconSet}`, `fa-${icon}`, 'fa-fw', hover ? 'fa-hover' : '']" :style="style"></span>
|
<span v-else aria-hidden="true" :class="[`fa${iconSet}`, `fa-${icon}`, 'fa-fw', hover ? 'fa-hover' : '']" :style></span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import opinions, { type Opinion } from '~/src/opinions.ts';
|
import opinions from '~/src/opinions.ts';
|
||||||
|
import type { Opinion } from '~/src/opinions.ts';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
word: string;
|
word: string;
|
||||||
|
@ -11,7 +11,7 @@ defineProps<{
|
|||||||
<AdPlaceholder :phkey="['aside-left', null]" class="d-none d-xxl-block" />
|
<AdPlaceholder :phkey="['aside-left', null]" class="d-none d-xxl-block" />
|
||||||
</slot>
|
</slot>
|
||||||
</aside>
|
</aside>
|
||||||
<main :class="[wide ? 'wide' : '']">
|
<main id="main" :class="[wide ? 'wide' : '']">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</main>
|
</main>
|
||||||
<aside v-if="!wide" class="aside-right">
|
<aside v-if="!wide" class="aside-right">
|
||||||
|
@ -20,7 +20,11 @@ defineProps<{
|
|||||||
</p>
|
</p>
|
||||||
<SimplePronounList :pronouns="Array.isArray(pronouns) ? pronouns : Object.values(pronouns)" />
|
<SimplePronounList :pronouns="Array.isArray(pronouns) ? pronouns : Object.values(pronouns)" />
|
||||||
</li>
|
</li>
|
||||||
<nuxt-link :to="{ name: 'pronouns' }" class="list-group-item list-group-item-action text-center">
|
<nuxt-link
|
||||||
|
:to="{ name: 'pronouns' }"
|
||||||
|
class="list-group-item list-group-item-action text-center"
|
||||||
|
:title="$t('home.pronouns')"
|
||||||
|
>
|
||||||
<Icon v="ellipsis-h-alt" />
|
<Icon v="ellipsis-h-alt" />
|
||||||
</nuxt-link>
|
</nuxt-link>
|
||||||
</ul>
|
</ul>
|
||||||
|
20
components/SkipLink.vue
Normal file
20
components/SkipLink.vue
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
router.afterEach(async (to, from) => {
|
||||||
|
if (to.path !== from.path) {
|
||||||
|
await nextTick();
|
||||||
|
// reset the focus to the start of the document
|
||||||
|
// so that the skip link is the first element in tab order after navigation
|
||||||
|
document.body.tabIndex = 0;
|
||||||
|
document.body.focus();
|
||||||
|
document.body.tabIndex = -1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<a ref="link" href="#main" class="sr-only sr-only-focusable position-fixed top-0 z-1">
|
||||||
|
<T>home.skipToContent</T>
|
||||||
|
</a>
|
||||||
|
</template>
|
@ -55,7 +55,7 @@ defineExpose({
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<section ref="section" class="table-responsive scroll-mt-7">
|
<section ref="section" class="table-responsive scroll-mt-7">
|
||||||
<div class="container">
|
<div class="container" role="table">
|
||||||
<nav v-if="pages > 1" class="d-flex justify-content-center p-2">
|
<nav v-if="pages > 1" class="d-flex justify-content-center p-2">
|
||||||
<ul class="pagination pagination-sm justify-content-center mb-0">
|
<ul class="pagination pagination-sm justify-content-center mb-0">
|
||||||
<li
|
<li
|
||||||
@ -78,7 +78,7 @@ defineExpose({
|
|||||||
<strong>{{ data.length }}</strong>
|
<strong>{{ data.length }}</strong>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row-header p-2 d-grid gap-2 border-top">
|
<div class="row-header p-2 d-grid gap-2 border-top" role="row">
|
||||||
<slot name="header"></slot>
|
<slot name="header"></slot>
|
||||||
</div>
|
</div>
|
||||||
<template v-if="data.length">
|
<template v-if="data.length">
|
||||||
@ -86,6 +86,7 @@ defineExpose({
|
|||||||
v-for="el in dataPage"
|
v-for="el in dataPage"
|
||||||
:key="el.id"
|
:key="el.id"
|
||||||
:class="['row-content p-2 d-grid gap-2 border-top', marked?.(el) ? 'marked' : '']"
|
:class="['row-content p-2 d-grid gap-2 border-top', marked?.(el) ? 'marked' : '']"
|
||||||
|
role="row"
|
||||||
>
|
>
|
||||||
<slot name="row" :el="el"></slot>
|
<slot name="row" :el="el"></slot>
|
||||||
</div>
|
</div>
|
||||||
|
@ -72,6 +72,7 @@ const setSpelling = (spelling: string) => {
|
|||||||
class="d-inline-block"
|
class="d-inline-block"
|
||||||
:end="end"
|
:end="end"
|
||||||
menu-class="locale-dropdown shadow"
|
menu-class="locale-dropdown shadow"
|
||||||
|
:title="$t('links.languageVersions')"
|
||||||
>
|
>
|
||||||
<template #toggle>
|
<template #toggle>
|
||||||
<Icon v="language" />
|
<Icon v="language" />
|
||||||
|
@ -119,7 +119,11 @@ const nounConventionGroup = computed(() => {
|
|||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<NounsConventionsIndexGroup :noun-convention-group />
|
<NounsConventionsIndexGroup :noun-convention-group />
|
||||||
</li>
|
</li>
|
||||||
<nuxt-link :to="{ name: 'nouns' }" class="list-group-item list-group-item-action text-center">
|
<nuxt-link
|
||||||
|
:to="{ name: 'nouns' }"
|
||||||
|
class="list-group-item list-group-item-action text-center"
|
||||||
|
:title="$t('nouns.conventions.header')"
|
||||||
|
>
|
||||||
<Icon v="ellipsis-h-alt" />
|
<Icon v="ellipsis-h-alt" />
|
||||||
</nuxt-link>
|
</nuxt-link>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -127,7 +127,12 @@ defineExpose({ loadNouns });
|
|||||||
fixed
|
fixed
|
||||||
>
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
<div v-for="gender in availableGenders(config)" :key="gender" class="d-none d-md-block bold">
|
<div
|
||||||
|
v-for="gender in availableGenders(config)"
|
||||||
|
:key="gender"
|
||||||
|
class="d-none d-md-block bold"
|
||||||
|
role="columnheader"
|
||||||
|
>
|
||||||
<NounsGenderLabel :gender="gender" />
|
<NounsGenderLabel :gender="gender" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { type Gender, iconNamesByGender, longIdentifierByGender } from '~/src/nouns.ts';
|
import { iconNamesByGender, longIdentifierByGender } from '~/src/nouns.ts';
|
||||||
|
import type { Gender } from '~/src/nouns.ts';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
gender: Gender;
|
gender: Gender;
|
||||||
|
@ -32,6 +32,7 @@ const numerus = computed(() => {
|
|||||||
v-for="plural in numerus"
|
v-for="plural in numerus"
|
||||||
:key="plural ? 'plural' : 'singular'"
|
:key="plural ? 'plural' : 'singular'"
|
||||||
:style="{ gridArea: `${gender}${plural ? 'Pl' : ''}` }"
|
:style="{ gridArea: `${gender}${plural ? 'Pl' : ''}` }"
|
||||||
|
role="cell"
|
||||||
>
|
>
|
||||||
<NounsItem :noun="noun" :gender="gender" :plural="plural" />
|
<NounsItem :noun="noun" :gender="gender" :plural="plural" />
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ export default () => {
|
|||||||
const filter: Ref<Filter> = ref({ text: '', category: '', moderation: undefined });
|
const filter: Ref<Filter> = ref({ text: '', category: '', moderation: undefined });
|
||||||
|
|
||||||
onBeforeRouteUpdate((to) => {
|
onBeforeRouteUpdate((to) => {
|
||||||
if (to.hash) {
|
if (to.hash && !document.querySelector(to.hash)) {
|
||||||
return { query: { filter: to.hash.substring(1).replace(/=$/, '') }, replace: true };
|
return { query: { filter: to.hash.substring(1).replace(/=$/, '') }, replace: true };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -141,9 +141,10 @@ export default withNuxt(
|
|||||||
})
|
})
|
||||||
.override('nuxt/import/rules', {
|
.override('nuxt/import/rules', {
|
||||||
rules: {
|
rules: {
|
||||||
|
'import/consistent-type-specifier-style': ['warn', 'prefer-top-level'],
|
||||||
'import/extensions': ['error', 'ignorePackages'],
|
'import/extensions': ['error', 'ignorePackages'],
|
||||||
'import/no-useless-path-segments': 'error',
|
'import/no-useless-path-segments': 'warn',
|
||||||
'import/order': ['error', {
|
'import/order': ['warn', {
|
||||||
'newlines-between': 'always',
|
'newlines-between': 'always',
|
||||||
'alphabetize': { order: 'asc', orderImportKind: 'desc' },
|
'alphabetize': { order: 'asc', orderImportKind: 'desc' },
|
||||||
}],
|
}],
|
||||||
|
@ -7,6 +7,7 @@ home:
|
|||||||
header: 'Pronouns'
|
header: 'Pronouns'
|
||||||
headerLong: 'List of pronouns'
|
headerLong: 'List of pronouns'
|
||||||
welcome: 'Welcome to pronouns.page!'
|
welcome: 'Welcome to pronouns.page!'
|
||||||
|
skipToContent: 'Skip to content'
|
||||||
intro: >
|
intro: >
|
||||||
We're creating a source of information about nonbinary and gender neutral language.
|
We're creating a source of information about nonbinary and gender neutral language.
|
||||||
why: 'What''s the deal with pronouns?'
|
why: 'What''s the deal with pronouns?'
|
||||||
@ -213,6 +214,7 @@ nouns:
|
|||||||
apply: 'Apply template'
|
apply: 'Apply template'
|
||||||
overwrite: 'Are you sure you want to apply this template? This will replace previous inputs'
|
overwrite: 'Are you sure you want to apply this template? This will replace previous inputs'
|
||||||
conventions:
|
conventions:
|
||||||
|
header: 'Noun conventions'
|
||||||
intro: 'Use for me'
|
intro: 'Use for me'
|
||||||
masculine: 'masculine'
|
masculine: 'masculine'
|
||||||
masculineShort: 'masc.'
|
masculineShort: 'masc.'
|
||||||
@ -958,6 +960,7 @@ crud:
|
|||||||
add: 'Add'
|
add: 'Add'
|
||||||
filter: 'Search…'
|
filter: 'Search…'
|
||||||
filterLong: 'Search…'
|
filterLong: 'Search…'
|
||||||
|
resetFilter: 'Reset filter'
|
||||||
search: 'Search…'
|
search: 'Search…'
|
||||||
all: 'All'
|
all: 'All'
|
||||||
author: 'Added by'
|
author: 'Added by'
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<Separator icon="book-alt" />
|
<Separator icon="book-alt" />
|
||||||
<h3>Substantivkonventionen</h3>
|
<h3><T>nouns.conventions.header</T></h3>
|
||||||
<NounsConventionsIndex />
|
<NounsConventionsIndex />
|
||||||
<Separator icon="book-open" />
|
<Separator icon="book-open" />
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
|
@ -7,6 +7,7 @@ home:
|
|||||||
header: 'Pronomen'
|
header: 'Pronomen'
|
||||||
headerLong: 'Liste von Pronomen'
|
headerLong: 'Liste von Pronomen'
|
||||||
welcome: 'Willkommen zu Pronomen.net!'
|
welcome: 'Willkommen zu Pronomen.net!'
|
||||||
|
skipToContent: 'zum Inhalt springen'
|
||||||
intro: >
|
intro: >
|
||||||
Wir sind eine Informationsquelle über nichtbinäre und geschlechtsneutrale Sprache.
|
Wir sind eine Informationsquelle über nichtbinäre und geschlechtsneutrale Sprache.
|
||||||
why: 'Warum sind Pronomen wichtig?'
|
why: 'Warum sind Pronomen wichtig?'
|
||||||
@ -233,6 +234,7 @@ nouns:
|
|||||||
apply: 'Vorlage anwenden'
|
apply: 'Vorlage anwenden'
|
||||||
overwrite: 'Bist du sicher, dass du diese Vorlage anwenden möchtest? Sie ersetzt die vorherigen Eingaben'
|
overwrite: 'Bist du sicher, dass du diese Vorlage anwenden möchtest? Sie ersetzt die vorherigen Eingaben'
|
||||||
conventions:
|
conventions:
|
||||||
|
header: 'Substantivkonventionen'
|
||||||
intro: 'Verwende für mich'
|
intro: 'Verwende für mich'
|
||||||
masculine: 'Maskulin'
|
masculine: 'Maskulin'
|
||||||
masculineShort: 'Mask.'
|
masculineShort: 'Mask.'
|
||||||
@ -1076,6 +1078,7 @@ crud:
|
|||||||
add: 'Hinzufügen'
|
add: 'Hinzufügen'
|
||||||
filter: 'Filter'
|
filter: 'Filter'
|
||||||
filterLong: 'Liste filtern...'
|
filterLong: 'Liste filtern...'
|
||||||
|
resetFilter: 'Filter zurücksetzen'
|
||||||
search: 'Suchen…'
|
search: 'Suchen…'
|
||||||
all: 'Alle'
|
all: 'Alle'
|
||||||
author: 'Hinzugefügt von'
|
author: 'Hinzugefügt von'
|
||||||
|
@ -7,6 +7,7 @@ home:
|
|||||||
header: 'Pronouns'
|
header: 'Pronouns'
|
||||||
headerLong: 'List of pronouns'
|
headerLong: 'List of pronouns'
|
||||||
welcome: 'Welcome to pronouns.page!'
|
welcome: 'Welcome to pronouns.page!'
|
||||||
|
skipToContent: 'Skip to content'
|
||||||
intro: >
|
intro: >
|
||||||
We're creating a source of information about nonbinary and gender neutral language.
|
We're creating a source of information about nonbinary and gender neutral language.
|
||||||
why: 'What''s the deal with pronouns?'
|
why: 'What''s the deal with pronouns?'
|
||||||
@ -1174,6 +1175,7 @@ crud:
|
|||||||
add: 'Add'
|
add: 'Add'
|
||||||
filter: 'Search…'
|
filter: 'Search…'
|
||||||
filterLong: 'Search…'
|
filterLong: 'Search…'
|
||||||
|
resetFilter: 'Reset filter'
|
||||||
search: 'Search…'
|
search: 'Search…'
|
||||||
all: 'All'
|
all: 'All'
|
||||||
author: 'Added by'
|
author: 'Added by'
|
||||||
|
@ -4,7 +4,8 @@ import { useNuxtApp } from 'nuxt/app';
|
|||||||
import NounsNav from './NounsNav.vue';
|
import NounsNav from './NounsNav.vue';
|
||||||
|
|
||||||
import useConfig from '~/composables/useConfig.ts';
|
import useConfig from '~/composables/useConfig.ts';
|
||||||
import { Noun, type Source, SourceLibrary } from '~/src/classes.ts';
|
import { Noun, SourceLibrary } from '~/src/classes.ts';
|
||||||
|
import type { Source } from '~/src/classes.ts';
|
||||||
|
|
||||||
const { $translator: translator } = useNuxtApp();
|
const { $translator: translator } = useNuxtApp();
|
||||||
useSimpleHead({
|
useSimpleHead({
|
||||||
|
@ -2,8 +2,10 @@
|
|||||||
import { useDebounce, useLocalStorage } from '@vueuse/core';
|
import { useDebounce, useLocalStorage } from '@vueuse/core';
|
||||||
import marked from 'marked';
|
import marked from 'marked';
|
||||||
|
|
||||||
import { extractMetadata, type Post } from '~/src/blog/metadata.ts';
|
import { extractMetadata } from '~/src/blog/metadata.ts';
|
||||||
import parseMarkdown, { type MarkdownInfo } from '~/src/parseMarkdown.ts';
|
import type { Post } from '~/src/blog/metadata.ts';
|
||||||
|
import parseMarkdown from '~/src/parseMarkdown.ts';
|
||||||
|
import type { MarkdownInfo } from '~/src/parseMarkdown.ts';
|
||||||
|
|
||||||
const content = useLocalStorage(
|
const content = useLocalStorage(
|
||||||
'admin/blog/editor',
|
'admin/blog/editor',
|
||||||
|
@ -12,8 +12,8 @@ import {
|
|||||||
MONTHS as months,
|
MONTHS as months,
|
||||||
AREAS as areas,
|
AREAS as areas,
|
||||||
TRANSFER_METHODS as transferMethods,
|
TRANSFER_METHODS as transferMethods,
|
||||||
type TimesheetData, type Timesheet,
|
|
||||||
} from '~/src/timesheets.ts';
|
} from '~/src/timesheets.ts';
|
||||||
|
import type { TimesheetData, Timesheet } from '~/src/timesheets.ts';
|
||||||
|
|
||||||
const { $translator: translator } = useNuxtApp();
|
const { $translator: translator } = useNuxtApp();
|
||||||
const dialogue = useDialogue();
|
const dialogue = useDialogue();
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { DateTime, type DurationInput } from 'luxon';
|
import { DateTime } from 'luxon';
|
||||||
|
import type { DurationInput } from 'luxon';
|
||||||
import { useNuxtApp } from 'nuxt/app';
|
import { useNuxtApp } from 'nuxt/app';
|
||||||
|
|
||||||
import useSimpleHead from '~/composables/useSimpleHead.ts';
|
import useSimpleHead from '~/composables/useSimpleHead.ts';
|
||||||
import { min, max, MONTHS, PERIODS, type TimesheetData } from '~/src/timesheets.ts';
|
import { min, max, MONTHS, PERIODS } from '~/src/timesheets.ts';
|
||||||
|
import type { TimesheetData } from '~/src/timesheets.ts';
|
||||||
|
|
||||||
function* range(start: number, end: number) {
|
function* range(start: number, end: number) {
|
||||||
for (let i = start; i <= end; i++) {
|
for (let i = start; i <= end; i++) {
|
||||||
|
@ -12,7 +12,8 @@ import { getUrlForLocale } from '~/src/domain.ts';
|
|||||||
import { buildFlags } from '~/src/flags.ts';
|
import { buildFlags } from '~/src/flags.ts';
|
||||||
import { sleep } from '~/src/helpers.ts';
|
import { sleep } from '~/src/helpers.ts';
|
||||||
import opinions from '~/src/opinions.ts';
|
import opinions from '~/src/opinions.ts';
|
||||||
import { applyProfileVisibilityRules, type UserWithProfiles, type Profile } from '~/src/profile.ts';
|
import { applyProfileVisibilityRules } from '~/src/profile.ts';
|
||||||
|
import type { UserWithProfiles, Profile } from '~/src/profile.ts';
|
||||||
|
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
translatedPaths: (config) => {
|
translatedPaths: (config) => {
|
||||||
|
@ -22,7 +22,8 @@ import forbidden from '~/src/forbidden.ts';
|
|||||||
import { clearLinkedText, buildImageUrl } from '~/src/helpers.ts';
|
import { clearLinkedText, buildImageUrl } from '~/src/helpers.ts';
|
||||||
import { genders, gendersWithNumerus } from '~/src/nouns.ts';
|
import { genders, gendersWithNumerus } from '~/src/nouns.ts';
|
||||||
import parseMarkdown from '~/src/parseMarkdown.ts';
|
import parseMarkdown from '~/src/parseMarkdown.ts';
|
||||||
import { normaliseQuery, type SearchDocument, validateQuery } from '~/src/search.ts';
|
import { normaliseQuery, validateQuery } from '~/src/search.ts';
|
||||||
|
import type { SearchDocument } from '~/src/search.ts';
|
||||||
|
|
||||||
interface SearchKind {
|
interface SearchKind {
|
||||||
kind: SearchDocument['kind'];
|
kind: SearchDocument['kind'];
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { type Config, type ConfigWithEnabled, isEnabled } from '../locale/config.ts';
|
import { isEnabled } from '../locale/config.ts';
|
||||||
|
import type { Config, ConfigWithEnabled } from '../locale/config.ts';
|
||||||
import type { PronounData, PronounGroupData } from '../locale/data.ts';
|
import type { PronounData, PronounGroupData } from '../locale/data.ts';
|
||||||
|
|
||||||
import { Pronoun, PronounGroup } from './classes.ts';
|
import { Pronoun, PronounGroup } from './classes.ts';
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import type { ExampleValues } from '~/src/language/examples.ts';
|
import type { ExampleValues } from '~/src/language/examples.ts';
|
||||||
import { type MorphemeValue, toMorphemeValue } from '~/src/language/morphemes.ts';
|
import { toMorphemeValue } from '~/src/language/morphemes.ts';
|
||||||
|
import type { MorphemeValue } from '~/src/language/morphemes.ts';
|
||||||
|
|
||||||
export type GrammarTablesDefinition = (GrammarTableDefinition | string)[]
|
export type GrammarTablesDefinition = (GrammarTableDefinition | string)[]
|
||||||
| { simple: (GrammarTableDefinition | string)[]; comprehensive: (GrammarTableDefinition | string)[] };
|
| { simple: (GrammarTableDefinition | string)[]; comprehensive: (GrammarTableDefinition | string)[] };
|
||||||
|
@ -8,7 +8,8 @@ import { loadSuml, loadTsv } from '~/server/loader.ts';
|
|||||||
import { normaliseKey } from '~/src/buildPronoun.ts';
|
import { normaliseKey } from '~/src/buildPronoun.ts';
|
||||||
import { Example } from '~/src/language/examples.ts';
|
import { Example } from '~/src/language/examples.ts';
|
||||||
import type { VariantsFromBaseConverter } from '~/src/language/grammarTables.ts';
|
import type { VariantsFromBaseConverter } from '~/src/language/grammarTables.ts';
|
||||||
import { availableGenders, gendersWithNumerus, type NounConventions } from '~/src/nouns.ts';
|
import { availableGenders, gendersWithNumerus } from '~/src/nouns.ts';
|
||||||
|
import type { NounConventions } from '~/src/nouns.ts';
|
||||||
|
|
||||||
function toHaveValidMorphemes(actual: string, morphemes: string[]): SyncExpectationResult {
|
function toHaveValidMorphemes(actual: string, morphemes: string[]): SyncExpectationResult {
|
||||||
const containedMorphemes = Example.parse(actual).parts
|
const containedMorphemes = Example.parse(actual).parts
|
||||||
|
@ -5,7 +5,8 @@ import { promisify } from 'util';
|
|||||||
|
|
||||||
import { chromium } from '@playwright/test';
|
import { chromium } from '@playwright/test';
|
||||||
import type { Browser, Page } from '@playwright/test';
|
import type { Browser, Page } from '@playwright/test';
|
||||||
import { execa, type ResultPromise } from 'execa';
|
import { execa } from 'execa';
|
||||||
|
import type { ResultPromise } from 'execa';
|
||||||
import tkKill from 'tree-kill';
|
import tkKill from 'tree-kill';
|
||||||
import { describe, it, beforeAll, afterAll, expect } from 'vitest';
|
import { describe, it, beforeAll, afterAll, expect } from 'vitest';
|
||||||
import { createRouter, createMemoryHistory } from 'vue-router';
|
import { createRouter, createMemoryHistory } from 'vue-router';
|
||||||
|
Loading…
x
Reference in New Issue
Block a user