Compare commits

..

No commits in common. "master" and "0.8.2" have entirely different histories.

135 changed files with 35347 additions and 7532 deletions

View file

@ -1,3 +1,3 @@
defaults
>1% and not dead
> 1%
last 2 versions
not dead

View file

@ -1,15 +0,0 @@
/* eslint-env node */
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'
],
parserOptions: {
ecmaVersion: 'latest'
}
}

14
.eslintrc.js Normal file
View file

@ -0,0 +1,14 @@
module.exports = {
root: true,
env: {
node: true,
},
extends: ["plugin:vue/vue3-essential", "eslint:recommended", "@vue/prettier"],
parserOptions: {
parser: "babel-eslint",
},
rules: {
"no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
"no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off",
},
};

29
.gitignore vendored
View file

@ -1,30 +1,23 @@
# Logs
logs
*.log
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist
dist-ssr
coverage
*.local
/cypress/videos/
/cypress/screenshots/
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
*.tsbuildinfo

3
.jshintrc Normal file
View file

@ -0,0 +1,3 @@
{
"esversion": 9
}

View file

@ -1,8 +0,0 @@
{
"$schema": "https://json.schemastore.org/prettierrc",
"semi": false,
"tabWidth": 2,
"singleQuote": true,
"printWidth": 100,
"trailingComma": "none"
}

View file

@ -1,7 +0,0 @@
{
"recommendations": [
"Vue.volar",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode"
]
}

15
.vscode/sftp.json vendored Normal file
View file

@ -0,0 +1,15 @@
{
"name": "sebin-reference",
"protocol": "sftp",
"port": 22,
"host": "sebin-ref",
"username": "sebin",
"privateKeyPath": "~/.ssh/id_sebin",
"passphrase": "HeyImGrump20!6",
"remotePath": "sebin-ref",
"watcher": {
"files": "dist/**",
"autoUpload": true,
"autoDelete": true
}
}

View file

@ -1,55 +1,24 @@
# Sebin Reference Page
# vue3-test
The official reference page of Sebin Nyshkim, the anthro dragon.
This page is primarily targeted at artists commissioned to draw Sebin. The idea is to have a single point of truth to easily point to.
The benefit of this is two-fold:
* Lack of attachments in Fur Affinity notes
* Participating in art raffles on Twitter without cluttering up the media tab with the same image over and over again
Furthermore, this page serves both for the development of Sebin as an independent character as well as a training ground for learning various new web technologies fitting such a project.
## Recommended IDE Setup
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).
## Type Support for `.vue` Imports in TS
TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin) to make the TypeScript language service aware of `.vue` types.
If the standalone TypeScript plugin doesn't feel fast enough to you, Volar has also implemented a [Take Over Mode](https://github.com/johnsoncodehk/volar/discussions/471#discussioncomment-1361669) that is more performant. You can enable it by the following steps:
1. Disable the built-in TypeScript Extension
1) Run `Extensions: Show Built-in Extensions` from VSCode's command palette
2) Find `TypeScript and JavaScript Language Features`, right click and select `Disable (Workspace)`
2. Reload the VSCode window by running `Developer: Reload Window` from the command palette.
## Customize configuration
See [Vite Configuration Reference](https://vitejs.dev/config/).
## Project Setup
```sh
## Project setup
```
npm install
```
### Compile and Hot-Reload for Development
```sh
npm run dev
### Compiles and hot-reloads for development
```
npm run serve
```
### Type-Check, Compile and Minify for Production
```sh
### Compiles and minifies for production
```
npm run build
```
### Lint with [ESLint](https://eslint.org/)
```sh
### Lints and fixes files
```
npm run lint
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).

3
babel.config.js Normal file
View file

@ -0,0 +1,3 @@
module.exports = {
presets: ["@vue/cli-plugin-babel/preset"],
};

View file

@ -1,44 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="flex">
<div class="image">
<img src="../../../src/assets/sebin-smug-icon.png" alt="Sebin Smug Icon" />
</div>
<div class="headings">
<h1>Sebin Nyshkim</h1>
<h2>
<span class="contact">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"/></svg>
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M503.5 204.6L502.8 202.8L433.1 21.02C431.7 17.45 429.2 14.43 425.9 12.38C423.5 10.83 420.8 9.865 417.9 9.57C415 9.275 412.2 9.653 409.5 10.68C406.8 11.7 404.4 13.34 402.4 15.46C400.5 17.58 399.1 20.13 398.3 22.9L351.3 166.9H160.8L113.7 22.9C112.9 20.13 111.5 17.59 109.6 15.47C107.6 13.35 105.2 11.72 102.5 10.7C99.86 9.675 96.98 9.295 94.12 9.587C91.26 9.878 88.51 10.83 86.08 12.38C82.84 14.43 80.33 17.45 78.92 21.02L9.267 202.8L8.543 204.6C-1.484 230.8-2.72 259.6 5.023 286.6C12.77 313.5 29.07 337.3 51.47 354.2L51.74 354.4L52.33 354.8L158.3 434.3L210.9 474L242.9 498.2C246.6 500.1 251.2 502.5 255.9 502.5C260.6 502.5 265.2 500.1 268.9 498.2L300.9 474L353.5 434.3L460.2 354.4L460.5 354.1C482.9 337.2 499.2 313.5 506.1 286.6C514.7 259.6 513.5 230.8 503.5 204.6z"/></svg>
<span class="handle">SebinNyshkim</span>
</span>
<span class="contact">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"/></svg>
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M248,8C111.033,8,0,119.033,0,256S111.033,504,248,504,496,392.967,496,256,384.967,8,248,8ZM362.952,176.66c-3.732,39.215-19.881,134.378-28.1,178.3-3.476,18.584-10.322,24.816-16.948,25.425-14.4,1.326-25.338-9.517-39.287-18.661-21.827-14.308-34.158-23.215-55.346-37.177-24.485-16.135-8.612-25,5.342-39.5,3.652-3.793,67.107-61.51,68.335-66.746.153-.655.3-3.1-1.154-4.384s-3.59-.849-5.135-.5q-3.283.746-104.608,69.142-14.845,10.194-26.894,9.934c-8.855-.191-25.888-5.006-38.551-9.123-15.531-5.048-27.875-7.717-26.8-16.291q.84-6.7,18.45-13.7,108.446-47.248,144.628-62.3c68.872-28.647,83.183-33.623,92.511-33.789,2.052-.034,6.639.474,9.61,2.885a10.452,10.452,0,0,1,3.53,6.716A43.765,43.765,0,0,1,362.952,176.66Z"/></svg>
<span class="handle">@SebinNyshkim</span>
</span>
<span class="contact">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M433 179.11c0-97.2-63.71-125.7-63.71-125.7-62.52-28.7-228.56-28.4-290.48 0 0 0-63.72 28.5-63.72 125.7 0 115.7-6.6 259.4 105.63 289.1 40.51 10.7 75.32 13 103.33 11.4 50.81-2.8 79.32-18.1 79.32-18.1l-1.7-36.9s-36.31 11.4-77.12 10.1c-40.41-1.4-83-4.4-89.63-54a102.54 102.54 0 0 1-.9-13.9c85.63 20.9 158.65 9.1 178.75 6.7 56.12-6.7 105-41.3 111.23-72.9 9.8-49.8 9-121.5 9-121.5zm-75.12 125.2h-46.63v-114.2c0-49.7-64-51.6-64 6.9v62.5h-46.33V197c0-58.5-64-56.6-64-6.9v114.2H90.19c0-122.1-5.2-147.9 18.41-175 25.9-28.9 79.82-30.8 103.83 6.1l11.6 19.5 11.6-19.5c24.11-37.1 78.12-34.8 103.83-6.1 23.71 27.3 18.4 53 18.4 175z"/></svg>
<span class="handle">@SebinNyshkim@meow.social</span>
</span>
<span class="contact">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M524.531,69.836a1.5,1.5,0,0,0-.764-.7A485.065,485.065,0,0,0,404.081,32.03a1.816,1.816,0,0,0-1.923.91,337.461,337.461,0,0,0-14.9,30.6,447.848,447.848,0,0,0-134.426,0,309.541,309.541,0,0,0-15.135-30.6,1.89,1.89,0,0,0-1.924-.91A483.689,483.689,0,0,0,116.085,69.137a1.712,1.712,0,0,0-.788.676C39.068,183.651,18.186,294.69,28.43,404.354a2.016,2.016,0,0,0,.765,1.375A487.666,487.666,0,0,0,176.02,479.918a1.9,1.9,0,0,0,2.063-.676A348.2,348.2,0,0,0,208.12,430.4a1.86,1.86,0,0,0-1.019-2.588,321.173,321.173,0,0,1-45.868-21.853,1.885,1.885,0,0,1-.185-3.126c3.082-2.309,6.166-4.711,9.109-7.137a1.819,1.819,0,0,1,1.9-.256c96.229,43.917,200.41,43.917,295.5,0a1.812,1.812,0,0,1,1.924.233c2.944,2.426,6.027,4.851,9.132,7.16a1.884,1.884,0,0,1-.162,3.126,301.407,301.407,0,0,1-45.89,21.83,1.875,1.875,0,0,0-1,2.611,391.055,391.055,0,0,0,30.014,48.815,1.864,1.864,0,0,0,2.063.7A486.048,486.048,0,0,0,610.7,405.729a1.882,1.882,0,0,0,.765-1.352C623.729,277.594,590.933,167.465,524.531,69.836ZM222.491,337.58c-28.972,0-52.844-26.587-52.844-59.239S193.056,219.1,222.491,219.1c29.665,0,53.306,26.82,52.843,59.239C275.334,310.993,251.924,337.58,222.491,337.58Zm195.38,0c-28.971,0-52.843-26.587-52.843-59.239S388.437,219.1,417.871,219.1c29.667,0,53.307,26.82,52.844,59.239C470.715,310.993,447.538,337.58,417.871,337.58Z"/></svg>
<span class="handle">Sebin Nyshkim#8877</span>
</span>
</h2>
</div>
</main>
<!-- Open in browser and set mobile view to 2048x1072 with DPR: 2 and take screenshot -->
</body>
</html>

View file

@ -1,139 +0,0 @@
@import "../../../src/assets/fonts/exo/exo.css";
:root {
font-size: 20px;
color: #fff;
--theme-c-muted-blue: #22759d;
--theme-c-amaranth: #e93f3f;
--theme-c-deep-purple: #33124a;
--theme-c-charcoal: #303030;
--container-box-shadow: 1vw 1vw 4vw rgba(0, 0, 0, 0.7);
--welcome-header-mainline-font-size: 25vh;
--welcome-header-subline-font-size: 10vh;
--icon-size: calc(var(--welcome-header-subline-font-size) * 1.25);
--page-background: radial-gradient(circle at bottom right,
var(--theme-c-amaranth) 5%,
transparent 50%),
radial-gradient(circle at top left,
var(--theme-c-muted-blue) 5%,
var(--theme-c-deep-purple) 100%);
}
*,
*::before,
*::after {
margin: 0;
box-sizing: border-box;
/* line-height: 1.5; */
}
body {
display: flex;
flex-flow: row nowrap;
justify-content: flex-start;
align-items: center;
min-height: 100vh;
}
main::before,
main::after {
content: "";
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
main::before {
background: url(../../../src/assets/subtle-prism.svg);
mix-blend-mode: multiply;
z-index: -1;
transform: scale(1.5);
}
main::after {
background: var(--page-background);
z-index: -2;
}
.flex {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
flex: 0 0 50vw;
padding: 0 2vw;
}
.flex > * {
flex: 0 0 auto;
}
.image {
flex: 0 0 60vh;
max-height: 100vh;
}
.image img {
display: block;
width: 100%;
border-radius: 100%;
border: 3vh solid #fff; box-shadow: var(--container-box-shadow);
}
.headings {
flex: 0 1 45vw;
margin: 0;
padding: 0 1vw;
}
.headings :where(h1, h2) {
font-family: "Exo", sans-serif;
text-align: center;
font-style: italic;
margin: 0;
}
.headings h1 {
font-size: var(--welcome-header-mainline-font-size);
font-weight: 900;
}
.headings h2 {
font-size: var(--welcome-header-subline-font-size);
font-weight: 300;
display: flex;
flex-flow: row wrap;
justify-content: space-evenly;
line-height: 1.75;
}
.headings .contact {
display: flex;
flex-flow: row nowrap;
justify-content: flex-start;
align-items: center;
}
.headings .icon,
.headings .handle {
flex: 0 0 auto;
}
.headings .icon {
flex: 0 0 var(--icon-size);
width: var(--icon-size);
height: var(--icon-size);
margin: 0 0.375em 0 0;
}
.headings .icon {
fill: #fff;
}

View file

@ -1,44 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="flex">
<div class="image">
<img src="../../../src/assets/sebin-smug-icon.png" alt="Sebin Smug Icon" />
</div>
<div class="headings">
<h1>Sebin Nyshkim</h1>
<h2>
<span class="contact">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"/></svg>
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M503.5 204.6L502.8 202.8L433.1 21.02C431.7 17.45 429.2 14.43 425.9 12.38C423.5 10.83 420.8 9.865 417.9 9.57C415 9.275 412.2 9.653 409.5 10.68C406.8 11.7 404.4 13.34 402.4 15.46C400.5 17.58 399.1 20.13 398.3 22.9L351.3 166.9H160.8L113.7 22.9C112.9 20.13 111.5 17.59 109.6 15.47C107.6 13.35 105.2 11.72 102.5 10.7C99.86 9.675 96.98 9.295 94.12 9.587C91.26 9.878 88.51 10.83 86.08 12.38C82.84 14.43 80.33 17.45 78.92 21.02L9.267 202.8L8.543 204.6C-1.484 230.8-2.72 259.6 5.023 286.6C12.77 313.5 29.07 337.3 51.47 354.2L51.74 354.4L52.33 354.8L158.3 434.3L210.9 474L242.9 498.2C246.6 500.1 251.2 502.5 255.9 502.5C260.6 502.5 265.2 500.1 268.9 498.2L300.9 474L353.5 434.3L460.2 354.4L460.5 354.1C482.9 337.2 499.2 313.5 506.1 286.6C514.7 259.6 513.5 230.8 503.5 204.6z"/></svg>
<span class="handle">SebinNyshkim</span>
</span>
<span class="contact">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"/></svg>
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M248,8C111.033,8,0,119.033,0,256S111.033,504,248,504,496,392.967,496,256,384.967,8,248,8ZM362.952,176.66c-3.732,39.215-19.881,134.378-28.1,178.3-3.476,18.584-10.322,24.816-16.948,25.425-14.4,1.326-25.338-9.517-39.287-18.661-21.827-14.308-34.158-23.215-55.346-37.177-24.485-16.135-8.612-25,5.342-39.5,3.652-3.793,67.107-61.51,68.335-66.746.153-.655.3-3.1-1.154-4.384s-3.59-.849-5.135-.5q-3.283.746-104.608,69.142-14.845,10.194-26.894,9.934c-8.855-.191-25.888-5.006-38.551-9.123-15.531-5.048-27.875-7.717-26.8-16.291q.84-6.7,18.45-13.7,108.446-47.248,144.628-62.3c68.872-28.647,83.183-33.623,92.511-33.789,2.052-.034,6.639.474,9.61,2.885a10.452,10.452,0,0,1,3.53,6.716A43.765,43.765,0,0,1,362.952,176.66Z"/></svg>
<span class="handle">@SebinNyshkim</span>
</span>
<span class="contact">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M433 179.11c0-97.2-63.71-125.7-63.71-125.7-62.52-28.7-228.56-28.4-290.48 0 0 0-63.72 28.5-63.72 125.7 0 115.7-6.6 259.4 105.63 289.1 40.51 10.7 75.32 13 103.33 11.4 50.81-2.8 79.32-18.1 79.32-18.1l-1.7-36.9s-36.31 11.4-77.12 10.1c-40.41-1.4-83-4.4-89.63-54a102.54 102.54 0 0 1-.9-13.9c85.63 20.9 158.65 9.1 178.75 6.7 56.12-6.7 105-41.3 111.23-72.9 9.8-49.8 9-121.5 9-121.5zm-75.12 125.2h-46.63v-114.2c0-49.7-64-51.6-64 6.9v62.5h-46.33V197c0-58.5-64-56.6-64-6.9v114.2H90.19c0-122.1-5.2-147.9 18.41-175 25.9-28.9 79.82-30.8 103.83 6.1l11.6 19.5 11.6-19.5c24.11-37.1 78.12-34.8 103.83-6.1 23.71 27.3 18.4 53 18.4 175z"/></svg>
<span class="handle">@SebinNyshkim@meow.social</span>
</span>
<span class="contact">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M524.531,69.836a1.5,1.5,0,0,0-.764-.7A485.065,485.065,0,0,0,404.081,32.03a1.816,1.816,0,0,0-1.923.91,337.461,337.461,0,0,0-14.9,30.6,447.848,447.848,0,0,0-134.426,0,309.541,309.541,0,0,0-15.135-30.6,1.89,1.89,0,0,0-1.924-.91A483.689,483.689,0,0,0,116.085,69.137a1.712,1.712,0,0,0-.788.676C39.068,183.651,18.186,294.69,28.43,404.354a2.016,2.016,0,0,0,.765,1.375A487.666,487.666,0,0,0,176.02,479.918a1.9,1.9,0,0,0,2.063-.676A348.2,348.2,0,0,0,208.12,430.4a1.86,1.86,0,0,0-1.019-2.588,321.173,321.173,0,0,1-45.868-21.853,1.885,1.885,0,0,1-.185-3.126c3.082-2.309,6.166-4.711,9.109-7.137a1.819,1.819,0,0,1,1.9-.256c96.229,43.917,200.41,43.917,295.5,0a1.812,1.812,0,0,1,1.924.233c2.944,2.426,6.027,4.851,9.132,7.16a1.884,1.884,0,0,1-.162,3.126,301.407,301.407,0,0,1-45.89,21.83,1.875,1.875,0,0,0-1,2.611,391.055,391.055,0,0,0,30.014,48.815,1.864,1.864,0,0,0,2.063.7A486.048,486.048,0,0,0,610.7,405.729a1.882,1.882,0,0,0,.765-1.352C623.729,277.594,590.933,167.465,524.531,69.836ZM222.491,337.58c-28.972,0-52.844-26.587-52.844-59.239S193.056,219.1,222.491,219.1c29.665,0,53.306,26.82,52.843,59.239C275.334,310.993,251.924,337.58,222.491,337.58Zm195.38,0c-28.971,0-52.843-26.587-52.843-59.239S388.437,219.1,417.871,219.1c29.667,0,53.307,26.82,52.844,59.239C470.715,310.993,447.538,337.58,417.871,337.58Z"/></svg>
<span class="handle">Sebin Nyshkim#8877</span>
</span>
</h2>
</div>
</main>
<!-- Open in browser and set mobile view to 2048x1072 with DPR: 2 and take screenshot -->
</body>
</html>

View file

@ -1,139 +0,0 @@
@import "../../../src/assets/fonts/exo/exo.css";
:root {
font-size: 20px;
color: #fff;
--theme-c-muted-blue: #22759d;
--theme-c-amaranth: #e93f3f;
--theme-c-deep-purple: #33124a;
--theme-c-charcoal: #303030;
--container-box-shadow: 1vw 1vw 4vw rgba(0, 0, 0, 0.7);
--welcome-header-mainline-font-size: 6vw;
--welcome-header-subline-font-size: 2vw;
--icon-size: calc(var(--welcome-header-subline-font-size) * 1.25);
--page-background: radial-gradient(circle at bottom right,
var(--theme-c-amaranth) 5%,
transparent 50%),
radial-gradient(circle at top left,
var(--theme-c-muted-blue) 5%,
var(--theme-c-deep-purple) 100%);
}
*,
*::before,
*::after {
margin: 0;
box-sizing: border-box;
/* line-height: 1.5; */
}
body {
display: flex;
flex-flow: row nowrap;
justify-content: center;
align-items: center;
min-height: 100vh;
}
main::before,
main::after {
content: "";
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
main::before {
background: url(../../../src/assets/subtle-prism.svg);
mix-blend-mode: multiply;
z-index: -1;
transform: scale(1.5);
}
main::after {
background: var(--page-background);
z-index: -2;
}
.flex {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
flex: 0 0 72vw;
}
.flex>* {
flex: 0 0 auto;
}
.image {
flex: 0 0 60vh;
max-height: 100vh;
}
.image img {
display: block;
width: 100%;
border-radius: 100%;
border: 1vw solid #fff;
box-shadow: var(--container-box-shadow);
}
.headings {
flex: 0 0 50vw;
margin: 0;
}
.headings :where(h1, h2) {
font-family: "Exo", sans-serif;
text-align: center;
font-style: italic;
margin: 0;
}
.headings h1 {
font-size: var(--welcome-header-mainline-font-size);
font-weight: 900;
line-height: 1.75;
}
.headings h2 {
font-size: var(--welcome-header-subline-font-size);
font-weight: 300;
display: flex;
flex-flow: row wrap;
justify-content: space-evenly;
line-height: 1.75;
}
.headings .contact {
display: flex;
flex-flow: row nowrap;
justify-content: flex-start;
align-items: center;
}
.headings .icon,
.headings .handle {
flex: 0 0 auto;
}
.headings .icon {
flex: 0 0 var(--icon-size);
width: var(--icon-size);
height: var(--icon-size);
margin: 0 0.375em 0 0;
}
.headings .icon {
fill: #fff;
}

View file

@ -1,44 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="flex">
<div class="image">
<img src="../../../src/assets/sebin-smug-icon.png" alt="Sebin Smug Icon" />
</div>
<div class="headings">
<h1>Sebin Nyshkim</h1>
<h2>
<span class="contact">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"/></svg>
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M503.5 204.6L502.8 202.8L433.1 21.02C431.7 17.45 429.2 14.43 425.9 12.38C423.5 10.83 420.8 9.865 417.9 9.57C415 9.275 412.2 9.653 409.5 10.68C406.8 11.7 404.4 13.34 402.4 15.46C400.5 17.58 399.1 20.13 398.3 22.9L351.3 166.9H160.8L113.7 22.9C112.9 20.13 111.5 17.59 109.6 15.47C107.6 13.35 105.2 11.72 102.5 10.7C99.86 9.675 96.98 9.295 94.12 9.587C91.26 9.878 88.51 10.83 86.08 12.38C82.84 14.43 80.33 17.45 78.92 21.02L9.267 202.8L8.543 204.6C-1.484 230.8-2.72 259.6 5.023 286.6C12.77 313.5 29.07 337.3 51.47 354.2L51.74 354.4L52.33 354.8L158.3 434.3L210.9 474L242.9 498.2C246.6 500.1 251.2 502.5 255.9 502.5C260.6 502.5 265.2 500.1 268.9 498.2L300.9 474L353.5 434.3L460.2 354.4L460.5 354.1C482.9 337.2 499.2 313.5 506.1 286.6C514.7 259.6 513.5 230.8 503.5 204.6z"/></svg>
<span class="handle">SebinNyshkim</span>
</span>
<span class="contact">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"/></svg>
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M248,8C111.033,8,0,119.033,0,256S111.033,504,248,504,496,392.967,496,256,384.967,8,248,8ZM362.952,176.66c-3.732,39.215-19.881,134.378-28.1,178.3-3.476,18.584-10.322,24.816-16.948,25.425-14.4,1.326-25.338-9.517-39.287-18.661-21.827-14.308-34.158-23.215-55.346-37.177-24.485-16.135-8.612-25,5.342-39.5,3.652-3.793,67.107-61.51,68.335-66.746.153-.655.3-3.1-1.154-4.384s-3.59-.849-5.135-.5q-3.283.746-104.608,69.142-14.845,10.194-26.894,9.934c-8.855-.191-25.888-5.006-38.551-9.123-15.531-5.048-27.875-7.717-26.8-16.291q.84-6.7,18.45-13.7,108.446-47.248,144.628-62.3c68.872-28.647,83.183-33.623,92.511-33.789,2.052-.034,6.639.474,9.61,2.885a10.452,10.452,0,0,1,3.53,6.716A43.765,43.765,0,0,1,362.952,176.66Z"/></svg>
<span class="handle">@SebinNyshkim</span>
</span>
<span class="contact">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M433 179.11c0-97.2-63.71-125.7-63.71-125.7-62.52-28.7-228.56-28.4-290.48 0 0 0-63.72 28.5-63.72 125.7 0 115.7-6.6 259.4 105.63 289.1 40.51 10.7 75.32 13 103.33 11.4 50.81-2.8 79.32-18.1 79.32-18.1l-1.7-36.9s-36.31 11.4-77.12 10.1c-40.41-1.4-83-4.4-89.63-54a102.54 102.54 0 0 1-.9-13.9c85.63 20.9 158.65 9.1 178.75 6.7 56.12-6.7 105-41.3 111.23-72.9 9.8-49.8 9-121.5 9-121.5zm-75.12 125.2h-46.63v-114.2c0-49.7-64-51.6-64 6.9v62.5h-46.33V197c0-58.5-64-56.6-64-6.9v114.2H90.19c0-122.1-5.2-147.9 18.41-175 25.9-28.9 79.82-30.8 103.83 6.1l11.6 19.5 11.6-19.5c24.11-37.1 78.12-34.8 103.83-6.1 23.71 27.3 18.4 53 18.4 175z"/></svg>
<span class="handle">@SebinNyshkim@meow.social</span>
</span>
<span class="contact">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M524.531,69.836a1.5,1.5,0,0,0-.764-.7A485.065,485.065,0,0,0,404.081,32.03a1.816,1.816,0,0,0-1.923.91,337.461,337.461,0,0,0-14.9,30.6,447.848,447.848,0,0,0-134.426,0,309.541,309.541,0,0,0-15.135-30.6,1.89,1.89,0,0,0-1.924-.91A483.689,483.689,0,0,0,116.085,69.137a1.712,1.712,0,0,0-.788.676C39.068,183.651,18.186,294.69,28.43,404.354a2.016,2.016,0,0,0,.765,1.375A487.666,487.666,0,0,0,176.02,479.918a1.9,1.9,0,0,0,2.063-.676A348.2,348.2,0,0,0,208.12,430.4a1.86,1.86,0,0,0-1.019-2.588,321.173,321.173,0,0,1-45.868-21.853,1.885,1.885,0,0,1-.185-3.126c3.082-2.309,6.166-4.711,9.109-7.137a1.819,1.819,0,0,1,1.9-.256c96.229,43.917,200.41,43.917,295.5,0a1.812,1.812,0,0,1,1.924.233c2.944,2.426,6.027,4.851,9.132,7.16a1.884,1.884,0,0,1-.162,3.126,301.407,301.407,0,0,1-45.89,21.83,1.875,1.875,0,0,0-1,2.611,391.055,391.055,0,0,0,30.014,48.815,1.864,1.864,0,0,0,2.063.7A486.048,486.048,0,0,0,610.7,405.729a1.882,1.882,0,0,0,.765-1.352C623.729,277.594,590.933,167.465,524.531,69.836ZM222.491,337.58c-28.972,0-52.844-26.587-52.844-59.239S193.056,219.1,222.491,219.1c29.665,0,53.306,26.82,52.843,59.239C275.334,310.993,251.924,337.58,222.491,337.58Zm195.38,0c-28.971,0-52.843-26.587-52.843-59.239S388.437,219.1,417.871,219.1c29.667,0,53.307,26.82,52.844,59.239C470.715,310.993,447.538,337.58,417.871,337.58Z"/></svg>
<span class="handle">Sebin Nyshkim#8877</span>
</span>
</h2>
</div>
</main>
<!-- Open in browser and set mobile view to 2048x1072 with DPR: 2 and take screenshot -->
</body>
</html>

View file

@ -1,143 +0,0 @@
@import "../../../src/assets/fonts/exo/exo.css";
:root {
font-size: 20px;
color: #fff;
--theme-c-muted-blue: #22759d;
--theme-c-amaranth: #e93f3f;
--theme-c-deep-purple: #33124a;
--theme-c-charcoal: #303030;
--container-box-shadow: 1vw 1vw 4vw rgba(0, 0, 0, 0.7);
--welcome-header-mainline-font-size: 8vw;
--welcome-header-subline-font-size: 2.5vw;
--icon-size: calc(var(--welcome-header-subline-font-size) * 1.25);
--page-background: radial-gradient(
circle at bottom right,
var(--theme-c-amaranth) 5%,
transparent 50%
),
radial-gradient(
circle at top left,
var(--theme-c-muted-blue) 5%,
var(--theme-c-deep-purple) 100%
);
}
*,
*::before,
*::after {
margin: 0;
box-sizing: border-box;
/* line-height: 1.5; */
}
body {
display: flex;
flex-flow: row nowrap;
justify-content: center;
align-items: center;
min-height: 100vh;
}
main::before,
main::after {
content: "";
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
main::before {
background: url(../../../src/assets/subtle-prism.svg);
mix-blend-mode: multiply;
z-index: -1;
transform: scale(1.5);
}
main::after {
background: var(--page-background);
z-index: -2;
}
.flex {
display: flex;
flex-flow: row nowrap;
justify-content: space-evenly;
align-items: center;
flex: 0 0 100%;
}
.flex > * {
flex: 0 0 auto;
}
.image {
flex: 0 0 60vh;
max-height: 100vh;
}
.image img {
display: block;
width: 100%;
border-radius: 100%;
border: 1vw solid #fff;
box-shadow: var(--container-box-shadow);
}
.headings {
flex: 0 0 60vw;
margin: 0;
}
.headings :where(h1, h2) {
font-family: "Exo", sans-serif;
text-align: center;
font-style: italic;
margin: 0;
}
.headings h1 {
font-size: var(--welcome-header-mainline-font-size);
font-weight: 900;
line-height: 1.75;
}
.headings h2 {
font-size: var(--welcome-header-subline-font-size);
font-weight: 300;
display: flex;
flex-flow: row wrap;
justify-content: space-evenly;
line-height: 1.75;
}
.headings .contact {
display: flex;
flex-flow: row nowrap;
justify-content: flex-start;
align-items: center;
}
.headings .icon,
.headings .handle {
flex: 0 0 auto;
}
.headings .icon {
flex: 0 0 var(--icon-size);
width: var(--icon-size);
height: var(--icon-size);
margin: 0 0.375em 0 0;
}
.headings .icon {
fill: #fff;
}

View file

@ -1,22 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="flex">
<div class="image">
<img src="../src/assets/sebin-smug-icon.png" alt="Sebin Smug Icon" />
</div>
<div class="headings">
<h1>Sebin Nyshkim</h1>
<h2>Character Reference Page</h2>
</div>
</main>
<!-- Open in browser and set mobile view to 2048x1072 with DPR: 2 and take screenshot -->
</body>
</html>

View file

@ -1,112 +0,0 @@
@import "../src/assets/fonts/exo/exo.css";
:root {
font-size: 20px;
color: #fff;
--theme-c-muted-blue: #22759d;
--theme-c-amaranth: #e93f3f;
--theme-c-deep-purple: #33124a;
--theme-c-charcoal: #303030;
--container-box-shadow: 1vw 1vw 4vw rgba(0, 0, 0, 0.7);
--welcome-header-mainline-font-size: 8vw;
--welcome-header-subline-font-size: 3.5vw;
--page-background: radial-gradient(
circle at bottom right,
var(--theme-c-amaranth) 5%,
transparent 50%
),
radial-gradient(
circle at top left,
var(--theme-c-muted-blue) 5%,
var(--theme-c-deep-purple) 100%
);
}
*,
*::before,
*::after {
margin: 0;
box-sizing: border-box;
}
body {
display: flex;
flex-flow: row nowrap;
justify-content: center;
align-items: center;
min-height: 100vh;
}
main::before,
main::after {
content: "";
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
main::before {
background: url(../src/assets/subtle-prism.svg);
mix-blend-mode: multiply;
z-index: -1;
transform: scale(1.5);
}
main::after {
background: var(--page-background);
z-index: -2;
}
.flex {
display: flex;
flex-flow: row nowrap;
justify-content: space-evenly;
align-items: center;
flex: 0 0 100%;
}
.flex > * {
flex: 0 0 auto;
}
.image {
flex: 0 0 60vh;
max-height: 100vh;
}
.image img {
display: block;
width: 100%;
border-radius: 100%;
border: 1vw solid #fff;
box-shadow: var(--container-box-shadow);
}
.headings {
flex: 0 0 60vw;
margin: 0;
}
.headings :where(h1, h2) {
font-family: "Exo", sans-serif;
text-align: center;
font-style: italic;
margin: 0;
}
.headings h1 {
font-size: var(--welcome-header-mainline-font-size);
font-weight: 900;
}
.headings h2 {
font-size: var(--welcome-header-subline-font-size);
font-weight: 300;
}

1
env.d.ts vendored
View file

@ -1 +0,0 @@
/// <reference types="vite/client" />

View file

@ -1,30 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
<link rel="favicon" href="favicon.png" type="image/png" />
<link rel="icon" href="favicon.png" type="image/png" />
<title>Sebin Nyshkim - Reference Page</title>
<meta name="theme-color" media="(prefers-color-scheme: light)" content="#22759d" />
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="#195673" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="@SebinNyshkim" />
<meta name="twitter:creator" content="@SebinNyshkim" />
<meta name="twitter:title" content="Sebin Nyshkim - Reference Page" />
<meta name="twitter:description" content="The official reference page for Sebin Nyshkim with picture references and in-depth character descriptions" />
<meta name="twitter:image" content="https://ref.sebin-nyshkim.net/sebin/preview.png" />
<meta property="og:type" content="website" />
<meta property="og:title" content="Sebin Nyshkim - Reference Page" />
<meta property="og:locale" content="en_US" />
<meta property="og:url" content="https://ref.sebin-nyshkim.net/sebin/" />
<meta property="og:image" content="https://ref.sebin-nyshkim.net/sebin/preview.png" />
<meta property="og:description" content="The official reference page for Sebin Nyshkim with picture references and in-depth character descriptions" />
</head>
<body>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

0
jsconfig.json Normal file
View file

34931
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,38 +1,32 @@
{
"name": "sebin-reference",
"version": "0.10.7",
"version": "0.8.2",
"private": true,
"scripts": {
"dev": "vite --host",
"build": "run-p type-check \"build-only {@}\" --",
"preview": "vite preview",
"build-only": "vite build",
"type-check": "vue-tsc --build --force",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
"format": "prettier --write src/"
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"vue": "^3.4.38",
"vue-router": "^4.4.3"
"core-js": "^3.6.5",
"normalize.css": "^8.0.1",
"vue": "^3.0.0",
"vue-router": "^4.0.0-0"
},
"devDependencies": {
"@rushstack/eslint-patch": "^1.10.4",
"@tsconfig/node20": "^20.1.4",
"@types/node": "^20.16.3",
"@vitejs/plugin-vue": "^5.1.3",
"@vue/eslint-config-prettier": "^9.0.0",
"@vue/eslint-config-typescript": "^13.0.0",
"@vue/tsconfig": "^0.5.1",
"autoprefixer": "^10.4.20",
"eslint": "^8.57.0",
"eslint-plugin-vue": "^9.28.0",
"normalize.css": "^8.0.1",
"npm-run-all2": "^6.2.2",
"prettier": "^3.3.3",
"sass": "^1.77.8",
"typescript": "~5.5.0",
"vite": "^5.4.2",
"vite-imagetools": "^6.2.9",
"vue-tsc": "^2.1.4"
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-eslint": "~4.5.0",
"@vue/cli-plugin-router": "~4.5.0",
"@vue/cli-service": "~4.5.0",
"@vue/compiler-sfc": "^3.0.0",
"@vue/eslint-config-prettier": "^6.0.0",
"babel-eslint": "^10.1.0",
"eslint": "^6.7.2",
"eslint-plugin-prettier": "^3.3.1",
"eslint-plugin-vue": "^7.0.0",
"image-webpack-loader": "^8.0.1",
"prettier": "^2.2.1",
"sass": "^1.26.5",
"sass-loader": "^8.0.2"
}
}

View file

@ -4,5 +4,5 @@
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /sebin/index.html [L]
RewriteRule . /index.html [L]
</IfModule>

17
public/index.html Normal file
View file

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0,viewport-fit=cover">
<link rel="<%= htmlWebpackPlugin.options.links.favicon.rel %>" href="<%= htmlWebpackPlugin.options.links.favicon.href %>" type="<%= htmlWebpackPlugin.options.links.favicon.type %>">
<link rel="<%= htmlWebpackPlugin.options.links.icon.rel %>" href="<%= htmlWebpackPlugin.options.links.icon.href %>" type="<%= htmlWebpackPlugin.options.links.icon.type %>">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body id="app">
<noscript>
<strong>Sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<!-- built files will be auto injected -->
</body>
</html>

BIN
public/preview.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 377 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 MiB

BIN
public/sebin-ref-full-NSFW-hires.jpg Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 MiB

After

Width:  |  Height:  |  Size: 9.7 MiB

Before After
Before After

BIN
public/sebin-ref-full-SFW-hires.jpg Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 MiB

After

Width:  |  Height:  |  Size: 9.5 MiB

Before After
Before After

View file

@ -1,99 +1,158 @@
<script setup lang="ts">
import { ref, provide } from 'vue'
import { RouterView } from 'vue-router'
import { modalResultKey, nsfwKey, showModalKey } from '@/keys'
import { version } from '../package.json'
import RefModal from '@/components/RefModal.vue'
import ButtonGroup from '@/components/ButtonGroup.vue'
import Button from '@/components/RefButton.vue'
import SiteHeader from '@/components/SiteHeader.vue'
import SiteFooter from '@/components/SiteFooter.vue'
import SiteNavigation from '@/components/SiteNavigation.vue'
const isNsfw = ref(false)
const isConfirmedHorny = ref(false)
const nsfwmodal = ref<InstanceType<typeof RefModal>>()
const showModal = (): void => {
if (!isConfirmedHorny.value) {
nsfwmodal.value?.showModal()
setTimeout(() => {
isNsfw.value = false
}, 1)
} else {
isNsfw.value = !isNsfw.value
}
}
const modalResult = (value: boolean): void => {
isNsfw.value = value
isConfirmedHorny.value = value
nsfwmodal.value?.close()
}
provide(modalResultKey, modalResult)
provide(nsfwKey, isNsfw)
provide(showModalKey, showModal)
</script>
<template>
<RefModal id="nsfw-warning" ref="nsfwmodal">
<template #heading>
<br />
Whoa, Nelly!
</template>
<ref-header>
<img
class="nav-logo"
src="@/assets/sebin-smug-icon.png"
alt="Sebin Avatar"
/>
<template #message>
By enabling NSFW mode you confirm that you are of legal age to view adult content.
</template>
<template #buttons>
<ButtonGroup col>
<Button positive @click.prevent="modalResult(true)"> Yes, show me the goods 👀 </Button>
<Button negative @click.prevent="modalResult(false)"> NO, STAHP 😱 </Button>
</ButtonGroup>
</template>
</RefModal>
<SiteHeader>
<!-- max 500px -->
<picture>
<source
srcset="
@/assets/sebin-smug-icon.png?w=36;40;48;56;72;80;96;112;108;120;144;168&format=avif&quality=75&as=srcset
"
sizes="(min-width: 120em) 56px, (min-width: 80em) 48px, (min-width: 35em) 40px, 36px"
type="image/avif"
/>
<source
srcset="
@/assets/sebin-smug-icon.png?w=36;40;48;56;72;80;96;112;108;120;144;168&format=webp&quality=100&as=srcset
"
sizes="(min-width: 120em) 56px, (min-width: 80em) 48px, (min-width: 35em) 40px, 36px"
type="image/webp"
/>
<img
class="nav-logo"
srcset="@/assets/sebin-smug-icon.png?w=36;40;48;56;72;80;96;112;108;120;144;168&format=png&as=srcset"
sizes="(min-width: 120em) 56px, (min-width: 80em) 48px, (min-width: 35em) 40px, 36px"
alt="Sebin Avatar"
/>
</picture>
<SiteNavigation />
</SiteHeader>
<navigation :routes="routes" />
</ref-header>
<main>
<RouterView />
<router-view />
</main>
<SiteFooter>
<ref-footer>
<p>v{{ version }} &copy; {{ new Date().getFullYear() }} Sebin Nyshkim</p>
<p>
Background Pattern &copy;
<a href="https://www.svgbackgrounds.com/">SVG Backgrounds</a>
</p>
</SiteFooter>
</ref-footer>
</template>
<script>
import Navigation from "@/components/Navigation.vue";
import RefHeader from "@/components/Header.vue";
import RefFooter from "@/components/Footer.vue";
export default {
components: { Navigation, RefHeader, RefFooter },
data() {
return {
nsfw: false,
isConfirmedHorny: false,
isWarn: false,
version: require("../package.json").version,
routes: [
{ path: "/", name: "Home" },
{ path: "/general", name: "General" },
{ path: "/anatomy", name: "Anatomy" },
{ path: "/clothing", name: "Clothing" },
{ path: "/abilities", name: "Abilities" },
{ path: "/overdrive", name: "Overdrive" },
],
links: [
{ href: "https://twitter.com/SebinNyshkim", text: "Twitter" },
{ href: "https://t.me/SebinNyshkim", text: "Telegram" },
{
href: "https://www.furaffinity.net/user/sonofdragons",
text: "Fur Affinity",
},
],
};
},
methods: {
showWarning() {
if (!this.isConfirmedHorny) {
this.isWarn = true;
document.body.classList.toggle("scroll-lock");
setTimeout(() => {
this.nsfw = false;
}, 1);
}
},
},
};
</script>
<style lang="scss">
@import "@/scss/base.scss";
@import "~normalize.css";
#app {
color: $copy-color;
font-size: 1.125em;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
transition: all ease-in-out 0.25s;
@include mq-desktop {
font-size: 1.25em;
}
@include mq-bigscreen {
font-size: 1.5em;
}
position: relative;
&:before,
&:after {
content: "";
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
&:before {
background: url("/subtle-prism.svg");
mix-blend-mode: multiply;
z-index: -1;
}
&:after {
background: radial-gradient(
circle at bottom right,
$bg-color-lighter 5%,
transparent 50%
),
radial-gradient(
circle at top left,
$bg-color-light 5%,
$bg-color-dark 100%
);
z-index: -2;
@include theme(dark) {
background: radial-gradient(
circle at bottom right,
darken($bg-color-lighter, 30%) 5%,
transparent 50%
),
radial-gradient(
circle at top left,
darken($bg-color-light, 10%) 5%,
darken($bg-color-dark, 10%) 100%
);
}
}
}
.nav-logo {
display: block;
margin: 0 0.5em 0 0.25em;
height: 2em;
border: 0.125em solid #fff;
border-radius: 100%;
box-shadow: 0.125em 0.125em 0.5em rgba(#000, 0.7);
}
main {
min-height: 100vh;
padding: 2em 0 1em 0;
}
.footer p {
margin: 0;
& + p {
margin: 0.5em auto 0 auto;
}
}
</style>

View file

@ -1,19 +0,0 @@
/* dosis-regular-latin */
@font-face {
font-family: Dosis;
font-style: normal;
font-weight: 400;
src: local("Dosis Regular"), local("Dosis-Regular"), url(dosis-regular-latin.woff2) format("woff2");
unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2212,U+2215;
font-display: swap;
}
/* dosis-bold-latin */
@font-face {
font-family: Dosis;
font-style: normal;
font-weight: 700;
src: local("Dosis Bold"), local("Dosis-Bold"), url(dosis-bold-latin.woff2) format("woff2");
unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2212,U+2215;
font-display: swap;
}

View file

@ -1,37 +0,0 @@
/* exo-light-latin */
@font-face {
font-family: Exo;
font-style: normal;
font-weight: 300;
src: local("Exo Light"), local("Exo-Light"), url(exo-light-latin.woff2) format("woff2");
unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2212,U+2215;
font-display: swap;
}
/* exo-black-latin */
@font-face {
font-family: Exo;
font-style: normal;
font-weight: 900;
src: local("Exo Black"), local("Exo-Black"), url(exo-black-latin.woff2) format("woff2");
unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2212,U+2215;
font-display: swap;
}
/* exo-light-italic-latin */
@font-face {
font-family: Exo;
font-style: italic;
font-weight: 300;
src: local("Exo Light Italic"), local("Exo-LightItalic"), url(exo-light-italic-latin.woff2) format("woff2");
unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2212,U+2215;
font-display: swap;
}
/* exo-black-italic-latin */
@font-face {
font-family: Exo;
font-style: italic;
font-weight: 900;
src: local("Exo Black Italic"), local("Exo-BlackItalic"), url(exo-black-italic-latin.woff2) format("woff2");
unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2212,U+2215;
font-display: swap;
}

View file

@ -1,10 +0,0 @@
/* permanent-marker-regular-latin */
@font-face {
font-family: Permanent Marker;
font-style: normal;
font-weight: 400;
src: local("Permanent Marker Regular"), local("PermanentMarker-Regular"), url(permanent-marker-regular-latin.woff2) format("woff2");
unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2212,U+2215;
font-display: swap;
}

View file

@ -1,10 +0,0 @@
/* zilla-slab-bold-latin */
@font-face {
font-family: Zilla Slab;
font-style: normal;
font-weight: 700;
src: local("Zilla Slab Bold"), local("ZillaSlab-Bold"), url(zilla-slab-bold-latin.woff2) format("woff2");
unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2212,U+2215;
font-display: swap;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 218 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 551 KiB

After

Width:  |  Height:  |  Size: 84 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 524 KiB

After

Width:  |  Height:  |  Size: 77 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 656 KiB

After

Width:  |  Height:  |  Size: 94 KiB

Before After
Before After

0
src/assets/refs/clothes/casual/fullbody.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 784 KiB

After

Width:  |  Height:  |  Size: 784 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 734 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 717 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 MiB

After

Width:  |  Height:  |  Size: 432 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 376 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 657 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 560 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 589 KiB

After

Width:  |  Height:  |  Size: 393 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 512 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 867 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 378 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 619 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 MiB

View file

@ -17,51 +17,76 @@
</template>
<style lang="scss">
@import "@/scss/_mixins.scss";
.attack {
flex: var(--attack-item-flex);
flex: 0 1 100%;
display: flex;
flex-flow: var(--attack-item-flex-flow);
flex-flow: row wrap;
align-items: center;
margin: 0;
padding: 0.375em 0;
&:nth-child(even) {
text-align: var(--attack-item-nth-child-even-text-align);
@include mq-desktop {
flex-flow: row nowrap;
&:nth-child(even) {
text-align: right;
.attack__illustration,
.attack__text {
&:first-child {
order: 1;
}
}
}
}
&:nth-child(even) &__illustration,
&:nth-child(even) &__text {
&:first-child {
order: var(--attack-item-first-child-order);
@media (min-width: 70em) {
text-align: left;
flex: 0 1 50%;
&:nth-child(even) {
text-align: left;
.attack__illustration,
.attack__text {
&:first-child {
order: 0;
}
}
}
}
&__illustration {
flex: var(--attack-item-illustration-flex);
display: flex;
flex-flow: row nowrap;
justify-content: center;
align-items: center;
flex: 1 1 auto;
text-align: center;
img {
max-width: 100%;
max-height: 100%;
}
@include mq-desktop {
flex: 0 0 15em;
height: 15em;
}
}
&__text {
flex: 1 1 auto;
padding: var(--attack-item-text-padding);
@include mq-desktop {
padding: 0 1rem;
}
}
&__name {
font-weight: bold;
margin: 0 0 1em 0;
font-weight: bold;
}
}
</style>

View file

@ -5,14 +5,22 @@
</template>
<style lang="scss">
@import "@/scss/_mixins.scss";
.attacks {
display: flex;
flex-flow: row wrap;
align-items: center;
width: 100%;
max-width: var(--attack-list-max-width);
margin: auto;
padding: 0 var(--container-spacing-right-safe) 0 var(--container-spacing-left-safe);
@include mq-desktop {
max-width: 45rem;
}
@media (min-width: 70em) {
max-width: 70em;
}
}
</style>

57
src/components/Button.vue Normal file
View file

@ -0,0 +1,57 @@
<template>
<a
class="btn"
:href="href"
:download="href.slice(href.lastIndexOf('/') + 1)"
v-if="download"
>
<slot></slot>
</a>
<a class="btn" :href="href" v-else><slot></slot></a>
</template>
<script>
export default {
props: {
href: String,
download: Boolean,
},
};
</script>
<style lang="scss">
@import "@/scss/_variables.scss";
@import "@/scss/_mixins.scss";
.btn {
margin: 0.5em 0;
padding: 0.5em 1em;
position: relative;
top: 0;
border-radius: 0.25em;
transition: all 0.1s ease-out;
font-weight: bold;
background-color: $bg-color-light;
text-decoration: none;
text-align: center;
@include button($bg-color-light);
@include theme(dark) {
@include button($bg-color-dark);
}
&:hover {
top: -0.25em;
}
&:active {
top: 0.25em;
}
}
</style>

View file

@ -1,48 +0,0 @@
<script setup lang="ts">
interface Props {
col?: boolean
grid?: boolean
}
defineProps<Props>()
</script>
<template>
<div class="btn-group" :class="{ col: col, grid: grid }">
<slot></slot>
</div>
</template>
<style lang="scss">
.btn-group {
display: flex;
flex-flow: row wrap;
justify-content: space-evenly;
&.col {
flex-flow: column nowrap;
gap: 1.5rem;
margin: 1rem 0;
> * {
margin: 0;
}
}
&.grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
margin: 1rem 0;
> * {
margin: 0;
}
}
> * {
flex: var(--button-group-flex);
margin: 1rem 0;
}
}
</style>

View file

@ -1,53 +0,0 @@
<script setup lang="ts">
import type { ColorDict } from '@/interfaces'
interface Props {
colors: ColorDict[]
}
defineProps<Props>()
</script>
<template>
<table class="color-table">
<thead class="color-table__head">
<tr class="color-table__row">
<th class="color-table__heading name">Body part</th>
<th class="color-table__heading value">Value</th>
<th class="color-table__heading color">Color</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">{{ color.name }}</td>
<td class="color-table__cell value">{{ color.value }}</td>
<td class="color-table__cell color" :style="{ 'background-color': color.value }"></td>
</tr>
</tbody>
</table>
</template>
<style lang="scss">
.color-table {
&__heading {
&.name {
text-align: right;
}
}
&__cell {
&.name {
text-align: right;
}
&.value {
font-family: monospace;
text-align: center;
}
&.color {
min-width: 10vw;
}
}
}
</style>

View file

@ -1,37 +1,152 @@
<script setup lang="ts">
interface Props {
headings: string[]
data: string[][]
}
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">
{{ heading }}
<table class="datatable">
<thead class="datatable__head">
<tr class="datatable__row">
<th
class="datatable__heading"
v-for="(header, idx) in dataset.headers"
:key="idx"
>
{{ header }}
</th>
</tr>
</thead>
<tbody class="data-table__body">
<tr class="data-table__row" v-for="(row, idx) in data" :key="idx">
<td class="data-table__cell" v-for="(cell, idx) in row" :key="idx">
{{ cell }}
<tbody class="datatable__body">
<tr class="datatable__row" v-for="(row, idx) in dataset.data" :key="idx">
<td
class="datatable__cell"
v-for="(cell, idx) in row"
:key="idx"
:colspan="idx === 1 && !isHexValue(row[1]) ? 2 : 1"
:class="{ 'datatable__cell--hex': idx === 1 && isHexValue(row[1]) }"
>
<template v-if="Array.isArray(cell)">
<ul class="col-2">
<li v-for="(item, idx) in cell" :key="idx">
{{ item }}
</li>
</ul>
</template>
<template v-else>
<template v-if="isHexValue(cell)">
<a href="#" @click.prevent="copyToClipboard(cell)">
{{ cell }}
</a>
</template>
<template v-else>
{{ cell }}
</template>
</template>
</td>
<td
v-if="isHexValue(row[1])"
class="datatable__cell--colorpick"
:style="{ backgroundColor: row[1] }"
></td>
</tr>
</tbody>
</table>
</template>
<style lang="scss">
.data-table {
table-layout: fixed;
<script>
export default {
name: "DataTable",
props: {
dataset: {
type: Object,
required: true,
},
},
methods: {
isHexValue(value) {
return /^#[0-9a-f]{6}$/i.test(value) ? value : false;
},
copyToClipboard(value) {
navigator.clipboard.writeText(value);
},
},
};
</script>
&__cell:first-child {
text-align: right;
<style lang="scss">
@import "@/scss/_variables.scss";
@import "@/scss/_mixins.scss";
.datatable {
border-collapse: collapse;
width: 100%;
margin: auto;
@include mq-desktop {
max-width: 45rem;
}
@include mq-bigscreen {
max-width: 55rem;
}
&__heading,
&__cell {
padding: 0.25em 0.5em;
@media (min-width: 35em) {
padding: 0.5em 1em;
}
ul {
margin: 0;
padding: 0;
@include mq-desktop {
&.col-2 {
columns: 2 auto;
}
&.col-3 {
columns: 3 auto;
}
}
}
li {
margin: 0 0 0 1em;
padding: 0;
}
}
&__head {
color: $copy-color;
border-top: 0.0625em solid $sebin-secondary;
}
&__body {
border: {
top: 0.0625em solid $sebin-secondary;
bottom: 0.0625em solid $sebin-secondary;
}
}
&__body &__row:hover {
background: rgba(#000, 0.3);
}
&__cell {
a {
text-decoration: none;
}
&:first-child {
text-align: right;
}
&--hex {
font-family: monospace;
}
&--colorpick {
border: 0.0625em solid #fff;
}
}
}
</style>

187
src/components/Figure.vue Normal file
View file

@ -0,0 +1,187 @@
<template>
<figure class="figure">
<div
class="figure__border"
:class="{ 'figure__border--polaroid': polaroidBorder }"
>
<template v-if="!nsfw || $root.nsfw">
<div
class="figure__image"
:class="{ 'figure__image--dropshadow': dropshadow }"
>
<slot name="img"></slot>
</div>
</template>
<template v-else>
<div class="figure__cencor">
<div class="hazard-tape"></div>
<div class="hazard-tape"></div>
<div class="hazard-tape"></div>
<div class="hazard-tape"></div>
<div class="figure__reveal">
<p>🔥 Here be spicy dragons 🌶</p>
<nsfw-switch
:id="id"
v-model="$root.nsfw"
@change="$root.showWarning()"
/>
</div>
</div>
</template>
<figcaption class="figure__meta">
<template v-if="!nsfw || $root.nsfw">
<div class="caption"><slot name="caption"></slot></div>
<div class="copyright">© <slot name="copyright"></slot></div>
</template>
<template v-else>
<p>😳 2 hot 4 u 🍆</p>
</template>
</figcaption>
</div>
</figure>
</template>
<script>
import NsfwSwitch from "@/components/NsfwSwitch.vue";
export default {
props: {
polaroidBorder: Boolean,
dropshadow: Boolean,
nsfw: Boolean,
id: String,
},
components: {
NsfwSwitch,
},
};
</script>
<style lang="scss">
@import "@/scss/_variables.scss";
@import "@/scss/_mixins.scss";
.figure {
display: flex;
flex-flow: row nowrap;
justify-content: center;
margin: 1em auto;
text-align: center;
&__border {
display: flex;
flex-flow: column nowrap;
justify-content: center;
margin: auto;
&--polaroid {
margin: 1em auto;
padding: 1em;
box-shadow: inset 0 0 1em rgba(#000, 0.7), 0 0 1em rgba(#000, 0.7);
border-radius: 0.325em;
background-color: #fff;
.figure__meta {
margin: 0.5em 0;
font-family: "Permanent Marker", fantasy;
color: $copy-color-darkgrey;
* {
color: inherit;
}
}
}
}
&__image {
flex: 1 0 auto;
img {
max-width: 100%;
max-height: 35em;
}
&--dropshadow {
filter: drop-shadow(0.5em 0.25em 0.375em #000);
}
}
&__meta {
flex: 0 0 auto;
}
&__cencor {
flex: 1 0 auto;
display: flex;
flex-flow: row wrap;
justify-content: center;
align-items: center;
padding: 0;
width: 50vw;
height: 35vh;
max-width: 35em;
max-height: 70em;
position: relative;
background-color: $bg-color-lighter;
overflow: hidden;
@include mq-desktop {
width: 20em;
height: 20em;
}
.figure__border & .nsfw-switch {
position: relative;
padding: 0;
}
.hazard-tape {
position: absolute;
left: -1em;
right: -1em;
top: 0;
transform: rotate(0deg);
height: 1em;
background-image: repeating-linear-gradient(
-55deg,
#000,
#000 0.75em,
#ffb101 0.75em,
#ffb101 1.5em
);
&:nth-child(1) {
top: 10%;
transform: rotate(5deg);
}
&:nth-child(2) {
top: 15%;
transform: rotate(-10deg);
}
&:nth-child(3) {
top: 75%;
transform: rotate(-15deg);
}
&:nth-child(4) {
top: 85%;
transform: translate(-5em, -2em) rotate(40deg);
}
}
}
}
</style>

View file

@ -1,161 +0,0 @@
<script setup lang="ts">
import { computed } from 'vue'
import { Ratings } from '@/interfaces'
interface Props {
modelValue: number[]
name?: string
value: Ratings
}
interface Emits {
(e: 'update:modelValue', value: number[]): void
}
const props = defineProps<Props>()
const emit = defineEmits<Emits>()
const checked = computed({
get() {
return props.modelValue
},
set(value) {
emit('update:modelValue', value)
}
})
</script>
<template>
<div class="filter-button">
<input
class="filter-button__input"
type="checkbox"
:name="name"
:id="Ratings[value].toLowerCase()"
:value="value"
v-model="checked"
/>
<label
:for="Ratings[value].toLowerCase()"
class="filter-button__label"
:class="[Ratings[value].toLowerCase()]"
>
{{ Ratings[value] }}
</label>
</div>
</template>
<style lang="scss">
.filter-button {
flex: 1 1 0;
&__input {
display: none;
}
&__input:checked + &__label {
top: 0.25rem;
box-shadow: 0 0.25rem 0 0 var(--color-button-box-shadow);
&.love {
box-shadow: 0 0.25rem 0 0 var(--theme-c-love-dark);
}
&.yes {
box-shadow: 0 0.25rem 0 0 var(--theme-c-yes-dark);
}
&.maybe {
box-shadow: 0 0.25rem 0 0 var(--theme-c-maybe-dark);
}
&.no {
box-shadow: 0 0.25rem 0 0 var(--theme-c-no-dark);
}
}
&__label {
display: block;
position: relative;
top: 0;
background-color: var(--color-button);
font-weight: 700;
text-decoration: none;
text-align: center;
margin: 0.5rem 0;
border-radius: 0.25rem;
padding: 0.5rem 1rem;
box-shadow: 0 0.5rem 0 0 var(--color-button-box-shadow);
transition: all 0.1s ease-out;
&:hover {
cursor: pointer;
top: -0.25rem;
box-shadow: 0 0.75rem 0 0 var(--color-button-box-shadow);
}
&:active {
top: 0.25rem;
box-shadow: 0 0.25rem 0 0 var(--color-button-box-shadow);
}
&.love {
background-color: var(--theme-c-love);
box-shadow: 0 0.5rem 0 0 var(--theme-c-love-dark);
&:hover {
box-shadow: 0 0.75rem 0 0 var(--theme-c-love-dark);
}
&:active {
box-shadow: 0 0.25rem 0 0 var(--theme-c-love-dark);
}
}
&.yes {
background-color: var(--theme-c-yes);
box-shadow: 0 0.5rem 0 0 var(--theme-c-yes-dark);
&:hover {
box-shadow: 0 0.75rem 0 0 var(--theme-c-yes-dark);
}
&:active {
box-shadow: 0 0.25rem 0 0 var(--theme-c-yes-dark);
}
}
&.maybe {
background-color: var(--theme-c-maybe);
box-shadow: 0 0.5rem 0 0 var(--theme-c-maybe-dark);
&:hover {
box-shadow: 0 0.75rem 0 0 var(--theme-c-maybe-dark);
}
&:active {
box-shadow: 0 0.25rem 0 0 var(--theme-c-maybe-dark);
}
}
&.no {
background-color: var(--theme-c-no);
box-shadow: 0 0.5rem 0 0 var(--theme-c-no-dark);
&:hover {
box-shadow: 0 0.75rem 0 0 var(--theme-c-no-dark);
}
&:active {
box-shadow: 0 0.25rem 0 0 var(--theme-c-no-dark);
}
}
}
}
</style>

View file

@ -1,77 +0,0 @@
<script setup lang="ts">
interface Props {
type: string
}
defineProps<Props>()
</script>
<template>
<span class="filter-list__tag" :class="type.toLowerCase()">
<span>{{ type }}</span>
</span>
</template>
<style lang="scss">
.filter-list {
&__tag {
flex: 0 0 0;
span {
display: block;
font-size: 0.75rem;
font-weight: bold;
text-align: center;
background: rgba(#f5f5f5, 0.7);
border: 1px solid #f5f5f5;
border-radius: 1em;
padding: 0 0.5em;
}
&.love span {
background: var(--theme-c-love);
border: 1px solid var(--theme-c-love-dark);
}
&.yes span {
background: var(--theme-c-yes);
border: 1px solid var(--theme-c-yes-dark);
}
&.maybe span {
background: var(--theme-c-maybe);
border: 1px solid var(--theme-c-maybe-dark);
}
&.no span {
background: var(--theme-c-no);
border: 1px solid var(--theme-c-no-dark);
}
&.category {
flex: 0 0 3rem;
}
&.receive {
flex: 0 0 3.125rem;
span {
background: var(--theme-c-receive);
border: 1px solid var(--theme-c-receive);
}
}
&.give {
flex: 0 0 2.125rem;
span {
background: var(--theme-c-give);
border: 1px solid var(--theme-c-give);
}
}
}
}
</style>

View file

@ -1,127 +0,0 @@
<script setup lang="ts">
import { computed, ref } from 'vue'
import { Ratings, Role } from '@/interfaces'
import type { Kink } from '@/interfaces'
import FilterButton from '@/components/FilterButton.vue'
import FilterListTag from '@/components/FilterListTag.vue'
interface Props {
data: Kink[]
}
const props = defineProps<Props>()
const filterOptions = ref<number[]>([])
const filteredItems = computed(() =>
[...props.data]
.sort((a, b) => a.rating - b.rating)
.filter((kink) => filterOptions.value.some((filterNum) => kink.rating === filterNum))
)
</script>
<template>
<div class="filter-list">
<div class="filter-list__filters">
<FilterButton name="rating" :value="Ratings.Love" v-model="filterOptions" />
<FilterButton name="rating" :value="Ratings.Yes" v-model="filterOptions" />
<FilterButton name="rating" :value="Ratings.Maybe" v-model="filterOptions" />
<FilterButton name="rating" :value="Ratings.No" v-model="filterOptions" />
</div>
<div class="filter-list__list-container">
<template v-if="filterOptions.length > 0">
<ul class="filter-list__list">
<li v-for="(item, idx) in filteredItems" :key="idx" class="filter-list__item">
<FilterListTag
v-if="filterOptions.length > 1"
class="category"
:type="Ratings[item.rating]"
/>
<span class="filter-list__item-name">
<span>{{ item.name }}</span>
</span>
<FilterListTag
v-if="((item.role ?? 0) & Role.Receive) === Role.Receive"
:type="Role[Role.Receive]"
/>
<FilterListTag
v-if="((item.role ?? 0) & Role.Give) === Role.Give"
:type="Role[Role.Give]"
/>
</li>
</ul>
</template>
<template v-else>
<p class="filter-list__intro-msg">Select one of the categories above</p>
</template>
</div>
</div>
</template>
<style lang="scss">
.filter-list {
background: var(--quickfacts-background);
border-radius: 1rem;
box-shadow: var(--container-box-shadow);
overflow: hidden;
&__options {
display: flex;
gap: 1rem;
margin: 0;
padding: 0;
list-style: none;
}
&__filters {
display: flex;
gap: 0.75rem;
border-collapse: collapse;
padding: 0.5rem 0.75rem;
}
&__intro-msg {
font-size: 2rem;
font-weight: bold;
font-style: italic;
text-align: center;
hyphens: none;
}
&__list-container {
border-top: 0.125rem solid var(--color-quickfacts-border);
border-collapse: collapse;
}
&__list {
max-height: 30rem;
margin: 0;
padding: 0;
overflow: scroll;
}
&__item {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
gap: 0.5rem;
padding: 0.25rem 0.875rem;
&:hover {
background: rgba(#000, 0.3);
}
}
&__item-name {
flex: 1 0 0;
line-height: 2;
}
}
</style>

22
src/components/Footer.vue Normal file
View file

@ -0,0 +1,22 @@
<template>
<footer class="footer">
<slot></slot>
</footer>
</template>
<script></script>
<style lang="scss">
@import "@/scss/_variables.scss";
@import "@/scss/_mixins.scss";
.footer {
background: url("/subtle-prism.svg") $bg-color-dark;
background-blend-mode: multiply;
padding: max(1em, env(safe-area-inset-top)) 0
max(1em, env(safe-area-inset-bottom)) 0;
text-align: center;
}
</style>

188
src/components/Gallery.vue Normal file
View file

@ -0,0 +1,188 @@
<template>
<div class="gallery">
<div class="gallery__images">
<a
href="#"
class="gallery__prev"
@click.prevent="prev()"
v-show="activeImage > 0"
></a>
<a
href="#"
class="gallery__next"
@click.prevent="next()"
v-show="activeImage < images.length - 1"
></a>
<div class="gallery__viewport" :style="offset">
<slot></slot>
</div>
</div>
<nav class="gallery__navigation">
<ul>
<li v-for="(image, idx) in images" :key="idx">
<a
href="#"
:class="{ active: activeImage === idx }"
@click.prevent="setActive(idx)"
></a>
</li>
</ul>
</nav>
</div>
</template>
<script>
export default {
name: "gallery",
data() {
return {
activeImage: 0,
images: [],
};
},
computed: {
offset() {
return `margin-left: -${this.activeImage * 100}%`;
},
},
methods: {
setActive(index) {
this.activeImage = index;
},
prev() {
if (this.activeImage > 0) {
this.activeImage -= 1;
}
},
next() {
if (this.activeImage < this.images.length - 1) {
this.activeImage += 1;
}
},
},
mounted() {
const sel = ".gallery__viewport .figure";
const elements = this.$el.querySelectorAll(sel);
const images = Array.from(elements);
this.images = images;
},
};
</script>
<style lang="scss">
@import "@/scss/_variables.scss";
@import "@/scss/_mixins.scss";
.gallery {
&__prev,
&__next {
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 1em;
height: 1em;
z-index: 1;
border: {
top: 0.125em solid #fff;
right: 0.125em solid #fff;
}
@include mq-desktop {
width: 1.5em;
height: 1.5em;
}
}
&__prev {
left: 1.5em;
transform: rotate(-135deg);
@include mq-desktop {
left: 2em;
}
}
&__next {
right: 1.5em;
transform: rotate(45deg);
@include mq-desktop {
right: 2em;
}
}
&__images {
position: relative;
overflow: hidden;
}
&__viewport {
display: flex;
flex-flow: row nowrap;
align-items: center;
width: 100%;
height: 100%;
transition: 0.3s all ease-in-out;
}
.figure {
margin: 0;
padding: 0 3em;
flex: 1 0 100%;
@include mq-desktop {
padding: 0 3.5em;
}
&__meta {
text-align: center;
p {
margin: 0.5em auto;
}
}
}
&__navigation {
display: flex;
flex-flow: row wrap;
justify-content: center;
ul {
flex: 0 1 auto;
display: flex;
flex-flow: row wrap;
justify-content: center;
list-style: none;
margin: 1em 0;
padding: 0;
}
li {
flex: 0 1 auto;
padding: 0.375em;
a {
display: block;
width: 0.5em;
height: 0.5em;
border-radius: 1em;
background: rgba(#fff, 0.5);
&.active {
background: #fff;
}
}
}
}
}
</style>

65
src/components/Header.vue Normal file
View file

@ -0,0 +1,65 @@
<template>
<header class="header">
<slot></slot>
</header>
</template>
<script></script>
<style lang="scss">
@import "@/scss/_variables.scss";
@import "@/scss/_mixins.scss";
.header {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
position: sticky;
top: max(1em, env(safe-area-inset-top));
right: max(1em, env(safe-area-inset-right));
left: max(1em, env(safe-area-inset-left));
z-index: 2;
max-width: 70em;
margin: 1em max(1em, env(safe-area-inset-right)) 1em
max(1em, env(safe-area-inset-left));
padding: 0.5em;
border-radius: 0.5em;
box-shadow: 0.125em 0.125em 0.5em rgba(#000, 0.7);
background: radial-gradient(
circle at bottom right,
darken($bg-color-lighter, 30%) 20%,
transparent 80%
),
radial-gradient(
circle at top left,
darken($sebin-secondary, 20%) 5%,
darken($sebin-primary, 20%) 100%
);
@include theme(dark) {
background: radial-gradient(
circle at bottom right,
darken($bg-color-lighter, 35%) 20%,
transparent 80%
),
radial-gradient(
circle at top left,
darken($sebin-secondary, 35%) 5%,
darken($sebin-primary, 35%) 100%
);
}
@include theme(dark) {
background-color: $bg-color-dark;
}
@media (min-width: 90em) {
margin: 0 auto;
}
}
</style>

View file

@ -1,43 +1,52 @@
<script setup lang="ts">
import { RouterLink } from 'vue-router'
import router from '@/router'
</script>
<template>
<nav class="nav">
<ul class="nav__list">
<li class="nav__item" v-for="(route, idx) in router.options.routes" :key="idx">
<RouterLink class="nav__link" :to="route.path">
<ul class="nav__list flex flex--row flex--nowrap flex--center-v">
<li class="nav__item" v-for="(route, idx) in routes" :key="idx">
<router-link class="nav__link" :to="route.path">
{{ route.name }}
</RouterLink>
</router-link>
<div class="nav__underline"></div>
</li>
</ul>
</nav>
</template>
<script>
export default {
props: {
routes: {
required: true,
type: Array,
},
},
};
</script>
<style lang="scss">
@import "@/scss/_variables.scss";
@import "@/scss/_mixins.scss";
.nav {
overflow: auto;
&__list {
display: flex;
flex-flow: row nowrap;
justify-content: var(--navigation-justify-content);
align-items: center;
width: 100%;
margin: 0;
padding: 0;
list-style-type: none;
z-index: 1;
overflow: auto;
width: 100%;
@include mq-desktop {
justify-content: center;
}
}
&__item {
padding: 0.375rem;
padding: 0.375em;
white-space: nowrap;
}
@ -45,22 +54,28 @@ import router from '@/router'
display: block;
font-weight: bold;
line-height: 1;
color: var(--color-text);
color: $copy-color;
margin-bottom: 0.375em;
text-decoration: none;
text-transform: capitalize;
&.router-link-exact-active {
color: var(--color-text);
color: #fff;
}
}
&__link:hover ~ &__underline {
&:before,
&:after {
width: 50%;
background-color: $copy-color;
}
}
&__link:hover ~ &__underline,
&__link.router-link-exact-active ~ &__underline {
&:before,
&:after {
width: 50%;
background-color: var(--color-text);
background-color: #fff;
}
}
@ -71,13 +86,11 @@ import router from '@/router'
&:before,
&:after {
content: '';
content: "";
position: absolute;
bottom: 0;
width: 0;
height: 0.125rem;
height: 0.125em;
bottom: 0;
transition: all 0.2s ease-in-out;
}

View file

@ -1,48 +1,36 @@
<script setup lang="ts">
import { computed } from 'vue'
interface Props {
modelValue: boolean
id: string
name?: string
}
interface Emits {
(e: 'update:modelValue', value: boolean): void
}
const props = defineProps<Props>()
const emit = defineEmits<Emits>()
const checked = computed({
get() {
return props.modelValue
},
set(value) {
emit('update:modelValue', value)
}
})
</script>
<template>
<label :for="id" class="toggle">
<div class="toggle__label">
<slot name="off"></slot>
</div>
<div class="toggle__input">
<input type="checkbox" :name="name" :id="id" v-model="checked" />
<div class="toggle__inner"></div>
</div>
<div class="toggle__label">
<slot name="on"></slot>
<label class="nsfw-switch" :for="id">
<div class="nsfw-switch__label">😇</div>
<div class="nsfw-switch__toggle">
<input
:checked="modelValue"
@change="$emit('update:modelValue', $event.target.checked)"
type="checkbox"
name="nsfw"
:id="id"
/>
<div class="nsfw-switch__toggle-inner"></div>
</div>
<div class="nsfw-switch__label">😈</div>
</label>
</template>
<script>
export default {
props: {
modelValue: Boolean,
id: { type: String, required: true },
},
};
</script>
<style lang="scss">
.toggle {
font-family: 'apple color emoji', 'noto color emoji', 'segoe ui emoji', 'android emoji',
'emojisymbols', 'emojione mozilla', 'twemoji mozilla', 'segoe ui symbol';
@import "@/scss/_variables.scss";
.nsfw-switch {
font-family: "apple color emoji", "segoe ui emoji", "noto color emoji",
"android emoji", "emojisymbols", "emojione mozilla", "twemoji mozilla",
"segoe ui symbol";
padding: 0.5em;
@ -59,23 +47,23 @@ const checked = computed({
text-align: center;
}
&__input {
&__toggle {
margin: 0 0.5em;
}
&__input input:checked + &__inner {
background-color: var(--color-toggle);
& input:checked + &-inner {
background-color: $sebin-primary;
&:before {
transform: translate3d(0.9em, 0.1em, 0) scale3d(0, 0, 0);
}
&:before {
transform: translate3d(0.9em, 0.1em, 0) scale3d(0, 0, 0);
}
&:after {
transform: translate3d(1.1em, 0.1em, 0);
&:after {
transform: translate3d(1.1em, 0.1em, 0);
}
}
}
&__inner {
&__toggle-inner {
position: relative;
display: inline-block;
width: 2.3em;
@ -87,7 +75,7 @@ const checked = computed({
&:before,
&:after {
content: '';
content: "";
position: absolute;
left: 0;
height: 1.1em;
@ -115,12 +103,12 @@ const checked = computed({
pointer-events: none;
}
&:active &__inner:after {
&:active &__toggle-inner:after {
width: 1.4em;
transform: translate3d(0.1em, 0.1em, 0);
}
&:active input:checked + &__inner:after {
&:active input:checked + &__toggle-inner:after {
transform: translate3d(0.8em, 0.1em, 0);
}
}

View file

@ -0,0 +1,122 @@
<template>
<div class="nsfw-warning">
<div class="nsfw-warning__background"></div>
<div class="nsfw-warning__message">
<div>
<h2><slot name="heading"></slot></h2>
<p><slot name="message"></slot></p>
<div class="btn-container">
<btn href="#" class="positive" @click.prevent="confirmNsfw(true)">
<slot name="yes"></slot>
</btn>
<btn href="#" class="negative" @click.prevent="confirmNsfw(false)">
<slot name="no"></slot>
</btn>
</div>
</div>
</div>
</div>
</template>
<script>
import btn from "@/components/Button.vue";
export default {
components: { btn },
methods: {
confirmNsfw(input) {
this.$root.nsfw = input;
this.$root.isConfirmedHorny = input;
this.$root.isWarn = false;
document.body.classList.toggle("scroll-lock");
},
},
};
</script>
<style lang="scss">
@import "@/scss/_variables.scss";
@import "@/scss/_mixins.scss";
.nsfw-warning {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 9001;
backdrop-filter: blur(1em);
background-color: rgba(#000, 0.5);
display: flex;
flex-flow: row nowrap;
justify-content: center;
padding: 2em;
text-align: center;
overflow: auto;
&__background {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
&__message {
flex: 0 1 30em;
display: flex;
flex-flow: row wrap;
justify-content: center;
align-content: center;
margin: auto;
border: 0.25em solid $sebin-secondary;
border-radius: 1em;
padding: 1em;
z-index: 9002;
@include theme(light) {
@include radial-background($bg-color-light, $bg-color-dark);
}
@include theme(dark) {
@include radial-background(
darken($bg-color-light, 20%),
darken($bg-color-dark, 5%)
);
}
> * {
flex: 0 1 100%;
}
}
}
.btn-container {
display: flex;
flex-flow: row wrap;
justify-content: space-around;
align-items: center;
}
.btn {
flex: 0 1 100%;
margin: 0.75em 0;
&.positive {
@include button(darken($sebin-eyes, 10%));
}
&.negative {
@include button(darken($bg-color-lighter, 20%));
}
}
</style>

35
src/components/Prose.vue Normal file
View file

@ -0,0 +1,35 @@
<template>
<div class="prose">
<slot name="default"></slot>
</div>
</template>
<style lang="scss">
@import "@/scss/_mixins.scss";
.prose {
padding: 0 max(1em, env(safe-area-inset-right)) 0
max(1em, env(safe-area-inset-left));
h1,
h2,
h3,
p,
ul,
blockquote,
.quickfacts,
.btn-group {
@include mq-desktop {
max-width: 45rem;
margin: {
left: auto;
right: auto;
}
}
@include mq-bigscreen {
max-width: 55rem;
}
}
}
</style>

View file

@ -1,93 +1,109 @@
<script setup lang="ts">
interface Props {
cols?: number
}
defineProps<Props>()
</script>
<template>
<details class="quickfacts">
<summary class="quickfacts__head">Quickfacts</summary>
<div class="quickfacts__list" :class="[`cols-${cols}`]">
<div class="quickfacts" :class="{ open: isExpanded }">
<h4 class="quickfacts__head" @click.prevent="toggle">Quickfacts</h4>
<div class="quickfacts__list">
<slot></slot>
</div>
</details>
</div>
</template>
<script>
export default {
data() {
return {
isExpanded: false,
};
},
methods: {
toggle() {
this.isExpanded = !this.isExpanded;
},
},
};
</script>
<style lang="scss">
@import "@/scss/_variables.scss";
@import "@/scss/_mixins.scss";
.quickfacts {
position: relative;
background: var(--quickfacts-background);
margin: 1rem 0;
border-radius: 1rem;
box-shadow: var(--container-box-shadow);
border-radius: 1em;
overflow: hidden;
transition: 0.3s all ease-in-out;
margin: 1em 0;
position: relative;
box-shadow: 0.125em 0.125em 0.5em rgba(#000, 0.7);
background: radial-gradient(
circle at bottom right,
$bg-color-lighter 5%,
transparent 50%
),
radial-gradient(circle at top left, $bg-color-light 5%, $bg-color-dark 100%);
@include theme(dark) {
background: radial-gradient(
circle at bottom right,
darken($bg-color-lighter, 30%) 5%,
transparent 50%
),
radial-gradient(
circle at top left,
darken($bg-color-light, 10%) 5%,
darken($bg-color-dark, 10%) 100%
);
}
&:before {
position: absolute;
content: "";
display: block;
content: '';
position: absolute;
top: 1.375rem;
right: 1.375rem;
top: 1em;
right: 1em;
transform: rotate(180deg);
transition: 0.3s all ease-in-out;
border: {
right: 0.625rem solid transparent;
bottom: 0.625rem solid #fff;
left: 0.625rem solid transparent;
right: 0.625em solid transparent;
bottom: 0.625em solid #fff;
left: 0.625em solid transparent;
}
}
&[open]:before {
&.open:before {
transform: rotate(0deg);
}
&__head {
font-family: var(--font-family-headings);
font-size: 1.125rem;
list-style: none;
margin: 0;
border: 0;
padding: 0.75rem 1.5rem;
cursor: pointer;
&::-webkit-details-marker {
display: none;
&.open & {
&__list {
max-height: 25em;
border-top: 0.125em solid $sebin-secondary;
padding: 1.5rem;
}
}
&__head {
margin: 0;
border: 0;
padding: 0.75rem 1.5rem;
transition: 0.3s all ease-in-out;
cursor: pointer;
}
&__list {
border-top: 0.125rem solid var(--color-quickfacts-border);
padding: 1.5rem;
&.cols-2 ul {
columns: var(--quickfacts-cols-double);
}
&.cols-3 ul {
columns: var(--quickfacts-cols-triple);
}
&.cols-4 ul {
columns: var(--quickfacts-cols-quadruple);
}
max-height: 0em;
padding: 0 1.5rem;
transition: 0.3s all ease-in-out;
ul {
margin: 0;
padding: 0 0.5rem;
padding: 0 0.5em;
}
li {
margin: 0 0 0 1rem;
margin: 0 0 0 1em;
padding: 0;
}
}

View file

@ -1,79 +0,0 @@
<script setup lang="ts">
interface Props {
positive?: boolean
negative?: boolean
href?: string
download?: boolean | any
}
defineProps<Props>()
</script>
<template>
<a
class="btn"
:class="{ positive: positive, negative: negative }"
:href="href"
:[download]="download"
>
<slot></slot>
</a>
</template>
<style lang="scss">
.btn {
position: relative;
top: 0;
background-color: var(--color-button);
font-weight: 700;
text-decoration: none;
text-align: center;
margin: 0.5rem 0;
border-radius: 0.25rem;
padding: 0.5rem 1rem;
box-shadow: 0 0.5rem 0 0 var(--color-button-box-shadow);
transition: all 0.1s ease-out;
&:hover {
cursor: pointer;
top: -0.25rem;
box-shadow: 0 0.75rem 0 0 var(--color-button-box-shadow);
}
&:active {
top: 0.25rem;
box-shadow: 0 0.25rem 0 0 var(--color-button-box-shadow);
}
&.positive {
background-color: #259410;
box-shadow: 0 0.5rem 0 0 #1a660b;
&:hover {
box-shadow: 0 0.75rem 0 0 #1a660b;
}
&:active {
box-shadow: 0 0.25rem 0 0 #1a660b;
}
}
&.negative {
background-color: #ae1414;
box-shadow: 0 0.5rem 0 0 #800f0f;
&:hover {
box-shadow: 0 0.75rem 0 0 #800f0f;
}
&:active {
box-shadow: 0 0.25rem 0 0 #800f0f;
}
}
}
</style>

View file

@ -1,223 +0,0 @@
<script setup lang="ts">
import { inject } from 'vue'
import { nsfwKey, showModalKey } from '@/keys'
import RefToggle from '@/components/RefToggle.vue'
interface Props {
cornerText?: boolean
polaroidBorder?: boolean
dropshadow?: boolean
nsfw?: boolean
id: string
}
const isNsfw = inject<boolean>(nsfwKey, false)
const showModal = inject<Function>(showModalKey, Function)
defineProps<Props>()
</script>
<template>
<figure class="figure">
<div
class="figure__border"
:class="{
'figure__border--polaroid': polaroidBorder,
'figure__border--cornertext': cornerText
}"
>
<template v-if="!nsfw || isNsfw">
<div class="figure__image" :class="{ 'figure__image--dropshadow': dropshadow }">
<slot name="img"></slot>
</div>
</template>
<template v-else>
<div class="figure__cencor">
<div class="figure__tape"></div>
<div class="figure__tape"></div>
<div class="figure__tape"></div>
<div class="figure__tape"></div>
<div class="figure__reveal">
<p>🔥 Here be spicy dragons 🌶</p>
<RefToggle
class="figure__toggle"
:id="id"
v-model="isNsfw"
@click.prevent="showModal()"
>
<template #off>😇</template>
<template #on>😈</template>
</RefToggle>
</div>
</div>
</template>
<template v-if="!nsfw || isNsfw">
<figcaption class="figure__meta">
<div class="caption">
<slot name="caption"></slot>
</div>
<div class="copyright">© <slot name="copyright"></slot></div>
</figcaption>
</template>
</div>
</figure>
</template>
<style lang="scss">
.figure {
display: flex;
flex-flow: row nowrap;
justify-content: center;
text-align: center;
margin: 1em auto;
padding: 0 var(--container-spacing-right-safe) 0 var(--container-spacing-left-safe);
&__border {
display: flex;
flex-flow: column nowrap;
justify-content: center;
margin: auto;
&--polaroid {
margin: 1em auto;
padding: 1em;
box-shadow: inset 0 0 1em rgba(0, 0, 0, 0.7), 0 0 1em rgba(0, 0, 0, 0.7);
border-radius: 0.325em;
background-color: #fff;
}
}
&__border--cornertext {
position: relative;
}
&__border--cornertext img,
&__border--cornertext &__cencor {
margin: 1rem 0;
border-radius: 1rem;
filter: drop-shadow(0 0 0.625rem black);
}
&__border--cornertext &__meta {
position: absolute;
bottom: 0;
right: 0;
background-color: rgba(0, 0, 0, 0.7);
font-size: 0.75rem;
margin: 0 0 1.35rem 0;
border-radius: 1em 0 1rem 0;
padding: 0.25rem 0.75rem;
.caption,
.copyright {
display: inline;
}
.caption {
margin: 0 0.125rem 0 0;
}
}
&__border--polaroid &__meta {
font-family: 'Permanent Marker', fantasy;
color: var(--color-figure-polaroid-text);
max-width: 35rem;
margin: 0.5rem auto;
* {
color: inherit;
}
}
&__image {
flex: 1 0 auto;
&--dropshadow {
filter: drop-shadow(0.5rem 0.25rem 0.375rem #000);
}
img {
max-width: 100%;
max-height: 35rem;
}
}
&__meta {
flex: 0 0 auto;
}
&__cencor {
flex: 1 0 auto;
display: flex;
flex-flow: row wrap;
justify-content: center;
align-items: center;
padding: 0;
width: var(--figure-cencor-width);
height: var(--figure-cencor-height);
max-width: 35rem;
max-height: 70rem;
position: relative;
background-color: var(--figure-cencor-background-color);
overflow: hidden;
}
&__toggle {
position: relative;
padding: 0;
}
&__tape {
position: absolute;
left: -1rem;
right: -1rem;
top: 0;
transform: rotate(0deg);
height: 1rem;
background-image: repeating-linear-gradient(
-55deg,
#000,
#000 0.75rem,
#ffb101 0.75rem,
#ffb101 1.5rem
);
&:nth-child(1) {
top: 10%;
transform: rotate(5deg);
}
&:nth-child(2) {
top: 15%;
transform: rotate(-10deg);
}
&:nth-child(3) {
top: 75%;
transform: rotate(-15deg);
}
&:nth-child(4) {
top: 85%;
transform: translate(-5rem, -2rem) rotate(40deg);
}
}
}
</style>

View file

@ -1,197 +0,0 @@
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { debounce } from '@/helpers'
const activeImage = ref(0)
const images = ref<Element[]>([])
const element = document.createElement('div')
const galleryViewport = ref<HTMLElement>(element)
const galleryItemWidth = ref<number>(1)
const resizeObserverCallback = (entries: ResizeObserverEntry[]): void => {
for (const entry of entries) {
galleryItemWidth.value = entry.contentRect.width
}
}
const resizeObserver = new ResizeObserver(debounce(resizeObserverCallback, 1000))
const setActiveImage = (index: number): void => {
activeImage.value = index
galleryViewport.value.scrollTo({
left: galleryItemWidth.value * index,
behavior: 'smooth'
})
}
const getActiveImage = (gallery: HTMLElement, itemWidth: number): number => {
return gallery.scrollLeft / itemWidth
}
const prev = (): void => {
if (activeImage.value > 0) {
galleryViewport.value.scrollBy({
left: galleryItemWidth.value * -1,
behavior: 'smooth'
})
}
}
const next = (): void => {
if (activeImage.value < images.value.length - 1) {
galleryViewport.value.scrollBy({
left: galleryItemWidth.value,
behavior: 'smooth'
})
}
}
const onScroll = (): void => {
const newImg = Math.floor(getActiveImage(galleryViewport.value, galleryItemWidth.value))
setActiveImage(newImg)
}
onMounted(() => {
resizeObserver.observe(galleryViewport.value)
images.value = Array.from(galleryViewport.value.children)
galleryItemWidth.value = galleryViewport.value.scrollWidth / images.value.length
galleryViewport.value.addEventListener('scroll', debounce(onScroll, 500))
})
</script>
<template>
<div class="gallery">
<div class="gallery__images">
<a href="#" class="gallery__prev" @click.prevent="prev()" v-show="activeImage > 0"></a>
<a
href="#"
class="gallery__next"
@click.prevent="next()"
v-show="activeImage < images.length - 1"
></a>
<div class="gallery__viewport" ref="galleryViewport">
<slot></slot>
</div>
</div>
<nav class="gallery__navigation">
<ul>
<li v-for="(image, idx) in images" :key="idx">
<a
href="#"
:class="{ active: activeImage === idx }"
@click.prevent="setActiveImage(idx)"
></a>
</li>
</ul>
</nav>
</div>
</template>
<style lang="scss">
.gallery {
&__prev,
&__next {
position: absolute;
top: 50%;
transform: translateY(-50%);
width: var(--gallery-size);
height: var(--gallery-size);
z-index: 1;
border: {
top: 0.125rem solid #fff;
right: 0.125rem solid #fff;
}
}
&__prev {
left: var(--gallery-arrow-position);
transform: rotate(-135deg);
}
&__next {
right: var(--gallery-arrow-position);
transform: rotate(45deg);
}
&__images {
position: relative;
overflow: hidden;
}
&__viewport {
display: flex;
flex-flow: row nowrap;
align-items: center;
width: 100%;
height: 100%;
overflow: auto;
scroll-snap-type: x mandatory;
scrollbar-width: none;
transition: 0.3s all ease-in-out;
&::-webkit-scrollbar {
display: none;
}
}
.figure {
margin: 0;
padding: var(--gallery-image-padding);
flex: 1 0 100%;
scroll-snap-align: center;
&__meta {
text-align: center;
p {
margin: 0.5rem auto;
}
}
}
&__navigation {
display: flex;
flex-flow: row wrap;
justify-content: center;
ul {
flex: 0 1 auto;
display: flex;
flex-flow: row wrap;
justify-content: center;
list-style: none;
margin: 1rem 0;
padding: 0;
}
li {
flex: 0 1 auto;
padding: 0.375em;
a {
display: block;
width: 0.5em;
height: 0.5em;
border-radius: 1em;
background: rgba(#fff, 0.5);
&.active {
background: #fff;
}
}
}
}
}
</style>

View file

@ -1,98 +0,0 @@
<script setup lang="ts">
import { ref } from 'vue'
interface Props {
id: string
}
defineProps<Props>()
const modal = ref<HTMLDialogElement>()
const showModal = () => {
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')
}
defineExpose({ showModal, close })
</script>
<template>
<dialog :id="id" class="modal" ref="modal">
<form method="dialog" class="modal__content">
<h2 class="modal__heading">
<slot name="heading"></slot>
</h2>
<div class="modal__message">
<slot name="message"></slot>
</div>
<div class="modal__buttons">
<slot name="buttons"></slot>
</div>
</form>
</dialog>
</template>
<style lang="scss">
.modal {
position: fixed;
background: var(--modal-background);
color: var(--color-text);
width: var(--modal-width);
margin: auto;
border: 0.25rem solid var(--color-modal-border);
border-radius: 1rem;
padding: 1rem;
overflow: auto;
animation: fade-in 1s;
&::backdrop {
backdrop-filter: blur(1rem);
background-color: rgba(0, 0, 0, 0.5);
animation: fade-in 1s;
}
&__content {
display: flex;
flex-flow: column nowrap;
justify-content: center;
text-align: center;
gap: 1.5rem;
> * {
flex: 1 1 auto;
}
}
&__heading {
margin: 1.875rem 0 0 0;
}
&__message {
flex: 1 1 100%;
}
@keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
}
</style>

View file

@ -1,25 +0,0 @@
<template>
<footer class="footer">
<slot></slot>
</footer>
</template>
<style lang="scss">
.footer {
background: url(@/assets/subtle-prism.svg) var(--color-background-footer);
background-blend-mode: multiply;
padding: var(--footer-padding);
text-align: center;
p {
text-align: center;
margin: 0;
+ p {
margin: 0.5em auto 0 auto;
}
}
}
</style>

View file

@ -1,30 +0,0 @@
<template>
<header class="header">
<slot></slot>
</header>
</template>
<style lang="scss">
.header {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
position: sticky;
top: var(--container-spacing-top-safe);
right: var(--container-spacing-right-safe);
left: var(--container-spacing-left-safe);
background: var(--header-background);
max-width: 70rem;
margin: var(--header-margin);
border-radius: 0.5rem;
padding: 0.5rem;
box-shadow: var(--container-box-shadow);
z-index: 2;
}
</style>

Some files were not shown because too many files have changed in this diff Show more