Compare commits
22 commits
Author | SHA1 | Date | |
---|---|---|---|
|
2830fd9350 | ||
|
986126a2bb | ||
|
3d13c256e3 | ||
|
f67ba1e655 | ||
|
1553825719 | ||
|
f1961f5cef | ||
|
a67cddc74b | ||
|
68a43b6b9c | ||
|
f2b408fce5 | ||
|
35f5343149 | ||
|
b5eae39f89 | ||
|
39993112b7 | ||
|
d4dc47b1e1 | ||
|
25ee71b615 | ||
|
23a24c5842 | ||
|
29f549ddd9 | ||
|
223a32580c | ||
|
3723e4b036 | ||
|
b57c5a9be8 | ||
|
bb724f581b | ||
|
44d974a870 | ||
|
3c83d66bf5 |
37 changed files with 1963 additions and 4553 deletions
|
@ -1,15 +1,15 @@
|
|||
/* eslint-env node */
|
||||
require("@rushstack/eslint-patch/modern-module-resolution");
|
||||
require('@rushstack/eslint-patch/modern-module-resolution')
|
||||
|
||||
module.exports = {
|
||||
root: true,
|
||||
extends: [
|
||||
"plugin:vue/vue3-essential",
|
||||
"eslint:recommended",
|
||||
"@vue/eslint-config-typescript",
|
||||
"@vue/eslint-config-prettier",
|
||||
'extends': [
|
||||
'plugin:vue/vue3-essential',
|
||||
'eslint:recommended',
|
||||
'@vue/eslint-config-typescript',
|
||||
'@vue/eslint-config-prettier/skip-formatting'
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaVersion: "latest",
|
||||
},
|
||||
};
|
||||
ecmaVersion: 'latest'
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1,8 @@
|
|||
{}
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/prettierrc",
|
||||
"semi": false,
|
||||
"tabWidth": 2,
|
||||
"singleQuote": true,
|
||||
"printWidth": 100,
|
||||
"trailingComma": "none"
|
||||
}
|
||||
|
|
16
index.html
16
index.html
|
@ -2,8 +2,8 @@
|
|||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="favicon" href="favicon.png" type="image/png" />
|
||||
<link rel="icon" href="favicon.png" type="image/png" />
|
||||
<link rel="favicon" href="/favicon.png" type="image/png" />
|
||||
<link rel="icon" href="/favicon.png" type="image/png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
|
||||
<title>Viktor Kraastav – Reference Page</title>
|
||||
|
||||
|
@ -17,11 +17,13 @@
|
|||
<meta name="twitter:description" content="The official reference page for Viktor Kraastav with picture references and in-depth character descriptions" />
|
||||
<meta name="twitter:image" content="https://ref.sebin-nyshkim.net/viktor/preview.png" />
|
||||
|
||||
<meta name="og:type" content="website" />
|
||||
<meta name="og:title" content="Viktor Kraastav - Reference Page" />
|
||||
<meta name="og:url" content="https://ref.sebin-nyshkim.net/viktor/" />
|
||||
<meta name="og:image" content="https://ref.sebin-nyshkim.net/viktor/preview.png" />
|
||||
<meta name="og:description" content="The official reference page for Viktor Kraastav with picture references and in-depth character descriptions" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:title" content="Viktor Kraastav - Reference Page" />
|
||||
<meta property="og:locale" content="en_US" />
|
||||
<meta property="og:locale:alternate" content="de_DE" />
|
||||
<meta property="og:url" content="https://ref.sebin-nyshkim.net/viktor/" />
|
||||
<meta property="og:image" content="https://ref.sebin-nyshkim.net/viktor/preview.png" />
|
||||
<meta property="og:description" content="The official reference page for Viktor Kraastav with picture references and in-depth character descriptions" />
|
||||
</head>
|
||||
<body>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
|
|
5227
package-lock.json
generated
5227
package-lock.json
generated
File diff suppressed because it is too large
Load diff
45
package.json
45
package.json
|
@ -1,37 +1,38 @@
|
|||
{
|
||||
"name": "viktor-reference",
|
||||
"version": "0.4.1",
|
||||
"version": "0.4.3",
|
||||
"scripts": {
|
||||
"dev": "vite --host",
|
||||
"build": "run-p type-check build-only",
|
||||
"preview": "vite preview --port 4173",
|
||||
"preview": "vite preview",
|
||||
"build-only": "vite build",
|
||||
"type-check": "vue-tsc --noEmit",
|
||||
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore"
|
||||
"type-check": "vue-tsc --noEmit -p tsconfig.app.json --composite false",
|
||||
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
|
||||
"format": "prettier --write src/"
|
||||
},
|
||||
"dependencies": {
|
||||
"vue": "^3.2.45",
|
||||
"vue": "^3.3.4",
|
||||
"vue-i18n": "^9.2.2",
|
||||
"vue-router": "^4.1.6"
|
||||
"vue-router": "^4.2.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rushstack/eslint-patch": "^1.2.0",
|
||||
"@types/node": "^18.15.10",
|
||||
"@types/vue-markdown": "^2.2.1",
|
||||
"@vitejs/plugin-vue": "^4.1.0",
|
||||
"@vue/eslint-config-prettier": "^7.1.0",
|
||||
"@vue/eslint-config-typescript": "^11.0.2",
|
||||
"@vue/tsconfig": "^0.1.3",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"eslint": "^8.36.0",
|
||||
"eslint-plugin-vue": "^9.10.0",
|
||||
"@rushstack/eslint-patch": "^1.3.3",
|
||||
"@tsconfig/node18": "^18.2.1",
|
||||
"@types/node": "^20.5.9",
|
||||
"@vitejs/plugin-vue": "^4.3.4",
|
||||
"@vue/eslint-config-prettier": "^8.0.0",
|
||||
"@vue/eslint-config-typescript": "^11.0.3",
|
||||
"@vue/tsconfig": "^0.4.0",
|
||||
"autoprefixer": "^10.4.15",
|
||||
"eslint": "^8.48.0",
|
||||
"eslint-plugin-vue": "^9.17.0",
|
||||
"normalize.css": "^8.0.1",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"prettier": "^2.8.7",
|
||||
"sass": "^1.60.0",
|
||||
"typescript": "^4.9.5",
|
||||
"vite": "^4.2.1",
|
||||
"vite-imagetools": "^4.0.18",
|
||||
"vue-tsc": "^1.2.0"
|
||||
"prettier": "^3.0.3",
|
||||
"sass": "^1.66.1",
|
||||
"typescript": "^5.2.2",
|
||||
"vite": "^4.4.9",
|
||||
"vite-imagetools": "^5.0.8",
|
||||
"vue-tsc": "^1.8.8"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
module.exports = {
|
||||
plugins: {
|
||||
autoprefixer: {}
|
||||
}
|
||||
}
|
67
src/App.vue
67
src/App.vue
|
@ -1,70 +1,69 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import { RouterView } from "vue-router";
|
||||
import { version } from "../package.json";
|
||||
import router from "@/router";
|
||||
import { ref } from 'vue'
|
||||
import { RouterView } from 'vue-router'
|
||||
import { version } from '../package.json'
|
||||
|
||||
import ModalDialog from "@/components/ModalDialog.vue";
|
||||
import LocaleSwitcher from "@/components/LocaleSwitcher.vue";
|
||||
import LinkButton from "@/components/LinkButton.vue";
|
||||
import SiteNavigation from "@/components/SiteNavigation.vue";
|
||||
import NavigationItem from "@/components/NavigationItem.vue";
|
||||
import LanguageButton from "@/components/LanguageButton.vue";
|
||||
import SiteFooter from "@/components/SiteFooter.vue";
|
||||
import ModalDialog from '@/components/ModalDialog.vue'
|
||||
import LocaleSwitcher from '@/components/LocaleSwitcher.vue'
|
||||
import LinkButton from '@/components/LinkButton.vue'
|
||||
import SiteNavigation from '@/components/SiteNavigation.vue'
|
||||
import NavigationItem from '@/components/NavigationItem.vue'
|
||||
import LanguageButton from '@/components/LanguageButton.vue'
|
||||
import SiteFooter from '@/components/SiteFooter.vue'
|
||||
|
||||
import LanguageIcon from "@/assets/icons/LanguageIcon.vue";
|
||||
import LanguageIcon from '@/assets/icons/LanguageIcon.vue'
|
||||
|
||||
const locales = [
|
||||
{ code: "en", name: "English", flag: "🇬🇧" },
|
||||
{ code: "de", name: "Deutsch", flag: "🇩🇪" },
|
||||
];
|
||||
{ code: 'en', name: 'English', flag: '🇬🇧' },
|
||||
{ code: 'de', name: 'Deutsch', flag: '🇩🇪' }
|
||||
]
|
||||
|
||||
const langswitcher = ref<InstanceType<typeof ModalDialog>>();
|
||||
const langswitcher = ref<InstanceType<typeof ModalDialog>>()
|
||||
|
||||
const showModal = () => {
|
||||
langswitcher.value?.showModal();
|
||||
};
|
||||
langswitcher.value?.showModal()
|
||||
}
|
||||
|
||||
const close = () => {
|
||||
langswitcher.value?.close();
|
||||
};
|
||||
langswitcher.value?.close()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ModalDialog id="lang-select" ref="langswitcher">
|
||||
<template #heading>{{ $t("langswitcher.title") }}</template>
|
||||
<template #heading>{{ $t('langswitcher.title') }}</template>
|
||||
<template #message>
|
||||
<p>{{ $t("langswitcher.prompt") }}</p>
|
||||
<LocaleSwitcher
|
||||
id="locale-switch"
|
||||
v-model="$i18n.locale"
|
||||
:locales="locales"
|
||||
/>
|
||||
<p>{{ $t('langswitcher.prompt') }}</p>
|
||||
<LocaleSwitcher id="locale-switch" v-model="$i18n.locale" :locales="locales" />
|
||||
</template>
|
||||
<template #buttons>
|
||||
<LinkButton @click.prevent="close()">
|
||||
{{ $t("langswitcher.buttonClose") }}
|
||||
{{ $t('langswitcher.buttonClose') }}
|
||||
</LinkButton>
|
||||
</template>
|
||||
</ModalDialog>
|
||||
|
||||
<SiteNavigation>
|
||||
<NavigationItem
|
||||
v-for="(route, idx) in router.options.routes"
|
||||
v-for="(route, idx) in $router.getRoutes()"
|
||||
:key="idx"
|
||||
:icon="route.meta?.icon"
|
||||
:href="route.path"
|
||||
>{{ $t(`${route.meta?.title}`) }}</NavigationItem>
|
||||
>
|
||||
{{ $t(`${route.meta?.title}`) }}
|
||||
</NavigationItem>
|
||||
</SiteNavigation>
|
||||
|
||||
<main>
|
||||
<LanguageButton>
|
||||
<LanguageIcon @click.prevent="showModal()" />
|
||||
</LanguageButton>
|
||||
<RouterView />
|
||||
<RouterView v-slot="{ Component }">
|
||||
<Transition name="fade" mode="out-in">
|
||||
<component :is="Component" :key="$route.path" />
|
||||
</Transition>
|
||||
</RouterView>
|
||||
</main>
|
||||
|
||||
<SiteFooter>
|
||||
v{{ version }} © {{ new Date().getFullYear() }} Sebin Nyshkim
|
||||
</SiteFooter>
|
||||
<SiteFooter>v{{ version }} © {{ new Date().getFullYear() }} Sebin Nyshkim</SiteFooter>
|
||||
</template>
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
<script setup lang="ts">
|
||||
import FAIcon from "@/assets/icons/FurAffinityIcon.vue";
|
||||
import TwitterIcon from "@/assets/icons/TwitterIcon.vue";
|
||||
import FAIcon from '@/assets/icons/FurAffinityIcon.vue'
|
||||
import TwitterIcon from '@/assets/icons/TwitterIcon.vue'
|
||||
|
||||
interface ArtistLink {
|
||||
furaffinity?: string;
|
||||
twitter?: string;
|
||||
furaffinity?: string
|
||||
twitter?: string
|
||||
}
|
||||
|
||||
interface Attribution {
|
||||
artwork: string;
|
||||
artist: string;
|
||||
links: ArtistLink;
|
||||
artwork: string
|
||||
artist: string
|
||||
links: ArtistLink
|
||||
}
|
||||
|
||||
interface Props {
|
||||
attributions: Attribution[];
|
||||
attributions: Attribution[]
|
||||
}
|
||||
|
||||
defineProps<Props>();
|
||||
defineProps<Props>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -25,19 +25,15 @@ defineProps<Props>();
|
|||
<thead class="attribution-table__head">
|
||||
<tr class="attribution-table__row">
|
||||
<th class="attribution-table__heading artwork">
|
||||
{{ $t("attributions.artwork.headings[0]") }}
|
||||
{{ $t('attributions.artwork.headings[0]') }}
|
||||
</th>
|
||||
<th class="attribution-table__heading artist">
|
||||
{{ $t("attributions.artwork.headings[1]") }}
|
||||
{{ $t('attributions.artwork.headings[1]') }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="attribution-table__body">
|
||||
<tr
|
||||
class="attribution-table__row"
|
||||
v-for="(attrib, idx) in attributions"
|
||||
:key="idx"
|
||||
>
|
||||
<tr class="attribution-table__row" v-for="(attrib, idx) in attributions" :key="idx">
|
||||
<td class="attribution-table__cell artwork">
|
||||
<img :src="attrib.artwork" alt="Image attribution" />
|
||||
</td>
|
||||
|
|
|
@ -1,33 +1,30 @@
|
|||
<script setup lang="ts">
|
||||
interface ColorDict {
|
||||
name: string;
|
||||
value: string;
|
||||
name: string
|
||||
value: string
|
||||
}
|
||||
|
||||
interface Props {
|
||||
colors: ColorDict[];
|
||||
colors: ColorDict[]
|
||||
}
|
||||
|
||||
defineProps<Props>();
|
||||
defineProps<Props>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<table class="color-table">
|
||||
<thead class="color-table__head">
|
||||
<tr class="color-table__row">
|
||||
<th class="color-table__heading name">{{ $t("data.colors.headings[0]") }}</th>
|
||||
<th class="color-table__heading value">{{ $t("data.colors.headings[1]") }}</th>
|
||||
<th class="color-table__heading color">{{ $t("data.colors.headings[2]") }}</th>
|
||||
<th class="color-table__heading name">{{ $t('data.colors.headings[0]') }}</th>
|
||||
<th class="color-table__heading value">{{ $t('data.colors.headings[1]') }}</th>
|
||||
<th class="color-table__heading color">{{ $t('data.colors.headings[2]') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="color-table__body">
|
||||
<tr class="color-table__row" v-for="(color, idx) in colors" :key="idx">
|
||||
<td class="color-table__cell name">{{ $t(color.name) }}</td>
|
||||
<td class="color-table__cell value">{{ color.value }}</td>
|
||||
<td
|
||||
class="color-table__cell color"
|
||||
:style="{ 'background-color': color.value }"
|
||||
></td>
|
||||
<td class="color-table__cell color" :style="{ 'background-color': color.value }"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -47,8 +44,16 @@ defineProps<Props>();
|
|||
}
|
||||
|
||||
&.value {
|
||||
font-family: Menlo, JetBrains Mono, Source Code Pro, Monaco, Ubuntu Mono,
|
||||
Roboto Mono, Cascadia Code, Consolas, monospace;
|
||||
font-family:
|
||||
Menlo,
|
||||
JetBrains Mono,
|
||||
Source Code Pro,
|
||||
Monaco,
|
||||
Ubuntu Mono,
|
||||
Roboto Mono,
|
||||
Cascadia Code,
|
||||
Consolas,
|
||||
monospace;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,21 +1,17 @@
|
|||
<script setup lang="ts">
|
||||
interface Props {
|
||||
headings: string[];
|
||||
data: string[][];
|
||||
headings: string[]
|
||||
data: string[][]
|
||||
}
|
||||
|
||||
defineProps<Props>();
|
||||
defineProps<Props>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<table class="data-table">
|
||||
<thead class="data-table__head">
|
||||
<tr class="data-table__row">
|
||||
<th
|
||||
class="data-table__heading"
|
||||
v-for="(heading, idx) in headings"
|
||||
:key="idx"
|
||||
>
|
||||
<th class="data-table__heading" v-for="(heading, idx) in headings" :key="idx">
|
||||
{{ $t(heading) }}
|
||||
</th>
|
||||
</tr>
|
||||
|
|
|
@ -7,14 +7,19 @@
|
|||
<style lang="scss">
|
||||
.lang-button {
|
||||
position: fixed;
|
||||
inset: 1rem 1rem auto auto;
|
||||
display: block;
|
||||
max-height: 2.5rem;
|
||||
min-width: 3.5rem;
|
||||
inset: 0.25rem 0.5rem auto auto;
|
||||
min-width: 3rem;
|
||||
z-index: 9001;
|
||||
color: var(--color-text);
|
||||
cursor: pointer;
|
||||
|
||||
&:before {
|
||||
position: absolute;
|
||||
inset: 0.325rem 0 0.7rem 0;
|
||||
content: '';
|
||||
background-color: var(--color-background);
|
||||
border-radius: 0.3rem;
|
||||
}
|
||||
|
||||
svg {
|
||||
fill: var(--color-text);
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<script setup lang="ts">
|
||||
interface Props {
|
||||
href?: string;
|
||||
download?: boolean | any;
|
||||
href?: string
|
||||
download?: boolean | any
|
||||
}
|
||||
|
||||
defineProps<Props>();
|
||||
defineProps<Props>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
@ -1,43 +1,46 @@
|
|||
<script setup lang="ts">
|
||||
import { computed } from "vue";
|
||||
import CircleCheckIcon from "@/assets/icons/CircleCheckIcon.vue";
|
||||
import CircleIcon from "@/assets/icons/CircleIcon.vue";
|
||||
import { computed } from 'vue'
|
||||
import CircleCheckIcon from '@/assets/icons/CircleCheckIcon.vue'
|
||||
import CircleIcon from '@/assets/icons/CircleIcon.vue'
|
||||
|
||||
interface LocaleOption {
|
||||
code: string;
|
||||
name: string;
|
||||
flag: string;
|
||||
code: string
|
||||
name: string
|
||||
flag: string
|
||||
}
|
||||
|
||||
interface Props {
|
||||
modelValue: string;
|
||||
id: string;
|
||||
locales: LocaleOption[];
|
||||
modelValue: string
|
||||
id: string
|
||||
locales: LocaleOption[]
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
const emit = defineEmits(["update:modelValue"]);
|
||||
interface Emits {
|
||||
(e: 'update:modelValue', value: string): void
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
const emit = defineEmits<Emits>()
|
||||
|
||||
const selectModel = computed({
|
||||
get() {
|
||||
return props.modelValue;
|
||||
return props.modelValue
|
||||
},
|
||||
set(value) {
|
||||
emit("update:modelValue", value);
|
||||
},
|
||||
});
|
||||
emit('update:modelValue', value)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="localeselect">
|
||||
<div v-for="locale in locales" class="localeselect__locale">
|
||||
<div v-for="locale in locales" class="localeselect__locale" :key="`locale-${locale.code}`">
|
||||
<input
|
||||
type="radio"
|
||||
name="lang"
|
||||
class="localeselect__input"
|
||||
:id="`lang-${locale.code}`"
|
||||
:value="locale.code"
|
||||
:key="`locale-${locale.code}`"
|
||||
v-model="selectModel"
|
||||
/>
|
||||
<label class="localeselect__label" :for="`lang-${locale.code}`">
|
||||
|
|
|
@ -1,27 +1,27 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import { ref } from 'vue'
|
||||
|
||||
interface Props {
|
||||
id: string;
|
||||
id: string
|
||||
}
|
||||
|
||||
defineProps<Props>();
|
||||
defineProps<Props>()
|
||||
|
||||
const modal = ref<HTMLDialogElement>();
|
||||
const modal = ref<HTMLDialogElement>()
|
||||
|
||||
const showModal = () => {
|
||||
modal.value?.showModal();
|
||||
document.body.inert = true;
|
||||
document.body.classList.add("scroll-lock");
|
||||
};
|
||||
modal.value?.showModal()
|
||||
document.body.inert = true
|
||||
document.body.classList.add('scroll-lock')
|
||||
}
|
||||
|
||||
const close = () => {
|
||||
modal.value?.close();
|
||||
document.body.inert = false;
|
||||
document.body.classList.remove("scroll-lock");
|
||||
};
|
||||
modal.value?.close()
|
||||
document.body.inert = false
|
||||
document.body.classList.remove('scroll-lock')
|
||||
}
|
||||
|
||||
defineExpose({ showModal, close });
|
||||
defineExpose({ showModal, close })
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
<script setup lang="ts">
|
||||
import { RouterLink } from "vue-router";
|
||||
import { RouterLink } from 'vue-router'
|
||||
|
||||
interface Props {
|
||||
icon: unknown | object;
|
||||
href: string;
|
||||
icon: unknown | object
|
||||
href: string
|
||||
}
|
||||
|
||||
defineProps<Props>();
|
||||
defineProps<Props>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<RouterLink class="navigation__link" :to="href">
|
||||
<component class="navigation__link-icon" :is="icon"></component>
|
||||
<component class="navigation__link-icon" :is="icon" />
|
||||
<span class="navigation__link-text">
|
||||
<slot></slot>
|
||||
</span>
|
||||
|
|
|
@ -1,17 +1,14 @@
|
|||
<script setup lang="ts">
|
||||
interface Props {
|
||||
dropshadow?: boolean;
|
||||
dropshadow?: boolean
|
||||
}
|
||||
|
||||
defineProps<Props>();
|
||||
defineProps<Props>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<figure class="figure">
|
||||
<picture
|
||||
class="figure__image"
|
||||
:class="{ 'figure__image--dropshadow': dropshadow }"
|
||||
>
|
||||
<picture class="figure__image" :class="{ 'figure__image--dropshadow': dropshadow }">
|
||||
<slot></slot>
|
||||
</picture>
|
||||
|
||||
|
|
|
@ -1,8 +1,3 @@
|
|||
<script setup lang="ts">
|
||||
import router from "@/router";
|
||||
import { RouterLink } from "vue-router";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<nav class="navigation">
|
||||
<div class="navigation__list">
|
||||
|
|
|
@ -26,12 +26,11 @@
|
|||
position: relative;
|
||||
|
||||
&:not(:last-child):before {
|
||||
content: "";
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: var(--timeline-stroke-position-odd);
|
||||
height: var(--timeline-stroke-length);
|
||||
border-left: var(--timeline-stroke-thickness) solid
|
||||
var(--timeline-stroke-color);
|
||||
border-left: var(--timeline-stroke-thickness) solid var(--timeline-stroke-color);
|
||||
}
|
||||
|
||||
&:nth-child(odd) {
|
||||
|
@ -58,8 +57,7 @@
|
|||
background-color: var(--timeline-circle-background);
|
||||
|
||||
margin: 0;
|
||||
border: var(--timeline-stroke-thickness) solid
|
||||
var(--timeline-stroke-color);
|
||||
border: var(--timeline-stroke-thickness) solid var(--timeline-stroke-color);
|
||||
border-radius: 100%;
|
||||
padding: var(--timeline-circle-padding);
|
||||
|
||||
|
|
|
@ -10,8 +10,7 @@
|
|||
position: relative;
|
||||
|
||||
margin: 0 auto;
|
||||
padding: 0 var(--container-spacing-right-safe) 0
|
||||
var(--container-spacing-left-safe);
|
||||
padding: 0 var(--container-spacing-right-safe) 0 var(--container-spacing-left-safe);
|
||||
|
||||
list-style: none;
|
||||
|
||||
|
|
|
@ -2,13 +2,9 @@
|
|||
<header class="welcome">
|
||||
<div class="welcome__image">
|
||||
<picture>
|
||||
<source
|
||||
srcset="@/assets/viktor-avatar.png?w=400;800&avif&quality=75&srcset"
|
||||
/>
|
||||
<source
|
||||
srcset="@/assets/viktor-avatar.png?w=400;800&webp&quality=100&srcset"
|
||||
/>
|
||||
<img src="@/assets/viktor-avatar.png?w=400&png" alt="Viktor Avatar" />
|
||||
<source srcset="@/assets/viktor-avatar.png?w=400;800&format=avif&quality=75&as=srcset" />
|
||||
<source srcset="@/assets/viktor-avatar.png?w=400;800&format=webp&quality=100&as=srcset" />
|
||||
<img src="@/assets/viktor-avatar.png?w=400&format=png" alt="Viktor Avatar" />
|
||||
</picture>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import en from "./translations/en.json";
|
||||
import de from "./translations/de.json";
|
||||
import en from './translations/en.json'
|
||||
import de from './translations/de.json'
|
||||
|
||||
export default {
|
||||
en,
|
||||
de,
|
||||
};
|
||||
de
|
||||
}
|
||||
|
|
35
src/main.ts
35
src/main.ts
|
@ -1,21 +1,24 @@
|
|||
import { createApp } from "vue";
|
||||
import App from "./App.vue";
|
||||
import router from "./router";
|
||||
import { createI18n } from "vue-i18n";
|
||||
import messages from "./lang";
|
||||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import router from './router'
|
||||
import { createI18n } from 'vue-i18n'
|
||||
import messages from './lang'
|
||||
|
||||
import "normalize.css";
|
||||
import "@/scss/main.scss";
|
||||
import 'normalize.css'
|
||||
import '@/scss/main.scss'
|
||||
|
||||
const i18n = createI18n({
|
||||
locale: "en",
|
||||
fallbackLocale: "en",
|
||||
messages,
|
||||
});
|
||||
type MessageSchema = typeof messages.en
|
||||
|
||||
const app = createApp(App);
|
||||
const i18n = createI18n<[MessageSchema], 'en' | 'de'>({
|
||||
legacy: false,
|
||||
locale: 'en',
|
||||
fallbackLocale: 'en',
|
||||
messages
|
||||
})
|
||||
|
||||
app.use(router);
|
||||
app.use(i18n);
|
||||
const app = createApp(App)
|
||||
|
||||
app.mount("body");
|
||||
app.use(router)
|
||||
app.use(i18n)
|
||||
|
||||
app.mount('body')
|
||||
|
|
|
@ -1,64 +1,68 @@
|
|||
import { createRouter, createWebHistory } from "vue-router";
|
||||
import HomeView from "../views/HomeView.vue";
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import HomeView from '@/views/HomeView.vue'
|
||||
|
||||
import HomeIcon from "@/assets/icons/HomeIcon.vue";
|
||||
import IdCardIcon from "@/assets/icons/IdCardIcon.vue";
|
||||
import PaletteIcon from "@/assets/icons/PaletteIcon.vue";
|
||||
import BriefcaseIcon from "@/assets/icons/BriefcaseIcon.vue";
|
||||
import CircleInfoIcon from "@/assets/icons/CircleInfoIcon.vue";
|
||||
import HomeIcon from '@/assets/icons/HomeIcon.vue'
|
||||
import IdCardIcon from '@/assets/icons/IdCardIcon.vue'
|
||||
import PaletteIcon from '@/assets/icons/PaletteIcon.vue'
|
||||
import BriefcaseIcon from '@/assets/icons/BriefcaseIcon.vue'
|
||||
import CircleInfoIcon from '@/assets/icons/CircleInfoIcon.vue'
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
scrollBehavior: () => {
|
||||
return { top: 0 };
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve({ top: 0 })
|
||||
}, 500)
|
||||
})
|
||||
},
|
||||
routes: [
|
||||
{
|
||||
path: "/",
|
||||
name: "home",
|
||||
path: '/',
|
||||
name: 'home',
|
||||
component: HomeView,
|
||||
meta: {
|
||||
title: "nav.home",
|
||||
icon: HomeIcon,
|
||||
},
|
||||
title: 'nav.home',
|
||||
icon: HomeIcon
|
||||
}
|
||||
},
|
||||
{
|
||||
path: "/general",
|
||||
name: "general",
|
||||
component: () => import("@/views/GeneralView.vue"),
|
||||
path: '/general',
|
||||
name: 'general',
|
||||
component: () => import('@/views/GeneralView.vue'),
|
||||
meta: {
|
||||
title: "nav.general",
|
||||
icon: IdCardIcon,
|
||||
},
|
||||
title: 'nav.general',
|
||||
icon: IdCardIcon
|
||||
}
|
||||
},
|
||||
{
|
||||
path: "/anatomy",
|
||||
name: "anatomy",
|
||||
component: () => import("@/views/AnatomyView.vue"),
|
||||
path: '/anatomy',
|
||||
name: 'anatomy',
|
||||
component: () => import('@/views/AnatomyView.vue'),
|
||||
meta: {
|
||||
title: "nav.anatomy",
|
||||
icon: PaletteIcon,
|
||||
},
|
||||
title: 'nav.anatomy',
|
||||
icon: PaletteIcon
|
||||
}
|
||||
},
|
||||
{
|
||||
path: "/career-path",
|
||||
name: "career-path",
|
||||
component: () => import("@/views/CareerPathView.vue"),
|
||||
path: '/career-path',
|
||||
name: 'career-path',
|
||||
component: () => import('@/views/CareerPathView.vue'),
|
||||
meta: {
|
||||
title: "nav.careerPath",
|
||||
icon: BriefcaseIcon,
|
||||
},
|
||||
title: 'nav.careerPath',
|
||||
icon: BriefcaseIcon
|
||||
}
|
||||
},
|
||||
{
|
||||
path: "/attributions",
|
||||
name: "attributions",
|
||||
component: () => import("@/views/AttributionsView.vue"),
|
||||
path: '/attributions',
|
||||
name: 'attributions',
|
||||
component: () => import('@/views/AttributionsView.vue'),
|
||||
meta: {
|
||||
title: "nav.attributions",
|
||||
icon: CircleInfoIcon,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
title: 'nav.attributions',
|
||||
icon: CircleInfoIcon
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
export default router;
|
||||
export default router
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@import "fontfaces";
|
||||
@import 'fontfaces';
|
||||
|
||||
/* theme colors */
|
||||
:root {
|
||||
|
@ -33,8 +33,8 @@
|
|||
|
||||
/* general purpose variables */
|
||||
:root {
|
||||
--font-family-copy: "Arvo", sans-serif;
|
||||
--font-family-headings: "Secular One", serif;
|
||||
--font-family-copy: 'Arvo', sans-serif;
|
||||
--font-family-headings: 'Secular One', serif;
|
||||
|
||||
--font-size: 18px;
|
||||
--text-line-height: 1.5;
|
||||
|
@ -43,6 +43,8 @@
|
|||
--page-background-image: url(@/assets/layered-waves-light.svg);
|
||||
--page-background-image-height: 100vw;
|
||||
--page-background-image-max-height: 50vh;
|
||||
--page-transition: opacity 0.5s ease, transform 0.5s cubic-bezier(0.68, -0.55, 0.27, 1.55);
|
||||
--page-transform: translateY(5em);
|
||||
|
||||
--paragraph-margin: 1rem;
|
||||
|
||||
|
@ -54,8 +56,7 @@
|
|||
--container-spacing-bottom-safe: max(1rem, env(safe-area-inset-bottom));
|
||||
--container-spacing-left-safe: max(1rem, env(safe-area-inset-left));
|
||||
|
||||
--textblock-padding: 0 var(--container-spacing-right-safe) 0
|
||||
var(--container-spacing-left-safe);
|
||||
--textblock-padding: 0 var(--container-spacing-right-safe) 0 var(--container-spacing-left-safe);
|
||||
|
||||
--welcome-padding: 2rem var(--container-spacing-right-safe) 2rem
|
||||
var(--container-spacing-left-safe);
|
||||
|
@ -75,19 +76,14 @@
|
|||
--navigation-height: auto;
|
||||
--navigation-padding: 0 0 0 env(safe-area-inset-left);
|
||||
|
||||
--navigation-cutout: 0 0
|
||||
calc(var(--navigation-size) + env(safe-area-inset-bottom)) 0;
|
||||
--navigation-cutout-page-background: calc(
|
||||
var(--navigation-size) + env(safe-area-inset-bottom)
|
||||
);
|
||||
--navigation-cutout: 0 0 calc(var(--navigation-size) + env(safe-area-inset-bottom)) 0;
|
||||
--navigation-cutout-page-background: calc(var(--navigation-size) + env(safe-area-inset-bottom));
|
||||
--navigation-cutout-main: 0;
|
||||
|
||||
--navigation-link-display: none;
|
||||
--navigation-link-flex: 1 0 var(--navigation-size);
|
||||
--navigation-link-justify: center;
|
||||
--navigation-link-height: calc(
|
||||
var(--navigation-size) + env(safe-area-inset-bottom)
|
||||
);
|
||||
--navigation-link-height: calc(var(--navigation-size) + env(safe-area-inset-bottom));
|
||||
--navigation-link-padding: 0 0 env(safe-area-inset-bottom) 0;
|
||||
--navigation-link-icon-size: calc(var(--navigation-size) / 2);
|
||||
--navigation-link-icon-spacing: calc(var(--navigation-size) * 0.25);
|
||||
|
@ -118,13 +114,10 @@
|
|||
--timeline-item-margin-even: var(--timeline-item-margin);
|
||||
--timeline-item-text-align-even: left;
|
||||
--timeline-item-content-padding-odd: 0 0 0 var(--container-spacing-left-safe);
|
||||
--timeline-item-content-padding-even: var(
|
||||
--timeline-item-content-padding-odd
|
||||
);
|
||||
--timeline-item-content-padding-even: var(--timeline-item-content-padding-odd);
|
||||
|
||||
--table-border-radius: 1rem;
|
||||
--table-outer-spacing: 0 var(--container-spacing-right-safe) 0
|
||||
var(--container-spacing-left-safe);
|
||||
--table-outer-spacing: 0 var(--container-spacing-right-safe) 0 var(--container-spacing-left-safe);
|
||||
--table-cell-padding: 0.25rem 0.5rem;
|
||||
}
|
||||
|
||||
|
@ -225,11 +218,9 @@
|
|||
--page-background-image-max-height: 100vh;
|
||||
|
||||
--color-table-color-cell-width: 10rem;
|
||||
--textblock-padding: 0 var(--container-spacing-right-safe) 0
|
||||
var(--container-spacing-left-safe);
|
||||
--textblock-padding: 0 var(--container-spacing-right-safe) 0 var(--container-spacing-left-safe);
|
||||
|
||||
--navigation-cutout: 0 0 0
|
||||
calc(var(--navigation-size) + env(safe-area-inset-left));
|
||||
--navigation-cutout: 0 0 0 calc(var(--navigation-size) + env(safe-area-inset-left));
|
||||
--navigation-cutout-page-background: 0;
|
||||
--navigation-cutout-main: var(--navigation-cutout);
|
||||
|
||||
|
@ -238,9 +229,7 @@
|
|||
--navigation-align: stretch;
|
||||
--navigation-position: 0 auto 0 0;
|
||||
|
||||
--navigation-width: calc(
|
||||
var(--navigation-size) + env(safe-area-inset-left)
|
||||
);
|
||||
--navigation-width: calc(var(--navigation-size) + env(safe-area-inset-left));
|
||||
--navigation-width-expanded: var(--navigation-width);
|
||||
|
||||
--navigation-link-display: block;
|
||||
|
@ -271,10 +260,8 @@
|
|||
--timeline-stroke-length: calc(100% - var(--timeline-circle-size));
|
||||
--timeline-stroke-position-even: var(--timeline-stroke-position-top)
|
||||
var(--timeline-stroke-position-horizontal) auto auto;
|
||||
--timeline-item-margin-odd: 0 0 0
|
||||
calc(50% - var(--timeline-circle-size) / 2);
|
||||
--timeline-item-margin-even: 0 calc(50% - var(--timeline-circle-size) / 2) 0
|
||||
0;
|
||||
--timeline-item-margin-odd: 0 0 0 calc(50% - var(--timeline-circle-size) / 2);
|
||||
--timeline-item-margin-even: 0 calc(50% - var(--timeline-circle-size) / 2) 0 0;
|
||||
--timeline-item-flex-order: 1;
|
||||
--timeline-item-content-margin-odd: 0 0 0 1rem;
|
||||
--timeline-item-content-margin-even: 0 1rem 0 0;
|
||||
|
@ -298,8 +285,13 @@
|
|||
|
||||
@media (hover: hover) and (min-width: 50em) {
|
||||
:root {
|
||||
--navigation-width-expanded: calc(
|
||||
var(--navigation-size) * 3.75 + env(safe-area-inset-left)
|
||||
);
|
||||
--navigation-width-expanded: calc(var(--navigation-size) * 3.75 + env(safe-area-inset-left));
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion) {
|
||||
:root {
|
||||
--page-transition: opacity 0.5s ease;
|
||||
--page-transform: none;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
@import "@/assets/fonts/arvo/arvo";
|
||||
@import "@/assets/fonts/secular-one/secular-one";
|
||||
@import '@/assets/fonts/arvo/arvo';
|
||||
@import '@/assets/fonts/secular-one/secular-one';
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@import "@/scss/base";
|
||||
@import '@/scss/base';
|
||||
|
||||
:root {
|
||||
font-family: var(--font-family-copy);
|
||||
|
@ -19,7 +19,9 @@ body {
|
|||
min-height: 100vh;
|
||||
color: var(--color-text);
|
||||
background: var(--color-background-body);
|
||||
transition: color 0.5s, background-color 0.5s;
|
||||
transition:
|
||||
color 0.5s,
|
||||
background-color 0.5s;
|
||||
line-height: var(--text-line-height);
|
||||
|
||||
text-rendering: optimizeLegibility;
|
||||
|
@ -41,7 +43,7 @@ main {
|
|||
&:after {
|
||||
display: block;
|
||||
|
||||
content: "";
|
||||
content: '';
|
||||
position: sticky;
|
||||
inset: auto 0 var(--navigation-cutout-page-background) 0;
|
||||
|
||||
|
@ -95,8 +97,7 @@ a {
|
|||
|
||||
&:hover {
|
||||
color: var(--color-link-text-hover);
|
||||
box-shadow: inset 0 calc(var(--link-inset-box-shadow) * -1) 0 0
|
||||
var(--color-link-text-underline);
|
||||
box-shadow: inset 0 calc(var(--link-inset-box-shadow) * -1) 0 0 var(--color-link-text-underline);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -170,3 +171,14 @@ table {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: var(--page-transition);
|
||||
}
|
||||
|
||||
.fade-enter-from,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
transform: var(--page-transform);
|
||||
}
|
||||
|
|
|
@ -1,20 +1,21 @@
|
|||
<script setup lang="ts">
|
||||
import RefImage from "@/components/RefImage.vue";
|
||||
import ColorTable from "@/components/ColorTable.vue";
|
||||
import RefImage from '@/components/RefImage.vue'
|
||||
import ColorTable from '@/components/ColorTable.vue'
|
||||
|
||||
const colors = [
|
||||
{ name: "data.colors.front", value: "#e7c7b1" },
|
||||
{ name: "data.colors.limbs", value: "#493428" },
|
||||
{ name: "data.colors.back", value: "#422322" },
|
||||
{ name: "data.colors.spine", value: "#341c1c" },
|
||||
{ name: "data.colors.tissue", value: "#6bb9db" },
|
||||
{ name: "data.colors.spikes", value: "#f8ebdd" },
|
||||
{ name: "data.colors.eyesPrimary", value: "#a7eef1" },
|
||||
{ name: "data.colors.eyesSecondary", value: "#6dabd1" },
|
||||
];
|
||||
{ name: 'data.colors.front', value: '#e7c7b1' },
|
||||
{ name: 'data.colors.limbs', value: '#493428' },
|
||||
{ name: 'data.colors.back', value: '#422322' },
|
||||
{ name: 'data.colors.spine', value: '#341c1c' },
|
||||
{ name: 'data.colors.tissue', value: '#6bb9db' },
|
||||
{ name: 'data.colors.spikes', value: '#f8ebdd' },
|
||||
{ name: 'data.colors.eyesPrimary', value: '#a7eef1' },
|
||||
{ name: 'data.colors.eyesSecondary', value: '#6dabd1' }
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<article>
|
||||
<section>
|
||||
<h1>{{ $t(`${$route.meta.title}`) }}</h1>
|
||||
</section>
|
||||
|
@ -23,21 +24,21 @@ const colors = [
|
|||
<template v-if="$route.query.nsfw">
|
||||
<source
|
||||
srcset="
|
||||
@/assets/viktor-ref-NSFW-alpha.png?w=375;420;500;750;840;1000;1125;1260;1500&avif&quality=75&withoutEnlargement&srcset
|
||||
@/assets/viktor-ref-NSFW-alpha.png?w=375;420;500;750;840;1000;1125;1260;1500&format=avif&quality=75&withoutEnlargement&as=srcset
|
||||
"
|
||||
sizes="(min-width: 64em) 500px, (min-width: 50em) 420px, 375px"
|
||||
type="image/avif"
|
||||
/>
|
||||
<source
|
||||
srcset="
|
||||
@/assets/viktor-ref-NSFW-alpha.png?w=375;420;500;750;840;1000;1125;1260;1500&webp&quality=100&withoutEnlargement&srcset
|
||||
@/assets/viktor-ref-NSFW-alpha.png?w=375;420;500;750;840;1000;1125;1260;1500&format=webp&quality=100&withoutEnlargement&as=srcset
|
||||
"
|
||||
sizes="(min-width: 64em) 500px, (min-width: 50em) 420px, 375px"
|
||||
type="image/webp"
|
||||
/>
|
||||
<img
|
||||
srcset="
|
||||
@/assets/viktor-ref-NSFW-alpha.png?w=375;420;500;750;840;1000;1125;1260;1500&png&withoutEnlargement&srcset
|
||||
@/assets/viktor-ref-NSFW-alpha.png?w=375;420;500;750;840;1000;1125;1260;1500&format=png&withoutEnlargement&as=srcset
|
||||
"
|
||||
sizes="(min-width: 64em) 500px, (min-width: 50em) 420px, 375px"
|
||||
alt="Viktor Ref by sabertoofs"
|
||||
|
@ -48,21 +49,21 @@ const colors = [
|
|||
<template v-else>
|
||||
<source
|
||||
srcset="
|
||||
@/assets/viktor-ref-SFW-alpha.png?w=375;420;500;750;840;1000;1125;1260;1500&avif&quality=75&withoutEnlargement&srcset
|
||||
@/assets/viktor-ref-SFW-alpha.png?w=375;420;500;750;840;1000;1125;1260;1500&format=avif&quality=75&withoutEnlargement&as=srcset
|
||||
"
|
||||
sizes="(min-width: 64em) 500px, (min-width: 50em) 420px, 375px"
|
||||
type="image/avif"
|
||||
/>
|
||||
<source
|
||||
srcset="
|
||||
@/assets/viktor-ref-SFW-alpha.png?w=375;420;500;750;840;1000;1125;1260;1500&webp&quality=100&withoutEnlargement&srcset
|
||||
@/assets/viktor-ref-SFW-alpha.png?w=375;420;500;750;840;1000;1125;1260;1500&format=webp&quality=100&withoutEnlargement&as=srcset
|
||||
"
|
||||
sizes="(min-width: 64em) 500px, (min-width: 50em) 420px, 375px"
|
||||
type="image/webp"
|
||||
/>
|
||||
<img
|
||||
srcset="
|
||||
@/assets/viktor-ref-SFW-alpha.png?w=375;420;500;750;840;1000;1125;1260;1500&png&withoutEnlargement&srcset
|
||||
@/assets/viktor-ref-SFW-alpha.png?w=375;420;500;750;840;1000;1125;1260;1500&format=png&withoutEnlargement&as=srcset
|
||||
"
|
||||
sizes="(min-width: 64em) 500px, (min-width: 50em) 420px, 375px"
|
||||
:alt="`${$t('anatomy.images.back.caption')} by sabertoofs`"
|
||||
|
@ -71,21 +72,22 @@ const colors = [
|
|||
</template>
|
||||
|
||||
<template #caption>
|
||||
{{ $t('anatomy.images.back.caption') }} © <a href="http://twitter.com/sabertoofs">sabertoofs</a>
|
||||
{{ $t('anatomy.images.back.caption') }} ©
|
||||
<a href="http://twitter.com/sabertoofs">sabertoofs</a>
|
||||
</template>
|
||||
</RefImage>
|
||||
|
||||
<ColorTable :colors="colors"></ColorTable>
|
||||
|
||||
<section>
|
||||
<p v-for="p in $tm('anatomy.paragraphs[0]')">{{ p }}</p>
|
||||
<p v-for="(p, i) in $tm('anatomy.paragraphs[0]')" :key="i">{{ p }}</p>
|
||||
</section>
|
||||
|
||||
<RefImage dropshadow>
|
||||
<template v-if="$route.query.nsfw">
|
||||
<source
|
||||
srcset="
|
||||
@/assets/viktor-front-NSFW-alpha.png?w=430;530;590;710;860;1060;1180;1420;1290;1590;1770;2130&avif&quality=75&withoutEnlargement&srcset
|
||||
@/assets/viktor-front-NSFW-alpha.png?w=430;530;590;710;860;1060;1180;1420;1290;1590;1770;2130&format=avif&quality=75&withoutEnlargement&as=srcset
|
||||
"
|
||||
sizes="(min-width: 64em) 710px,
|
||||
(min-width: 50em) 590px,
|
||||
|
@ -95,7 +97,7 @@ const colors = [
|
|||
/>
|
||||
<source
|
||||
srcset="
|
||||
@/assets/viktor-front-NSFW-alpha.png?w=430;530;590;710;860;1060;1180;1420;1290;1590;1770;2130&webp&quality=100&withoutEnlargement&srcset
|
||||
@/assets/viktor-front-NSFW-alpha.png?w=430;530;590;710;860;1060;1180;1420;1290;1590;1770;2130&format=webp&quality=100&withoutEnlargement&as=srcset
|
||||
"
|
||||
sizes="(min-width: 64em) 710px,
|
||||
(min-width: 50em) 590px,
|
||||
|
@ -105,7 +107,7 @@ const colors = [
|
|||
/>
|
||||
<img
|
||||
srcset="
|
||||
@/assets/viktor-front-NSFW-alpha.png?w=430;530;590;710;860;1060;1180;1420;1290;1590;1770;2130&png&withoutEnlargement&srcset
|
||||
@/assets/viktor-front-NSFW-alpha.png?w=430;530;590;710;860;1060;1180;1420;1290;1590;1770;2130&format=png&withoutEnlargement&as=srcset
|
||||
"
|
||||
sizes="(min-width: 64em) 710px,
|
||||
(min-width: 50em) 590px,
|
||||
|
@ -119,7 +121,7 @@ const colors = [
|
|||
<template v-else>
|
||||
<source
|
||||
srcset="
|
||||
@/assets/viktor-front-SFW-alpha.png?w=430;530;590;710;860;1060;1180;1420;1290;1590;1770;2130&avif&quality=75&withoutEnlargement&srcset
|
||||
@/assets/viktor-front-SFW-alpha.png?w=430;530;590;710;860;1060;1180;1420;1290;1590;1770;2130&format=avif&quality=75&withoutEnlargement&as=srcset
|
||||
"
|
||||
sizes="(min-width: 64em) 710px,
|
||||
(min-width: 50em) 590px,
|
||||
|
@ -129,7 +131,7 @@ const colors = [
|
|||
/>
|
||||
<source
|
||||
srcset="
|
||||
@/assets/viktor-front-SFW-alpha.png?w=430;530;590;710;860;1060;1180;1420;1290;1590;1770;2130&webp&quality=100&withoutEnlargement&srcset
|
||||
@/assets/viktor-front-SFW-alpha.png?w=430;530;590;710;860;1060;1180;1420;1290;1590;1770;2130&format=webp&quality=100&withoutEnlargement&as=srcset
|
||||
"
|
||||
sizes="(min-width: 64em) 710px,
|
||||
(min-width: 50em) 590px,
|
||||
|
@ -139,7 +141,7 @@ const colors = [
|
|||
/>
|
||||
<img
|
||||
srcset="
|
||||
@/assets/viktor-front-SFW-alpha.png?w=430;530;590;710;860;1060;1180;1420;1290;1590;1770;2130&png&withoutEnlargement&srcset
|
||||
@/assets/viktor-front-SFW-alpha.png?w=430;530;590;710;860;1060;1180;1420;1290;1590;1770;2130&format=png&withoutEnlargement&as=srcset
|
||||
"
|
||||
sizes="(min-width: 64em) 710px,
|
||||
(min-width: 50em) 590px,
|
||||
|
@ -151,12 +153,13 @@ const colors = [
|
|||
</template>
|
||||
|
||||
<template #caption>
|
||||
{{ $t("anatomy.images.front.caption") }} ©
|
||||
{{ $t('anatomy.images.front.caption') }} ©
|
||||
<a href="http://twitter.com/sabertoofs">sabertoofs</a>
|
||||
</template>
|
||||
</RefImage>
|
||||
|
||||
<section>
|
||||
<p v-for="p in $tm('anatomy.paragraphs[1]')">{{ p }}</p>
|
||||
<p v-for="(p, i) in $tm('anatomy.paragraphs[1]')" :key="i">{{ p }}</p>
|
||||
</section>
|
||||
</article>
|
||||
</template>
|
||||
|
|
|
@ -1,48 +1,49 @@
|
|||
<script setup lang="ts">
|
||||
import AttributionTable from "@/components/AttributionTable.vue";
|
||||
import AttributionTable from '@/components/AttributionTable.vue'
|
||||
|
||||
import ViktorRefAlpha from "@/assets/viktor-ref-SFW-alpha.png?w=400&webp&quality=100&imagetools";
|
||||
import ViktorFront from "@/assets/viktor-front-SFW-alpha.png?w=400&webp&quality=100&imagetools";
|
||||
import ViktorRefAlpha from '@/assets/viktor-ref-SFW-alpha.png?w=400&format=webp&quality=100&imagetools'
|
||||
import ViktorFront from '@/assets/viktor-front-SFW-alpha.png?w=400&format=webp&quality=100&imagetools'
|
||||
|
||||
const attributions = [
|
||||
{
|
||||
artwork: ViktorRefAlpha,
|
||||
artist: "sabertoofs",
|
||||
artist: 'sabertoofs',
|
||||
links: {
|
||||
furaffinity: "https://www.furaffinity.net/user/sabertoofs",
|
||||
twitter: "https://twitter.com/sabertoofs",
|
||||
},
|
||||
furaffinity: 'https://www.furaffinity.net/user/sabertoofs',
|
||||
twitter: 'https://twitter.com/sabertoofs'
|
||||
}
|
||||
},
|
||||
{
|
||||
artwork: ViktorFront,
|
||||
artist: "sabertoofs",
|
||||
artist: 'sabertoofs',
|
||||
links: {
|
||||
furaffinity: "https://www.furaffinity.net/user/sabertoofs",
|
||||
twitter: "https://twitter.com/sabertoofs",
|
||||
},
|
||||
},
|
||||
];
|
||||
furaffinity: 'https://www.furaffinity.net/user/sabertoofs',
|
||||
twitter: 'https://twitter.com/sabertoofs'
|
||||
}
|
||||
}
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<article>
|
||||
<section>
|
||||
<h1>{{ $t(`${$route.meta.title}`) }}</h1>
|
||||
<h2>{{ $t("attributions.artwork.heading") }}</h2>
|
||||
<h2>{{ $t('attributions.artwork.heading') }}</h2>
|
||||
</section>
|
||||
<AttributionTable :attributions="attributions" />
|
||||
<section>
|
||||
<h2>{{ $t("attributions.other.heading") }}</h2>
|
||||
<h2>{{ $t('attributions.other.heading') }}</h2>
|
||||
</section>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ $t("attributions.other.headings[0]") }}</th>
|
||||
<th>{{ $t("attributions.other.headings[1]") }}</th>
|
||||
<th>{{ $t('attributions.other.headings[0]') }}</th>
|
||||
<th>{{ $t('attributions.other.headings[1]') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{{ $t("attributions.other.icons[0]") }}</td>
|
||||
<td>{{ $t('attributions.other.icons[0]') }}</td>
|
||||
<td>
|
||||
<a
|
||||
href="https://fontawesome.com/license/free"
|
||||
|
@ -54,7 +55,7 @@ const attributions = [
|
|||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ $t("attributions.other.headingFont[0]") }}</td>
|
||||
<td>{{ $t('attributions.other.headingFont[0]') }}</td>
|
||||
<td>
|
||||
<a
|
||||
href="https://github.com/MichalSahar/Secular"
|
||||
|
@ -63,18 +64,14 @@ const attributions = [
|
|||
>
|
||||
Secular One
|
||||
</a>
|
||||
{{ $t("attributions.other.headingFont[1]") }}
|
||||
<a
|
||||
href="https://github.com/MichalSahar"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{{ $t('attributions.other.headingFont[1]') }}
|
||||
<a href="https://github.com/MichalSahar" target="_blank" rel="noopener noreferrer">
|
||||
Michal Sahar
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ $t("attributions.other.copyFont[0]") }}</td>
|
||||
<td>{{ $t('attributions.other.copyFont[0]') }}</td>
|
||||
<td>
|
||||
<a
|
||||
href="https://antonkoovit.com/typefaces/arvo"
|
||||
|
@ -83,39 +80,24 @@ const attributions = [
|
|||
>
|
||||
Arvo
|
||||
</a>
|
||||
{{ $t("attributions.other.copyFont[1]") }}
|
||||
<a
|
||||
href="https://antonkoovit.com/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{{ $t('attributions.other.copyFont[1]') }}
|
||||
<a href="https://antonkoovit.com/" target="_blank" rel="noopener noreferrer">
|
||||
Anton Koovit
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ $t("attributions.other.background[0]") }}</td>
|
||||
<td>{{ $t('attributions.other.background[0]') }}</td>
|
||||
<td>
|
||||
{{ $t("attributions.other.background[1][0]") }}
|
||||
<a
|
||||
href="https://haikei.app/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Haikei
|
||||
</a>
|
||||
{{ $t("attributions.other.background[1][1]") }}
|
||||
<a
|
||||
href="https://zcreativelabs.com/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{{ $t('attributions.other.background[1][0]') }}
|
||||
<a href="https://haikei.app/" target="_blank" rel="noopener noreferrer">Haikei</a>
|
||||
{{ $t('attributions.other.background[1][1]') }}
|
||||
<a href="https://zcreativelabs.com/" target="_blank" rel="noopener noreferrer">
|
||||
z creative labs
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</article>
|
||||
</template>
|
||||
|
||||
<style lang="scss"></style>
|
||||
|
|
|
@ -1,13 +1,18 @@
|
|||
<script setup lang="ts">
|
||||
import TimelineList from "@/components/TimelineList.vue";
|
||||
import TimelineItem from "@/components/TimelineItem.vue";
|
||||
import WhiskeyGlassIcon from "@/assets/icons/WhiskeyGlassIcon.vue";
|
||||
import TreeIcon from "@/assets/icons/TreeIcon.vue";
|
||||
import CarIcon from "@/assets/icons/CarIcon.vue";
|
||||
import HelmetSafetyIcon from "@/assets/icons/HelmetSafetyIcon.vue";
|
||||
import IndustryIcon from "@/assets/icons/IndustryIcon.vue";
|
||||
import TruckIcon from "@/assets/icons/TruckIcon.vue";
|
||||
import BoxesIcon from "@/assets/icons/BoxesIcon.vue";
|
||||
import TimelineList from '@/components/TimelineList.vue'
|
||||
import TimelineItem from '@/components/TimelineItem.vue'
|
||||
import WhiskeyGlassIcon from '@/assets/icons/WhiskeyGlassIcon.vue'
|
||||
import TreeIcon from '@/assets/icons/TreeIcon.vue'
|
||||
import CarIcon from '@/assets/icons/CarIcon.vue'
|
||||
import HelmetSafetyIcon from '@/assets/icons/HelmetSafetyIcon.vue'
|
||||
import IndustryIcon from '@/assets/icons/IndustryIcon.vue'
|
||||
import TruckIcon from '@/assets/icons/TruckIcon.vue'
|
||||
import BoxesIcon from '@/assets/icons/BoxesIcon.vue'
|
||||
|
||||
interface Job {
|
||||
title: string
|
||||
desc: string
|
||||
}
|
||||
|
||||
const jobIcons = [
|
||||
WhiskeyGlassIcon,
|
||||
|
@ -16,18 +21,19 @@ const jobIcons = [
|
|||
HelmetSafetyIcon,
|
||||
IndustryIcon,
|
||||
TruckIcon,
|
||||
BoxesIcon,
|
||||
];
|
||||
BoxesIcon
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<article>
|
||||
<section>
|
||||
<h1>{{ $t(`${$route.meta.title}`) }}</h1>
|
||||
<p v-for="p in $tm('career.paragraphs')">{{ p }}</p>
|
||||
<p v-for="(p, i) in $tm('career.paragraphs')" :key="i">{{ p }}</p>
|
||||
</section>
|
||||
|
||||
<TimelineList>
|
||||
<TimelineItem v-for="(job, idx) in $tm('career.jobs')">
|
||||
<TimelineItem v-for="(job, idx) in ($tm('career.jobs') as Job[])" :key="idx">
|
||||
<template #icon>
|
||||
<component :is="jobIcons[idx as number]"></component>
|
||||
</template>
|
||||
|
@ -37,4 +43,5 @@ const jobIcons = [
|
|||
</template>
|
||||
</TimelineItem>
|
||||
</TimelineList>
|
||||
</article>
|
||||
</template>
|
||||
|
|
|
@ -1,53 +1,54 @@
|
|||
<script setup lang="ts">
|
||||
import DataTable from "@/components/DataTable.vue";
|
||||
import DataTable from '@/components/DataTable.vue'
|
||||
|
||||
const dob = new Date("1987-12-08");
|
||||
const locale = "en-US";
|
||||
const dob = new Date('1987-12-08')
|
||||
const locale = 'en-US'
|
||||
const dateFormat = new Intl.DateTimeFormat(locale, {
|
||||
year: "numeric",
|
||||
month: "long",
|
||||
day: "2-digit",
|
||||
});
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: '2-digit'
|
||||
})
|
||||
|
||||
const height = 227;
|
||||
const weight = 175;
|
||||
const height = 227
|
||||
const weight = 175
|
||||
|
||||
const toImperial = (cm: number): string => {
|
||||
const realFeet = (cm * 0.3937) / 12;
|
||||
const feet = Math.floor(realFeet);
|
||||
const inches = Math.round((realFeet - feet) * 12);
|
||||
const realFeet = (cm * 0.3937) / 12
|
||||
const feet = Math.floor(realFeet)
|
||||
const inches = Math.round((realFeet - feet) * 12)
|
||||
|
||||
return `${feet}'${inches}"`;
|
||||
};
|
||||
return `${feet}'${inches}"`
|
||||
}
|
||||
|
||||
const toInch = (cm: number): string => {
|
||||
return `${Math.round(cm / 2.45)} in`;
|
||||
};
|
||||
return `${Math.round(cm / 2.45)} in`
|
||||
}
|
||||
|
||||
const toLbs = (kg: number): number => {
|
||||
const nearExact = kg / 0.45359237;
|
||||
const lbs = Math.floor(nearExact);
|
||||
const nearExact = kg / 0.45359237
|
||||
const lbs = Math.floor(nearExact)
|
||||
|
||||
return lbs;
|
||||
};
|
||||
return lbs
|
||||
}
|
||||
|
||||
const heads = ["data.general.heading[0]", "data.general.heading[1]"];
|
||||
const heads = ['data.general.heading[0]', 'data.general.heading[1]']
|
||||
const data = [
|
||||
["data.general.fullName[0]", "data.general.fullName[1]"],
|
||||
["data.general.dob[0]", dateFormat.format(dob)],
|
||||
["data.general.gender[0]", "data.general.gender[1]"],
|
||||
["data.general.height[0]", `${height} cm (${toImperial(height)})`],
|
||||
["data.general.weight[0]", `${weight} kg (${toLbs(weight)} lbs)`],
|
||||
];
|
||||
['data.general.fullName[0]', 'data.general.fullName[1]'],
|
||||
['data.general.dob[0]', dateFormat.format(dob)],
|
||||
['data.general.gender[0]', 'data.general.gender[1]'],
|
||||
['data.general.height[0]', `${height} cm (${toImperial(height)})`],
|
||||
['data.general.weight[0]', `${weight} kg (${toLbs(weight)} lbs)`]
|
||||
]
|
||||
|
||||
const sexHeads = ["data.sexuality.heading[0]", "data.sexuality.heading[1]"];
|
||||
const sexHeads = ['data.sexuality.heading[0]', 'data.sexuality.heading[1]']
|
||||
const sexData = [
|
||||
["data.sexuality.identifiesAs[0]", "data.sexuality.identifiesAs[1]"],
|
||||
["data.sexuality.preferredRole[0]", "data.sexuality.preferredRole[1]"],
|
||||
];
|
||||
['data.sexuality.identifiesAs[0]', 'data.sexuality.identifiesAs[1]'],
|
||||
['data.sexuality.preferredRole[0]', 'data.sexuality.preferredRole[1]']
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<article>
|
||||
<section>
|
||||
<h1>{{ $t(`${$route.meta.title}`) }}</h1>
|
||||
</section>
|
||||
|
@ -55,17 +56,18 @@ const sexData = [
|
|||
<DataTable :headings="heads" :data="data"></DataTable>
|
||||
|
||||
<section>
|
||||
<h2>{{ $t("general.personality.heading") }}</h2>
|
||||
<p v-for="p in $tm('general.personality.paragraphs')">{{ p }}</p>
|
||||
<h2>{{ $t('general.personality.heading') }}</h2>
|
||||
<p v-for="(p, i) in $tm('general.personality.paragraphs')" :key="i">{{ p }}</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>{{ $t("general.sexuality.heading") }}</h2>
|
||||
<h2>{{ $t('general.sexuality.heading') }}</h2>
|
||||
</section>
|
||||
|
||||
<DataTable :headings="sexHeads" :data="sexData"></DataTable>
|
||||
|
||||
<section>
|
||||
<p v-for="p in $tm('general.sexuality.paragraphs')">{{ p }}</p>
|
||||
<p v-for="(p, i) in $tm('general.sexuality.paragraphs')" :key="i">{{ p }}</p>
|
||||
</section>
|
||||
</article>
|
||||
</template>
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
<script setup lang="ts">
|
||||
import WelcomeHeader from "@/components/WelcomeHeader.vue";
|
||||
import WelcomeHeader from '@/components/WelcomeHeader.vue'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<article>
|
||||
<WelcomeHeader>
|
||||
<template #main>{{ $t("welcomeHeader.mainTitle") }}</template>
|
||||
<template #sub>{{ $t("welcomeHeader.subTitle") }}</template>
|
||||
<template #main>{{ $t('welcomeHeader.mainTitle') }}</template>
|
||||
<template #sub>{{ $t('welcomeHeader.subTitle') }}</template>
|
||||
</WelcomeHeader>
|
||||
|
||||
<section>
|
||||
<h3>{{ $t("home.heading") }}</h3>
|
||||
<h3>{{ $t('home.heading') }}</h3>
|
||||
|
||||
<p v-for="p in $tm('home.paragraphs')">{{ p }}</p>
|
||||
<p v-for="(p, i) in $tm('home.paragraphs')" :key="i">{{ p }}</p>
|
||||
</section>
|
||||
</article>
|
||||
</template>
|
||||
|
|
12
tsconfig.app.json
Normal file
12
tsconfig.app.json
Normal file
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"extends": "@vue/tsconfig/tsconfig.dom.json",
|
||||
"include": ["globals.d.ts", "env.d.ts", "src/**/*", "src/**/*.json", "src/**/*.vue", "package.json"],
|
||||
"exclude": ["src/**/__tests__/*"],
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
{
|
||||
"extends": "@vue/tsconfig/tsconfig.node.json",
|
||||
"include": ["vite.config.*", "vitest.config.*", "cypress.config.*"],
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"types": ["node"]
|
||||
}
|
||||
}
|
|
@ -1,16 +1,11 @@
|
|||
{
|
||||
"extends": "@vue/tsconfig/tsconfig.web.json",
|
||||
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
|
||||
"files": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.config.json"
|
||||
"path": "./tsconfig.node.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.app.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
17
tsconfig.node.json
Normal file
17
tsconfig.node.json
Normal file
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"extends": "@tsconfig/node18/tsconfig.json",
|
||||
"include": [
|
||||
"globals.d.ts",
|
||||
"vite.config.*",
|
||||
"vitest.config.*",
|
||||
"cypress.config.*",
|
||||
"nightwatch.conf.*",
|
||||
"playwright.config.*"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Bundler",
|
||||
"types": ["node"]
|
||||
}
|
||||
}
|
23
vite.config.mts
Normal file
23
vite.config.mts
Normal file
|
@ -0,0 +1,23 @@
|
|||
import { fileURLToPath, URL } from 'node:url'
|
||||
|
||||
import { defineConfig } from 'vite'
|
||||
import { imagetools } from 'vite-imagetools'
|
||||
import autoprefixer from 'autoprefixer'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
base: "/viktor/",
|
||||
plugins: [vue(), imagetools()],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': fileURLToPath(new URL('./src', import.meta.url))
|
||||
}
|
||||
},
|
||||
css: {
|
||||
devSourcemap: true,
|
||||
postcss: {
|
||||
plugins: [autoprefixer({})]
|
||||
}
|
||||
}
|
||||
})
|
|
@ -1,19 +0,0 @@
|
|||
import { fileURLToPath, URL } from "node:url";
|
||||
|
||||
import { defineConfig } from "vite";
|
||||
import { imagetools } from "vite-imagetools";
|
||||
import vue from "@vitejs/plugin-vue";
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
base: "/viktor/",
|
||||
plugins: [vue(), imagetools()],
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": fileURLToPath(new URL("./src", import.meta.url)),
|
||||
},
|
||||
},
|
||||
css: {
|
||||
devSourcemap: true,
|
||||
},
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue