Compare commits

...

115 commits

Author SHA1 Message Date
Sebin Nyshkim
15d487ec6f chore: bump version number 2024-09-03 14:41:04 +02:00
Sebin Nyshkim
d716e192bb build: update packages 2024-09-03 14:41:04 +02:00
Sebin Nyshkim
6aa34c1648 build: update scaffolding to current create-vue template 2024-09-03 14:40:57 +02:00
Sebin Nyshkim
34823665c6 chore: bump version number 2023-11-30 23:18:28 +01:00
Sebin Nyshkim
134e2c79cc fix: wrong order of v-if evaluation 2023-11-30 23:17:49 +01:00
Sebin Nyshkim
b0abfd8311 chore: bump version number 2023-11-30 22:55:32 +01:00
Sebin Nyshkim
61cd15fd5b build: update npm packages 2023-11-30 22:55:05 +01:00
Sebin Nyshkim
f3f94be6ae build: update browserslist definitions 2023-11-30 22:54:18 +01:00
Sebin Nyshkim
61147be693 build: update browserslist definition file 2023-11-30 22:53:41 +01:00
Sebin Nyshkim
6a1474eb52 build: update npm packages 2023-10-19 01:54:10 +02:00
Sebin Nyshkim
f4b1003801 chore: bump version number 2023-09-01 13:13:07 +02:00
Sebin Nyshkim
5d94323bdd feat: update overdrive ref image to new border style 2023-09-01 13:12:30 +02:00
Sebin Nyshkim
d2774e8150 refactor: update vite-imagetools asset link directives
Starting with v5 vite-imagetools has removed shorthands
2023-09-01 13:06:40 +02:00
Sebin Nyshkim
89831a64a2 build: add package.json to list of includes 2023-09-01 13:04:08 +02:00
Sebin Nyshkim
4c8d576f13 build: migrate autoprefixer from CJS require to ES module import 2023-09-01 12:30:33 +02:00
Sebin Nyshkim
0c8a3b0348 build: update scaffolding to current create-vue template 2023-09-01 12:29:06 +02:00
Sebin Nyshkim
0335006ee5 build: update packages to latest versions 2023-09-01 12:28:40 +02:00
Sebin Nyshkim
07bd197c29 refactor: add types for emits 2023-09-01 12:11:51 +02:00
Sebin Nyshkim
a0b2062137 chore: bump version number 2023-07-22 02:15:08 +02:00
Sebin Nyshkim
d5cf84e592 refactor: move buttons and tags to separate components 2023-07-22 02:14:22 +02:00
Sebin Nyshkim
cd9c1d950d feat: add FilterListTag component 2023-07-22 02:12:52 +02:00
Sebin Nyshkim
665f2c6b35 feat: add FilterButton component 2023-07-22 02:12:09 +02:00
Sebin Nyshkim
30a573e9cf feat: reorganize list tag positioning 2023-07-22 01:28:08 +02:00
Sebin Nyshkim
ddde6df30b fix: remove duplicate entry 2023-07-22 01:18:40 +02:00
Sebin Nyshkim
d5703cc274 chore: bump version number 2023-07-21 15:41:23 +02:00
Sebin Nyshkim
778142c4c1 build: update npm packages 2023-07-21 15:41:08 +02:00
Sebin Nyshkim
d984651fc8 feat: update responsive image srcsets, genereate fewer images 2023-07-21 15:40:33 +02:00
Sebin Nyshkim
9a529b62fb feat: update figure cencor size constraints 2023-07-21 15:15:23 +02:00
Sebin Nyshkim
c143956e9f feat: add new RefFigure style 2023-07-21 15:14:56 +02:00
Sebin Nyshkim
120a1a03e3 feat: replace placeholder images with artwork 2023-07-21 15:13:17 +02:00
Sebin Nyshkim
08e01502c5 fix: eliminate unintended side-effects in computed property 2023-07-20 19:15:38 +02:00
Sebin Nyshkim
314255dc31 chore: bump version number 2023-07-18 21:53:14 +02:00
Sebin Nyshkim
1b036d3278 feat: replace DataTable component with new FilteredList component 2023-07-18 21:51:32 +02:00
Sebin Nyshkim
b450849075 feat: expand css color variables 2023-07-18 21:51:14 +02:00
Sebin Nyshkim
f100c524af feat: add FilteredList component 2023-07-18 21:50:06 +02:00
Sebin Nyshkim
d196c1e680 feat: update interface definitions 2023-07-18 21:48:41 +02:00
Sebin Nyshkim
f147510c04 feat: expand Sebin data object 2023-07-18 21:48:18 +02:00
Sebin Nyshkim
6cf6e6d045 chore: bump version number 2023-07-17 14:49:13 +02:00
Sebin Nyshkim
ff665a6cea build: update npm packages 2023-07-17 14:45:00 +02:00
Sebin Nyshkim
a2e2c1f791 fix: wrong open graph meta tag attributes 2023-07-17 14:36:42 +02:00
Sebin Nyshkim
0b4813e285 chore: bump version number 2023-04-03 00:55:46 +02:00
Sebin Nyshkim
4853e1ec63 style: run linter 2023-04-03 00:55:28 +02:00
Sebin Nyshkim
de3862bf77 build: inline postcss config into vite config 2023-04-03 00:29:59 +02:00
Sebin Nyshkim
6094a2a559 feat: update prettier config 2023-04-03 00:29:40 +02:00
Sebin Nyshkim
939610ed61 build: update typescript 2023-04-03 00:03:18 +02:00
Sebin Nyshkim
5ef3d6c0f9 build: add browserslist config 2023-04-02 23:55:44 +02:00
Sebin Nyshkim
35562692e4 build: update tsconfig 2023-04-02 23:55:24 +02:00
Sebin Nyshkim
5f65a341a0 refactor: change how version is read from package.json 2023-04-02 23:46:46 +02:00
Sebin Nyshkim
e3f2e0c256 feat: migrate to native details element for quickfacts component 2023-04-02 23:35:59 +02:00
Sebin Nyshkim
51e72e2021 feat: remove no longer needed modalResultKey inject 2023-04-02 20:08:29 +02:00
Sebin Nyshkim
b8c9d8de17 feat: remove no longer needed isWarn property and injection key 2023-04-02 17:45:08 +02:00
Sebin Nyshkim
cc664a764d feat: move modal out of views and into global app context 2023-04-02 17:42:26 +02:00
Sebin Nyshkim
d0f9434700 feat: migrate to native dialog element for modal component 2023-04-02 17:28:48 +02:00
Sebin Nyshkim
b9fe7113ed feat: extend column styling 2023-04-02 17:27:27 +02:00
Sebin Nyshkim
0e225f95c9 fix: make sure paragraphs in footer are always center aligned 2023-04-02 17:08:38 +02:00
Sebin Nyshkim
8e0756f166 feat: add column and grid styling to button group 2023-04-02 17:07:57 +02:00
Sebin Nyshkim
e67a220223 feat: add props for button styling 2023-04-02 17:07:13 +02:00
Sebin Nyshkim
dd70061798 feat: use buttons instead of list for social links 2023-04-02 17:05:41 +02:00
Sebin Nyshkim
c7444256f1 feat: justify paragraphs, add hyphenation 2023-04-02 17:04:30 +02:00
Sebin Nyshkim
3c8b726d83 refactor: decouple social link styling from fixed elements 2023-04-02 17:03:27 +02:00
Sebin Nyshkim
a670952e15 build: add autoprefixer 2023-04-02 15:47:07 +02:00
Sebin Nyshkim
d6f94c26d4 build: update npm packages 2023-04-02 15:46:46 +02:00
Sebin Nyshkim
62795740b3 chore: bump version number 2023-01-25 19:30:20 +01:00
Sebin Nyshkim
6b0acce446 fix: make sure setActiveImage gets integer value after scroll 2023-01-25 19:28:54 +01:00
Sebin Nyshkim
a0182fe447 chore: add header template for Fur Affinity 2023-01-23 02:02:44 +01:00
Sebin Nyshkim
fe785f6ed3 chore: add header template for Mastodon 2023-01-23 02:02:35 +01:00
Sebin Nyshkim
52d2f12b75 chore: add header template for Twitter 2023-01-23 02:02:25 +01:00
Sebin Nyshkim
7a3a58d8fc chore: bump version number 2023-01-22 17:29:52 +01:00
Sebin Nyshkim
21df633e9e style: remove unused <script> sections from components 2023-01-22 16:55:38 +01:00
Sebin Nyshkim
014451ffa0 style: use shorter array type declarations 2023-01-22 16:55:09 +01:00
Sebin Nyshkim
6ecba14f6f style: add explicit return value 2023-01-22 16:50:37 +01:00
Sebin Nyshkim
9893373a43 fix: increase z-index to stay on top of other page elements 2023-01-22 16:49:49 +01:00
Sebin Nyshkim
d84c415b22 feat: update RefGallery to native scrolling 2023-01-22 16:48:12 +01:00
Sebin Nyshkim
c77854667b feat: add debounce function 2023-01-22 16:45:14 +01:00
Sebin Nyshkim
2c4c07441b fix: update meta tag URLs 2023-01-22 16:44:42 +01:00
Sebin Nyshkim
c834b7c49e chore: bump version number 2023-01-20 01:02:21 +01:00
Sebin Nyshkim
d000c4a4fb feat: add social card template 2023-01-20 01:00:28 +01:00
Sebin Nyshkim
6d9515498f refactor: remove sftp config 2023-01-20 00:59:51 +01:00
Sebin Nyshkim
88e437d001 chore: apply higher compression on full res ref sheets 2023-01-20 00:59:16 +01:00
Sebin Nyshkim
fb413a5fba feat: update .htaccess 2023-01-20 00:58:19 +01:00
Sebin Nyshkim
9aa5579bde feat: use bespoke social preview image 2023-01-20 00:57:53 +01:00
Sebin Nyshkim
c7baf62833 feat: serve fonts locally 2023-01-20 00:57:20 +01:00
Sebin Nyshkim
092fc92658 feat: use higher resolution image assets 2023-01-20 00:56:58 +01:00
Sebin Nyshkim
ec9e975bda refactor: move background pattern SVG into assets dir 2023-01-20 00:54:00 +01:00
Sebin Nyshkim
9dcda9d3dd refactor: migrate Overdrive view 2023-01-20 00:53:11 +01:00
Sebin Nyshkim
05b8e0c410 refactor: migrate Home view 2023-01-20 00:52:59 +01:00
Sebin Nyshkim
9ddc4e5a8c refactor: migrate General view 2023-01-20 00:52:47 +01:00
Sebin Nyshkim
7670634cda refactor: migrate Clothing view 2023-01-20 00:52:34 +01:00
Sebin Nyshkim
a9b6b815e8 refactor: migrate Anatomy view 2023-01-20 00:52:19 +01:00
Sebin Nyshkim
3a1a5942df refactor: migrate Abilities view 2023-01-20 00:51:54 +01:00
Sebin Nyshkim
a78ad22578 refactor: migrate Welcome component 2023-01-20 00:51:18 +01:00
Sebin Nyshkim
40f5b32970 refactor: migrate QuickFacts component 2023-01-20 00:51:01 +01:00
Sebin Nyshkim
a729113b71 refactor: remove Prose component
Now just a regular HTML5 section element
2023-01-20 00:50:39 +01:00
Sebin Nyshkim
600a82d3f2 refactor: migrate NsfwWarning component 2023-01-20 00:49:40 +01:00
Sebin Nyshkim
eb749e1796 refactor: migrate NsfwSwitch component 2023-01-20 00:49:22 +01:00
Sebin Nyshkim
267830b15d refactor: migrate Navigation component 2023-01-20 00:48:52 +01:00
Sebin Nyshkim
c1b7bdbbb4 refactor: migrate Header component 2023-01-20 00:48:34 +01:00
Sebin Nyshkim
6e2a633b45 refactor: migrate Gallery component 2023-01-20 00:48:15 +01:00
Sebin Nyshkim
4384759616 refactor: rename component imports 2023-01-20 00:47:53 +01:00
Sebin Nyshkim
32c63efeaa refactor: migrate Footer component 2023-01-20 00:43:03 +01:00
Sebin Nyshkim
81941a9e45 refactor: migrate Figure component 2023-01-20 00:36:42 +01:00
Sebin Nyshkim
b37e067efd refactor: migrate DataTable component 2023-01-20 00:36:03 +01:00
Sebin Nyshkim
af4427cf3d feat: add ColorTable component 2023-01-20 00:35:51 +01:00
Sebin Nyshkim
e902589427 feat: add ButtonGroup component 2023-01-20 00:35:21 +01:00
Sebin Nyshkim
5cf33f6dfa refactor: migrate Button component 2023-01-20 00:35:05 +01:00
Sebin Nyshkim
3ba5e0aa2b refactor: migrate AttackItem component 2023-01-20 00:34:03 +01:00
Sebin Nyshkim
97ff935b13 refactor: migrate AttackList component 2023-01-20 00:33:35 +01:00
Sebin Nyshkim
313d6f2302 refactor: migrate base App 2023-01-20 00:32:56 +01:00
Sebin Nyshkim
7aeecdb656 feat: add InjectionKey exports 2023-01-20 00:32:06 +01:00
Sebin Nyshkim
baf6161d95 feat: add typed props exports 2023-01-20 00:32:00 +01:00
Sebin Nyshkim
579e57f631 refactor: migrate vue router config 2023-01-20 00:29:34 +01:00
Sebin Nyshkim
b63a14d8ce refactor: migrate base styles 2023-01-20 00:28:44 +01:00
Sebin Nyshkim
5b5c027ea6 refactor: migrate helper functions mixin 2023-01-20 00:25:49 +01:00
Sebin Nyshkim
6494354a6d refactor: migrate Sebin data mixin 2023-01-20 00:23:52 +01:00
Sebin Nyshkim
90ef5eaf06 feat: migrate vue-cli based scaffold to vue-create 2023-01-19 23:59:53 +01:00
135 changed files with 7487 additions and 35374 deletions

View file

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

15
.eslintrc.cjs Normal file
View file

@ -0,0 +1,15 @@
/* 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'
}
}

View file

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

29
.gitignore vendored
View file

@ -1,23 +1,30 @@
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
# Logs
logs
*.log
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

View file

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

8
.prettierrc.json Normal file
View file

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

7
.vscode/extensions.json vendored Normal file
View file

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

15
.vscode/sftp.json vendored
View file

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

View file

@ -1,24 +1,55 @@
# vue3-test
# Sebin Reference Page
## Project setup
```
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
npm install
```
### Compiles and hot-reloads for development
```
npm run serve
### Compile and Hot-Reload for Development
```sh
npm run dev
```
### Compiles and minifies for production
```
### Type-Check, Compile and Minify for Production
```sh
npm run build
```
### Lints and fixes files
```
### Lint with [ESLint](https://eslint.org/)
```sh
npm run lint
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,143 @@
@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;
}

22
card/index.html Normal file
View file

@ -0,0 +1,22 @@
<!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 Normal file
View file

@ -0,0 +1,112 @@
@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 Normal file
View file

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

30
index.html Normal file
View file

@ -0,0 +1,30 @@
<!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>

View file

34849
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,32 +1,38 @@
{
"name": "sebin-reference",
"version": "0.8.3",
"version": "0.10.7",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
"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/"
},
"dependencies": {
"core-js": "^3.6.5",
"normalize.css": "^8.0.1",
"vue": "^3.0.0",
"vue-router": "^4.0.0-0"
"vue": "^3.4.38",
"vue-router": "^4.4.3"
},
"devDependencies": {
"@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"
"@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"
}
}

View file

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

View file

@ -1,17 +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,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>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 377 KiB

BIN
public/preview.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 MiB

After

Width:  |  Height:  |  Size: 3.3 MiB

Before After
Before After

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 MiB

After

Width:  |  Height:  |  Size: 3.2 MiB

Before After
Before After

View file

@ -1,158 +1,99 @@
<template>
<ref-header>
<img
class="nav-logo"
src="@/assets/sebin-smug-icon.png"
alt="Sebin Avatar"
/>
<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'
<navigation :routes="routes" />
</ref-header>
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"
/>
<img
class="nav-logo"
srcset="@/assets/sebin-smug-icon.png?w=36;40;48;56;72;80;96;112;108;120;144;168&format=png&as=srcset"
sizes="(min-width: 120em) 56px, (min-width: 80em) 48px, (min-width: 35em) 40px, 36px"
alt="Sebin Avatar"
/>
</picture>
<SiteNavigation />
</SiteHeader>
<main>
<router-view />
<RouterView />
</main>
<ref-footer>
<SiteFooter>
<p>v{{ version }} &copy; {{ new Date().getFullYear() }} Sebin Nyshkim</p>
<p>
Background Pattern &copy;
<a href="https://www.svgbackgrounds.com/">SVG Backgrounds</a>
</p>
</ref-footer>
</SiteFooter>
</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>

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,19 @@
/* 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;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

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

View file

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

View file

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 218 KiB

After

Width:  |  Height:  |  Size: 1.2 MiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 551 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

After

Width:  |  Height:  |  Size: 524 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

After

Width:  |  Height:  |  Size: 656 KiB

Before After
Before After

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

Before

Width:  |  Height:  |  Size: 784 KiB

After

Width:  |  Height:  |  Size: 784 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 734 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 3.9 MiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 717 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 432 KiB

After

Width:  |  Height:  |  Size: 9.2 MiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 376 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 657 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 560 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 16 MiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 393 KiB

After

Width:  |  Height:  |  Size: 589 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 512 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 867 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 378 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 619 KiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 MiB

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,152 +1,37 @@
<script setup lang="ts">
interface Props {
headings: string[]
data: string[][]
}
defineProps<Props>()
</script>
<template>
<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 }}
<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 }}
</th>
</tr>
</thead>
<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>
<tbody class="data-table__body">
<tr class="data-table__row" v-for="(row, idx) in data" :key="idx">
<td class="data-table__cell" v-for="(cell, idx) in row" :key="idx">
{{ cell }}
</td>
<td
v-if="isHexValue(row[1])"
class="datatable__cell--colorpick"
:style="{ backgroundColor: row[1] }"
></td>
</tr>
</tbody>
</table>
</template>
<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>
<style lang="scss">
@import "@/scss/_variables.scss";
@import "@/scss/_mixins.scss";
.data-table {
table-layout: fixed;
.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;
}
&__cell:first-child {
text-align: right;
}
}
</style>

View file

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

View file

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

View file

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

View file

@ -0,0 +1,127 @@
<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>

View file

@ -1,22 +0,0 @@
<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>

View file

@ -1,188 +0,0 @@
<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>

View file

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

View file

@ -1,122 +0,0 @@
<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>

View file

@ -1,36 +0,0 @@
<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,
h4,
p,
ul,
blockquote,
.quickfacts,
.btn-group {
@include mq-desktop {
max-width: 45rem;
margin: {
left: auto;
right: auto;
}
}
@include mq-bigscreen {
max-width: 55rem;
}
}
}
</style>

View file

@ -1,109 +1,93 @@
<template>
<div class="quickfacts" :class="{ open: isExpanded }">
<h4 class="quickfacts__head" @click.prevent="toggle">Quickfacts</h4>
<script setup lang="ts">
interface Props {
cols?: number
}
<div class="quickfacts__list">
<slot></slot>
</div>
</div>
</template>
<script>
export default {
data() {
return {
isExpanded: false,
};
},
methods: {
toggle() {
this.isExpanded = !this.isExpanded;
},
},
};
defineProps<Props>()
</script>
<template>
<details class="quickfacts">
<summary class="quickfacts__head">Quickfacts</summary>
<div class="quickfacts__list" :class="[`cols-${cols}`]">
<slot></slot>
</div>
</details>
</template>
<style lang="scss">
@import "@/scss/_variables.scss";
@import "@/scss/_mixins.scss";
.quickfacts {
border-radius: 1em;
overflow: hidden;
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%);
background: var(--quickfacts-background);
@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%
);
}
margin: 1rem 0;
border-radius: 1rem;
box-shadow: var(--container-box-shadow);
overflow: hidden;
transition: 0.3s all ease-in-out;
&:before {
position: absolute;
content: "";
display: block;
top: 1em;
right: 1em;
content: '';
position: absolute;
top: 1.375rem;
right: 1.375rem;
transform: rotate(180deg);
transition: 0.3s all ease-in-out;
border: {
right: 0.625em solid transparent;
bottom: 0.625em solid #fff;
left: 0.625em solid transparent;
right: 0.625rem solid transparent;
bottom: 0.625rem solid #fff;
left: 0.625rem 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 {
max-height: 0em;
padding: 0 1.5rem;
transition: 0.3s all ease-in-out;
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);
}
ul {
margin: 0;
padding: 0 0.5em;
padding: 0 0.5rem;
}
li {
margin: 0 0 0 1em;
margin: 0 0 0 1rem;
padding: 0;
}
}

View file

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

View file

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

View file

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

View file

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

View file

@ -1,36 +1,48 @@
<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 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>
<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>
</div>
<div class="nsfw-switch__label">😈</div>
</label>
</template>
<script>
export default {
props: {
modelValue: Boolean,
id: { type: String, required: true },
},
};
</script>
<style lang="scss">
@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";
.toggle {
font-family: 'apple color emoji', 'noto color emoji', 'segoe ui emoji', 'android emoji',
'emojisymbols', 'emojione mozilla', 'twemoji mozilla', 'segoe ui symbol';
padding: 0.5em;
@ -47,23 +59,23 @@ export default {
text-align: center;
}
&__toggle {
&__input {
margin: 0 0.5em;
}
& input:checked + &-inner {
background-color: $sebin-primary;
&__input input:checked + &__inner {
background-color: var(--color-toggle);
&:before {
transform: translate3d(0.9em, 0.1em, 0) scale3d(0, 0, 0);
}
&:before {
transform: translate3d(0.9em, 0.1em, 0) scale3d(0, 0, 0);
}
&:after {
transform: translate3d(1.1em, 0.1em, 0);
}
&:after {
transform: translate3d(1.1em, 0.1em, 0);
}
}
&__toggle-inner {
&__inner {
position: relative;
display: inline-block;
width: 2.3em;
@ -75,7 +87,7 @@ export default {
&:before,
&:after {
content: "";
content: '';
position: absolute;
left: 0;
height: 1.1em;
@ -103,12 +115,12 @@ export default {
pointer-events: none;
}
&:active &__toggle-inner:after {
&:active &__inner:after {
width: 1.4em;
transform: translate3d(0.1em, 0.1em, 0);
}
&:active input:checked + &__toggle-inner:after {
&:active input:checked + &__inner:after {
transform: translate3d(0.8em, 0.1em, 0);
}
}

View file

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

View file

@ -0,0 +1,30 @@
<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>

View file

@ -1,52 +1,43 @@
<script setup lang="ts">
import { RouterLink } from 'vue-router'
import router from '@/router'
</script>
<template>
<nav class="nav">
<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">
<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">
{{ route.name }}
</router-link>
</RouterLink>
<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.375em;
padding: 0.375rem;
white-space: nowrap;
}
@ -54,28 +45,22 @@ export default {
display: block;
font-weight: bold;
line-height: 1;
color: $copy-color;
color: var(--color-text);
margin-bottom: 0.375em;
text-decoration: none;
text-transform: capitalize;
&.router-link-exact-active {
color: #fff;
}
}
&__link:hover ~ &__underline {
&:before,
&:after {
width: 50%;
background-color: $copy-color;
color: var(--color-text);
}
}
&__link:hover ~ &__underline,
&__link.router-link-exact-active ~ &__underline {
&:before,
&:after {
width: 50%;
background-color: #fff;
background-color: var(--color-text);
}
}
@ -86,11 +71,13 @@ export default {
&:before,
&:after {
content: "";
content: '';
position: absolute;
width: 0;
height: 0.125em;
bottom: 0;
width: 0;
height: 0.125rem;
transition: all 0.2s ease-in-out;
}

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