style: run linter
This commit is contained in:
parent
de3862bf77
commit
4853e1ec63
26 changed files with 502 additions and 631 deletions
|
@ -1,15 +1,15 @@
|
||||||
/* eslint-env node */
|
/* eslint-env node */
|
||||||
require("@rushstack/eslint-patch/modern-module-resolution");
|
require('@rushstack/eslint-patch/modern-module-resolution')
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
root: true,
|
root: true,
|
||||||
extends: [
|
extends: [
|
||||||
"plugin:vue/vue3-essential",
|
'plugin:vue/vue3-essential',
|
||||||
"eslint:recommended",
|
'eslint:recommended',
|
||||||
"@vue/eslint-config-typescript",
|
'@vue/eslint-config-typescript',
|
||||||
"@vue/eslint-config-prettier",
|
'@vue/eslint-config-prettier'
|
||||||
],
|
],
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
ecmaVersion: "latest",
|
ecmaVersion: 'latest'
|
||||||
},
|
}
|
||||||
};
|
}
|
||||||
|
|
65
src/App.vue
65
src/App.vue
|
@ -1,41 +1,41 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, provide } from "vue";
|
import { ref, provide } from 'vue'
|
||||||
import { RouterView } from "vue-router";
|
import { RouterView } from 'vue-router'
|
||||||
import { modalResultKey, nsfwKey, showModalKey } from "@/keys";
|
import { modalResultKey, nsfwKey, showModalKey } from '@/keys'
|
||||||
import { version } from "../package.json";
|
import { version } from '../package.json'
|
||||||
import RefModal from "@/components/RefModal.vue";
|
import RefModal from '@/components/RefModal.vue'
|
||||||
import ButtonGroup from "@/components/ButtonGroup.vue";
|
import ButtonGroup from '@/components/ButtonGroup.vue'
|
||||||
import Button from "@/components/RefButton.vue";
|
import Button from '@/components/RefButton.vue'
|
||||||
import SiteHeader from "@/components/SiteHeader.vue";
|
import SiteHeader from '@/components/SiteHeader.vue'
|
||||||
import SiteFooter from "@/components/SiteFooter.vue";
|
import SiteFooter from '@/components/SiteFooter.vue'
|
||||||
import SiteNavigation from "@/components/SiteNavigation.vue";
|
import SiteNavigation from '@/components/SiteNavigation.vue'
|
||||||
|
|
||||||
const isNsfw = ref(false);
|
const isNsfw = ref(false)
|
||||||
const isConfirmedHorny = ref(false);
|
const isConfirmedHorny = ref(false)
|
||||||
|
|
||||||
const nsfwmodal = ref<InstanceType<typeof RefModal>>();
|
const nsfwmodal = ref<InstanceType<typeof RefModal>>()
|
||||||
|
|
||||||
const showModal = (): void => {
|
const showModal = (): void => {
|
||||||
if (!isConfirmedHorny.value) {
|
if (!isConfirmedHorny.value) {
|
||||||
nsfwmodal.value?.showModal();
|
nsfwmodal.value?.showModal()
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
isNsfw.value = false;
|
isNsfw.value = false
|
||||||
}, 1);
|
}, 1)
|
||||||
} else {
|
} else {
|
||||||
isNsfw.value = !isNsfw.value;
|
isNsfw.value = !isNsfw.value
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
const modalResult = (value: boolean): void => {
|
const modalResult = (value: boolean): void => {
|
||||||
isNsfw.value = value;
|
isNsfw.value = value
|
||||||
isConfirmedHorny.value = value;
|
isConfirmedHorny.value = value
|
||||||
nsfwmodal.value?.close();
|
nsfwmodal.value?.close()
|
||||||
};
|
}
|
||||||
|
|
||||||
provide(modalResultKey, modalResult);
|
provide(modalResultKey, modalResult)
|
||||||
provide(nsfwKey, isNsfw);
|
provide(nsfwKey, isNsfw)
|
||||||
provide(showModalKey, showModal);
|
provide(showModalKey, showModal)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -46,18 +46,13 @@ provide(showModalKey, showModal);
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #message>
|
<template #message>
|
||||||
By enabling NSFW mode you confirm that you are of legal age to view adult
|
By enabling NSFW mode you confirm that you are of legal age to view adult content.
|
||||||
content.
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #buttons>
|
<template #buttons>
|
||||||
<ButtonGroup col>
|
<ButtonGroup col>
|
||||||
<Button positive @click.prevent="modalResult(true)">
|
<Button positive @click.prevent="modalResult(true)"> Yes, show me the goods 👀 </Button>
|
||||||
Yes, show me the goods 👀
|
<Button negative @click.prevent="modalResult(false)"> NO, STAHP 😱 </Button>
|
||||||
</Button>
|
|
||||||
<Button negative @click.prevent="modalResult(false)">
|
|
||||||
NO, STAHP 😱
|
|
||||||
</Button>
|
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
</template>
|
</template>
|
||||||
</RefModal>
|
</RefModal>
|
||||||
|
@ -81,9 +76,7 @@ provide(showModalKey, showModal);
|
||||||
/>
|
/>
|
||||||
<img
|
<img
|
||||||
class="nav-logo"
|
class="nav-logo"
|
||||||
srcset="
|
srcset="@/assets/sebin-smug-icon.png?w=36;40;48;56;72;80;96;112;108;120;144;168&png&srcset"
|
||||||
@/assets/sebin-smug-icon.png?w=36;40;48;56;72;80;96;112;108;120;144;168&png&srcset
|
|
||||||
"
|
|
||||||
sizes="(min-width: 120em) 56px, (min-width: 80em) 48px, (min-width: 35em) 40px, 36px"
|
sizes="(min-width: 120em) 56px, (min-width: 80em) 48px, (min-width: 35em) 40px, 36px"
|
||||||
alt="Sebin Avatar"
|
alt="Sebin Avatar"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: var(--attack-list-max-width);
|
max-width: var(--attack-list-max-width);
|
||||||
margin: auto;
|
margin: auto;
|
||||||
padding: 0 var(--container-spacing-right-safe) 0
|
padding: 0 var(--container-spacing-right-safe) 0 var(--container-spacing-left-safe);
|
||||||
var(--container-spacing-left-safe);
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
interface Props {
|
interface Props {
|
||||||
col?: boolean;
|
col?: boolean
|
||||||
grid?: boolean;
|
grid?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
defineProps<Props>();
|
defineProps<Props>()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { ColorDict } from "@/interfaces";
|
import type { ColorDict } from '@/interfaces'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
colors: ColorDict[];
|
colors: ColorDict[]
|
||||||
}
|
}
|
||||||
|
|
||||||
defineProps<Props>();
|
defineProps<Props>()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -21,10 +21,7 @@ defineProps<Props>();
|
||||||
<tr class="color-table__row" v-for="(color, idx) in colors" :key="idx">
|
<tr class="color-table__row" v-for="(color, idx) in colors" :key="idx">
|
||||||
<td class="color-table__cell name">{{ color.name }}</td>
|
<td class="color-table__cell name">{{ color.name }}</td>
|
||||||
<td class="color-table__cell value">{{ color.value }}</td>
|
<td class="color-table__cell value">{{ color.value }}</td>
|
||||||
<td
|
<td class="color-table__cell color" :style="{ 'background-color': color.value }"></td>
|
||||||
class="color-table__cell color"
|
|
||||||
:style="{ 'background-color': color.value }"
|
|
||||||
></td>
|
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
|
@ -1,21 +1,17 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
interface Props {
|
interface Props {
|
||||||
headings: string[];
|
headings: string[]
|
||||||
data: string[][];
|
data: string[][]
|
||||||
}
|
}
|
||||||
|
|
||||||
defineProps<Props>();
|
defineProps<Props>()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<table class="data-table">
|
<table class="data-table">
|
||||||
<thead class="data-table__head">
|
<thead class="data-table__head">
|
||||||
<tr class="data-table__row">
|
<tr class="data-table__row">
|
||||||
<th
|
<th class="data-table__heading" v-for="(heading, idx) in headings" :key="idx">
|
||||||
class="data-table__heading"
|
|
||||||
v-for="(heading, idx) in headings"
|
|
||||||
:key="idx"
|
|
||||||
>
|
|
||||||
{{ heading }}
|
{{ heading }}
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
interface Props {
|
interface Props {
|
||||||
cols?: number;
|
cols?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
defineProps<Props>();
|
defineProps<Props>()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -32,7 +32,7 @@ defineProps<Props>();
|
||||||
&:before {
|
&:before {
|
||||||
display: block;
|
display: block;
|
||||||
|
|
||||||
content: "";
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 1.375rem;
|
top: 1.375rem;
|
||||||
right: 1.375rem;
|
right: 1.375rem;
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
interface Props {
|
interface Props {
|
||||||
positive?: boolean;
|
positive?: boolean
|
||||||
negative?: boolean;
|
negative?: boolean
|
||||||
href?: string;
|
href?: string
|
||||||
download?: boolean | any;
|
download?: boolean | any
|
||||||
}
|
}
|
||||||
|
|
||||||
defineProps<Props>();
|
defineProps<Props>()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
|
@ -1,32 +1,26 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { inject } from "vue";
|
import { inject } from 'vue'
|
||||||
import { nsfwKey, showModalKey } from "@/keys";
|
import { nsfwKey, showModalKey } from '@/keys'
|
||||||
import RefToggle from "@/components/RefToggle.vue";
|
import RefToggle from '@/components/RefToggle.vue'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
polaroidBorder?: boolean;
|
polaroidBorder?: boolean
|
||||||
dropshadow?: boolean;
|
dropshadow?: boolean
|
||||||
nsfw?: boolean;
|
nsfw?: boolean
|
||||||
id: string;
|
id: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const isNsfw = inject<boolean>(nsfwKey, false);
|
const isNsfw = inject<boolean>(nsfwKey, false)
|
||||||
const showModal = inject<Function>(showModalKey, Function);
|
const showModal = inject<Function>(showModalKey, Function)
|
||||||
|
|
||||||
defineProps<Props>();
|
defineProps<Props>()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<figure class="figure">
|
<figure class="figure">
|
||||||
<div
|
<div class="figure__border" :class="{ 'figure__border--polaroid': polaroidBorder }">
|
||||||
class="figure__border"
|
|
||||||
:class="{ 'figure__border--polaroid': polaroidBorder }"
|
|
||||||
>
|
|
||||||
<template v-if="!nsfw || isNsfw">
|
<template v-if="!nsfw || isNsfw">
|
||||||
<div
|
<div class="figure__image" :class="{ 'figure__image--dropshadow': dropshadow }">
|
||||||
class="figure__image"
|
|
||||||
:class="{ 'figure__image--dropshadow': dropshadow }"
|
|
||||||
>
|
|
||||||
<slot name="img"></slot>
|
<slot name="img"></slot>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -79,8 +73,7 @@ defineProps<Props>();
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
margin: 1em auto;
|
margin: 1em auto;
|
||||||
padding: 0 var(--container-spacing-right-safe) 0
|
padding: 0 var(--container-spacing-right-safe) 0 var(--container-spacing-left-safe);
|
||||||
var(--container-spacing-left-safe);
|
|
||||||
|
|
||||||
&__border {
|
&__border {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -101,7 +94,7 @@ defineProps<Props>();
|
||||||
}
|
}
|
||||||
|
|
||||||
&__border--polaroid &__meta {
|
&__border--polaroid &__meta {
|
||||||
font-family: "Permanent Marker", fantasy;
|
font-family: 'Permanent Marker', fantasy;
|
||||||
color: var(--color-figure-polaroid-text);
|
color: var(--color-figure-polaroid-text);
|
||||||
|
|
||||||
max-width: 35rem;
|
max-width: 35rem;
|
||||||
|
|
|
@ -1,78 +1,68 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted } from "vue";
|
import { ref, onMounted } from 'vue'
|
||||||
import { debounce } from "@/helpers";
|
import { debounce } from '@/helpers'
|
||||||
|
|
||||||
const activeImage = ref(0);
|
const activeImage = ref(0)
|
||||||
const images = ref<Element[]>([]);
|
const images = ref<Element[]>([])
|
||||||
const element = document.createElement("div");
|
const element = document.createElement('div')
|
||||||
const galleryViewport = ref<HTMLElement>(element);
|
const galleryViewport = ref<HTMLElement>(element)
|
||||||
const galleryItemWidth = ref<number>(1);
|
const galleryItemWidth = ref<number>(1)
|
||||||
|
|
||||||
const resizeObserverCallback = (entries: ResizeObserverEntry[]): void => {
|
const resizeObserverCallback = (entries: ResizeObserverEntry[]): void => {
|
||||||
for (const entry of entries) {
|
for (const entry of entries) {
|
||||||
galleryItemWidth.value = entry.contentRect.width;
|
galleryItemWidth.value = entry.contentRect.width
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
const resizeObserver = new ResizeObserver(
|
const resizeObserver = new ResizeObserver(debounce(resizeObserverCallback, 1000))
|
||||||
debounce(resizeObserverCallback, 1000)
|
|
||||||
);
|
|
||||||
|
|
||||||
const setActiveImage = (index: number): void => {
|
const setActiveImage = (index: number): void => {
|
||||||
activeImage.value = index;
|
activeImage.value = index
|
||||||
galleryViewport.value.scrollTo({
|
galleryViewport.value.scrollTo({
|
||||||
left: galleryItemWidth.value * index,
|
left: galleryItemWidth.value * index,
|
||||||
behavior: "smooth",
|
behavior: 'smooth'
|
||||||
});
|
})
|
||||||
};
|
}
|
||||||
|
|
||||||
const getActiveImage = (gallery: HTMLElement, itemWidth: number): number => {
|
const getActiveImage = (gallery: HTMLElement, itemWidth: number): number => {
|
||||||
return gallery.scrollLeft / itemWidth;
|
return gallery.scrollLeft / itemWidth
|
||||||
};
|
}
|
||||||
|
|
||||||
const prev = (): void => {
|
const prev = (): void => {
|
||||||
if (activeImage.value > 0) {
|
if (activeImage.value > 0) {
|
||||||
galleryViewport.value.scrollBy({
|
galleryViewport.value.scrollBy({
|
||||||
left: galleryItemWidth.value * -1,
|
left: galleryItemWidth.value * -1,
|
||||||
behavior: "smooth",
|
behavior: 'smooth'
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
const next = (): void => {
|
const next = (): void => {
|
||||||
if (activeImage.value < images.value.length - 1) {
|
if (activeImage.value < images.value.length - 1) {
|
||||||
galleryViewport.value.scrollBy({
|
galleryViewport.value.scrollBy({
|
||||||
left: galleryItemWidth.value,
|
left: galleryItemWidth.value,
|
||||||
behavior: "smooth",
|
behavior: 'smooth'
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
const onScroll = (): void => {
|
const onScroll = (): void => {
|
||||||
const newImg = Math.floor(
|
const newImg = Math.floor(getActiveImage(galleryViewport.value, galleryItemWidth.value))
|
||||||
getActiveImage(galleryViewport.value, galleryItemWidth.value)
|
setActiveImage(newImg)
|
||||||
);
|
}
|
||||||
setActiveImage(newImg);
|
|
||||||
};
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
resizeObserver.observe(galleryViewport.value);
|
resizeObserver.observe(galleryViewport.value)
|
||||||
images.value = Array.from(galleryViewport.value.children);
|
images.value = Array.from(galleryViewport.value.children)
|
||||||
galleryItemWidth.value =
|
galleryItemWidth.value = galleryViewport.value.scrollWidth / images.value.length
|
||||||
galleryViewport.value.scrollWidth / images.value.length;
|
galleryViewport.value.addEventListener('scroll', debounce(onScroll, 500))
|
||||||
galleryViewport.value.addEventListener("scroll", debounce(onScroll, 500));
|
})
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="gallery">
|
<div class="gallery">
|
||||||
<div class="gallery__images">
|
<div class="gallery__images">
|
||||||
<a
|
<a href="#" class="gallery__prev" @click.prevent="prev()" v-show="activeImage > 0"></a>
|
||||||
href="#"
|
|
||||||
class="gallery__prev"
|
|
||||||
@click.prevent="prev()"
|
|
||||||
v-show="activeImage > 0"
|
|
||||||
></a>
|
|
||||||
<a
|
<a
|
||||||
href="#"
|
href="#"
|
||||||
class="gallery__next"
|
class="gallery__next"
|
||||||
|
|
|
@ -1,27 +1,27 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from "vue";
|
import { ref } from 'vue'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
id: string;
|
id: string
|
||||||
}
|
}
|
||||||
|
|
||||||
defineProps<Props>();
|
defineProps<Props>()
|
||||||
|
|
||||||
const modal = ref<HTMLDialogElement>();
|
const modal = ref<HTMLDialogElement>()
|
||||||
|
|
||||||
const showModal = () => {
|
const showModal = () => {
|
||||||
modal.value?.showModal();
|
modal.value?.showModal()
|
||||||
document.body.inert = true;
|
document.body.inert = true
|
||||||
document.body.classList.add("scroll-lock");
|
document.body.classList.add('scroll-lock')
|
||||||
};
|
}
|
||||||
|
|
||||||
const close = () => {
|
const close = () => {
|
||||||
modal.value?.close();
|
modal.value?.close()
|
||||||
document.body.inert = false;
|
document.body.inert = false
|
||||||
document.body.classList.remove("scroll-lock");
|
document.body.classList.remove('scroll-lock')
|
||||||
};
|
}
|
||||||
|
|
||||||
defineExpose({ showModal, close });
|
defineExpose({ showModal, close })
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
|
@ -1,23 +1,23 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from "vue";
|
import { computed } from 'vue'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
modelValue: boolean;
|
modelValue: boolean
|
||||||
id: string;
|
id: string
|
||||||
name?: string;
|
name?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<Props>();
|
const props = defineProps<Props>()
|
||||||
const emit = defineEmits(["update:modelValue"]);
|
const emit = defineEmits(['update:modelValue'])
|
||||||
|
|
||||||
const checked = computed({
|
const checked = computed({
|
||||||
get() {
|
get() {
|
||||||
return props.modelValue;
|
return props.modelValue
|
||||||
},
|
},
|
||||||
set(value) {
|
set(value) {
|
||||||
emit("update:modelValue", value);
|
emit('update:modelValue', value)
|
||||||
},
|
}
|
||||||
});
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -37,9 +37,8 @@ const checked = computed({
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.toggle {
|
.toggle {
|
||||||
font-family: "apple color emoji", "noto color emoji", "segoe ui emoji",
|
font-family: 'apple color emoji', 'noto color emoji', 'segoe ui emoji', 'android emoji',
|
||||||
"android emoji", "emojisymbols", "emojione mozilla", "twemoji mozilla",
|
'emojisymbols', 'emojione mozilla', 'twemoji mozilla', 'segoe ui symbol';
|
||||||
"segoe ui symbol";
|
|
||||||
|
|
||||||
padding: 0.5em;
|
padding: 0.5em;
|
||||||
|
|
||||||
|
@ -84,7 +83,7 @@ const checked = computed({
|
||||||
|
|
||||||
&:before,
|
&:before,
|
||||||
&:after {
|
&:after {
|
||||||
content: "";
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
height: 1.1em;
|
height: 1.1em;
|
||||||
|
|
|
@ -1,16 +1,12 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { RouterLink } from "vue-router";
|
import { RouterLink } from 'vue-router'
|
||||||
import router from "@/router";
|
import router from '@/router'
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<nav class="nav">
|
<nav class="nav">
|
||||||
<ul class="nav__list">
|
<ul class="nav__list">
|
||||||
<li
|
<li class="nav__item" v-for="(route, idx) in router.options.routes" :key="idx">
|
||||||
class="nav__item"
|
|
||||||
v-for="(route, idx) in router.options.routes"
|
|
||||||
:key="idx"
|
|
||||||
>
|
|
||||||
<RouterLink class="nav__link" :to="route.path">
|
<RouterLink class="nav__link" :to="route.path">
|
||||||
{{ route.name }}
|
{{ route.name }}
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
|
@ -75,7 +71,7 @@ import router from "@/router";
|
||||||
|
|
||||||
&:before,
|
&:before,
|
||||||
&:after {
|
&:after {
|
||||||
content: "";
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
|
||||||
|
|
|
@ -68,7 +68,7 @@
|
||||||
|
|
||||||
&__mainline,
|
&__mainline,
|
||||||
&__subline {
|
&__subline {
|
||||||
font-family: "Exo", sans-serif;
|
font-family: 'Exo', sans-serif;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|
|
@ -1,76 +1,67 @@
|
||||||
const debounce = (fn: Function, delay: number = 300): any => {
|
const debounce = (fn: Function, delay: number = 300): any => {
|
||||||
let timer = 0;
|
let timer = 0
|
||||||
const debounced = (...args: any[]): void => {
|
const debounced = (...args: any[]): void => {
|
||||||
if (!args) args = [];
|
if (!args) args = []
|
||||||
clearTimeout(timer);
|
clearTimeout(timer)
|
||||||
|
|
||||||
timer = setTimeout(() => {
|
timer = setTimeout(() => {
|
||||||
fn.apply(fn, args);
|
fn.apply(fn, args)
|
||||||
}, delay);
|
}, delay)
|
||||||
};
|
}
|
||||||
|
|
||||||
return debounced;
|
return debounced
|
||||||
};
|
}
|
||||||
|
|
||||||
const getClientLocale = (): string => {
|
const getClientLocale = (): string => {
|
||||||
return navigator.languages.length > 0 ? navigator.languages[0] : "en-US";
|
return navigator.languages.length > 0 ? navigator.languages[0] : 'en-US'
|
||||||
};
|
}
|
||||||
|
|
||||||
const getAge = (dateOfBirth: Date): number => {
|
const getAge = (dateOfBirth: Date): number => {
|
||||||
const today = new Date();
|
const today = new Date()
|
||||||
|
|
||||||
const thisYear = today.getFullYear();
|
const thisYear = today.getFullYear()
|
||||||
const thisMonth = today.getMonth();
|
const thisMonth = today.getMonth()
|
||||||
const thisDay = today.getDate();
|
const thisDay = today.getDate()
|
||||||
|
|
||||||
const dobYear = dateOfBirth.getFullYear();
|
const dobYear = dateOfBirth.getFullYear()
|
||||||
const dobMonth = dateOfBirth.getMonth();
|
const dobMonth = dateOfBirth.getMonth()
|
||||||
const dobDay = dateOfBirth.getDate();
|
const dobDay = dateOfBirth.getDate()
|
||||||
|
|
||||||
let age = thisYear - dobYear;
|
let age = thisYear - dobYear
|
||||||
|
|
||||||
if (thisMonth < dobMonth) age--;
|
if (thisMonth < dobMonth) age--
|
||||||
if (thisMonth === dobMonth && thisDay < dobDay) age--;
|
if (thisMonth === dobMonth && thisDay < dobDay) age--
|
||||||
|
|
||||||
return age;
|
return age
|
||||||
};
|
}
|
||||||
|
|
||||||
const toImperial = (cm: number): string => {
|
const toImperial = (cm: number): string => {
|
||||||
const realFeet = (cm * 0.3937) / 12;
|
const realFeet = (cm * 0.3937) / 12
|
||||||
const feet = Math.floor(realFeet);
|
const feet = Math.floor(realFeet)
|
||||||
const inches = Math.round((realFeet - feet) * 12);
|
const inches = Math.round((realFeet - feet) * 12)
|
||||||
|
|
||||||
return `${feet}'${inches}"`;
|
return `${feet}'${inches}"`
|
||||||
};
|
}
|
||||||
|
|
||||||
const toInch = (cm: number): string => {
|
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 toLbs = (kg: number): number => {
|
||||||
const nearExact = kg / 0.45359237;
|
const nearExact = kg / 0.45359237
|
||||||
const lbs = Math.floor(nearExact);
|
const lbs = Math.floor(nearExact)
|
||||||
|
|
||||||
return lbs;
|
return lbs
|
||||||
};
|
}
|
||||||
|
|
||||||
const toFahrenheit = (celsius: number): number => {
|
const toFahrenheit = (celsius: number): number => {
|
||||||
return celsius * 1.8 + 32;
|
return celsius * 1.8 + 32
|
||||||
};
|
}
|
||||||
|
|
||||||
const dateFormat = new Intl.DateTimeFormat(getClientLocale(), {
|
const dateFormat = new Intl.DateTimeFormat(getClientLocale(), {
|
||||||
year: "numeric",
|
year: 'numeric',
|
||||||
month: "long",
|
month: 'long',
|
||||||
day: "2-digit",
|
day: '2-digit'
|
||||||
});
|
})
|
||||||
|
|
||||||
export {
|
export { debounce, getClientLocale, getAge, toImperial, toInch, toLbs, toFahrenheit, dateFormat }
|
||||||
debounce,
|
|
||||||
getClientLocale,
|
|
||||||
getAge,
|
|
||||||
toImperial,
|
|
||||||
toInch,
|
|
||||||
toLbs,
|
|
||||||
toFahrenheit,
|
|
||||||
dateFormat,
|
|
||||||
};
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
interface ColorDict {
|
interface ColorDict {
|
||||||
name: string;
|
name: string
|
||||||
value: string;
|
value: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Kink {
|
interface Kink {
|
||||||
name: string;
|
name: string
|
||||||
receive: boolean;
|
receive: boolean
|
||||||
give: boolean;
|
give: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export type { ColorDict, Kink };
|
export type { ColorDict, Kink }
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import type { InjectionKey, Ref } from "vue";
|
import type { InjectionKey, Ref } from 'vue'
|
||||||
|
|
||||||
export const nsfwKey: InjectionKey<Ref<boolean>> = Symbol("nsfwKey");
|
export const nsfwKey: InjectionKey<Ref<boolean>> = Symbol('nsfwKey')
|
||||||
export const showModalKey: InjectionKey<Function> = Symbol("showModalKey");
|
export const showModalKey: InjectionKey<Function> = Symbol('showModalKey')
|
||||||
export const modalResultKey: InjectionKey<Function> = Symbol("modalResultKey");
|
export const modalResultKey: InjectionKey<Function> = Symbol('modalResultKey')
|
||||||
|
|
16
src/main.ts
16
src/main.ts
|
@ -1,12 +1,12 @@
|
||||||
import { createApp } from "vue";
|
import { createApp } from 'vue'
|
||||||
import App from "./App.vue";
|
import App from './App.vue'
|
||||||
import router from "./router";
|
import router from './router'
|
||||||
|
|
||||||
import "normalize.css";
|
import 'normalize.css'
|
||||||
import "@/scss/main.scss";
|
import '@/scss/main.scss'
|
||||||
|
|
||||||
const app = createApp(App);
|
const app = createApp(App)
|
||||||
|
|
||||||
app.use(router);
|
app.use(router)
|
||||||
|
|
||||||
app.mount("body");
|
app.mount('body')
|
||||||
|
|
|
@ -1,43 +1,43 @@
|
||||||
import { createRouter, createWebHistory } from "vue-router";
|
import { createRouter, createWebHistory } from 'vue-router'
|
||||||
import HomeView from "@/views/HomeView.vue";
|
import HomeView from '@/views/HomeView.vue'
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHistory(import.meta.env.BASE_URL),
|
history: createWebHistory(import.meta.env.BASE_URL),
|
||||||
scrollBehavior() {
|
scrollBehavior() {
|
||||||
return { top: 0, behavior: "smooth" };
|
return { top: 0, behavior: 'smooth' }
|
||||||
},
|
},
|
||||||
routes: [
|
routes: [
|
||||||
{
|
{
|
||||||
path: "/",
|
path: '/',
|
||||||
name: "home",
|
name: 'home',
|
||||||
component: HomeView,
|
component: HomeView
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/general",
|
path: '/general',
|
||||||
name: "general",
|
name: 'general',
|
||||||
component: () => import("@/views/GeneralView.vue"),
|
component: () => import('@/views/GeneralView.vue')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/anatomy",
|
path: '/anatomy',
|
||||||
name: "anatomy",
|
name: 'anatomy',
|
||||||
component: () => import("@/views/AnatomyView.vue"),
|
component: () => import('@/views/AnatomyView.vue')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/clothing",
|
path: '/clothing',
|
||||||
name: "clothing",
|
name: 'clothing',
|
||||||
component: () => import("@/views/ClothingView.vue"),
|
component: () => import('@/views/ClothingView.vue')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/abilities",
|
path: '/abilities',
|
||||||
name: "abilities",
|
name: 'abilities',
|
||||||
component: () => import("@/views/AbilitiesView.vue"),
|
component: () => import('@/views/AbilitiesView.vue')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/overdrive",
|
path: '/overdrive',
|
||||||
name: "overdrive",
|
name: 'overdrive',
|
||||||
component: () => import("@/views/OverdriveView.vue"),
|
component: () => import('@/views/OverdriveView.vue')
|
||||||
},
|
}
|
||||||
],
|
]
|
||||||
});
|
})
|
||||||
|
|
||||||
export default router;
|
export default router
|
||||||
|
|
80
src/sebin.ts
80
src/sebin.ts
|
@ -1,51 +1,51 @@
|
||||||
export const firstName = "Sebin",
|
export const firstName = 'Sebin',
|
||||||
middleName = "Antario",
|
middleName = 'Antario',
|
||||||
lastName = "Nyshkim",
|
lastName = 'Nyshkim',
|
||||||
dateOfBirth = new Date("1993-10-17"),
|
dateOfBirth = new Date('1993-10-17'),
|
||||||
gender = "male ♂️",
|
gender = 'male ♂️',
|
||||||
orientation = "gay",
|
orientation = 'gay',
|
||||||
position = "vers, prefers top",
|
position = 'vers, prefers top',
|
||||||
height = 210, // cm
|
height = 210, // cm
|
||||||
weight = 124, // kg
|
weight = 124, // kg
|
||||||
tailLength = 104, // cm
|
tailLength = 104, // cm
|
||||||
wingspan = 417, // cm
|
wingspan = 417, // cm
|
||||||
colors = {
|
colors = {
|
||||||
hairPrimary: "#4b608f",
|
hairPrimary: '#4b608f',
|
||||||
hairSecondary: "#6684c0",
|
hairSecondary: '#6684c0',
|
||||||
eyes: "#31c215",
|
eyes: '#31c215',
|
||||||
scalesPrimary: "#c64c35",
|
scalesPrimary: '#c64c35',
|
||||||
scalesSecondary: "#eda958",
|
scalesSecondary: '#eda958',
|
||||||
eyebrows: "#eda958",
|
eyebrows: '#eda958',
|
||||||
tailspikes: "#7f4539",
|
tailspikes: '#7f4539',
|
||||||
horns: "#413a3a",
|
horns: '#413a3a',
|
||||||
claws: "#413a3a",
|
claws: '#413a3a',
|
||||||
nipples: "#413a3a",
|
nipples: '#413a3a',
|
||||||
penis: "#413a3a",
|
penis: '#413a3a'
|
||||||
},
|
},
|
||||||
hobbies = ["working out", "travels", "camping", "video games", "tech"],
|
hobbies = ['working out', 'travels', 'camping', 'video games', 'tech'],
|
||||||
penis = {
|
penis = {
|
||||||
shape: "humanoid",
|
shape: 'humanoid',
|
||||||
type: "grower",
|
type: 'grower',
|
||||||
special: "ridged, no foreskin",
|
special: 'ridged, no foreskin',
|
||||||
size: 20, // cm
|
size: 20, // cm
|
||||||
girth: 5, // cm
|
girth: 5 // cm
|
||||||
},
|
},
|
||||||
kinks = [
|
kinks = [
|
||||||
{ name: "Oral", receive: true, give: true },
|
{ name: 'Oral', receive: true, give: true },
|
||||||
{ name: "Anal", receive: true, give: true },
|
{ name: 'Anal', receive: true, give: true },
|
||||||
{ name: "Facial", receive: true, give: true },
|
{ name: 'Facial', receive: true, give: true },
|
||||||
{ name: "Creampie", receive: true, give: true },
|
{ name: 'Creampie', receive: true, give: true },
|
||||||
{ name: "Bukkake", receive: true, give: true },
|
{ name: 'Bukkake', receive: true, give: true },
|
||||||
{ name: "Biting", receive: true, give: true },
|
{ name: 'Biting', receive: true, give: true },
|
||||||
{ name: "Nipple Play", receive: true, give: true },
|
{ name: 'Nipple Play', receive: true, give: true },
|
||||||
{ name: "Rough", receive: true, give: true },
|
{ name: 'Rough', receive: true, give: true },
|
||||||
{ name: "Toys", receive: true, give: true },
|
{ name: 'Toys', receive: true, give: true },
|
||||||
|
|
||||||
{ name: "Frotting", receive: true, give: true },
|
{ name: 'Frotting', receive: true, give: true },
|
||||||
{ name: "Muscle Worship", receive: true, give: true },
|
{ name: 'Muscle Worship', receive: true, give: true },
|
||||||
{ name: "Filled Condoms", receive: true, give: true },
|
{ name: 'Filled Condoms', receive: true, give: true },
|
||||||
{ name: "Growth/Macro", receive: true, give: true },
|
{ name: 'Growth/Macro', receive: true, give: true },
|
||||||
{ name: "Size Difference", receive: true, give: true },
|
{ name: 'Size Difference', receive: true, give: true },
|
||||||
{ name: "Underwear", receive: true, give: true },
|
{ name: 'Underwear', receive: true, give: true },
|
||||||
{ name: "Chubbies", receive: true, give: true },
|
{ name: 'Chubbies', receive: true, give: true }
|
||||||
];
|
]
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import AttackItem from "@/components/AttackItem.vue";
|
import AttackItem from '@/components/AttackItem.vue'
|
||||||
import AttackList from "@/components/AttackList.vue";
|
import AttackList from '@/components/AttackList.vue'
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -8,8 +8,8 @@ import AttackList from "@/components/AttackList.vue";
|
||||||
<h1>{{ $route.name }}</h1>
|
<h1>{{ $route.name }}</h1>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Since Sebin is a fire dragon there's a myriad of abilities he has at his
|
Since Sebin is a fire dragon there's a myriad of abilities he has at his disposal to defend
|
||||||
disposal to defend himself.
|
himself.
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
@ -48,12 +48,10 @@ import AttackList from "@/components/AttackList.vue";
|
||||||
</template>
|
</template>
|
||||||
<template #name>Fire Breath</template>
|
<template #name>Fire Breath</template>
|
||||||
<template #desc>
|
<template #desc>
|
||||||
Like most fire dragons, Sebin can breathe fire. In order to do this, he
|
Like most fire dragons, Sebin can breathe fire. In order to do this, he takes a deep breath
|
||||||
takes a deep breath to enrich the oxygen in his lungs with gases, which,
|
to enrich the oxygen in his lungs with gases, which, together with special glands in his
|
||||||
together with special glands in his mouth, produce a combustible
|
mouth, produce a combustible mixture. The resulting jet of fire, reaching several hundred
|
||||||
mixture. The resulting jet of fire, reaching several hundred degrees
|
degrees Celsius, spreads out on its way to its target, scorching everything in its path.
|
||||||
Celsius, spreads out on its way to its target, scorching everything in
|
|
||||||
its path.
|
|
||||||
</template>
|
</template>
|
||||||
</AttackItem>
|
</AttackItem>
|
||||||
|
|
||||||
|
@ -87,11 +85,10 @@ import AttackList from "@/components/AttackList.vue";
|
||||||
</template>
|
</template>
|
||||||
<template #name>Flame Toss</template>
|
<template #name>Flame Toss</template>
|
||||||
<template #desc>
|
<template #desc>
|
||||||
By spitting fire into his hands, Sebin can form it into a ball and use
|
By spitting fire into his hands, Sebin can form it into a ball and use it as a projectile.
|
||||||
it as a projectile. His scales are fireproof and can withstand the high
|
His scales are fireproof and can withstand the high temperatures. Due to their high
|
||||||
temperatures. Due to their high concentration, the projectiles explode
|
concentration, the projectiles explode upon impact. By combining two fireballs the explosion
|
||||||
upon impact. By combining two fireballs the explosion radius increases
|
radius increases dramatically.
|
||||||
dramatically.
|
|
||||||
</template>
|
</template>
|
||||||
</AttackItem>
|
</AttackItem>
|
||||||
|
|
||||||
|
@ -125,10 +122,9 @@ import AttackList from "@/components/AttackList.vue";
|
||||||
</template>
|
</template>
|
||||||
<template #name>Kindled Fist</template>
|
<template #name>Kindled Fist</template>
|
||||||
<template #desc>
|
<template #desc>
|
||||||
Apart from throwing projectiles, Sebin can also use the fireballs to
|
Apart from throwing projectiles, Sebin can also use the fireballs to wrap his fists in fire.
|
||||||
wrap his fists in fire. This allows him to inflict severe burns on his
|
This allows him to inflict severe burns on his opponent with each blow. In addition, he can
|
||||||
opponent with each blow. In addition, he can release the fire from his
|
release the fire from his fists with aimed blows and hurl it at his opponents.
|
||||||
fists with aimed blows and hurl it at his opponents.
|
|
||||||
</template>
|
</template>
|
||||||
</AttackItem>
|
</AttackItem>
|
||||||
|
|
||||||
|
@ -162,9 +158,8 @@ import AttackList from "@/components/AttackList.vue";
|
||||||
</template>
|
</template>
|
||||||
<template #name>Burning Twister</template>
|
<template #name>Burning Twister</template>
|
||||||
<template #desc>
|
<template #desc>
|
||||||
A technique used in aerial combat, Sebin uses his fire breath to engulf
|
A technique used in aerial combat, Sebin uses his fire breath to engulf his body in flames
|
||||||
his body in flames while spinning to become a fire tornado that singes
|
while spinning to become a fire tornado that singes opponents.
|
||||||
opponents.
|
|
||||||
</template>
|
</template>
|
||||||
</AttackItem>
|
</AttackItem>
|
||||||
</AttackList>
|
</AttackList>
|
||||||
|
|
|
@ -1,39 +1,39 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { inject } from "vue";
|
import { inject } from 'vue'
|
||||||
import { nsfwKey, showModalKey } from "@/keys";
|
import { nsfwKey, showModalKey } from '@/keys'
|
||||||
import type { ColorDict } from "@/interfaces";
|
import type { ColorDict } from '@/interfaces'
|
||||||
import { tailLength, wingspan, penis, colors } from "@/sebin";
|
import { tailLength, wingspan, penis, colors } from '@/sebin'
|
||||||
import { toImperial, toFahrenheit } from "@/helpers";
|
import { toImperial, toFahrenheit } from '@/helpers'
|
||||||
import RefToggle from "@/components/RefToggle.vue";
|
import RefToggle from '@/components/RefToggle.vue'
|
||||||
import RefGallery from "@/components/RefGallery.vue";
|
import RefGallery from '@/components/RefGallery.vue'
|
||||||
import RefFigure from "@/components/RefFigure.vue";
|
import RefFigure from '@/components/RefFigure.vue'
|
||||||
import ColorTable from "@/components/ColorTable.vue";
|
import ColorTable from '@/components/ColorTable.vue'
|
||||||
import DataTable from "@/components/DataTable.vue";
|
import DataTable from '@/components/DataTable.vue'
|
||||||
import QuickFacts from "@/components/QuickFacts.vue";
|
import QuickFacts from '@/components/QuickFacts.vue'
|
||||||
|
|
||||||
const sebinColors: ColorDict[] = [
|
const sebinColors: ColorDict[] = [
|
||||||
{ name: "Scales", value: colors.scalesPrimary },
|
{ name: 'Scales', value: colors.scalesPrimary },
|
||||||
{ name: "Chest, Wings (front)", value: colors.scalesSecondary },
|
{ name: 'Chest, Wings (front)', value: colors.scalesSecondary },
|
||||||
{ name: "Hair", value: colors.hairPrimary },
|
{ name: 'Hair', value: colors.hairPrimary },
|
||||||
{ name: "Hair Streaks (optional)", value: colors.hairSecondary },
|
{ name: 'Hair Streaks (optional)', value: colors.hairSecondary },
|
||||||
{ name: "Eyes", value: colors.eyes },
|
{ name: 'Eyes', value: colors.eyes },
|
||||||
{ name: "Facial Spikes", value: colors.eyebrows },
|
{ name: 'Facial Spikes', value: colors.eyebrows },
|
||||||
{ name: "Horns/Claws/Nipples", value: colors.horns },
|
{ name: 'Horns/Claws/Nipples', value: colors.horns },
|
||||||
{ name: "Tail Spikes", value: colors.tailspikes },
|
{ name: 'Tail Spikes', value: colors.tailspikes }
|
||||||
];
|
]
|
||||||
|
|
||||||
const sebinPenisHeadings = ["Key", "Value"];
|
const sebinPenisHeadings = ['Key', 'Value']
|
||||||
const sebinPenisData = [
|
const sebinPenisData = [
|
||||||
["Shape", penis.shape],
|
['Shape', penis.shape],
|
||||||
["Type", penis.type],
|
['Type', penis.type],
|
||||||
["Special Traits", penis.special],
|
['Special Traits', penis.special],
|
||||||
["Color", colors.penis],
|
['Color', colors.penis],
|
||||||
["Length", `${penis.size} cm (${toImperial(penis.size)})`],
|
['Length', `${penis.size} cm (${toImperial(penis.size)})`],
|
||||||
["Girth", `${penis.girth} cm (${toImperial(penis.girth)})`],
|
['Girth', `${penis.girth} cm (${toImperial(penis.girth)})`]
|
||||||
];
|
]
|
||||||
|
|
||||||
const isNsfw = inject<boolean>(nsfwKey, false);
|
const isNsfw = inject<boolean>(nsfwKey, false)
|
||||||
const showModal = inject<Function>(showModalKey, Function);
|
const showModal = inject<Function>(showModalKey, Function)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -137,11 +137,7 @@ const showModal = inject<Function>(showModalKey, Function);
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #caption>
|
<template #caption>
|
||||||
<RefToggle
|
<RefToggle id="sebin-fullbody-ref" v-model="isNsfw" @click.prevent="showModal()">
|
||||||
id="sebin-fullbody-ref"
|
|
||||||
v-model="isNsfw"
|
|
||||||
@click.prevent="showModal()"
|
|
||||||
>
|
|
||||||
<template #off>😇</template>
|
<template #off>😇</template>
|
||||||
<template #on>😈</template>
|
<template #on>😈</template>
|
||||||
</RefToggle>
|
</RefToggle>
|
||||||
|
@ -165,24 +161,19 @@ const showModal = inject<Function>(showModalKey, Function);
|
||||||
<li>Athletic to body builder physique</li>
|
<li>Athletic to body builder physique</li>
|
||||||
<li>Sharp, black claws on fingers and toes</li>
|
<li>Sharp, black claws on fingers and toes</li>
|
||||||
<li>Brown blunt spikes running over back and top-side of tail</li>
|
<li>Brown blunt spikes running over back and top-side of tail</li>
|
||||||
<li>
|
<li>Tail about {{ tailLength / 100 }} meter ({{ toImperial(tailLength) }}) in length</li>
|
||||||
Tail about {{ tailLength / 100 }} meter ({{ toImperial(tailLength) }})
|
|
||||||
in length
|
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</QuickFacts>
|
</QuickFacts>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
As the offspring of a union between human and dragon, Sebin is a bipedal
|
As the offspring of a union between human and dragon, Sebin is a bipedal plantigrade. The
|
||||||
plantigrade. The majority of his body is covered in red scales. A strip of
|
majority of his body is covered in red scales. A strip of yellow scales runs from the
|
||||||
yellow scales runs from the underside of his jaw, extending down his chest
|
underside of his jaw, extending down his chest through his legs to the underside of the tip of
|
||||||
through his legs to the underside of the tip of his tail. The scales on
|
his tail. The scales on his chest are characterized by a special toughness to better protect
|
||||||
his chest are characterized by a special toughness to better protect vital
|
vital organs. He also has an athletic to muscular physique that he continuously tends to keep
|
||||||
organs. He also has an athletic to muscular physique that he continuously
|
in shape. Finger and toe tips are armed with sharp, black claws, which serve him equally as
|
||||||
tends to keep in shape. Finger and toe tips are armed with sharp, black
|
tools and weapons. Brown spines run from head to spine to tip of tail, though they are too
|
||||||
claws, which serve him equally as tools and weapons. Brown spines run from
|
blunt to pose a risk of injury. His tail is about
|
||||||
head to spine to tip of tail, though they are too blunt to pose a risk of
|
|
||||||
injury. His tail is about
|
|
||||||
{{ tailLength / 100 }} meters ({{ toImperial(tailLength) }}) in length.
|
{{ tailLength / 100 }} meters ({{ toImperial(tailLength) }}) in length.
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
|
@ -192,9 +183,7 @@ const showModal = inject<Function>(showModalKey, Function);
|
||||||
|
|
||||||
<QuickFacts :cols="2">
|
<QuickFacts :cols="2">
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>Wingspan {{ wingspan / 100 }} meters ({{ toImperial(wingspan) }})</li>
|
||||||
Wingspan {{ wingspan / 100 }} meters ({{ toImperial(wingspan) }})
|
|
||||||
</li>
|
|
||||||
<li>Closed when on the ground</li>
|
<li>Closed when on the ground</li>
|
||||||
<li>Function like a second pair of arms</li>
|
<li>Function like a second pair of arms</li>
|
||||||
<li>Pointy talon on end of "hand"</li>
|
<li>Pointy talon on end of "hand"</li>
|
||||||
|
@ -202,17 +191,14 @@ const showModal = inject<Function>(showModalKey, Function);
|
||||||
</QuickFacts>
|
</QuickFacts>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Sebin's wings have a span of about {{ wingspan / 100 }} meters ({{
|
Sebin's wings have a span of about {{ wingspan / 100 }} meters ({{ toImperial(wingspan) }}).
|
||||||
toImperial(wingspan)
|
They function very much like a second pair of arms: two interconnected limbs that form a
|
||||||
}}). They function very much like a second pair of arms: two
|
bendable arm, at the end of which sits a hand-like structure, adorned with a talon in exchange
|
||||||
interconnected limbs that form a bendable arm, at the end of which sits a
|
for a thumb, with a sturdy membrane stretched between its long fingers. On solid ground, he
|
||||||
hand-like structure, adorned with a talon in exchange for a thumb, with a
|
keeps his wings closed so as not to accidentally bump into anything with them. Sebin also pays
|
||||||
sturdy membrane stretched between its long fingers. On solid ground, he
|
a lot of attention to his wings when working out, so that they can keep carrying him reliably
|
||||||
keeps his wings closed so as not to accidentally bump into anything with
|
through the air. Though, he only travels short to medium distances through the air before he
|
||||||
them. Sebin also pays a lot of attention to his wings when working out, so
|
has to take a rest - as long as the airspace in the area has been declared open for wing
|
||||||
that they can keep carrying him reliably through the air. Though, he only
|
|
||||||
travels short to medium distances through the air before he has to take a
|
|
||||||
rest - as long as the airspace in the area has been declared open for wing
|
|
||||||
bearers.
|
bearers.
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
|
@ -291,20 +277,17 @@ const showModal = inject<Function>(showModalKey, Function);
|
||||||
</QuickFacts>
|
</QuickFacts>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Despite what one might expect with reptilians, Sebin's pupils are rounded
|
Despite what one might expect with reptilians, Sebin's pupils are rounded instead of
|
||||||
instead of slit-shaped. Yellow spikes running above his eyelids serve as
|
slit-shaped. Yellow spikes running above his eyelids serve as eyebrows. These spikes are also
|
||||||
eyebrows. These spikes are also found along his jaw bone. Two pointed,
|
found along his jaw bone. Two pointed, slightly curved, black horns protrude from his head. He
|
||||||
slightly curved, black horns protrude from his head. He usually wears his
|
usually wears his medium-length, blue hair loose. His long, pointed ears are very flexible,
|
||||||
medium-length, blue hair loose. His long, pointed ears are very flexible,
|
allowing him to hear sounds around him without having to turn his head. They are also used for
|
||||||
allowing him to hear sounds around him without having to turn his head.
|
non-verbal communication, to express emotions through body language. His hearing perceives a
|
||||||
They are also used for non-verbal communication, to express emotions
|
wider range of frequencies, making it superior to that of a human. His jaws are equipped with
|
||||||
through body language. His hearing perceives a wider range of frequencies,
|
razor-sharp teeth that effortlessly sink into anything he manages to bite, be it nourishment
|
||||||
making it superior to that of a human. His jaws are equipped with
|
or adversaries. Embedded between them lies his tongue, which is typically pointed for
|
||||||
razor-sharp teeth that effortlessly sink into anything he manages to bite,
|
reptilians. Glands in his throat produce a mixture which he uses to spit fire, which can reach
|
||||||
be it nourishment or adversaries. Embedded between them lies his tongue,
|
up to around 100 °C ({{ toFahrenheit(100) }} °F).
|
||||||
which is typically pointed for reptilians. Glands in his throat produce a
|
|
||||||
mixture which he uses to spit fire, which can reach up to around 100 °C
|
|
||||||
({{ toFahrenheit(100) }} °F).
|
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
@ -318,18 +301,17 @@ const showModal = inject<Function>(showModalKey, Function);
|
||||||
<li>Defined abs</li>
|
<li>Defined abs</li>
|
||||||
<li>Black nipples</li>
|
<li>Black nipples</li>
|
||||||
<li>
|
<li>
|
||||||
Any muscle mass from athletic to body builder is fine, with a
|
Any muscle mass from athletic to body builder is fine, with a preference towards body
|
||||||
preference towards body builder
|
builder
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</QuickFacts>
|
</QuickFacts>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
At the age of 17, Sebin gradually began to keep his body in shape on a
|
At the age of 17, Sebin gradually began to keep his body in shape on a regular basis. His
|
||||||
regular basis. His favorite exercises include weightlifting (with both
|
favorite exercises include weightlifting (with both dumbbells and barbells), lat pulldown, leg
|
||||||
dumbbells and barbells), lat pulldown, leg press and cable curls. He works
|
press and cable curls. He works out three days a week with one day off between training days,
|
||||||
out three days a week with one day off between training days, rotating the
|
rotating the body regions he trains each day.
|
||||||
body regions he trains each day.
|
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
@ -369,10 +351,9 @@ const showModal = inject<Function>(showModalKey, Function);
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<p>
|
<p>
|
||||||
Sebin is very concerned with an even distribution of muscle mass, but pays
|
Sebin is very concerned with an even distribution of muscle mass, but pays particular
|
||||||
particular attention to his back, chest and arms. A strong chest with
|
attention to his back, chest and arms. A strong chest with strong arms helps to throw fire
|
||||||
strong arms helps to throw fire projectiles as far as possible. A strong
|
projectiles as far as possible. A strong back guarantees a longer stay in the air.
|
||||||
back guarantees a longer stay in the air.
|
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
@ -510,9 +491,7 @@ const showModal = inject<Function>(showModalKey, Function);
|
||||||
</template>
|
</template>
|
||||||
<template #caption>Sebin flexing</template>
|
<template #caption>Sebin flexing</template>
|
||||||
<template #copyright>
|
<template #copyright>
|
||||||
<a href="https://www.furaffinity.net/user/Marsel-Defender">
|
<a href="https://www.furaffinity.net/user/Marsel-Defender"> Marsel-Defender </a>
|
||||||
Marsel-Defender
|
|
||||||
</a>
|
|
||||||
</template>
|
</template>
|
||||||
</RefFigure>
|
</RefFigure>
|
||||||
<RefFigure id="sebin-muscle-ref4" polaroidBorder nsfw>
|
<RefFigure id="sebin-muscle-ref4" polaroidBorder nsfw>
|
||||||
|
@ -791,16 +770,12 @@ const showModal = inject<Function>(showModalKey, Function);
|
||||||
<template #img>
|
<template #img>
|
||||||
<picture>
|
<picture>
|
||||||
<source
|
<source
|
||||||
srcset="
|
srcset="@/assets/refs/sebin-ref-penis.png?w=480;720;0&avif&quality=75&srcset"
|
||||||
@/assets/refs/sebin-ref-penis.png?w=480;720;0&avif&quality=75&srcset
|
|
||||||
"
|
|
||||||
sizes="(min-width: 45em) 1155px, (min-width: 30em) 720px, 480px"
|
sizes="(min-width: 45em) 1155px, (min-width: 30em) 720px, 480px"
|
||||||
type="image/avif"
|
type="image/avif"
|
||||||
/>
|
/>
|
||||||
<source
|
<source
|
||||||
srcset="
|
srcset="@/assets/refs/sebin-ref-penis.png?w=480;720;0&webp&quality=100&srcset"
|
||||||
@/assets/refs/sebin-ref-penis.png?w=480;720;0&webp&quality=100&srcset
|
|
||||||
"
|
|
||||||
sizes="(min-width: 45em) 1155px, (min-width: 30em) 720px, 480px"
|
sizes="(min-width: 45em) 1155px, (min-width: 30em) 720px, 480px"
|
||||||
type="image/webp"
|
type="image/webp"
|
||||||
/>
|
/>
|
||||||
|
@ -827,24 +802,20 @@ const showModal = inject<Function>(showModalKey, Function);
|
||||||
<ul>
|
<ul>
|
||||||
<li>Human-shaped with ridges</li>
|
<li>Human-shaped with ridges</li>
|
||||||
<li>Ring-like sheath surrounding shaft</li>
|
<li>Ring-like sheath surrounding shaft</li>
|
||||||
<li>
|
<li>Extends from sheath when erect, lives inside sheath when not erect</li>
|
||||||
Extends from sheath when erect, lives inside sheath when not erect
|
|
||||||
</li>
|
|
||||||
<li>External balls</li>
|
<li>External balls</li>
|
||||||
</ul>
|
</ul>
|
||||||
</QuickFacts>
|
</QuickFacts>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Despite his reptilian appearance, Sebin has nipples, a feature of the
|
Despite his reptilian appearance, Sebin has nipples, a feature of the human side of his
|
||||||
human side of his family. Furthermore, his external testicles represent
|
family. Furthermore, his external testicles represent another humanized feature. Where
|
||||||
another humanized feature. Where relatives of his ilk possess a slit in
|
relatives of his ilk possess a slit in which the penis lies protectively, Sebin possesses a
|
||||||
which the penis lies protectively, Sebin possesses a pouch-like sheath
|
pouch-like sheath from which the tip of the penis protrudes slightly. The shape of his shaft
|
||||||
from which the tip of the penis protrudes slightly. The shape of his
|
is predominantly humanoid, but it is surrounded by ridges and has no equivalent of a
|
||||||
shaft is predominantly humanoid, but it is surrounded by ridges and has
|
foreskin. When aroused, the coal-black shaft swells and pushes out of the sheath until fully
|
||||||
no equivalent of a foreskin. When aroused, the coal-black shaft swells
|
erect, the sheath wrapping around the root of the shaft like a ring. However, he can also
|
||||||
and pushes out of the sheath until fully erect, the sheath wrapping
|
push it out in a flaccid state, e.g. when needing to pass water.
|
||||||
around the root of the shaft like a ring. However, he can also push it
|
|
||||||
out in a flaccid state, e.g. when needing to pass water.
|
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
@ -854,16 +825,12 @@ const showModal = inject<Function>(showModalKey, Function);
|
||||||
<h2>But, wait! There's more...</h2>
|
<h2>But, wait! There's more...</h2>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Sebin like you haven't seen him yet! Flip the switch to reveal his
|
Sebin like you haven't seen him yet! Flip the switch to reveal his naughty secrets. If you
|
||||||
naughty secrets. If you dare...! Don't say I didn't warn you!!
|
dare...! Don't say I didn't warn you!!
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<RefToggle
|
<RefToggle id="sebin-manly-bits" v-model="isNsfw" @click.prevent="showModal()">
|
||||||
id="sebin-manly-bits"
|
|
||||||
v-model="isNsfw"
|
|
||||||
@click.prevent="showModal()"
|
|
||||||
>
|
|
||||||
<template #off>😇</template>
|
<template #off>😇</template>
|
||||||
<template #on>😈</template>
|
<template #on>😈</template>
|
||||||
</RefToggle>
|
</RefToggle>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import RefFigure from "@/components/RefFigure.vue";
|
import RefFigure from '@/components/RefFigure.vue'
|
||||||
import RefGallery from "@/components/RefGallery.vue";
|
import RefGallery from '@/components/RefGallery.vue'
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -40,9 +40,7 @@ import RefGallery from "@/components/RefGallery.vue";
|
||||||
|
|
||||||
<template #caption>
|
<template #caption>
|
||||||
<p>Sebin in his casual outfit</p>
|
<p>Sebin in his casual outfit</p>
|
||||||
<p>
|
<p>Black tank top, flannell shirt, shorts (w/ dangling bands), sneakers</p>
|
||||||
Black tank top, flannell shirt, shorts (w/ dangling bands), sneakers
|
|
||||||
</p>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #copyright>
|
<template #copyright>
|
||||||
|
@ -117,8 +115,7 @@ import RefGallery from "@/components/RefGallery.vue";
|
||||||
<template #caption>
|
<template #caption>
|
||||||
<p>Sebin in his workout outfit</p>
|
<p>Sebin in his workout outfit</p>
|
||||||
<p>
|
<p>
|
||||||
<strong>Full body:</strong> Snapback hat, tank top, fingerless gloves,
|
<strong>Full body:</strong> Snapback hat, tank top, fingerless gloves, shorts, sneakers
|
||||||
shorts, sneakers
|
|
||||||
</p>
|
</p>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -157,8 +154,8 @@ import RefGallery from "@/components/RefGallery.vue";
|
||||||
<template #caption>
|
<template #caption>
|
||||||
<p>Sebin in his workout outfit</p>
|
<p>Sebin in his workout outfit</p>
|
||||||
<p>
|
<p>
|
||||||
<strong>Close-up:</strong> Snapback hat, headphones, tank top,
|
<strong>Close-up:</strong> Snapback hat, headphones, tank top, fingerless gloves, shorts,
|
||||||
fingerless gloves, shorts, smartwatch
|
smartwatch
|
||||||
</p>
|
</p>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -199,9 +196,8 @@ import RefGallery from "@/components/RefGallery.vue";
|
||||||
<template #caption>
|
<template #caption>
|
||||||
<p>Tracksuit pants</p>
|
<p>Tracksuit pants</p>
|
||||||
<p>
|
<p>
|
||||||
Sebin likes to wear comfortable clothes at home when he doesn't need
|
Sebin likes to wear comfortable clothes at home when he doesn't need to leave the house or
|
||||||
to leave the house or is enjoying some leisure time after work or on
|
is enjoying some leisure time after work or on weekends.
|
||||||
weekends.
|
|
||||||
</p>
|
</p>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -213,23 +209,17 @@ import RefGallery from "@/components/RefGallery.vue";
|
||||||
<template #img>
|
<template #img>
|
||||||
<picture>
|
<picture>
|
||||||
<source
|
<source
|
||||||
srcset="
|
srcset="@/assets/refs/clothes/lazy/undies.jpg?w=0&avif&withoutEnlargement&srcset"
|
||||||
@/assets/refs/clothes/lazy/undies.jpg?w=0&avif&withoutEnlargement&srcset
|
|
||||||
"
|
|
||||||
sizes="333px"
|
sizes="333px"
|
||||||
type="image/avif"
|
type="image/avif"
|
||||||
/>
|
/>
|
||||||
<source
|
<source
|
||||||
srcset="
|
srcset="@/assets/refs/clothes/lazy/undies.jpg?w=0&webp&withoutEnlargement&srcset"
|
||||||
@/assets/refs/clothes/lazy/undies.jpg?w=0&webp&withoutEnlargement&srcset
|
|
||||||
"
|
|
||||||
sizes="333px"
|
sizes="333px"
|
||||||
type="image/webp"
|
type="image/webp"
|
||||||
/>
|
/>
|
||||||
<img
|
<img
|
||||||
srcset="
|
srcset="@/assets/refs/clothes/lazy/undies.jpg?w=0&withoutEnlargement&srcset"
|
||||||
@/assets/refs/clothes/lazy/undies.jpg?w=0&withoutEnlargement&srcset
|
|
||||||
"
|
|
||||||
sizes="333px"
|
sizes="333px"
|
||||||
alt="Shorts"
|
alt="Shorts"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
|
@ -240,8 +230,8 @@ import RefGallery from "@/components/RefGallery.vue";
|
||||||
<template #caption>
|
<template #caption>
|
||||||
<p>Topless w/ jockstrap/boxer briefs</p>
|
<p>Topless w/ jockstrap/boxer briefs</p>
|
||||||
<p>
|
<p>
|
||||||
For even more comfort, Sebin tends to forgoe pants completely and save
|
For even more comfort, Sebin tends to forgoe pants completely and save on laundry by only
|
||||||
on laundry by only wearing the absolute necessary.
|
wearing the absolute necessary.
|
||||||
</p>
|
</p>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { inject } from "vue";
|
import { inject } from 'vue'
|
||||||
import {
|
import {
|
||||||
firstName,
|
firstName,
|
||||||
middleName,
|
middleName,
|
||||||
|
@ -13,45 +13,42 @@ import {
|
||||||
tailLength,
|
tailLength,
|
||||||
wingspan,
|
wingspan,
|
||||||
hobbies,
|
hobbies,
|
||||||
kinks,
|
kinks
|
||||||
} from "@/sebin";
|
} from '@/sebin'
|
||||||
import { dateFormat, getAge, toImperial, toLbs } from "@/helpers";
|
import { dateFormat, getAge, toImperial, toLbs } from '@/helpers'
|
||||||
import { nsfwKey, showModalKey } from "@/keys";
|
import { nsfwKey, showModalKey } from '@/keys'
|
||||||
import type { Kink } from "@/interfaces";
|
import type { Kink } from '@/interfaces'
|
||||||
import DataTable from "@/components/DataTable.vue";
|
import DataTable from '@/components/DataTable.vue'
|
||||||
import QuickFacts from "@/components/QuickFacts.vue";
|
import QuickFacts from '@/components/QuickFacts.vue'
|
||||||
import RefToggle from "@/components/RefToggle.vue";
|
import RefToggle from '@/components/RefToggle.vue'
|
||||||
|
|
||||||
const generalHeadings = ["Key", "Value"];
|
const generalHeadings = ['Key', 'Value']
|
||||||
const generalData = [
|
const generalData = [
|
||||||
["Full Name", `${firstName} ${middleName} ${lastName} `],
|
['Full Name', `${firstName} ${middleName} ${lastName} `],
|
||||||
[
|
['Date of Birth', `${dateFormat.format(dateOfBirth)} (${getAge(dateOfBirth)})`],
|
||||||
"Date of Birth",
|
['Sex/Gender', gender],
|
||||||
`${dateFormat.format(dateOfBirth)} (${getAge(dateOfBirth)})`,
|
['Height', `${height} cm (${toImperial(height)})`],
|
||||||
],
|
['Weight', `${weight} kg (${toLbs(weight)} lbs)`],
|
||||||
["Sex/Gender", gender],
|
['Tail Length', `${tailLength / 100} m (${toImperial(tailLength)})`],
|
||||||
["Height", `${height} cm (${toImperial(height)})`],
|
['Wingspan', `${wingspan / 100} m (${toImperial(wingspan)})`]
|
||||||
["Weight", `${weight} kg (${toLbs(weight)} lbs)`],
|
]
|
||||||
["Tail Length", `${tailLength / 100} m (${toImperial(tailLength)})`],
|
|
||||||
["Wingspan", `${wingspan / 100} m (${toImperial(wingspan)})`],
|
|
||||||
];
|
|
||||||
|
|
||||||
const nsfwHeadings = ["Key", "Value"];
|
const nsfwHeadings = ['Key', 'Value']
|
||||||
const nsfwData = [
|
const nsfwData = [
|
||||||
["Orientation", orientation],
|
['Orientation', orientation],
|
||||||
["Position", position],
|
['Position', position]
|
||||||
];
|
]
|
||||||
|
|
||||||
const kinksHeadings = ["Kink", "Receive", "Give"];
|
const kinksHeadings = ['Kink', 'Receive', 'Give']
|
||||||
const kinksData = kinks.map((kink: Kink): string[] => {
|
const kinksData = kinks.map((kink: Kink): string[] => {
|
||||||
const receive = kink.receive ? "✅" : "🚫";
|
const receive = kink.receive ? '✅' : '🚫'
|
||||||
const give = kink.give ? "✅" : "🚫";
|
const give = kink.give ? '✅' : '🚫'
|
||||||
|
|
||||||
return [kink.name, receive, give];
|
return [kink.name, receive, give]
|
||||||
});
|
})
|
||||||
|
|
||||||
const isNsfw = inject<boolean>(nsfwKey, false);
|
const isNsfw = inject<boolean>(nsfwKey, false)
|
||||||
const showModal = inject<Function>(showModalKey, Function);
|
const showModal = inject<Function>(showModalKey, Function)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -78,38 +75,34 @@ const showModal = inject<Function>(showModalKey, Function);
|
||||||
</QuickFacts>
|
</QuickFacts>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Sebin is a warm-hearted guy who cares a lot about the well-being of his
|
Sebin is a warm-hearted guy who cares a lot about the well-being of his loved ones. Bad vibes
|
||||||
loved ones. Bad vibes rarely escape him and he offers his help without
|
rarely escape him and he offers his help without hesitation. He also won't avoid difficult
|
||||||
hesitation. He also won't avoid difficult conversations in the process.
|
conversations in the process. Not being able to help a friend in need is synonymous with
|
||||||
Not being able to help a friend in need is synonymous with failing them, a
|
failing them, a realization that can leave him feeling uneasy long after the fact.
|
||||||
realization that can leave him feeling uneasy long after the fact.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
At the same time, he is very open and honest about his feelings. He does
|
At the same time, he is very open and honest about his feelings. He does not mince words and
|
||||||
not mince words and finds clear words when speaking his mind.
|
finds clear words when speaking his mind. Unfortunately, Sebin sometimes forgets his good
|
||||||
Unfortunately, Sebin sometimes forgets his good manners in the heat of the
|
manners in the heat of the moment, once he gets invested into a quarrel — especially when it
|
||||||
moment, once he gets invested into a quarrel — especially when it comes to
|
comes to topics that are near and dear to his heart. Anyone looking to have a bad time can try
|
||||||
topics that are near and dear to his heart. Anyone looking to have a bad
|
their luck at pissing him off even once. This includes an equally vulgar vocabulary. It is not
|
||||||
time can try their luck at pissing him off even once. This includes an
|
uncommon to hear him swear.
|
||||||
equally vulgar vocabulary. It is not uncommon to hear him swear.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Nevertheless, Sebin strives to put his best foot forward at all times. He
|
Nevertheless, Sebin strives to put his best foot forward at all times. He is of the sociable
|
||||||
is of the sociable type and likes to laugh a lot, as he is easily amused.
|
type and likes to laugh a lot, as he is easily amused. Sometimes to a degree where it can
|
||||||
Sometimes to a degree where it can become very childish and immature very
|
become very childish and immature very quickly.
|
||||||
quickly.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Physical strength is not the only thing that plays a big role for Sebin.
|
Physical strength is not the only thing that plays a big role for Sebin. He is of a firm
|
||||||
He is of a firm believe that a healthy body must also have a healthy mind
|
believe that a healthy body must also have a healthy mind in order to find a balance. But he
|
||||||
in order to find a balance. But he only came to this realization at the
|
only came to this realization at the end of a rocky road. While a setback in the past could
|
||||||
end of a rocky road. While a setback in the past could easily throw him
|
easily throw him off track, today he stands much more firmly in life. Not only for his own
|
||||||
off track, today he stands much more firmly in life. Not only for his own
|
sake, but also to be a kind of anchor for others. He always keeps his cool, so he can be a
|
||||||
sake, but also to be a kind of anchor for others. He always keeps his
|
tower of strenth for others.
|
||||||
cool, so he can be a tower of strenth for others.
|
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
@ -125,18 +118,16 @@ const showModal = inject<Function>(showModalKey, Function);
|
||||||
</QuickFacts>
|
</QuickFacts>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Sebin is passionate about his hobbies. If he notices even the smallest
|
Sebin is passionate about his hobbies. If he notices even the smallest spark of interest in
|
||||||
spark of interest in his hobbies you should bring a lot of time, as he
|
his hobbies you should bring a lot of time, as he will chew your ear off first. Patience is
|
||||||
will chew your ear off first. Patience is known to be a virtue — one
|
known to be a virtue — one unknown to this dragon.
|
||||||
unknown to this dragon.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
When he indulges in his hobbies, he does so with devotion. Every move has
|
When he indulges in his hobbies, he does so with devotion. Every move has to be right and
|
||||||
to be right and everything has to be in perfect harmony. Once he is in his
|
everything has to be in perfect harmony. Once he is in his flow, he must not be disturbed,
|
||||||
flow, he must not be disturbed, otherwise he can sometimes become quite
|
otherwise he can sometimes become quite eccentric in expressing his dismay of being disrupted,
|
||||||
eccentric in expressing his dismay of being disrupted, possibly losing a
|
possibly losing a very important train of thought.
|
||||||
very important train of thought.
|
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
@ -161,21 +152,19 @@ const showModal = inject<Function>(showModalKey, Function);
|
||||||
</QuickFacts>
|
</QuickFacts>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Sebin's day starts with a strong cup of black coffee and sandwiches. He's
|
Sebin's day starts with a strong cup of black coffee and sandwiches. He's also a massive sweet
|
||||||
also a massive sweet tooth which sounds like a big detriment to his
|
tooth which sounds like a big detriment to his fitness routine. That's because it is and it's
|
||||||
fitness routine. That's because it is and it's often very hard for him to
|
often very hard for him to resist.
|
||||||
resist.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Besides snacking, Sebin also likes to eat hearty and savory things. He
|
Besides snacking, Sebin also likes to eat hearty and savory things. He doesn't disdain a
|
||||||
doesn't disdain a cheese platter with a wide selection, nor a medium-rare
|
cheese platter with a wide selection, nor a medium-rare steak.
|
||||||
steak.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Sebin rarely says no to a good beer with friends, just as he rarely says
|
Sebin rarely says no to a good beer with friends, just as he rarely says no to a bar tour to
|
||||||
no to a bar tour to try new and interesting cocktails.
|
try new and interesting cocktails.
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
@ -198,17 +187,14 @@ const showModal = inject<Function>(showModalKey, Function);
|
||||||
</QuickFacts>
|
</QuickFacts>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
But above all Sebin is a very naughty hornball. He knows what he's got
|
But above all Sebin is a very naughty hornball. He knows what he's got and he's not afraid
|
||||||
and he's not afraid to flaunt it. He is a generally dominant lover who
|
to flaunt it. He is a generally dominant lover who likes to have it rough. But he is not
|
||||||
likes to have it rough. But he is not lacking in tenderness. He
|
lacking in tenderness. He considers himself somewhat of a "service top", who doesn't only
|
||||||
considers himself somewhat of a "service top", who doesn't only have his
|
have his own fun in mind. His job is only done if he's benn able to satisfy. However, that
|
||||||
own fun in mind. His job is only done if he's benn able to satisfy.
|
doesn't mean that he doesn't let others have their fun with him too from time to time. It
|
||||||
However, that doesn't mean that he doesn't let others have their fun
|
always depends on his playmates, which makes him effectively a switch. He loves to wear
|
||||||
with him too from time to time. It always depends on his playmates,
|
bottomless jockstraps and boxer briefs to direct the attention of onlookers exactly where he
|
||||||
which makes him effectively a switch. He loves to wear bottomless
|
wants it. After all he is well endowed enough to peddle it around.
|
||||||
jockstraps and boxer briefs to direct the attention of onlookers exactly
|
|
||||||
where he wants it. After all he is well endowed enough to peddle it
|
|
||||||
around.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<DataTable class="kinks" :headings="kinksHeadings" :data="kinksData" />
|
<DataTable class="kinks" :headings="kinksHeadings" :data="kinksData" />
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { inject } from "vue";
|
import { inject } from 'vue'
|
||||||
import { nsfwKey, showModalKey } from "@/keys";
|
import { nsfwKey, showModalKey } from '@/keys'
|
||||||
import RefToggle from "@/components/RefToggle.vue";
|
import RefToggle from '@/components/RefToggle.vue'
|
||||||
import WelcomeHeader from "@/components/WelcomeHeader.vue";
|
import WelcomeHeader from '@/components/WelcomeHeader.vue'
|
||||||
import ButtonGroup from "@/components/ButtonGroup.vue";
|
import ButtonGroup from '@/components/ButtonGroup.vue'
|
||||||
import Button from "@/components/RefButton.vue";
|
import Button from '@/components/RefButton.vue'
|
||||||
|
|
||||||
const isNsfw = inject<boolean>(nsfwKey, false);
|
const isNsfw = inject<boolean>(nsfwKey, false)
|
||||||
const showModal = inject<Function>(showModalKey, Function);
|
const showModal = inject<Function>(showModalKey, Function)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -18,44 +18,33 @@ const showModal = inject<Function>(showModalKey, Function);
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<h3>Welcome to Sebin's Ref Page</h3>
|
<h3>Welcome to Sebin's Ref Page</h3>
|
||||||
<p>
|
<p>On this page your can learn all about Sebin, your friendly neighborhood dragon!</p>
|
||||||
On this page your can learn all about Sebin, your friendly neighborhood
|
|
||||||
dragon!
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
I started this page to have a single point of truth with all the info
|
I started this page to have a single point of truth with all the info artists I commission can
|
||||||
artists I commission can possibly need. If you're missing some crucial
|
possibly need. If you're missing some crucial info, or you would like to give me some general
|
||||||
info, or you would like to give me some general feedback about this page,
|
feedback about this page, feel free to reach out!
|
||||||
feel free to reach out!
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<ButtonGroup grid class="social">
|
<ButtonGroup grid class="social">
|
||||||
<Button href="https://twitter.com/SebinNyshkim" class="twitter">
|
<Button href="https://twitter.com/SebinNyshkim" class="twitter"> Twitter </Button>
|
||||||
Twitter
|
<Button href="https://meow.social/@SebinNyshkim" class="mastodon" rel="me"> Mastodon </Button>
|
||||||
</Button>
|
<Button href="https://t.me/SebinNyshkim" class="telegram"> Telegram </Button>
|
||||||
<Button href="https://meow.social/@SebinNyshkim" class="mastodon" rel="me" >
|
|
||||||
Mastodon
|
|
||||||
</Button>
|
|
||||||
<Button href="https://t.me/SebinNyshkim" class="telegram">
|
|
||||||
Telegram
|
|
||||||
</Button>
|
|
||||||
<Button href="https://www.furaffinity.net/user/sonofdragons" class="furaffinity">
|
<Button href="https://www.furaffinity.net/user/sonofdragons" class="furaffinity">
|
||||||
Fur Affinity
|
Fur Affinity
|
||||||
</Button>
|
</Button>
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
|
|
||||||
<blockquote>
|
<blockquote>
|
||||||
<strong>Note:</strong> This page is still under heavy construction, as
|
<strong>Note:</strong> This page is still under heavy construction, as indicated by the 0.x.x
|
||||||
indicated by the 0.x.x version number in the footer. I'm continously
|
version number in the footer. I'm continously updating the site and adding details and
|
||||||
updating the site and adding details and information to it. In case you
|
information to it. In case you run into something weird, definitely let me know!
|
||||||
run into something weird, definitely let me know!
|
|
||||||
</blockquote>
|
</blockquote>
|
||||||
|
|
||||||
<h3>Complete Ref Sheet</h3>
|
<h3>Complete Ref Sheet</h3>
|
||||||
<p>
|
<p>
|
||||||
Just here to fetch the ref sheet? Click the button with the ref sheet you
|
Just here to fetch the ref sheet? Click the button with the ref sheet you need and get
|
||||||
need and get started!
|
started!
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<ButtonGroup>
|
<ButtonGroup>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
// import AttackItem from "@/components/AttackItem.vue";
|
// import AttackItem from "@/components/AttackItem.vue";
|
||||||
// import AttackList from "@/components/AttackList.vue";
|
// import AttackList from "@/components/AttackList.vue";
|
||||||
import RefFigure from "@/components/RefFigure.vue";
|
import RefFigure from '@/components/RefFigure.vue'
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -45,34 +45,30 @@ import RefFigure from "@/components/RefFigure.vue";
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<p>
|
<p>
|
||||||
Sebin can enter an Overdrive Form which greatly increases his strength and
|
Sebin can enter an Overdrive Form which greatly increases his strength and abilities but it
|
||||||
abilities but it comes at a cost.
|
comes at a cost.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
He enters Overdrive by engulfing himself in a pillar of flames which
|
He enters Overdrive by engulfing himself in a pillar of flames which transforms his exterior
|
||||||
transforms his exterior physique. During Overdrive transformation his hair
|
physique. During Overdrive transformation his hair ignites and flickers with blue flames. The
|
||||||
ignites and flickers with blue flames. The corners of his eyes flicker
|
corners of his eyes flicker with long green flames. His arms and legs become part carbon black
|
||||||
with long green flames. His arms and legs become part carbon black and are
|
and are crossed by several glowing veins which pulsate like flowing lava. Fire in this form
|
||||||
crossed by several glowing veins which pulsate like flowing lava. Fire in
|
burns several degrees hotter than usual because his body becomes a living blast furnace, which
|
||||||
this form burns several degrees hotter than usual because his body becomes
|
is why his limbs have to be of more fire-proof material to withstand the increased heat.
|
||||||
a living blast furnace, which is why his limbs have to be of more
|
|
||||||
fire-proof material to withstand the increased heat.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
To complete the transformation he inhales the flames from the pillar
|
To complete the transformation he inhales the flames from the pillar surrounding him which
|
||||||
surrounding him which heats up his body from within. Even if Sebin is a
|
heats up his body from within. Even if Sebin is a fire dragon who can sustain high degrees of
|
||||||
fire dragon who can sustain high degrees of heat he is essentially
|
heat he is essentially overheating himself from the inside. Because of this he can't maintain
|
||||||
overheating himself from the inside. Because of this he can't maintain
|
this form for more than a few hours before he does permanent damage to his own body.
|
||||||
this form for more than a few hours before he does permanent damage to his
|
|
||||||
own body.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Direct body contact with Sebin during overdrive causes 3rd degree burns as
|
Direct body contact with Sebin during overdrive causes 3rd degree burns as he emits an extreme
|
||||||
he emits an extreme temperature, although less than he keeps inside his
|
temperature, although less than he keeps inside his body. His immediate surroundings are
|
||||||
body. His immediate surroundings are likely to burn or melt.
|
likely to burn or melt.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>Attacks</h2>
|
<h2>Attacks</h2>
|
||||||
|
@ -88,75 +84,69 @@ import RefFigure from "@/components/RefFigure.vue";
|
||||||
<tr>
|
<tr>
|
||||||
<td>Fire Breath (improved)</td>
|
<td>Fire Breath (improved)</td>
|
||||||
<td>
|
<td>
|
||||||
The reach of Sebin's Fire Breath increases as well as the frequency
|
The reach of Sebin's Fire Breath increases as well as the frequency at which he can fire
|
||||||
at which he can fire shots from his mouth.
|
shots from his mouth.
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Flame Toss (improved)</td>
|
<td>Flame Toss (improved)</td>
|
||||||
<td>
|
<td>
|
||||||
Overdrive Form eliminates the need for Sebin to spit fire into his
|
Overdrive Form eliminates the need for Sebin to spit fire into his palms. It instead
|
||||||
palms. It instead enables him to fire the shots directly from the
|
enables him to fire the shots directly from the palm palm of his hands, as the firey
|
||||||
palm palm of his hands, as the firey veins crossing his arms act as
|
veins crossing his arms act as an orifice to do so. The explosion radius of the burning
|
||||||
an orifice to do so. The explosion radius of the burning projectiles
|
projectiles that explode on impact is greatly increased.
|
||||||
that explode on impact is greatly increased.
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Kindled Fist (improved)</td>
|
<td>Kindled Fist (improved)</td>
|
||||||
<td>
|
<td>
|
||||||
As his arms and legs are infused with fire his punches and kicks
|
As his arms and legs are infused with fire his punches and kicks exert trails of flames
|
||||||
exert trails of flames while doing so. Landing a punch or kick sears
|
while doing so. Landing a punch or kick sears enemies.
|
||||||
enemies.
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Searing Discus</td>
|
<td>Searing Discus</td>
|
||||||
<td>
|
<td>
|
||||||
Overdrive allows Sebin to form rings of fire by igniting flames from
|
Overdrive allows Sebin to form rings of fire by igniting flames from his fingertips and
|
||||||
his fingertips and swirling them in a circle motion. He can use them
|
swirling them in a circle motion. He can use them for both close quarters or ranged
|
||||||
for both close quarters or ranged combat.
|
combat.
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Combustion Flare</td>
|
<td>Combustion Flare</td>
|
||||||
<td>
|
<td>
|
||||||
Clinking both of his wrists against each other like flints unleashes
|
Clinking both of his wrists against each other like flints unleashes a devestating fire
|
||||||
a devestating fire blast from both of his fire-infused hands. A
|
blast from both of his fire-infused hands. A secure foothold is needed to prevent Sebin
|
||||||
secure foothold is needed to prevent Sebin from being thrown back by
|
from being thrown back by the recoil of the attack. Using this technique in the air is
|
||||||
the recoil of the attack. Using this technique in the air is
|
|
||||||
therefore highly risky.
|
therefore highly risky.
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Blazing Pandemonium</td>
|
<td>Blazing Pandemonium</td>
|
||||||
<td>
|
<td>
|
||||||
A heavy impact into the ground from a great height with both fists,
|
A heavy impact into the ground from a great height with both fists, tearing deep cracks
|
||||||
tearing deep cracks in the ground around the impact crater. Combined
|
in the ground around the impact crater. Combined with
|
||||||
with
|
|
||||||
<strong><em>Kindled Fist</em></strong>
|
<strong><em>Kindled Fist</em></strong>
|
||||||
the heat in Sebin's arms are forced through the newly created
|
the heat in Sebin's arms are forced through the newly created furrows, transforming the
|
||||||
furrows, transforming the scene into an inferno.
|
scene into an inferno.
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Scorching Edge</td>
|
<td>Scorching Edge</td>
|
||||||
<td>
|
<td>
|
||||||
A fiery blade towering several meters into the air that Sebin sends
|
A fiery blade towering several meters into the air that Sebin sends careening towards
|
||||||
careening towards his enemies from his fire-infused legs with a
|
his enemies from his fire-infused legs with a backflip kick, leaving a swath of
|
||||||
backflip kick, leaving a swath of destruction in its wake. Upon
|
destruction in its wake. Upon impact the force of the attack is distributed sideways.
|
||||||
impact the force of the attack is distributed sideways.
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Circling Fire Shield</td>
|
<td>Circling Fire Shield</td>
|
||||||
<td>
|
<td>
|
||||||
A rather defensive technique. By spinning around with stretched out
|
A rather defensive technique. By spinning around with stretched out arms Sebin creates
|
||||||
arms Sebin creates fire balls, which he usually hurls towards
|
fire balls, which he usually hurls towards enemies, that circle around his body
|
||||||
enemies, that circle around his body diagonally. They act as a
|
diagonally. They act as a shield while he can still move his arms relatively freely.
|
||||||
shield while he can still move his arms relatively freely. Enemies
|
Enemies would be well advised to keep their distance to this spinning shield, as the
|
||||||
would be well advised to keep their distance to this spinning
|
fire balls will still explode on contact.
|
||||||
shield, as the fire balls will still explode on contact.
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue