added car and themes
|
|
@ -0,0 +1,12 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 6.8 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 7.5 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 8.8 KiB |
|
After Width: | Height: | Size: 8.1 KiB |
|
After Width: | Height: | Size: 8.3 KiB |
|
After Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 5.8 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 6.0 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 6.4 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 8.4 KiB |
|
After Width: | Height: | Size: 7.8 KiB |
|
After Width: | Height: | Size: 5.8 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
|
After Width: | Height: | Size: 6.8 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 9.2 KiB |
|
After Width: | Height: | Size: 9.5 KiB |
|
After Width: | Height: | Size: 9.8 KiB |
|
After Width: | Height: | Size: 7.8 KiB |
|
After Width: | Height: | Size: 7.7 KiB |
|
After Width: | Height: | Size: 8.6 KiB |
|
After Width: | Height: | Size: 8.0 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 9.9 KiB |
|
After Width: | Height: | Size: 9.6 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
|
After Width: | Height: | Size: 6.4 KiB |
|
After Width: | Height: | Size: 6.6 KiB |
|
After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 6.4 KiB |
|
After Width: | Height: | Size: 6.6 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 6.4 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 6.0 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 9.1 KiB |
|
After Width: | Height: | Size: 6.6 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 8.1 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
|
@ -0,0 +1,54 @@
|
|||
<svg version="1.1" id="Estrogen" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 556.37 303.36" style="enable-background:new 0 0 556.37 303.36;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:none;}
|
||||
</style>
|
||||
<g>
|
||||
<polygon points="32.85,271.82 17.96,271.82 17.96,260.06 14.17,260.06 14.17,288.69 17.96,288.69 17.96,275.2 32.85,275.2
|
||||
32.85,288.69 36.63,288.69 36.63,260.06 32.85,260.06 "/>
|
||||
<path d="M62.65,261.45c-2.12-1.26-4.51-1.89-7.15-1.89c-4.04,0-7.33,1.34-9.88,4.04c-2.55,2.69-3.83,6.41-3.83,11.16
|
||||
c0,2.52,0.55,4.9,1.64,7.15c1.09,2.25,2.7,4.03,4.82,5.33c2.12,1.3,4.53,1.95,7.23,1.95c2.49,0,4.8-0.59,6.95-1.77
|
||||
c2.15-1.18,3.81-2.91,4.98-5.21c1.17-2.29,1.76-4.89,1.76-7.79c0-2.86-0.56-5.43-1.67-7.68C66.39,264.47,64.77,262.71,62.65,261.45
|
||||
z M62.5,282.93c-1.84,2.01-4.19,3.01-7.04,3.01c-2.8,0-5.13-0.99-6.98-2.98c-1.86-1.99-2.78-4.7-2.78-8.16
|
||||
c0-4.31,0.97-7.39,2.9-9.23c1.93-1.84,4.24-2.77,6.92-2.77c1.89,0,3.59,0.48,5.11,1.44s2.67,2.3,3.46,4.04
|
||||
c0.79,1.74,1.18,3.77,1.18,6.1C65.27,278.08,64.35,280.93,62.5,282.93z"/>
|
||||
<polygon points="262.41,214.22 247.52,214.22 247.52,202.46 243.73,202.46 243.73,231.1 247.52,231.1 247.52,217.6 262.41,217.6
|
||||
262.41,231.1 266.2,231.1 266.2,202.46 262.41,202.46 "/>
|
||||
<polygon points="312.29,127.82 297.4,127.82 297.4,116.06 293.62,116.06 293.62,144.7 297.4,144.7 297.4,131.2 312.29,131.2
|
||||
312.29,144.7 316.08,144.7 316.08,116.06 312.29,116.06 "/>
|
||||
<rect x="173.77" y="159.62" transform="matrix(0.4998 -0.8661 0.8661 0.4998 -70.4902 242.7992)" width="2.4" height="45.62"/>
|
||||
<rect x="114.5" y="193.83" width="2.4" height="45.64"/>
|
||||
<rect x="152.16" y="249.67" transform="matrix(0.8662 -0.4997 0.4997 0.8662 -101.9474 120.9965)" width="45.62" height="2.4"/>
|
||||
<polygon points="260.54,193.57 249.4,193.57 248.97,195.97 260.97,195.97 "/>
|
||||
<polygon points="258.36,181.33 251.59,181.33 251.16,183.73 258.79,183.73 "/>
|
||||
<polygon points="256.17,169.09 253.77,169.09 253.35,171.49 256.6,171.49 "/>
|
||||
<path d="M420.15,41.85c2.12,1.3,4.53,1.95,7.23,1.95c2.49,0,4.8-0.59,6.95-1.77s3.81-2.91,4.98-5.21s1.76-4.89,1.76-7.79
|
||||
c0-2.87-0.56-5.43-1.67-7.69s-2.73-4.02-4.85-5.28c-2.12-1.26-4.51-1.89-7.15-1.89c-4.04,0-7.33,1.34-9.88,4.03
|
||||
c-2.55,2.69-3.83,6.41-3.83,11.16c0,2.51,0.55,4.9,1.64,7.15S418.03,40.55,420.15,41.85z M420.5,20.2
|
||||
c1.93-1.84,4.24-2.76,6.92-2.76c1.89,0,3.59,0.48,5.11,1.44s2.67,2.3,3.46,4.04s1.18,3.77,1.18,6.1c0,3.69-0.92,6.53-2.77,8.54
|
||||
s-4.19,3.01-7.04,3.01c-2.8,0-5.13-0.99-6.98-2.98s-2.78-4.7-2.78-8.15C417.6,25.12,418.56,22.04,420.5,20.2z"/>
|
||||
<polygon points="464.75,26.44 449.87,26.44 449.87,14.68 446.08,14.68 446.08,43.31 449.87,43.31 449.87,29.82 464.75,29.82
|
||||
464.75,43.31 468.54,43.31 468.54,14.68 464.75,14.68 "/>
|
||||
<path d="M426.42,51.04l-11.41-3.71l-6.53,35.4l-52.4,17.03l4.66-55.9h-12l4.62,55.42l-48.5-28l-51.08,29.49v57.59l-48.68,28.12
|
||||
l-49.88-28.8l-51.08,29.48v57.6l-31.34,18.1l1.2,2.06l31.35-18.08l49.88,28.8l49.88-28.8l49.88,28.8l51.08-29.48v-57.6l48.82-28.2
|
||||
l55.1,17.92l34.88-48.02L410.9,83.51L426.42,51.04z M155.21,272.87l-48.68-28.12v-56.2l48.68-28.12l48.68,28.12v56.2L155.21,272.87
|
||||
z M254.97,272.87l-48.68-28.12v-56.2l48.68-28.12l48.68,28.12v56.2L254.97,272.87z M306.35,185.61l4.51-34.64h-12l4.51,34.64
|
||||
l-47.19-27.26v-56.21l48.68-28.11l48.68,28.11v56.21L306.35,185.61z M441.89,130.25l-32.83,45.18l-53.12-17.26v-55.85l53.12-17.26
|
||||
L441.89,130.25z"/>
|
||||
<polygon points="362.17,214.22 347.28,214.22 347.28,202.46 343.49,202.46 343.49,231.1 347.28,231.1 347.28,217.6 362.17,217.6
|
||||
362.17,231.1 365.96,231.1 365.96,202.46 362.17,202.46 "/>
|
||||
<polygon points="348.73,195.97 360.73,195.97 360.31,193.57 349.16,193.57 "/>
|
||||
<polygon points="350.92,183.73 358.55,183.73 358.12,181.33 351.35,181.33 "/>
|
||||
<polygon points="353.53,169.09 353.11,171.49 356.36,171.49 355.93,169.09 "/>
|
||||
<path d="M508.21,117.45c-2.12-1.26-4.51-1.89-7.15-1.89c-4.04,0-7.33,1.34-9.88,4.03c-2.55,2.69-3.83,6.41-3.83,11.16
|
||||
c0,2.51,0.55,4.9,1.64,7.15s2.7,4.03,4.82,5.33c2.12,1.3,4.53,1.95,7.23,1.95c2.49,0,4.8-0.59,6.95-1.77s3.81-2.91,4.98-5.21
|
||||
c1.17-2.29,1.76-4.89,1.76-7.79c0-2.87-0.56-5.43-1.67-7.69C511.95,120.47,510.33,118.71,508.21,117.45z M508.06,138.93
|
||||
c-1.84,2.01-4.19,3.01-7.04,3.01c-2.8,0-5.13-0.99-6.98-2.98s-2.78-4.7-2.78-8.15c0-4.31,0.96-7.39,2.9-9.23s4.24-2.76,6.92-2.76
|
||||
c1.89,0,3.59,0.48,5.11,1.44s2.67,2.3,3.46,4.04s1.18,3.77,1.18,6.1C510.83,134.08,509.9,136.93,508.06,138.93z"/>
|
||||
<polygon points="538.4,116.06 538.4,127.82 523.52,127.82 523.52,116.06 519.73,116.06 519.73,144.7 523.52,144.7 523.52,131.2
|
||||
538.4,131.2 538.4,144.7 542.19,144.7 542.19,116.06 "/>
|
||||
<polygon points="478.41,135.83 480.81,136.25 480.81,124.25 478.41,124.67 "/>
|
||||
<polygon points="465.9,133.63 468.3,134.05 468.3,126.45 465.9,126.85 "/>
|
||||
<polygon points="453.38,131.45 455.78,131.87 455.78,128.63 453.38,129.05 "/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.3 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
|
@ -0,0 +1,31 @@
|
|||
@font-face {
|
||||
font-family: 'Comic Code';
|
||||
src: url('https://fonts.doughmination.co.uk/ComicCode-Regular_2022-05-24-151938_hsmz.woff2') format('woff2'),
|
||||
url('https://fonts.doughmination.co.uk/ComicCode-Regular_2022-05-24-151938_hsmz.woff') format('woff');
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Comic Code';
|
||||
src: url('https://fonts.doughmination.co.uk/ComicCode-Italic_2022-05-24-151939_rdtu.woff2') format('woff2'),
|
||||
url('https://fonts.doughmination.co.uk/ComicCode-Italic_2022-05-24-151939_rdtu.woff') format('woff');
|
||||
font-weight: 400;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Comic Code';
|
||||
src: url('https://fonts.doughmination.co.uk/ComicCode-Medium_2022-05-24-151941_ugqm.woff2') format('woff2'),
|
||||
url('https://fonts.doughmination.co.uk/ComicCode-Medium_2022-05-24-151941_ugqm.woff') format('woff');
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Comic Code';
|
||||
src: url('https://fonts.doughmination.co.uk/ComicCode-Bold_2022-05-24-152309_zqkm.woff2') format('woff2'),
|
||||
url('https://fonts.doughmination.co.uk/ComicCode-Bold_2022-05-24-152309_zqkm.woff') format('woff');
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
}
|
||||
103
css/index.css
|
|
@ -1,84 +1,49 @@
|
|||
@font-face {
|
||||
font-family: 'Comic Code';
|
||||
src: url('https://fonts.doughmination.co.uk/ComicCode-Regular_2022-05-24-151938_hsmz.woff2') format('woff2'),
|
||||
url('https://fonts.doughmination.co.uk/ComicCode-Regular_2022-05-24-151938_hsmz.woff') format('woff');
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
}
|
||||
@import url("fonts.css");
|
||||
@import url(theme-switcher.css);
|
||||
@import url("picker.css");
|
||||
@import url(themes/mocha.css);
|
||||
@import url(themes/macciato.css);
|
||||
@import url(themes/frappe.css);
|
||||
@import url(themes/latte.css);
|
||||
|
||||
@font-face {
|
||||
font-family: 'Comic Code';
|
||||
src: url('https://fonts.doughmination.co.uk/ComicCode-Italic_2022-05-24-151939_rdtu.woff2') format('woff2'),
|
||||
url('https://fonts.doughmination.co.uk/ComicCode-Italic_2022-05-24-151939_rdtu.woff') format('woff');
|
||||
font-weight: 400;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Comic Code';
|
||||
src: url('https://fonts.doughmination.co.uk/ComicCode-Medium_2022-05-24-151941_ugqm.woff2') format('woff2'),
|
||||
url('https://fonts.doughmination.co.uk/ComicCode-Medium_2022-05-24-151941_ugqm.woff') format('woff');
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Comic Code';
|
||||
src: url('https://fonts.doughmination.co.uk/ComicCode-Bold_2022-05-24-152309_zqkm.woff2') format('woff2'),
|
||||
url('https://fonts.doughmination.co.uk/ComicCode-Bold_2022-05-24-152309_zqkm.woff') format('woff');
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
:root {
|
||||
/* https://catppuccin.com/palette/ */
|
||||
/* Catppuccin Mocha */
|
||||
/* accents */
|
||||
--rosewater: #f5e0dc;
|
||||
--flamingo: #f2cdcd;
|
||||
--pink: #f5c2e7;
|
||||
--mauve: #cba6f7;
|
||||
--red: #f38ba8;
|
||||
--maroon: #eba0ac;
|
||||
--peach: #fab387;
|
||||
--yellow: #f9e2af;
|
||||
--green: #a6e3a1;
|
||||
--teal: #94e2d5;
|
||||
--sky: #89dceb;
|
||||
--saphire: #74c7ec;
|
||||
--blue: #89b4fa; /* a lovely new blue passport */
|
||||
--lavender: #b4befe;
|
||||
/* Text */
|
||||
--text: #cdd6f4;
|
||||
--subtext-0: #a6adc8;
|
||||
--subtext-1: #bac2de;
|
||||
--overlay-0: #6c7086;
|
||||
--overlay-1: #7f849c;
|
||||
--overlay-2: #9399b2;
|
||||
--surface-0: #313244;
|
||||
--surface-1: #45475a;
|
||||
--surface-2: #585b70;
|
||||
/* Backgrounds */
|
||||
--base: #1e1e2e;
|
||||
--mantle: #181825;
|
||||
--crust: #11111b; /* Is this the crusty crab? */
|
||||
}
|
||||
|
||||
html, body {
|
||||
background-color: var(--base);
|
||||
color: var(--text);
|
||||
font-family: 'Comic Code', sans-serif;
|
||||
overflow-x: hidden;
|
||||
max-width: 100vw;
|
||||
margin: 0;
|
||||
min-height: 100vh;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
html {
|
||||
background: linear-gradient(135deg, var(--base) 0%, var(--mantle) 60%, var(--crust) 100%);
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Comic Code', sans-serif;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
height: 100dvh;
|
||||
margin: 0;
|
||||
padding: 1.5rem 1rem;
|
||||
background: linear-gradient(135deg, var(--base) 0%, var(--mantle) 60%, var(--crust) 100%);
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
/* Estrogen watermark blended into the background */
|
||||
body::before {
|
||||
content: "";
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: url(/assets/theme/estrogen.svg) center / cover no-repeat;
|
||||
filter: invert(86%) sepia(8%) saturate(900%) hue-rotate(190deg) brightness(105%);
|
||||
opacity: 0.05;
|
||||
pointer-events: none;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
|
||||
.intro {
|
||||
margin-top: 20vh;
|
||||
color: var(--text);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,65 @@
|
|||
/* oneko skin switcher — standalone picker styles.
|
||||
No framework, no CSS variables required. Restyle freely. */
|
||||
|
||||
/* https://github.com/doughmination/oneko.clove.is-a.dev/releases/tag/v1.0.0 */
|
||||
|
||||
#oneko { position: fixed; width: 32px; height: 32px; image-rendering: pixelated;
|
||||
z-index: 2147483647; pointer-events: none; }
|
||||
|
||||
.cat-picker {
|
||||
position: fixed; inset: 0; z-index: 2147483646;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
background: rgba(17, 17, 27, 0.72); backdrop-filter: blur(4px); padding: 20px;
|
||||
}
|
||||
.cat-picker[hidden] { display: none; }
|
||||
.cat-picker-panel {
|
||||
background: #181825; color: #cdd6f4; border: 1px solid #313244;
|
||||
border-radius: 14px; width: min(720px, 100%); max-height: 82vh;
|
||||
display: flex; flex-direction: column; font-family: system-ui, sans-serif;
|
||||
box-shadow: 0 24px 60px rgba(0,0,0,0.5);
|
||||
}
|
||||
.cat-picker-head {
|
||||
display: flex; align-items: center; justify-content: space-between;
|
||||
padding: 16px 20px; border-bottom: 1px solid #313244; font-weight: 700;
|
||||
}
|
||||
.cat-picker-close {
|
||||
background: none; border: none; color: #a6adc8; font-size: 1.5rem;
|
||||
line-height: 1; cursor: pointer; padding: 0 4px;
|
||||
}
|
||||
.cat-picker-close:hover { color: #f38ba8; }
|
||||
.cat-grid { overflow-y: auto; padding: 18px 20px; }
|
||||
.cat-section { margin-bottom: 18px; }
|
||||
.cat-section-title {
|
||||
margin: 0 0 10px; font-size: 0.8rem; text-transform: uppercase;
|
||||
letter-spacing: 0.06em; color: #cba6f7;
|
||||
}
|
||||
.cat-section-items {
|
||||
display: grid; gap: 10px; grid-template-columns: repeat(auto-fill, minmax(74px, 1fr));
|
||||
}
|
||||
.cat-option {
|
||||
background: #1e1e2e; border: 1px solid #313244; border-radius: 10px;
|
||||
padding: 10px 6px 8px; cursor: pointer; color: inherit;
|
||||
display: flex; flex-direction: column; align-items: center; gap: 6px;
|
||||
transition: border-color .12s, transform .1s, background .12s;
|
||||
}
|
||||
.cat-option:hover { border-color: #cba6f7; transform: translateY(-2px); background: #313244; }
|
||||
.cat-option.current { border-color: #cba6f7; background: #313244; box-shadow: inset 0 0 0 1px #cba6f7; }
|
||||
.cat-option .cat-preview {
|
||||
width: 32px; height: 32px; image-rendering: pixelated;
|
||||
background-repeat: no-repeat; border-radius: 4px;
|
||||
}
|
||||
.cat-option .cat-name { font-size: 0.68rem; color: #bac2de; text-align: center; line-height: 1.1; word-break: break-word; }
|
||||
.cat-hint { margin: 0; padding: 12px 20px; border-top: 1px solid #313244;
|
||||
font-size: 0.78rem; color: #a6adc8; text-align: center; }
|
||||
.cat-hide-btn { background: none; border: none; color: #f38ba8; cursor: pointer;
|
||||
font-size: 0.78rem; padding: 0; }
|
||||
.cat-hide-btn:hover { text-decoration: underline; }
|
||||
.oneko-show-btn {
|
||||
position: fixed; left: 14px; bottom: 14px; z-index: 2147483646;
|
||||
background: #1e1e2e; color: #bac2de; border: 1px solid #313244; border-radius: 999px;
|
||||
padding: 7px 14px; font-size: 0.8rem; cursor: pointer; opacity: 0.85;
|
||||
box-shadow: 0 6px 18px rgba(0,0,0,0.35); font-family: system-ui, sans-serif;
|
||||
}
|
||||
.oneko-show-btn:hover { opacity: 1; border-color: #cba6f7; color: #cdd6f4; }
|
||||
kbd { background:#313244; border:1px solid #585b70; border-bottom-width:2px;
|
||||
border-radius:6px; padding:.05em .45em; font-size:.85em; }
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
.beta-bar {
|
||||
position: fixed;
|
||||
top: 1rem;
|
||||
right: 1rem;
|
||||
z-index: 7;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
/* cat-collection button icon: the classic oneko idle frame, scaled down
|
||||
from the 256x128 sprite sheet (idle frame lives at -96px,-96px) */
|
||||
.beta-cat-icon {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
display: block;
|
||||
background-image: url('/assets/oneko/classics/classic.png');
|
||||
background-repeat: no-repeat;
|
||||
background-size: 176px 88px;
|
||||
background-position: -66px -66px;
|
||||
image-rendering: pixelated;
|
||||
}
|
||||
|
||||
.beta-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0.35rem;
|
||||
border-radius: 999px;
|
||||
background: var(--surface-0);
|
||||
border: 1px solid var(--surface-1);
|
||||
cursor: pointer;
|
||||
transition: border-color 0.15s ease, transform 0.15s ease;
|
||||
}
|
||||
|
||||
.beta-btn:hover {
|
||||
border-color: var(--pink);
|
||||
transform: translateY(2px);
|
||||
}
|
||||
|
||||
.beta-icon {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
display: block;
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/* Catppuccin Frappé — official palette
|
||||
https://github.com/catppuccin/catppuccin (dark) */
|
||||
html[data-flavor="frappe"] {
|
||||
color-scheme: dark;
|
||||
|
||||
/* accents */
|
||||
--rosewater: #f2d5cf;
|
||||
--flamingo: #eebebe;
|
||||
--pink: #f4b8e4;
|
||||
--accent-rgb: 244, 184, 228; /* live accent default = theme pink */
|
||||
--mauve: #ca9ee6;
|
||||
--red: #e78284;
|
||||
--maroon: #ea999c;
|
||||
--peach: #ef9f76;
|
||||
--yellow: #e5c890;
|
||||
--green: #a6d189;
|
||||
--teal: #81c8be;
|
||||
--sky: #99d1db;
|
||||
--saphire: #85c1dc;
|
||||
--blue: #8caaee;
|
||||
--lavender: #babbf1;
|
||||
|
||||
/* text */
|
||||
--text: #c6d0f5;
|
||||
--subtext-1: #b5bfe2;
|
||||
--subtext-0: #a5adce;
|
||||
--overlay-2: #949cbb;
|
||||
--overlay-1: #838ba7;
|
||||
--overlay-0: #737994;
|
||||
|
||||
/* surfaces + backgrounds */
|
||||
--surface-2: #626880;
|
||||
--surface-1: #51576d;
|
||||
--surface-0: #414559;
|
||||
--base: #303446;
|
||||
--mantle: #292c3c;
|
||||
--crust: #232634;
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
/* Catppuccin Latte — official palette
|
||||
https://github.com/catppuccin/catppuccin (light) */
|
||||
html[data-flavor="latte"] {
|
||||
color-scheme: light;
|
||||
|
||||
/* accents */
|
||||
--rosewater: #dc8a78;
|
||||
--flamingo: #dd7878;
|
||||
--pink: #ea76cb;
|
||||
--accent-rgb: 234, 118, 203; /* live accent default = theme pink */
|
||||
--mauve: #8839ef;
|
||||
--red: #d20f39;
|
||||
--maroon: #e64553;
|
||||
--peach: #fe640b;
|
||||
--yellow: #df8e1d;
|
||||
--green: #40a02b;
|
||||
--teal: #179299;
|
||||
--sky: #04a5e5;
|
||||
--saphire: #209fb5;
|
||||
--blue: #1e66f5;
|
||||
--lavender: #7287fd;
|
||||
|
||||
/* text */
|
||||
--text: #4c4f69;
|
||||
--subtext-1: #5c5f77;
|
||||
--subtext-0: #6c6f85;
|
||||
--overlay-2: #7c7f93;
|
||||
--overlay-1: #8c8fa1;
|
||||
--overlay-0: #9ca0b0;
|
||||
|
||||
/* surfaces + backgrounds */
|
||||
--surface-2: #acb0be;
|
||||
--surface-1: #bcc0cc;
|
||||
--surface-0: #ccd0da;
|
||||
--base: #eff1f5;
|
||||
--mantle: #e6e9ef;
|
||||
--crust: #dce0e8;
|
||||
}
|
||||
|
||||
/* Light-mode readability fixes (icons are white-filtered by default) */
|
||||
html[data-flavor="latte"] .icon {
|
||||
filter: brightness(0);
|
||||
}
|
||||
|
||||
html[data-flavor="latte"] .link-card:hover .icon {
|
||||
filter: none;
|
||||
}
|
||||
|
||||
html[data-flavor="latte"] .badge-icon {
|
||||
filter: none;
|
||||
}
|
||||
|
||||
html[data-flavor="latte"] body::before {
|
||||
filter: invert(14%) sepia(0.2) saturate(300%) hue-rotate(200deg) brightness(1.3);
|
||||
opacity: 0.05;
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/* Catppuccin Macchiato — official palette
|
||||
https://github.com/catppuccin/catppuccin (dark) */
|
||||
html[data-flavor="macchiato"] {
|
||||
color-scheme: dark;
|
||||
|
||||
/* accents */
|
||||
--rosewater: #f4dbd6;
|
||||
--flamingo: #f0c6c6;
|
||||
--pink: #f5bde6;
|
||||
--accent-rgb: 245, 189, 230; /* live accent default = theme pink */
|
||||
--mauve: #c6a0f6;
|
||||
--red: #ed8796;
|
||||
--maroon: #ee99a0;
|
||||
--peach: #f5a97f;
|
||||
--yellow: #eed49f;
|
||||
--green: #a6da95;
|
||||
--teal: #8bd5ca;
|
||||
--sky: #91d7e3;
|
||||
--saphire: #7dc4e4;
|
||||
--blue: #8aadf4;
|
||||
--lavender: #b7bdf8;
|
||||
|
||||
/* text */
|
||||
--text: #cad3f5;
|
||||
--subtext-1: #b8c0e0;
|
||||
--subtext-0: #a5adcb;
|
||||
--overlay-2: #939ab7;
|
||||
--overlay-1: #8087a2;
|
||||
--overlay-0: #6e738d;
|
||||
|
||||
/* surfaces + backgrounds */
|
||||
--surface-2: #5b6078;
|
||||
--surface-1: #494d64;
|
||||
--surface-0: #363a4f;
|
||||
--base: #24273a;
|
||||
--mantle: #1e2030;
|
||||
--crust: #181926;
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/* Catppuccin Mocha — official palette
|
||||
https://github.com/catppuccin/catppuccin (dark, default) */
|
||||
html[data-flavor="mocha"] {
|
||||
color-scheme: dark;
|
||||
|
||||
/* accents */
|
||||
--rosewater: #f5e0dc;
|
||||
--flamingo: #f2cdcd;
|
||||
--pink: #f5c2e7;
|
||||
--accent-rgb: 245, 194, 231; /* live accent default = theme pink */
|
||||
--mauve: #cba6f7;
|
||||
--red: #f38ba8;
|
||||
--maroon: #eba0ac;
|
||||
--peach: #fab387;
|
||||
--yellow: #f9e2af;
|
||||
--green: #a6e3a1;
|
||||
--teal: #94e2d5;
|
||||
--sky: #89dceb;
|
||||
--saphire: #74c7ec;
|
||||
--blue: #89b4fa;
|
||||
--lavender: #b4befe;
|
||||
|
||||
/* Text */
|
||||
--text: #cdd6f4;
|
||||
--subtext-0: #a6adc8;
|
||||
--subtext-1: #bac2de;
|
||||
--overlay-0: #6c7086;
|
||||
--overlay-1: #7f849c;
|
||||
--overlay-2: #9399b2;
|
||||
--surface-0: #313244;
|
||||
--surface-1: #45475a;
|
||||
--surface-2: #585b70;
|
||||
|
||||
/* Backgrounds */
|
||||
--base: #1e1e2e;
|
||||
--mantle: #181825;
|
||||
--crust: #11111b;
|
||||
}
|
||||
|
|
@ -35,6 +35,7 @@
|
|||
<meta name="twitter:title" content="Ari Stuff" />
|
||||
<meta name="twitter:description" content="Personal Site for Ari on git.gay" />
|
||||
<link href="css/index.css" rel="stylesheet" />
|
||||
<link href="css/picker.css" rel="stylesheet" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="intro">
|
||||
|
|
@ -50,5 +51,6 @@
|
|||
|
||||
</body>
|
||||
<script src="js/index.js"></script>
|
||||
<script src="js/cat.js" data-cat="assets/media/oneko.gif"></script>
|
||||
<script src="js/flavors.js"></script>
|
||||
<script src="js/cat.js"></script>
|
||||
</html>
|
||||
300
js/cat.js
|
|
@ -277,3 +277,303 @@
|
|||
|
||||
init();
|
||||
})();
|
||||
|
||||
const BASE_SPRITE = "/assets/oneko/classics/classic.png";
|
||||
|
||||
let CAT_MODES = [];
|
||||
|
||||
// Order the category sections appear in the menu
|
||||
const CATEGORY_ORDER = ["Classics", "Pride", "Cats", "Romance", "Gaming", "Pokémon", "Other Animals", "Things", "Rare"];
|
||||
|
||||
// click-count goals (total clicks on the cat)
|
||||
const CLICK_GOALS = { filter: 13, romance: 69, weed: 420 };
|
||||
const SPRITE = BASE_SPRITE; // base sprite used for filter modes + previews
|
||||
const IDLE_POS = "-97px -97px"; // idle frame, inset 1px to avoid neighbour-frame bleed
|
||||
const spriteFor = (c) => c.sprite || BASE_SPRITE;
|
||||
|
||||
(async function catModes() {
|
||||
try {
|
||||
// index.json lists which per-folder configs to load (one per oneko folder)
|
||||
const index = await fetch("/js/on/index.json").then((r) => {
|
||||
if (!r.ok) throw new Error(`index.json (${r.status})`);
|
||||
return r.json();
|
||||
});
|
||||
// load every /js/on/<folder>.json and merge them into one list
|
||||
const lists = await Promise.all(
|
||||
index.map((name) =>
|
||||
fetch(`/js/on/${name}.json`)
|
||||
.then((r) => (r.ok ? r.json() : []))
|
||||
.catch(() => [])
|
||||
)
|
||||
);
|
||||
CAT_MODES = lists.flat();
|
||||
} catch (err) {
|
||||
console.error("Could not load cat data:", err);
|
||||
return;
|
||||
}
|
||||
const oneko = document.getElementById("oneko");
|
||||
if (!oneko) return;
|
||||
|
||||
oneko.style.pointerEvents = "auto";
|
||||
oneko.style.cursor = "pointer";
|
||||
|
||||
const ls = window.localStorage;
|
||||
let clicks = parseInt(ls.getItem("onekoClicks") || "0", 10);
|
||||
let mode = parseInt(ls.getItem("onekoMode") || "0", 10);
|
||||
|
||||
// permanently-earned methods (konami, gold, pokemon, + any click goal hit)
|
||||
let unlocks;
|
||||
try { unlocks = new Set(JSON.parse(ls.getItem("onekoUnlocks") || "[]")); }
|
||||
catch (e) { unlocks = new Set(); }
|
||||
const saveUnlocks = () => ls.setItem("onekoUnlocks", JSON.stringify([...unlocks]));
|
||||
|
||||
// Returns true if a method was newly unlocked (false if already had it)
|
||||
function unlockMethod(key) {
|
||||
if (unlocks.has(key)) return false;
|
||||
unlocks.add(key);
|
||||
saveUnlocks();
|
||||
if (overlay && !overlay.hidden) renderGrid();
|
||||
return true;
|
||||
}
|
||||
|
||||
const methodOf = (c) => c.unlockMethod || "gay";
|
||||
const isUnlocked = (i) => {
|
||||
const key = methodOf(CAT_MODES[i]);
|
||||
if (key === "gay") return true;
|
||||
if (key in CLICK_GOALS) return clicks >= CLICK_GOALS[key] || unlocks.has(key);
|
||||
return unlocks.has(key); // konami / gold / pokemon
|
||||
};
|
||||
const unlockedIndices = () =>
|
||||
CAT_MODES.map((_, i) => i).filter(isUnlocked);
|
||||
|
||||
const apply = (i) => {
|
||||
const c = CAT_MODES[i];
|
||||
oneko.style.backgroundImage = `url('${spriteFor(c)}')`;
|
||||
oneko.style.filter = c.filter || "none";
|
||||
};
|
||||
|
||||
/* ---------- picker overlay (no visible trigger — press C to find it) ---------- */
|
||||
const overlay = document.createElement("div");
|
||||
overlay.className = "cat-picker";
|
||||
overlay.hidden = true;
|
||||
overlay.innerHTML = `
|
||||
<div class="cat-picker-panel" role="dialog" aria-label="Choose a cat">
|
||||
<div class="cat-picker-head">
|
||||
<span>Cat collection</span>
|
||||
<button class="cat-picker-close" type="button" aria-label="Close">×</button>
|
||||
</div>
|
||||
<div class="cat-grid"></div>
|
||||
<p class="cat-hint">Some cats are still hidden… · press C to toggle</p>
|
||||
</div>`;
|
||||
document.body.appendChild(overlay);
|
||||
const grid = overlay.querySelector(".cat-grid");
|
||||
|
||||
function makeOption(i) {
|
||||
const c = CAT_MODES[i];
|
||||
const unlocked = isUnlocked(i);
|
||||
const opt = document.createElement(unlocked ? "button" : "div");
|
||||
opt.className =
|
||||
"cat-option" + (unlocked ? "" : " locked") + (i === mode ? " current" : "");
|
||||
if (unlocked) opt.type = "button";
|
||||
const previewFilter = unlocked ? (c.filter || "none") : "brightness(0) opacity(0.3)";
|
||||
opt.innerHTML = `
|
||||
<span class="cat-preview" style="background-image:url('${spriteFor(c)}');background-position:${IDLE_POS};filter:${previewFilter}"></span>
|
||||
<span class="cat-name">${unlocked ? c.name : "???"}</span>`;
|
||||
if (unlocked) opt.addEventListener("click", () => selectMode(i));
|
||||
return opt;
|
||||
}
|
||||
|
||||
function renderGrid() {
|
||||
grid.innerHTML = "";
|
||||
|
||||
// bucket cat indices by category
|
||||
const byCat = {};
|
||||
CAT_MODES.forEach((c, i) => {
|
||||
const cat = c.category || "Classics";
|
||||
(byCat[cat] = byCat[cat] || []).push(i);
|
||||
});
|
||||
|
||||
// known categories first (in order), then any stragglers
|
||||
const order = CATEGORY_ORDER.filter((c) => byCat[c])
|
||||
.concat(Object.keys(byCat).filter((c) => !CATEGORY_ORDER.includes(c)));
|
||||
|
||||
order.forEach((cat) => {
|
||||
const section = document.createElement("div");
|
||||
section.className = "cat-section";
|
||||
|
||||
const title = document.createElement("h4");
|
||||
title.className = "cat-section-title";
|
||||
title.textContent = cat;
|
||||
section.appendChild(title);
|
||||
|
||||
const items = document.createElement("div");
|
||||
items.className = "cat-section-items";
|
||||
byCat[cat].forEach((i) => items.appendChild(makeOption(i)));
|
||||
section.appendChild(items);
|
||||
|
||||
grid.appendChild(section);
|
||||
});
|
||||
}
|
||||
|
||||
function selectMode(i) {
|
||||
mode = i;
|
||||
ls.setItem("onekoMode", String(i));
|
||||
apply(i);
|
||||
renderGrid();
|
||||
}
|
||||
|
||||
const openPicker = () => {
|
||||
renderGrid();
|
||||
overlay.hidden = false;
|
||||
};
|
||||
const closePicker = () => (overlay.hidden = true);
|
||||
const togglePicker = () => (overlay.hidden ? openPicker() : closePicker());
|
||||
|
||||
// let other scripts (e.g. the theme-bar button) open the cat menu
|
||||
window.toggleCatPicker = togglePicker;
|
||||
|
||||
overlay
|
||||
.querySelector(".cat-picker-close")
|
||||
.addEventListener("click", closePicker);
|
||||
overlay.addEventListener("click", (e) => {
|
||||
if (e.target === overlay) closePicker();
|
||||
});
|
||||
document.addEventListener("keydown", (e) => {
|
||||
// ignore while typing in a field or with modifier keys held
|
||||
const typing = /^(INPUT|TEXTAREA|SELECT)$/.test(document.activeElement?.tagName || "");
|
||||
if (e.key === "Escape" && !overlay.hidden) {
|
||||
closePicker();
|
||||
} else if (
|
||||
(e.key === "c" || e.key === "C") &&
|
||||
!e.ctrlKey && !e.metaKey && !e.altKey && !typing
|
||||
) {
|
||||
togglePicker();
|
||||
} else if ((e.key === "x" || e.key === "X") &&
|
||||
!e.ctrlKey && !e.metaKey && !e.altKey && !typing) {
|
||||
if (unlockMethod("gaming")) {
|
||||
toast("✨ Gaming sprites unlocked!");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/* ---------- toast ---------- */
|
||||
let toastEl, toastTimer;
|
||||
function toast(msg) {
|
||||
if (!toastEl) {
|
||||
toastEl = document.createElement("div");
|
||||
toastEl.className = "cat-toast";
|
||||
document.body.appendChild(toastEl);
|
||||
}
|
||||
toastEl.textContent = msg;
|
||||
toastEl.classList.remove("show");
|
||||
void toastEl.offsetWidth;
|
||||
toastEl.classList.add("show");
|
||||
clearTimeout(toastTimer);
|
||||
toastTimer = setTimeout(() => toastEl.classList.remove("show"), 1700);
|
||||
}
|
||||
|
||||
/* ---------- squeak / boop sound on click ---------- */
|
||||
const boop = new Audio("/assets/oneko/boop.mp3");
|
||||
boop.preload = "auto";
|
||||
function playBoop() {
|
||||
try {
|
||||
boop.currentTime = 0; // rewind so rapid clicks each squeak
|
||||
boop.play().catch(() => { }); // ignore autoplay/missing-file errors
|
||||
} catch (e) { /* no-op */ }
|
||||
}
|
||||
|
||||
/* ---------- init + cat click ---------- */
|
||||
if (!isUnlocked(mode)) mode = 0; // fall back to Classic if current is locked
|
||||
apply(mode);
|
||||
|
||||
// Clicking the cat no longer changes its look — it only counts toward
|
||||
// the click-based unlocks (13 / 69 / 420). Pick a cat from the menu.
|
||||
oneko.addEventListener("click", (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
playBoop();
|
||||
clicks += 1;
|
||||
ls.setItem("onekoClicks", String(clicks));
|
||||
|
||||
// Did this click hit a click-count goal exactly? (13 / 69 / 420)
|
||||
for (const key in CLICK_GOALS) {
|
||||
if (clicks === CLICK_GOALS[key]) {
|
||||
unlocks.add(key);
|
||||
saveUnlocks();
|
||||
const idx = CAT_MODES.findIndex((c) => methodOf(c) === key);
|
||||
const name = idx >= 0 ? CAT_MODES[idx].name : key;
|
||||
toast(`✨ Unlocked: ${name}! — open the cat menu 🐱`);
|
||||
if (!overlay.hidden) renderGrid();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/* ---------- Konami code → press Enter to confirm ---------- */
|
||||
const KONAMI = ["ArrowUp", "ArrowUp", "ArrowDown", "ArrowDown",
|
||||
"ArrowLeft", "ArrowRight", "ArrowLeft", "ArrowRight", "b", "a"];
|
||||
let kProg = 0, kArmed = false;
|
||||
document.addEventListener("keydown", (e) => {
|
||||
const typing = /^(INPUT|TEXTAREA|SELECT)$/.test(document.activeElement?.tagName || "");
|
||||
if (typing || e.ctrlKey || e.metaKey || e.altKey) return;
|
||||
|
||||
if (kArmed && e.key === "Enter") {
|
||||
kArmed = false;
|
||||
if (unlockMethod("konami")) toast("✨ Konami cats unlocked!");
|
||||
return;
|
||||
}
|
||||
|
||||
const key = e.key.length === 1 ? e.key.toLowerCase() : e.key;
|
||||
if (key === KONAMI[kProg]) {
|
||||
kProg += 1;
|
||||
if (kProg === KONAMI.length) {
|
||||
kProg = 0;
|
||||
kArmed = true;
|
||||
toast("Konami code… press Enter ↵");
|
||||
}
|
||||
} else {
|
||||
kProg = key === KONAMI[0] ? 1 : 0; // allow a fresh start on ↑
|
||||
}
|
||||
});
|
||||
|
||||
/* ---------- Gold → opened the site while Discord status is Idle ---------- */
|
||||
const np = document.getElementById("now-playing");
|
||||
if (np) {
|
||||
const checkIdle = () => {
|
||||
if (np.dataset.status === "idle" && unlockMethod("gold")) {
|
||||
toast("✨ Gold Cat unlocked!");
|
||||
}
|
||||
};
|
||||
checkIdle();
|
||||
new MutationObserver(checkIdle)
|
||||
.observe(np, { attributes: true, attributeFilter: ["data-status"] });
|
||||
}
|
||||
|
||||
/* ---------- Pokémon → find & click the hidden pokéball ---------- */
|
||||
const poke = document.getElementById("pokeball-secret");
|
||||
if (poke) {
|
||||
poke.addEventListener("click", (e) => {
|
||||
e.preventDefault();
|
||||
poke.classList.add("found");
|
||||
if (unlockMethod("pokemon")) toast("✨ Pokémon cats unlocked!");
|
||||
});
|
||||
}
|
||||
|
||||
/* ---------- Timer → keep the page open for a while ---------- */
|
||||
// Counts only while the tab is visible; resets each visit, but once the
|
||||
// goal is reached the unlock is saved for good.
|
||||
const TIMER_GOAL_MS = 5 * 60 * 1000; // 5 minutes
|
||||
if (!unlocks.has("timer")) {
|
||||
let elapsed = 0;
|
||||
let last = Date.now();
|
||||
const timer = setInterval(() => {
|
||||
if (document.hidden) { last = Date.now(); return; }
|
||||
const now = Date.now();
|
||||
elapsed += now - last;
|
||||
last = now;
|
||||
if (elapsed >= TIMER_GOAL_MS) {
|
||||
clearInterval(timer);
|
||||
if (unlockMethod("timer")) toast("✨ Patience pays off — timer cats unlocked!");
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,76 @@
|
|||
(function flavors() {
|
||||
// Metadata only — colors are defined in the per-flavor CSS files.
|
||||
const FLAVORS = {
|
||||
mocha: { label: "Mocha", dot: "#f5c2e7" },
|
||||
macchiato: { label: "Macchiato", dot: "#f5bde6" },
|
||||
frappe: { label: "Frappé", dot: "#f4b8e4" },
|
||||
latte: { label: "Latte", dot: "#ea76cb" },
|
||||
};
|
||||
const ORDER = ["mocha", "macchiato", "frappe", "latte"];
|
||||
|
||||
const root = document.documentElement;
|
||||
const ls = window.localStorage;
|
||||
|
||||
function apply(name) {
|
||||
const f = FLAVORS[name] || FLAVORS.mocha;
|
||||
root.setAttribute("data-flavor", name); // CSS does the rest
|
||||
const meta = document.querySelector('meta[name="theme-color"]');
|
||||
if (meta) meta.setAttribute("content", f.dot);
|
||||
}
|
||||
|
||||
let current = ls.getItem("ctpFlavor");
|
||||
if (!ORDER.includes(current)) current = "mocha";
|
||||
apply(current); // the <head> snippet already set this to avoid a flash
|
||||
|
||||
// ---- top-right corner icon button ----
|
||||
const bar = document.createElement("div");
|
||||
bar.className = "beta-bar";
|
||||
bar.innerHTML = `
|
||||
<button class="beta-btn" id="flavor-btn" type="button">
|
||||
<img class="beta-icon" alt="">
|
||||
</button>`;
|
||||
// Group the single-item widgets (now-playing + theme toggle) into one
|
||||
// top bar. On mobile they sit side by side; on desktop both stay
|
||||
// position:fixed, so this wrapper is zero-size and invisible.
|
||||
let topbar = document.querySelector(".topbar");
|
||||
if (!topbar) {
|
||||
topbar = document.createElement("div");
|
||||
topbar.className = "topbar";
|
||||
document.body.insertBefore(topbar, document.body.firstChild);
|
||||
const np = document.getElementById("now-playing");
|
||||
if (np) topbar.appendChild(np);
|
||||
}
|
||||
topbar.appendChild(bar);
|
||||
|
||||
const btn = bar.querySelector("#flavor-btn");
|
||||
const icon = bar.querySelector(".beta-icon");
|
||||
|
||||
function paintBtn() {
|
||||
const f = FLAVORS[current];
|
||||
icon.src = `/assets/theme/${current}.png`; // e.g. /assets/theme/mocha.png
|
||||
icon.alt = f.label;
|
||||
btn.title = `Theme: ${f.label} (click to cycle)`;
|
||||
}
|
||||
paintBtn();
|
||||
|
||||
btn.addEventListener("click", () => {
|
||||
current = ORDER[(ORDER.indexOf(current) + 1) % ORDER.length];
|
||||
ls.setItem("ctpFlavor", current);
|
||||
apply(current);
|
||||
paintBtn();
|
||||
});
|
||||
|
||||
// ---- cat collection button (sits next to the theme button) ----
|
||||
const catBtn = document.createElement("button");
|
||||
catBtn.className = "beta-btn";
|
||||
catBtn.id = "cat-btn";
|
||||
catBtn.type = "button";
|
||||
catBtn.title = "Cat collection";
|
||||
catBtn.setAttribute("aria-label", "Open cat collection");
|
||||
catBtn.innerHTML = `<span class="beta-cat-icon" aria-hidden="true"></span>`;
|
||||
bar.appendChild(catBtn);
|
||||
|
||||
catBtn.addEventListener("click", () => {
|
||||
if (typeof window.toggleCatPicker === "function") window.toggleCatPicker();
|
||||
});
|
||||
})();
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
[
|
||||
{
|
||||
"name": "Ace",
|
||||
"sprite": "/assets/oneko/cats/ace.png",
|
||||
"category": "Cats"
|
||||
},
|
||||
{
|
||||
"name": "Blue Tapy",
|
||||
"sprite": "/assets/oneko/cats/blue-tapy.png",
|
||||
"category": "Cats"
|
||||
},
|
||||
{
|
||||
"name": "Calico",
|
||||
"sprite": "/assets/oneko/cats/calico.png",
|
||||
"category": "Cats"
|
||||
},
|
||||
{
|
||||
"name": "Cattail",
|
||||
"sprite": "/assets/oneko/cats/cattail.png",
|
||||
"category": "Cats"
|
||||
},
|
||||
{
|
||||
"name": "Esmeralda",
|
||||
"sprite": "/assets/oneko/cats/esmeralda.png",
|
||||
"category": "Romance"
|
||||
},
|
||||
{
|
||||
"name": "Jess",
|
||||
"sprite": "/assets/oneko/cats/jess.png",
|
||||
"category": "Cats"
|
||||
},
|
||||
{
|
||||
"name": "Kina",
|
||||
"sprite": "/assets/oneko/cats/kina.png",
|
||||
"category": "Cats"
|
||||
},
|
||||
{
|
||||
"name": "Lucy",
|
||||
"sprite": "/assets/oneko/cats/lucy.png",
|
||||
"category": "Cats"
|
||||
},
|
||||
{
|
||||
"name": "Maia",
|
||||
"sprite": "/assets/oneko/cats/maia.png",
|
||||
"category": "Cats"
|
||||
},
|
||||
{
|
||||
"name": "Maria",
|
||||
"sprite": "/assets/oneko/cats/maria.png",
|
||||
"category": "Cats"
|
||||
},
|
||||
{
|
||||
"name": "Mike",
|
||||
"sprite": "/assets/oneko/cats/mike.png",
|
||||
"category": "Cats"
|
||||
},
|
||||
{
|
||||
"name": "Rainbow Tapy",
|
||||
"sprite": "/assets/oneko/cats/rainbow-tapy.png",
|
||||
"category": "Cats"
|
||||
},
|
||||
{
|
||||
"name": "Silver",
|
||||
"sprite": "/assets/oneko/cats/silver.png",
|
||||
"category": "Cats"
|
||||
},
|
||||
{
|
||||
"name": "Spirit",
|
||||
"sprite": "/assets/oneko/cats/spirit.png",
|
||||
"category": "Cats"
|
||||
},
|
||||
{
|
||||
"name": "Tapy",
|
||||
"sprite": "/assets/oneko/cats/tapy.png",
|
||||
"category": "Cats"
|
||||
},
|
||||
{
|
||||
"name": "USA",
|
||||
"sprite": "/assets/oneko/cats/usa.png",
|
||||
"category": "Romance"
|
||||
},
|
||||
{
|
||||
"name": "Valentine",
|
||||
"sprite": "/assets/oneko/cats/valentine.png",
|
||||
"category": "Romance"
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
[
|
||||
{
|
||||
"name": "Classic",
|
||||
"sprite": "/assets/oneko/classics/classic.png",
|
||||
"filter": "none",
|
||||
"category": "Classics"
|
||||
},
|
||||
{
|
||||
"name": "Aquaneon",
|
||||
"sprite": "/assets/oneko/classics/aquaneon.png",
|
||||
"category": "Classics"
|
||||
},
|
||||
{
|
||||
"name": "Black Green",
|
||||
"sprite": "/assets/oneko/classics/black-green.png",
|
||||
"category": "Classics"
|
||||
},
|
||||
{
|
||||
"name": "Black",
|
||||
"sprite": "/assets/oneko/classics/black.png",
|
||||
"category": "Classics"
|
||||
},
|
||||
{
|
||||
"name": "Byte Green",
|
||||
"sprite": "/assets/oneko/classics/byte-green.png",
|
||||
"category": "Classics"
|
||||
},
|
||||
{
|
||||
"name": "Deedee",
|
||||
"sprite": "/assets/oneko/classics/deedee.png",
|
||||
"category": "Classics"
|
||||
},
|
||||
{
|
||||
"name": "Dusty Cat",
|
||||
"sprite": "/assets/oneko/classics/dusty.png",
|
||||
"category": "Classics"
|
||||
},
|
||||
{
|
||||
"name": "Ghost",
|
||||
"sprite": "/assets/oneko/classics/ghost.png",
|
||||
"category": "Classics"
|
||||
},
|
||||
{
|
||||
"name": "Ghost Spirit",
|
||||
"sprite": "/assets/oneko/classics/ghostspirit.png",
|
||||
"filter": "drop-shadow(0 0 4px #89dceb)",
|
||||
"category": "Classics"
|
||||
},
|
||||
{
|
||||
"name": "Gold Cat",
|
||||
"sprite": "/assets/oneko/classics/gold.png",
|
||||
"category": "Rare"
|
||||
},
|
||||
{
|
||||
"name": "Gray",
|
||||
"sprite": "/assets/oneko/classics/gray.png",
|
||||
"category": "Classics"
|
||||
},
|
||||
{
|
||||
"name": "Red",
|
||||
"sprite": "/assets/oneko/classics/red.png",
|
||||
"category": "Classics"
|
||||
},
|
||||
{
|
||||
"name": "Sapphire Cat",
|
||||
"sprite": "/assets/oneko/classics/sapphire.png",
|
||||
"category": "Classics"
|
||||
},
|
||||
{
|
||||
"name": "Silver Sky",
|
||||
"sprite": "/assets/oneko/classics/silversky.png",
|
||||
"category": "Classics"
|
||||
},
|
||||
{
|
||||
"name": "Vaporwave",
|
||||
"sprite": "/assets/oneko/classics/vaporwave.png",
|
||||
"category": "Classics"
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
[
|
||||
{
|
||||
"name": "Andriod",
|
||||
"sprite": "/assets/oneko/gaming/andriod.png",
|
||||
"category": "Gaming"
|
||||
},
|
||||
{
|
||||
"name": "Lololowka",
|
||||
"sprite": "/assets/oneko/gaming/lololowka.png",
|
||||
"category": "Gaming"
|
||||
},
|
||||
{
|
||||
"name": "Niko",
|
||||
"sprite": "/assets/oneko/gaming/niko.png",
|
||||
"category": "Gaming"
|
||||
},
|
||||
{
|
||||
"name": "Sans",
|
||||
"sprite": "/assets/oneko/gaming/sans.png",
|
||||
"category": "Gaming"
|
||||
},
|
||||
{
|
||||
"name": "Sonic",
|
||||
"sprite": "/assets/oneko/gaming/sonic.png",
|
||||
"category": "Gaming"
|
||||
},
|
||||
{
|
||||
"name": "Toothless",
|
||||
"sprite": "/assets/oneko/gaming/toothless.png",
|
||||
"category": "Gaming"
|
||||
},
|
||||
{
|
||||
"name": "Yumi Nikki 1 Skin",
|
||||
"sprite": "/assets/oneko/gaming/yumi-nikki-1-skin.png",
|
||||
"category": "Gaming"
|
||||
},
|
||||
{
|
||||
"name": "Yumi Nikki 2 Skin",
|
||||
"sprite": "/assets/oneko/gaming/yumi-nikki-2-skin.png",
|
||||
"category": "Gaming"
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
[
|
||||
"cats",
|
||||
"classics",
|
||||
"gaming",
|
||||
"operating-systems",
|
||||
"other-animals",
|
||||
"pokemon",
|
||||
"pride",
|
||||
"things"
|
||||
]
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
[
|
||||
{
|
||||
"name": "Bsd",
|
||||
"sprite": "/assets/oneko/operating-systems/bsd.png",
|
||||
"category": "Operating Systems"
|
||||
}
|
||||
]
|
||||