Compare commits
No commits in common. "master" and "0.8.0" have entirely different histories.
|
@ -1,3 +1,3 @@
|
|||
defaults
|
||||
>1% and not dead
|
||||
> 1%
|
||||
last 2 versions
|
||||
not dead
|
||||
|
|
|
@ -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
|
@ -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
|
@ -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
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"esversion": 9
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
{
|
||||
"$schema": "https://json.schemastore.org/prettierrc",
|
||||
"semi": false,
|
||||
"tabWidth": 2,
|
||||
"singleQuote": true,
|
||||
"printWidth": 100,
|
||||
"trailingComma": "none"
|
||||
}
|
7
.vscode/extensions.json
vendored
|
@ -1,7 +0,0 @@
|
|||
{
|
||||
"recommendations": [
|
||||
"Vue.volar",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"esbenp.prettier-vscode"
|
||||
]
|
||||
}
|
15
.vscode/sftp.json
vendored
Normal 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
|
||||
}
|
||||
}
|
57
README.md
|
@ -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
|
@ -0,0 +1,3 @@
|
|||
module.exports = {
|
||||
presets: ["@vue/cli-plugin-babel/preset"],
|
||||
};
|
|
@ -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>
|
|
@ -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;
|
||||
}
|
|
@ -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>
|
|
@ -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;
|
||||
}
|
|
@ -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>
|
|
@ -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;
|
||||
}
|
|
@ -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>
|
112
card/style.css
|
@ -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
|
@ -1 +0,0 @@
|
|||
/// <reference types="vite/client" />
|
30
index.html
|
@ -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
34629
package-lock.json
generated
50
package.json
|
@ -1,38 +1,32 @@
|
|||
{
|
||||
"name": "sebin-reference",
|
||||
"version": "0.10.7",
|
||||
"version": "0.8.0",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
@ -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
After Width: | Height: | Size: 377 KiB |
Before Width: | Height: | Size: 2.7 MiB |
BIN
public/sebin-ref-full-NSFW-hires.jpg
Normal file → Executable file
Before Width: | Height: | Size: 3.3 MiB After Width: | Height: | Size: 9.7 MiB |
BIN
public/sebin-ref-full-SFW-hires.jpg
Normal file → Executable file
Before Width: | Height: | Size: 3.2 MiB After Width: | Height: | Size: 9.5 MiB |
225
src/App.vue
|
@ -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>
|
||||
|
||||
<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"
|
||||
/>
|
||||
<ref-header>
|
||||
<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"
|
||||
src="@/assets/sebin-smug-icon.png"
|
||||
alt="Sebin Avatar"
|
||||
/>
|
||||
</picture>
|
||||
|
||||
<SiteNavigation />
|
||||
</SiteHeader>
|
||||
<navigation :routes="routes" />
|
||||
</ref-header>
|
||||
|
||||
<main>
|
||||
<RouterView />
|
||||
<router-view />
|
||||
</main>
|
||||
|
||||
<SiteFooter>
|
||||
<ref-footer>
|
||||
<p>v{{ version }} © {{ new Date().getFullYear() }} Sebin Nyshkim</p>
|
||||
<p>
|
||||
Background Pattern ©
|
||||
<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>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 218 KiB |
Before Width: | Height: | Size: 551 KiB After Width: | Height: | Size: 84 KiB |
Before Width: | Height: | Size: 524 KiB After Width: | Height: | Size: 77 KiB |
Before Width: | Height: | Size: 656 KiB After Width: | Height: | Size: 94 KiB |
0
src/assets/refs/clothes/casual/fullbody.png
Normal file → Executable file
Before Width: | Height: | Size: 784 KiB After Width: | Height: | Size: 784 KiB |
Before Width: | Height: | Size: 1.5 MiB |
BIN
src/assets/refs/clothes/lazy/pants.jpg
Normal file
After Width: | Height: | Size: 128 KiB |
BIN
src/assets/refs/clothes/lazy/undies.jpg
Normal file
After Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 1.4 MiB |
BIN
src/assets/refs/clothes/workout/closeup.jpg
Normal file
After Width: | Height: | Size: 734 KiB |
Before Width: | Height: | Size: 3.9 MiB After Width: | Height: | Size: 1.3 MiB |
BIN
src/assets/refs/muscle/muscle-ref1.jpg
Normal file
After Width: | Height: | Size: 717 KiB |
Before Width: | Height: | Size: 14 MiB |
Before Width: | Height: | Size: 9.2 MiB After Width: | Height: | Size: 432 KiB |
BIN
src/assets/refs/muscle/muscle-ref11.jpg
Normal file
After Width: | Height: | Size: 151 KiB |
Before Width: | Height: | Size: 2.4 MiB |
BIN
src/assets/refs/muscle/muscle-ref12.jpg
Normal file
After Width: | Height: | Size: 376 KiB |
Before Width: | Height: | Size: 3.6 MiB |
BIN
src/assets/refs/muscle/muscle-ref2.jpg
Normal file
After Width: | Height: | Size: 657 KiB |
Before Width: | Height: | Size: 8.3 MiB |
BIN
src/assets/refs/muscle/muscle-ref3.jpg
Normal file
After Width: | Height: | Size: 560 KiB |
Before Width: | Height: | Size: 17 MiB |
Before Width: | Height: | Size: 16 MiB After Width: | Height: | Size: 1.2 MiB |
Before Width: | Height: | Size: 589 KiB After Width: | Height: | Size: 393 KiB |
BIN
src/assets/refs/muscle/muscle-ref6.jpg
Normal file
After Width: | Height: | Size: 512 KiB |
Before Width: | Height: | Size: 1.8 MiB |
BIN
src/assets/refs/muscle/muscle-ref7.jpg
Normal file
After Width: | Height: | Size: 867 KiB |
BIN
src/assets/refs/muscle/muscle-ref8.jpg
Normal file
After Width: | Height: | Size: 378 KiB |
Before Width: | Height: | Size: 4 MiB |
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 619 KiB |
BIN
src/assets/refs/upper-body-ref.jpg
Normal file
After Width: | Height: | Size: 1.8 MiB |
Before Width: | Height: | Size: 14 MiB |
|
@ -1,67 +0,0 @@
|
|||
<template>
|
||||
<figure class="attack">
|
||||
<div class="attack__illustration">
|
||||
<slot name="image"></slot>
|
||||
</div>
|
||||
|
||||
<figcaption class="attack__text">
|
||||
<div class="attack__name">
|
||||
<slot name="name"></slot>
|
||||
</div>
|
||||
|
||||
<div class="attack__description">
|
||||
<slot name="desc"></slot>
|
||||
</div>
|
||||
</figcaption>
|
||||
</figure>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.attack {
|
||||
flex: var(--attack-item-flex);
|
||||
|
||||
display: flex;
|
||||
flex-flow: var(--attack-item-flex-flow);
|
||||
align-items: center;
|
||||
|
||||
margin: 0;
|
||||
padding: 0.375em 0;
|
||||
|
||||
&:nth-child(even) {
|
||||
text-align: var(--attack-item-nth-child-even-text-align);
|
||||
}
|
||||
|
||||
&:nth-child(even) &__illustration,
|
||||
&:nth-child(even) &__text {
|
||||
&:first-child {
|
||||
order: var(--attack-item-first-child-order);
|
||||
}
|
||||
}
|
||||
|
||||
&__illustration {
|
||||
flex: var(--attack-item-illustration-flex);
|
||||
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
text-align: center;
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&__text {
|
||||
flex: 1 1 auto;
|
||||
padding: var(--attack-item-text-padding);
|
||||
}
|
||||
|
||||
&__name {
|
||||
font-weight: bold;
|
||||
margin: 0 0 1em 0;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,18 +0,0 @@
|
|||
<template>
|
||||
<div class="attacks">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="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);
|
||||
}
|
||||
</style>
|
57
src/components/Button.vue
Normal 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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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">
|
||||
<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 {
|
||||
<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
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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
|
@ -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
|
@ -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
|
@ -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>
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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,12 +47,11 @@ 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);
|
||||
|
@ -74,8 +61,9 @@ const checked = computed({
|
|||
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);
|
||||
}
|
||||
}
|
122
src/components/NsfwWarning.vue
Normal 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
|
@ -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>
|
|
@ -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);
|
||||
}
|
||||
|
||||
&.open & {
|
||||
&__list {
|
||||
max-height: 25em;
|
||||
border-top: 0.125em solid $sebin-secondary;
|
||||
padding: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
&__head {
|
||||
font-family: var(--font-family-headings);
|
||||
font-size: 1.125rem;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
padding: 0.75rem 1.5rem;
|
||||
transition: 0.3s all ease-in-out;
|
||||
cursor: pointer;
|
||||
|
||||
&::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&__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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|