updated a bit

This commit is contained in:
2026-11-08 21:22:32 -08:00
parent 5ae74952bb
commit 48d15f8ab1
18 changed files with 571 additions and 780 deletions

113
home.txt
View File

@@ -10,7 +10,7 @@
.home-header { .home-header {
position: relative; position: relative;
width: 100vw; width: 100vw;
height: 80vh; height: 70vh;
min-height: 400px; min-height: 400px;
margin-left: calc(-50vw + 50%); margin-left: calc(-50vw + 50%);
margin-right: calc(-50vw + 50%); margin-right: calc(-50vw + 50%);
@@ -87,31 +87,74 @@
gap: 10px; gap: 10px;
} }
.btn-primary { .btn-primary,
.btn-secondary {
position: relative;
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
gap: 6px; justify-content: center;
padding: 10px 22px; overflow: hidden;
border-radius: 100px; border-radius: 100px;
background: var(--btn-primary-bg);
color: var(--btn-primary-text) !important;
font-size: 13.5px;
font-weight: 600;
text-decoration: none !important; text-decoration: none !important;
transition: transform 0.15s ease; transition: transform 0.2s ease, opacity 0.26s ease-out;
}
.btn-primary {
color: light-dark(#000000, #ffffff) !important;
} }
.btn-secondary { .btn-secondary {
display: inline-flex; color: var(--text) !important;
}
.btn-primary:hover,
.btn-secondary:hover {
transform: translateY(-1px);
}
.glass-surface__filter {
width: 100%;
height: 100%;
pointer-events: none;
position: absolute;
inset: 0;
opacity: 0;
z-index: -1;
}
.glass-surface__content {
width: 100%;
height: 100%;
display: flex;
align-items: center; align-items: center;
padding: 10px 20px; justify-content: center;
border-radius: 100px; gap: 6px;
padding: 10px 22px;
border-radius: inherit;
position: relative;
z-index: 1;
font-size: 13.5px; font-size: 13.5px;
font-weight: 600; font-weight: 600;
text-decoration: none !important; }
backdrop-filter: blur(25px) saturate(2);
-webkit-backdrop-filter: blur(25px) saturate(2); .btn-secondary .glass-surface__content {
transition: transform 0.15s ease; padding: 10px 20px;
}
.glass-surface--svg {
background: transparent !important;
border: none !important;
box-shadow: none !important;
backdrop-filter: var(--filter-id, url(#glass-filter)) saturate(var(--glass-saturation, 1)) !important;
-webkit-backdrop-filter: var(--filter-id, url(#glass-filter)) saturate(var(--glass-saturation, 1)) !important;
}
.glass-surface--fallback {
background: transparent!important;
-webkit-backdrop-filter: blur(12px);
backdrop-filter: blur(12px);
border: transparent !important;
box-shadow: none !important;
} }
@keyframes fadeVideoBg { @keyframes fadeVideoBg {
@@ -247,18 +290,24 @@
opacity: 0.75; opacity: 0.75;
} }
.hero-greeting { .hero-greeting {
margin: 0 0 14px; position: relative;
padding: 6px 16px; display: inline-flex;
border-radius: 100px; align-items: center;
background: var(--hover-bg); justify-content: center;
backdrop-filter: blur(16px); overflow: hidden;
-webkit-backdrop-filter: blur(16px); margin: 0 0 14px;
color: var(--text); border-radius: 100px;
font-size: 13px; color: var(--text);
font-weight: 600; letter-spacing: 0.01em;
letter-spacing: 0.01em; }
}
.hero-greeting .glass-surface__content {
padding: 6px 16px;
font-size: 13px;
font-weight: 600;
letter-spacing: 0.01em;
}
.hero-resume { .hero-resume {
max-width: min(90vw, 360px); max-width: min(90vw, 360px);
@@ -319,15 +368,15 @@
<div class="home-container"> <div class="home-container">
<div class="body-blurred-backdrop"> <div class="body-blurred-backdrop">
<video class="body-blurred-video" autoplay muted loop playsinline <video class="body-blurred-video" autoplay muted loop playsinline
src="https://www.pexels.com/download/video/14517238/"></video> src=""></video>
</div> </div>
<link rel="preload" href="https://www.pexels.com/download/video/14517238/" as="video" type="video/mp4" <link rel="preload" href="" as="video" type="video/mp4"
crossorigin="anonymous"> crossorigin="anonymous">
<header class="home-header"> <header class="home-header">
<video class="header-video" autoplay muted loop playsinline preload="auto" <video class="header-video" autoplay muted loop playsinline preload="auto"
src="https://www.pexels.com/download/video/14517238/"></video> src=""></video>
<div class="header-tint"></div> <div class="header-tint"></div>
@@ -341,7 +390,7 @@
<div class="header-actions"> <div class="header-actions">
<div class="header-actions-row"> <div class="header-actions-row">
<a href="/start-here/introduction" class="btn-primary"> <a href="/start-here/introduction" class="btn-secondary">
Get Started Get Started
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"> stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">

View File

@@ -75,16 +75,16 @@
} }
</script> </script>
<link rel="icon" href="/favicon.ico" /> <link rel="icon" href="/favicon.ico" />
<link rel="preload" href="/src/assets/css/roots.css" as="style" /> <link rel="preload" href="/src/css/roots.css" as="style" />
<link rel="stylesheet" href="/src/assets/css/roots.css" /> <link rel="stylesheet" href="/src/css/roots.css" />
<link rel="stylesheet" href="/src/assets/css/layout.css" /> <link rel="stylesheet" href="/src/css/layout.css" />
<link rel="stylesheet" href="/src/assets/css/prose.css" /> <link rel="stylesheet" href="/src/css/prose.css" />
<link rel="stylesheet" href="/src/assets/css/components.css" /> <link rel="stylesheet" href="/src/css/components.css" />
<link rel="stylesheet" href="/src/assets/css/themes.css" /> <link rel="stylesheet" href="/src/css/themes.css" />
<link rel="stylesheet" href="/src/assets/css/overlay.css" /> <link rel="stylesheet" href="/src/css/overlay.css" />
<link rel="stylesheet" href="/src/assets/css/features.css" /> <link rel="stylesheet" href="/src/css/features.css" />
<link rel="stylesheet" href="/src/assets/css/highlight.css" /> <link rel="stylesheet" href="/src/css/highlight.css" />
<link rel="stylesheet" href="/src/assets/css/404.css" /> <link rel="stylesheet" href="/src/css/404.css" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link rel="manifest" href="/manifest.webmanifest" /> <link rel="manifest" href="/manifest.webmanifest" />
<link rel="ard" href="/.well-known/ard.json" /> <link rel="ard" href="/.well-known/ard.json" />
@@ -105,21 +105,6 @@
</head> </head>
<body> <body>
<div class="cobweb cobweb-top-left" aria-hidden="true">
<img class="cobweb-media" src="/src/assets/images/themes/halloween/cobweb.png" alt="" />
</div>
<div class="cobweb cobweb-top-right" aria-hidden="true">
<img class="cobweb-media" src="/src/assets/images/themes/halloween/cobweb.png" alt="" />
</div>
<div class="spider-container" aria-hidden="true">
<div class="spider-thread"></div>
<div class="spider-body">
<img class="spider-media" src="https://www.pngmart.com/files/1/Spider-PNG-File.png" alt="" />
</div>
</div>
<div class="snowfall" aria-hidden="true"></div>
<div class="leaf-fall" aria-hidden="true"></div>
<div class="light-string" aria-hidden="true"></div>
<video class="video-bg" autoplay muted loop playsinline></video> <video class="video-bg" autoplay muted loop playsinline></video>
<div id="banner"> <div id="banner">
<span> <span>
@@ -178,7 +163,8 @@
</g> </g>
</svg> </svg>
</a> </a>
<a href="https://reddit.com" target="_blank" rel="noopener" aria-label="Reddit"> <a href="https://www.reddit.com/r/Vyla/" target="_blank" rel="noopener"
aria-label="Reddit">
<svg class="footer-icon" viewBox="0 0 24 24" fill="currentColor"> <svg class="footer-icon" viewBox="0 0 24 24" fill="currentColor">
<path <path
d="M12 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0zm5.01 4.744c.688 0 1.25.561 1.25 1.249a1.25 1.25 0 0 1-2.498.056l-2.597-.547-.8 3.747c1.824.07 3.48.632 4.674 1.488.308-.309.73-.491 1.207-.491.968 0 1.754.786 1.754 1.754 0 .716-.435 1.333-1.01 1.614a3.111 3.111 0 0 1 .042.52c0 2.694-3.13 4.87-7.004 4.87-3.874 0-7.004-2.176-7.004-4.87 0-.183.015-.366.043-.534A1.748 1.748 0 0 1 4.028 12c0-.968.786-1.754 1.754-1.754.463 0 .898.196 1.207.49 1.207-.883 2.878-1.43 4.744-1.487l.885-4.182a.342.342 0 0 1 .14-.197.35.35 0 0 1 .238-.042l2.906.617a1.214 1.214 0 0 1 1.108-.702zM9.25 12C8.561 12 8 12.562 8 13.25c0 .687.561 1.248 1.25 1.248.687 0 1.248-.561 1.248-1.249 0-.688-.561-1.249-1.249-1.249zm5.5 0c-.687 0-1.248.561-1.248 1.25 0 .687.561 1.248 1.249 1.248.688 0 1.249-.561 1.249-1.249 0-.687-.562-1.249-1.25-1.249zm-5.466 3.99a.327.327 0 0 0-.231.094.33.33 0 0 0 0 .463c.842.842 2.484.913 2.961.913.477 0 2.105-.056 2.961-.913a.361.361 0 0 0 .029-.463.33.33 0 0 0-.464 0c-.547.533-1.684.73-2.512.73-.828 0-1.979-.197-2.512-.73a.326.326 0 0 0-.232-.095z" /> d="M12 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0zm5.01 4.744c.688 0 1.25.561 1.25 1.249a1.25 1.25 0 0 1-2.498.056l-2.597-.547-.8 3.747c1.824.07 3.48.632 4.674 1.488.308-.309.73-.491 1.207-.491.968 0 1.754.786 1.754 1.754 0 .716-.435 1.333-1.01 1.614a3.111 3.111 0 0 1 .042.52c0 2.694-3.13 4.87-7.004 4.87-3.874 0-7.004-2.176-7.004-4.87 0-.183.015-.366.043-.534A1.748 1.748 0 0 1 4.028 12c0-.968.786-1.754 1.754-1.754.463 0 .898.196 1.207.49 1.207-.883 2.878-1.43 4.744-1.487l.885-4.182a.342.342 0 0 1 .14-.197.35.35 0 0 1 .238-.042l2.906.617a1.214 1.214 0 0 1 1.108-.702zM9.25 12C8.561 12 8 12.562 8 13.25c0 .687.561 1.248 1.25 1.248.687 0 1.248-.561 1.248-1.249 0-.688-.561-1.249-1.249-1.249zm5.5 0c-.687 0-1.248.561-1.248 1.25 0 .687.561 1.248 1.249 1.248.688 0 1.249-.561 1.249-1.249 0-.687-.562-1.249-1.25-1.249zm-5.466 3.99a.327.327 0 0 0-.231.094.33.33 0 0 0 0 .463c.842.842 2.484.913 2.961.913.477 0 2.105-.056 2.961-.913a.361.361 0 0 0 .029-.463.33.33 0 0 0-.464 0c-.547.533-1.684.73-2.512.73-.828 0-1.979-.197-2.512-.73a.326.326 0 0 0-.232-.095z" />
@@ -194,11 +180,12 @@
</aside> </aside>
</div> </div>
</div> </div>
<script src="/src/assets/js/main.js"></script> <script src="/src/js/glass.js"></script>
<script src="/src/assets/js/api/contribute.js"></script> <script src="/src/js/main.js"></script>
<script src="/src/assets/js/api/download.js"></script> <script src="/src/js/api/contribute.js"></script>
<script src="/src/assets/js/api/release.js"></script> <script src="/src/js/api/download.js"></script>
<script src="/src/assets/js/main/settings.js"></script> <script src="/src/js/api/release.js"></script>
<script src="/src/js/main/settings.js"></script>
</body> </body>

View File

@@ -1,574 +0,0 @@
:root[data-theme="halloween"] {
--bg: #0a0604;
--text: #f5ebe6;
--text: #ff7518;
--muted: #a37559;
--border: #3d1c0c;
--bg-elevated: rgba(255, 117, 24, 0.12);
--bg-card: rgba(28, 14, 8, 0.6);
--bg-card-hover: rgba(46, 21, 10, 0.85);
--bg-code: #050201;
--code-inline-bg: rgba(255, 117, 24, 0.15);
--code-inline-text: #ff944d;
--code-text: #fed7aa;
--bg-menu: #0e0704;
--bg-modal: rgba(10, 6, 4, 0.92);
--hover-bg: rgba(255, 117, 24, 0.12);
--search-bg: rgba(255, 117, 24, 0.08);
--search-panel-bg: rgba(14, 7, 4, 0.95);
--code-group-bg: #1c0e07;
--code-group-panel-bg: #0a0604;
--code-tab-active: #ff7518;
--footer-border: #3d1c0c;
--border-subtle: rgba(255, 117, 24, 0.15);
--btn-primary-bg: #ff7518;
--btn-primary-text: #000000;
--btn-home-bg: #ff7518;
--btn-home-text: #000000;
--callout-note-bg: rgba(255, 117, 24, 0.14);
--callout-info-bg: rgba(168, 85, 247, 0.15);
--callout-warning-bg: rgba(255, 154, 77, 0.18);
--callout-warning-text: #ffaa5e;
--body-radial-tint: rgba(10, 6, 4, 0.85);
--skeleton-pulse-1: rgba(255, 117, 24, 0.06);
--skeleton-pulse-2: rgba(255, 117, 24, 0.18);
--spider-display: block;
--cobweb-display: block;
--spider-thread: rgba(255, 154, 77, 0.4);
--hl-comment: #7c4f34;
--hl-punct: #fed7aa;
--hl-func: #ff944d;
--hl-keyword: #a855f7;
--hl-string: #84cc16;
--hl-var: #ff7518;
--hl-op: #a855f7;
--hl-num: #f59e0b;
--hl-param: #ffedd5;
--hl-class: #c084fc;
--hl-tag: #ff7518;
--hl-deleted-color: #ef4444;
--hl-deleted-bg: rgba(239, 68, 68, 0.2);
--hl-inserted-color: #84cc16;
--hl-inserted-bg: rgba(132, 204, 22, 0.2);
}
:root[data-theme="christmas"] {
--bg: #07110c;
--text: #f4efe6;
--text: #ff5c5c;
--muted: #8fa89a;
--border: #1f3a2b;
--bg-elevated: rgba(255, 92, 92, 0.1);
--bg-card: rgba(10, 26, 18, 0.6);
--bg-card-hover: rgba(18, 44, 30, 0.85);
--bg-code: #040a07;
--code-inline-bg: rgba(245, 196, 81, 0.14);
--code-inline-text: #f5c451;
--code-text: #e8f5e9;
--bg-menu: #09150e;
--bg-modal: rgba(7, 17, 12, 0.9);
--hover-bg: rgba(255, 92, 92, 0.12);
--search-bg: rgba(245, 196, 81, 0.08);
--search-panel-bg: rgba(9, 21, 14, 0.95);
--code-group-bg: #11261a;
--code-group-panel-bg: #07110c;
--code-tab-active: #ff5c5c;
--footer-border: #1f3a2b;
--border-subtle: rgba(245, 196, 81, 0.14);
--btn-primary-bg: #d92d3a;
--btn-primary-text: #ffffff;
--btn-home-bg: #d92d3a;
--btn-home-text: #ffffff;
--callout-note-bg: rgba(47, 191, 113, 0.14);
--callout-info-bg: rgba(245, 196, 81, 0.14);
--callout-warning-bg: rgba(255, 92, 92, 0.18);
--callout-warning-text: #ff9a9a;
--body-radial-tint: rgba(7, 17, 12, 0.85);
--skeleton-pulse-1: rgba(245, 196, 81, 0.06);
--skeleton-pulse-2: rgba(245, 196, 81, 0.16);
--snow-display: block;
--lights-display: block;
--hl-comment: #5f8a72;
--hl-punct: #e8f5e9;
--hl-func: #f5c451;
--hl-keyword: #ff6b6b;
--hl-string: #5fd68f;
--hl-var: #ff9f68;
--hl-op: #ff6b6b;
--hl-num: #f5c451;
--hl-param: #fdf2d0;
--hl-class: #7fe3b0;
--hl-tag: #ff6b6b;
--hl-deleted-color: #ff6b6b;
--hl-deleted-bg: rgba(255, 107, 107, 0.18);
--hl-inserted-color: #5fd68f;
--hl-inserted-bg: rgba(95, 214, 143, 0.18);
}
:root[data-theme="autumn"] {
--bg: #1a0f08;
--text: #f7ead7;
--text: #f4b942;
--muted: #a68a6d;
--border: #3a2412;
--bg-elevated: rgba(244, 185, 66, 0.1);
--bg-card: rgba(40, 23, 11, 0.6);
--bg-card-hover: rgba(58, 36, 18, 0.85);
--bg-code: #0e0703;
--code-inline-bg: rgba(244, 185, 66, 0.14);
--code-inline-text: #f4b942;
--code-text: #fde7c0;
--bg-menu: #1a0f08;
--bg-modal: rgba(26, 15, 8, 0.9);
--hover-bg: rgba(244, 185, 66, 0.12);
--search-bg: rgba(244, 185, 66, 0.08);
--search-panel-bg: rgba(26, 15, 8, 0.95);
--code-group-bg: #28170b;
--code-group-panel-bg: #1a0f08;
--code-tab-active: #f4b942;
--footer-border: #3a2412;
--border-subtle: rgba(244, 185, 66, 0.14);
--btn-primary-bg: #f4b942;
--btn-primary-text: #1a0f08;
--btn-home-bg: #f4b942;
--btn-home-text: #1a0f08;
--callout-note-bg: rgba(200, 69, 44, 0.16);
--callout-info-bg: rgba(132, 160, 60, 0.16);
--callout-warning-bg: rgba(244, 185, 66, 0.18);
--callout-warning-text: #f8cf7a;
--body-radial-tint: rgba(26, 15, 8, 0.85);
--skeleton-pulse-1: rgba(244, 185, 66, 0.06);
--skeleton-pulse-2: rgba(244, 185, 66, 0.17);
--leaf-display: block;
--hl-comment: #8a6a4a;
--hl-punct: #fde7c0;
--hl-func: #f4b942;
--hl-keyword: #e0643f;
--hl-string: #a3b94a;
--hl-var: #e8913a;
--hl-op: #e0643f;
--hl-num: #f4b942;
--hl-param: #fdf0d8;
--hl-class: #d9a35b;
--hl-tag: #e0643f;
--hl-deleted-color: #e0643f;
--hl-deleted-bg: rgba(224, 100, 63, 0.18);
--hl-inserted-color: #a3b94a;
--hl-inserted-bg: rgba(163, 185, 74, 0.18);
}
:root[data-theme="winter"] {
--bg: #0d1b2a;
--text: #e6f0fa;
--text: #d6ecff;
--muted: #7f98b3;
--border: #1b2c44;
--bg-elevated: rgba(138, 209, 255, 0.1);
--bg-card: rgba(16, 32, 52, 0.6);
--bg-card-hover: rgba(26, 48, 76, 0.85);
--bg-code: #08121e;
--code-inline-bg: rgba(138, 209, 255, 0.14);
--code-inline-text: #8ad1ff;
--code-text: #cfe4f7;
--bg-menu: #0d1b2a;
--bg-modal: rgba(13, 27, 42, 0.88);
--hover-bg: rgba(138, 209, 255, 0.1);
--search-bg: rgba(138, 209, 255, 0.08);
--search-panel-bg: rgba(13, 27, 42, 0.95);
--code-group-bg: #132640;
--code-group-panel-bg: #0d1b2a;
--code-tab-active: #8ad1ff;
--footer-border: #1b2c44;
--border-subtle: rgba(138, 209, 255, 0.14);
--btn-primary-bg: #8ad1ff;
--btn-primary-text: #06101c;
--btn-home-bg: #8ad1ff;
--btn-home-text: #06101c;
--callout-note-bg: rgba(138, 209, 255, 0.14);
--callout-info-bg: rgba(185, 166, 255, 0.14);
--callout-warning-bg: rgba(255, 214, 138, 0.16);
--callout-warning-text: #ffd68a;
--body-radial-tint: rgba(13, 27, 42, 0.85);
--skeleton-pulse-1: rgba(138, 209, 255, 0.06);
--skeleton-pulse-2: rgba(138, 209, 255, 0.16);
--snow-display: block;
--hl-comment: #5b7491;
--hl-punct: #cfe4f7;
--hl-func: #8ad1ff;
--hl-keyword: #b9a6ff;
--hl-string: #9be7d4;
--hl-var: #ffb4c7;
--hl-op: #8ad1ff;
--hl-num: #ffd68a;
--hl-param: #e6f0fa;
--hl-class: #a9e4ff;
--hl-tag: #b9a6ff;
--hl-deleted-color: #ff8fa3;
--hl-deleted-bg: rgba(255, 143, 163, 0.18);
--hl-inserted-color: #9be7d4;
--hl-inserted-bg: rgba(155, 231, 212, 0.18);
}
.cobweb {
display: var(--cobweb-display);
position: fixed;
width: 160px;
height: 160px;
pointer-events: none;
z-index: 35;
opacity: 0.8;
}
.cobweb-top-left {
top: 0;
left: 0;
transform: scaleX(-1);
}
.cobweb-top-right {
top: 0;
right: 0;
}
.cobweb-media {
width: 100%;
height: 100%;
object-fit: contain;
display: block;
}
.spider-container {
display: var(--spider-display);
position: fixed;
top: 0;
right: 12%;
pointer-events: none;
z-index: 100;
animation: spiderDescend 10s ease-in-out infinite;
}
.spider-thread {
width: 1.5px;
height: 100vh;
position: absolute;
bottom: 24px;
left: 50%;
transform: translateX(-50%);
background: var(--spider-thread);
}
.spider-body {
position: relative;
width: 48px;
height: 48px;
margin-top: 100px;
pointer-events: auto;
cursor: pointer;
animation: spiderSway 3s ease-in-out infinite alternate;
}
.spider-media {
width: 100%;
height: 100%;
object-fit: contain;
display: block;
scale: 2;
padding-top: 20px;
}
@keyframes spiderDescend {
0% {
transform: translateY(-80px);
}
45% {
transform: translateY(240px);
}
55% {
transform: translateY(240px);
}
90% {
transform: translateY(10px);
}
100% {
transform: translateY(-80px);
}
}
@keyframes spiderSway {
0% {
transform: rotate(-10deg);
}
100% {
transform: rotate(10deg);
}
}
@keyframes spiderDrop {
from {
transform: translateY(240px);
}
to {
transform: translateY(130vh);
}
}
:root {
--snow-tile: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cg fill='white'%3E%3Ccircle cx='22' cy='38' r='2.4' fill-opacity='.9'/%3E%3Ccircle cx='96' cy='126' r='1.8' fill-opacity='.7'/%3E%3Ccircle cx='168' cy='28' r='3' fill-opacity='.85'/%3E%3Ccircle cx='236' cy='204' r='2' fill-opacity='.75'/%3E%3Ccircle cx='272' cy='92' r='2.8' fill-opacity='.9'/%3E%3Ccircle cx='58' cy='252' r='2.2' fill-opacity='.8'/%3E%3Ccircle cx='196' cy='282' r='1.6' fill-opacity='.7'/%3E%3Ccircle cx='140' cy='190' r='2.4' fill-opacity='.85'/%3E%3C/g%3E%3Cg stroke='white' stroke-opacity='.9' stroke-width='1.3' stroke-linecap='round' fill='none'%3E%3Cpath transform='translate(126 72)' d='M0 -8V8M-6.9 -4L6.9 4M-6.9 4L6.9 -4'/%3E%3Cpath transform='translate(246 150)' d='M0 -6V6M-5.2 -3L5.2 3M-5.2 3L5.2 -3'/%3E%3Cpath transform='translate(40 160)' d='M0 -7V7M-6 -3.5L6 3.5M-6 3.5L6 -3.5'/%3E%3Cpath transform='translate(210 250)' d='M0 -6V6M-5.2 -3L5.2 3M-5.2 3L5.2 -3'/%3E%3C/g%3E%3C/svg%3E");
--leaf-tile: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='360' height='360'%3E%3Cg transform='translate(50 60) rotate(25) scale(1.2)' fill='%23e8710a'%3E%3Cpath d='M0 -14C10 -8 12 6 0 16C-12 6 -10 -8 0 -14Z'/%3E%3Cpath d='M0 -12V14' stroke='%23000' stroke-opacity='.25' stroke-width='1'/%3E%3C/g%3E%3Cg transform='translate(190 40) rotate(-40)' fill='%23c2410c'%3E%3Cpath d='M0 -14C10 -8 12 6 0 16C-12 6 -10 -8 0 -14Z'/%3E%3Cpath d='M0 -12V14' stroke='%23000' stroke-opacity='.25' stroke-width='1'/%3E%3C/g%3E%3Cg transform='translate(300 130) rotate(70) scale(1.3)' fill='%23eab308'%3E%3Cpath d='M0 -14C10 -8 12 6 0 16C-12 6 -10 -8 0 -14Z'/%3E%3Cpath d='M0 -12V14' stroke='%23000' stroke-opacity='.25' stroke-width='1'/%3E%3C/g%3E%3Cg transform='translate(120 200) rotate(-15) scale(1.1)' fill='%23b45309'%3E%3Cpath d='M0 -14C10 -8 12 6 0 16C-12 6 -10 -8 0 -14Z'/%3E%3Cpath d='M0 -12V14' stroke='%23000' stroke-opacity='.25' stroke-width='1'/%3E%3C/g%3E%3Cg transform='translate(250 280) rotate(140) scale(1.2)' fill='%23d97706'%3E%3Cpath d='M0 -14C10 -8 12 6 0 16C-12 6 -10 -8 0 -14Z'/%3E%3Cpath d='M0 -12V14' stroke='%23000' stroke-opacity='.25' stroke-width='1'/%3E%3C/g%3E%3Cg transform='translate(40 310) rotate(-80)' fill='%23ca8a04'%3E%3Cpath d='M0 -14C10 -8 12 6 0 16C-12 6 -10 -8 0 -14Z'/%3E%3Cpath d='M0 -12V14' stroke='%23000' stroke-opacity='.25' stroke-width='1'/%3E%3C/g%3E%3C/svg%3E");
--lights-tile: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='56'%3E%3Cpath d='M0 4Q40 32 80 4Q120 32 160 4' fill='none' stroke='%23245c3a' stroke-width='1.6'/%3E%3Cg fill='%23222'%3E%3Crect x='18' y='13' width='4' height='4'/%3E%3Crect x='38' y='17' width='4' height='4'/%3E%3Crect x='58' y='13' width='4' height='4'/%3E%3Crect x='98' y='13' width='4' height='4'/%3E%3Crect x='118' y='17' width='4' height='4'/%3E%3Crect x='138' y='13' width='4' height='4'/%3E%3C/g%3E%3Cellipse cx='20' cy='22' rx='4' ry='5.5' fill='%23ff4d4d'/%3E%3Cellipse cx='40' cy='26' rx='4' ry='5.5' fill='%23ffd24d'/%3E%3Cellipse cx='60' cy='22' rx='4' ry='5.5' fill='%234dff88'/%3E%3Cellipse cx='100' cy='22' rx='4' ry='5.5' fill='%234da6ff'/%3E%3Cellipse cx='120' cy='26' rx='4' ry='5.5' fill='%23ff4d4d'/%3E%3Cellipse cx='140' cy='22' rx='4' ry='5.5' fill='%23ffd24d'/%3E%3C/svg%3E");
}
.snowfall,
.leaf-fall {
position: fixed;
inset: 0;
overflow: hidden;
pointer-events: none;
z-index: 30;
}
.snowfall {
display: var(--snow-display);
}
.leaf-fall {
display: var(--leaf-display);
}
.snowfall::before,
.snowfall::after,
.leaf-fall::before,
.leaf-fall::after {
content: "";
position: absolute;
background-repeat: repeat;
will-change: transform;
}
.snowfall::before {
top: -600px;
left: 0;
right: 0;
bottom: 0;
background-image: var(--snow-tile);
background-size: 300px 300px;
opacity: 0.9;
animation: snowFallNear 18s linear infinite;
}
.snowfall::after {
top: -500px;
left: 0;
right: 0;
bottom: 0;
background-image: var(--snow-tile);
background-size: 500px 500px;
opacity: 0.6;
animation: snowFallFar 30s linear infinite;
}
.leaf-fall::before {
top: -720px;
left: 0;
right: -360px;
bottom: 0;
background-image: var(--leaf-tile);
background-size: 360px 360px;
opacity: 0.9;
animation: leafFallNear 26s linear infinite;
}
.leaf-fall::after {
top: -540px;
left: -540px;
right: 0;
bottom: 0;
background-image: var(--leaf-tile);
background-size: 540px 540px;
opacity: 0.7;
animation: leafFallFar 40s linear infinite;
}
.light-string {
display: var(--lights-display);
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 56px;
pointer-events: none;
z-index: 100;
background-image: var(--lights-tile);
background-repeat: repeat-x;
background-size: 160px 56px;
animation: lightTwinkle 2.6s ease-in-out infinite alternate;
}
@keyframes snowFallNear {
from {
transform: translate3d(0, 0, 0);
}
to {
transform: translate3d(0, 600px, 0);
}
}
@keyframes snowFallFar {
from {
transform: translate3d(0, 0, 0);
}
to {
transform: translate3d(0, 500px, 0);
}
}
@keyframes leafFallNear {
from {
transform: translate3d(0, 0, 0);
}
to {
transform: translate3d(-360px, 720px, 0);
}
}
@keyframes leafFallFar {
from {
transform: translate3d(0, 0, 0);
}
to {
transform: translate3d(540px, 540px, 0);
}
}
@keyframes lightTwinkle {
from {
opacity: 0.65;
filter: drop-shadow(0 0 3px rgba(255, 214, 120, 0.5));
}
to {
opacity: 1;
filter: drop-shadow(0 0 8px rgba(255, 214, 120, 0.9));
}
}
@media (prefers-reduced-motion: reduce) {
.snowfall::before,
.snowfall::after,
.leaf-fall::before,
.leaf-fall::after,
.light-string {
animation: none;
}
}
#navbar .brand {
position: relative;
}
#navbar .brand::after {
content: "";
position: absolute;
top: -9px;
right: -9px;
font-size: 14px;
line-height: 1;
pointer-events: none;
}
:root[data-theme="halloween"] #navbar .brand::after {
content: "🎃";
}
:root[data-theme="autumn"] #navbar .brand::after {
content: "🍂";
}
:root[data-theme="winter"] #navbar .brand::after {
content: "❄️";
}
:root[data-theme="christmas"] #navbar .brand::after {
content: "🎄";
}
.st-themes {
padding: 14px 16px 16px;
}
.st-sub {
margin: 0 0 8px;
font-size: 11px;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--muted);
}
.st-theme-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 8px;
margin-bottom: 16px;
}
.st-theme-grid:last-child {
margin-bottom: 0;
}
.st-theme {
display: flex;
align-items: center;
gap: 10px;
min-width: 0;
height: 40px;
padding: 0 14px;
border: 1px solid transparent;
border-radius: 100px;
background: var(--search-bg);
color: var(--muted);
font: inherit;
font-size: 13.5px;
font-weight: 500;
cursor: pointer;
transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.st-theme .ico {
width: 16px;
height: 16px;
flex-shrink: 0;
}
.st-theme span {
min-width: 0;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.st-theme:hover {
color: var(--text);
}
.st-theme.on {
border-color: var(--text);
background: var(--hover-bg);
color: var(--text);
font-weight: 600;
}

View File

@@ -32,10 +32,9 @@
} }
.personal-card { .personal-card {
margin: 18px 0 8px; margin-top: 20px;
padding: 16px 18px; margin-bottom: 50px;
border-radius: 22px; border-radius: 22px;
background: var(--callout-note-bg);
} }
.personal-card label { .personal-card label {
@@ -56,7 +55,7 @@
min-width: 0; min-width: 0;
height: 36px; height: 36px;
padding: 0 14px; padding: 0 14px;
border: 1px solid var(--border); border: none;
border-radius: 100px; border-radius: 100px;
background: var(--search-bg); background: var(--search-bg);
color: var(--text); color: var(--text);

View File

@@ -73,8 +73,7 @@
:root[data-theme="light"] { :root[data-theme="light"] {
--bg: #ffffff; --bg: #ffffff;
--text: #0b0b0c; --text: #000000;
--text: #111827;
--muted: #6b7280; --muted: #6b7280;
--border: #e5e7eb; --border: #e5e7eb;
--bg-elevated: rgba(0, 0, 0, 0.05); --bg-elevated: rgba(0, 0, 0, 0.05);

250
src/css/themes.css Normal file
View File

@@ -0,0 +1,250 @@
:root {
--snow-tile: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cg fill='white'%3E%3Ccircle cx='22' cy='38' r='2.4' fill-opacity='.9'/%3E%3Ccircle cx='96' cy='126' r='1.8' fill-opacity='.7'/%3E%3Ccircle cx='168' cy='28' r='3' fill-opacity='.85'/%3E%3Ccircle cx='236' cy='204' r='2' fill-opacity='.75'/%3E%3Ccircle cx='272' cy='92' r='2.8' fill-opacity='.9'/%3E%3Ccircle cx='58' cy='252' r='2.2' fill-opacity='.8'/%3E%3Ccircle cx='196' cy='282' r='1.6' fill-opacity='.7'/%3E%3Ccircle cx='140' cy='190' r='2.4' fill-opacity='.85'/%3E%3C/g%3E%3Cg stroke='white' stroke-opacity='.9' stroke-width='1.3' stroke-linecap='round' fill='none'%3E%3Cpath transform='translate(126 72)' d='M0 -8V8M-6.9 -4L6.9 4M-6.9 4L6.9 -4'/%3E%3Cpath transform='translate(246 150)' d='M0 -6V6M-5.2 -3L5.2 3M-5.2 3L5.2 -3'/%3E%3Cpath transform='translate(40 160)' d='M0 -7V7M-6 -3.5L6 3.5M-6 3.5L6 -3.5'/%3E%3Cpath transform='translate(210 250)' d='M0 -6V6M-5.2 -3L5.2 3M-5.2 3L5.2 -3'/%3E%3C/g%3E%3C/svg%3E");
--leaf-tile: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='360' height='360'%3E%3Cg transform='translate(50 60) rotate(25) scale(1.2)' fill='%23e8710a'%3E%3Cpath d='M0 -14C10 -8 12 6 0 16C-12 6 -10 -8 0 -14Z'/%3E%3Cpath d='M0 -12V14' stroke='%23000' stroke-opacity='.25' stroke-width='1'/%3E%3C/g%3E%3Cg transform='translate(190 40) rotate(-40)' fill='%23c2410c'%3E%3Cpath d='M0 -14C10 -8 12 6 0 16C-12 6 -10 -8 0 -14Z'/%3E%3Cpath d='M0 -12V14' stroke='%23000' stroke-opacity='.25' stroke-width='1'/%3E%3C/g%3E%3Cg transform='translate(300 130) rotate(70) scale(1.3)' fill='%23eab308'%3E%3Cpath d='M0 -14C10 -8 12 6 0 16C-12 6 -10 -8 0 -14Z'/%3E%3Cpath d='M0 -12V14' stroke='%23000' stroke-opacity='.25' stroke-width='1'/%3E%3C/g%3E%3Cg transform='translate(120 200) rotate(-15) scale(1.1)' fill='%23b45309'%3E%3Cpath d='M0 -14C10 -8 12 6 0 16C-12 6 -10 -8 0 -14Z'/%3E%3Cpath d='M0 -12V14' stroke='%23000' stroke-opacity='.25' stroke-width='1'/%3E%3C/g%3E%3Cg transform='translate(250 280) rotate(140) scale(1.2)' fill='%23d97706'%3E%3Cpath d='M0 -14C10 -8 12 6 0 16C-12 6 -10 -8 0 -14Z'/%3E%3Cpath d='M0 -12V14' stroke='%23000' stroke-opacity='.25' stroke-width='1'/%3E%3C/g%3E%3Cg transform='translate(40 310) rotate(-80)' fill='%23ca8a04'%3E%3Cpath d='M0 -14C10 -8 12 6 0 16C-12 6 -10 -8 0 -14Z'/%3E%3Cpath d='M0 -12V14' stroke='%23000' stroke-opacity='.25' stroke-width='1'/%3E%3C/g%3E%3C/svg%3E");
--lights-tile: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='56'%3E%3Cpath d='M0 4Q40 32 80 4Q120 32 160 4' fill='none' stroke='%23245c3a' stroke-width='1.6'/%3E%3Cg fill='%23222'%3E%3Crect x='18' y='13' width='4' height='4'/%3E%3Crect x='38' y='17' width='4' height='4'/%3E%3Crect x='58' y='13' width='4' height='4'/%3E%3Crect x='98' y='13' width='4' height='4'/%3E%3Crect x='118' y='17' width='4' height='4'/%3E%3Crect x='138' y='13' width='4' height='4'/%3E%3C/g%3E%3Cellipse cx='20' cy='22' rx='4' ry='5.5' fill='%23ff4d4d'/%3E%3Cellipse cx='40' cy='26' rx='4' ry='5.5' fill='%23ffd24d'/%3E%3Cellipse cx='60' cy='22' rx='4' ry='5.5' fill='%234dff88'/%3E%3Cellipse cx='100' cy='22' rx='4' ry='5.5' fill='%234da6ff'/%3E%3Cellipse cx='120' cy='26' rx='4' ry='5.5' fill='%23ff4d4d'/%3E%3Cellipse cx='140' cy='22' rx='4' ry='5.5' fill='%23ffd24d'/%3E%3C/svg%3E");
}
.snowfall,
.leaf-fall {
position: fixed;
inset: 0;
overflow: hidden;
pointer-events: none;
z-index: 30;
}
.snowfall {
display: var(--snow-display);
}
.leaf-fall {
display: var(--leaf-display);
}
.snowfall::before,
.snowfall::after,
.leaf-fall::before,
.leaf-fall::after {
content: "";
position: absolute;
background-repeat: repeat;
will-change: transform;
}
.snowfall::before {
top: -600px;
left: 0;
right: 0;
bottom: 0;
background-image: var(--snow-tile);
background-size: 300px 300px;
opacity: 0.9;
animation: snowFallNear 18s linear infinite;
}
.snowfall::after {
top: -500px;
left: 0;
right: 0;
bottom: 0;
background-image: var(--snow-tile);
background-size: 500px 500px;
opacity: 0.6;
animation: snowFallFar 30s linear infinite;
}
.leaf-fall::before {
top: -720px;
left: 0;
right: -360px;
bottom: 0;
background-image: var(--leaf-tile);
background-size: 360px 360px;
opacity: 0.9;
animation: leafFallNear 26s linear infinite;
}
.leaf-fall::after {
top: -540px;
left: -540px;
right: 0;
bottom: 0;
background-image: var(--leaf-tile);
background-size: 540px 540px;
opacity: 0.7;
animation: leafFallFar 40s linear infinite;
}
.light-string {
display: var(--lights-display);
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 56px;
pointer-events: none;
z-index: 100;
background-image: var(--lights-tile);
background-repeat: repeat-x;
background-size: 160px 56px;
animation: lightTwinkle 2.6s ease-in-out infinite alternate;
}
@keyframes snowFallNear {
from {
transform: translate3d(0, 0, 0);
}
to {
transform: translate3d(0, 600px, 0);
}
}
@keyframes snowFallFar {
from {
transform: translate3d(0, 0, 0);
}
to {
transform: translate3d(0, 500px, 0);
}
}
@keyframes leafFallNear {
from {
transform: translate3d(0, 0, 0);
}
to {
transform: translate3d(-360px, 720px, 0);
}
}
@keyframes leafFallFar {
from {
transform: translate3d(0, 0, 0);
}
to {
transform: translate3d(540px, 540px, 0);
}
}
@keyframes lightTwinkle {
from {
opacity: 0.65;
filter: drop-shadow(0 0 3px rgba(255, 214, 120, 0.5));
}
to {
opacity: 1;
filter: drop-shadow(0 0 8px rgba(255, 214, 120, 0.9));
}
}
@media (prefers-reduced-motion: reduce) {
.snowfall::before,
.snowfall::after,
.leaf-fall::before,
.leaf-fall::after,
.light-string {
animation: none;
}
}
#navbar .brand {
position: relative;
}
#navbar .brand::after {
content: "";
position: absolute;
top: -9px;
right: -9px;
font-size: 14px;
line-height: 1;
pointer-events: none;
}
:root[data-theme="halloween"] #navbar .brand::after {
content: "🎃";
}
:root[data-theme="autumn"] #navbar .brand::after {
content: "🍂";
}
:root[data-theme="winter"] #navbar .brand::after {
content: "❄️";
}
:root[data-theme="christmas"] #navbar .brand::after {
content: "🎄";
}
.st-themes {
padding: 14px 16px 16px;
}
.st-sub {
margin: 0 0 8px;
font-size: 11px;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--muted);
}
.st-theme-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 8px;
margin-bottom: 16px;
}
.st-theme-grid:last-child {
margin-bottom: 0;
}
.st-theme {
display: flex;
align-items: center;
gap: 10px;
min-width: 0;
height: 40px;
padding: 0 14px;
border: 1px solid transparent;
border-radius: 100px;
background: var(--search-bg);
color: var(--muted);
font: inherit;
font-size: 13.5px;
font-weight: 500;
cursor: pointer;
transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.st-theme .ico {
width: 16px;
height: 16px;
flex-shrink: 0;
}
.st-theme span {
min-width: 0;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.st-theme:hover {
color: var(--text);
}
.st-theme.on {
border-color: var(--text);
background: var(--hover-bg);
color: var(--text);
font-weight: 600;
}

123
src/js/glass.js Normal file
View File

@@ -0,0 +1,123 @@
var GLASS_TARGETS = [
{
selector: ".btn-primary",
options: {
distortionScale: -300,
displace: 0,
backgroundOpacity: 0.1
}
},
{
selector: ".btn-secondary",
options: {
distortionScale: -300,
displace: 0,
backgroundOpacity: 0.1
}
},
{
selector: ".hero-greeting",
options: {
distortionScale: -200,
displace: 0,
backgroundOpacity: 0.08
}
}
];
function initGlassSurface(el, opts) {
if (!el || el.getAttribute("data-glass")) return;
el.setAttribute("data-glass", "true");
opts = opts || {};
var distortionScale = opts.distortionScale !== undefined ? opts.distortionScale : -180;
var displace = opts.displace !== undefined ? opts.displace : 0;
var backgroundOpacity = opts.backgroundOpacity !== undefined ? opts.backgroundOpacity : 0;
var saturation = opts.saturation !== undefined ? opts.saturation : 1;
var redOffset = opts.redOffset !== undefined ? opts.redOffset : 0;
var greenOffset = opts.greenOffset !== undefined ? opts.greenOffset : 10;
var blueOffset = opts.blueOffset !== undefined ? opts.blueOffset : 20;
var borderWidth = opts.borderWidth !== undefined ? opts.borderWidth : 0.07;
var brightness = opts.brightness !== undefined ? opts.brightness : 50;
var opacity = opts.opacity !== undefined ? opts.opacity : 0.93;
var blur = opts.blur !== undefined ? opts.blur : 11;
var mixBlendMode = opts.mixBlendMode || "difference";
var uid = Math.random().toString(36).slice(2, 9);
var filterId = "glass-filter-" + uid;
var redGradId = "red-grad-" + uid;
var blueGradId = "blue-grad-" + uid;
var softId = "soft-" + uid;
var isWebkit = /Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent);
var isFirefox = /Firefox/.test(navigator.userAgent);
var div = document.createElement("div");
div.style.backdropFilter = "url(#" + filterId + ")";
var svgSupported = !isWebkit && !isFirefox && div.style.backdropFilter !== "";
var rect = el.getBoundingClientRect();
var w = Math.round(rect.width) || 160;
var h = Math.round(rect.height) || 40;
var r = Math.round(h / 2);
var edge = Math.min(w, h) * (borderWidth * 0.5);
var mapSvg = '<svg width="' + w + '" height="' + h + '" viewBox="0 0 ' + w + ' ' + h + '" xmlns="http://www.w3.org/2000/svg">' +
'<defs>' +
'<linearGradient id="' + redGradId + '" x1="100%" y1="0%" x2="0%" y2="0%"><stop offset="0%" stop-color="#0000"/><stop offset="100%" stop-color="red"/></linearGradient>' +
'<linearGradient id="' + blueGradId + '" x1="0%" y1="0%" x2="0%" y2="100%"><stop offset="0%" stop-color="#0000"/><stop offset="100%" stop-color="blue"/></linearGradient>' +
'<filter id="' + softId + '" filterUnits="userSpaceOnUse" x="0" y="0" width="' + w + '" height="' + h + '" color-interpolation-filters="sRGB"><feGaussianBlur stdDeviation="' + blur + '"/></filter>' +
'</defs>' +
'<rect x="0" y="0" width="' + w + '" height="' + h + '" fill="black"/>' +
'<rect x="0" y="0" width="' + w + '" height="' + h + '" rx="' + r + '" fill="url(#' + redGradId + ')"/>' +
'<rect x="0" y="0" width="' + w + '" height="' + h + '" rx="' + r + '" fill="url(#' + blueGradId + ')" style="mix-blend-mode:' + mixBlendMode + '"/>' +
'<rect x="' + edge + '" y="' + edge + '" width="' + (w - edge * 2) + '" height="' + (h - edge * 2) + '" rx="' + r + '" fill="hsl(0 0% ' + brightness + '% / ' + opacity + ')" filter="url(#' + softId + ')"/>' +
'</svg>';
var mapUrl = "data:image/svg+xml," + encodeURIComponent(mapSvg);
el.style.setProperty("--glass-frost", backgroundOpacity);
el.style.setProperty("--glass-saturation", saturation);
el.style.setProperty("--filter-id", "url(#" + filterId + ")");
el.classList.add(svgSupported ? "glass-surface--svg" : "glass-surface--fallback");
var filterSvg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
filterSvg.setAttribute("class", "glass-surface__filter");
filterSvg.innerHTML = '<defs>' +
'<filter id="' + filterId + '" color-interpolation-filters="sRGB" x="0%" y="0%" width="100%" height="100%">' +
'<feImage href="' + mapUrl + '" x="0" y="0" width="100%" height="100%" preserveAspectRatio="none" result="map"/>' +
'<feDisplacementMap in="SourceGraphic" in2="map" scale="' + (distortionScale + redOffset) + '" xChannelSelector="R" yChannelSelector="G" result="dispRed"/>' +
'<feColorMatrix in="dispRed" type="matrix" values="1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0" result="red"/>' +
'<feDisplacementMap in="SourceGraphic" in2="map" scale="' + (distortionScale + greenOffset) + '" xChannelSelector="R" yChannelSelector="G" result="dispGreen"/>' +
'<feColorMatrix in="dispGreen" type="matrix" values="0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0" result="green"/>' +
'<feDisplacementMap in="SourceGraphic" in2="map" scale="' + (distortionScale + blueOffset) + '" xChannelSelector="R" yChannelSelector="G" result="dispBlue"/>' +
'<feColorMatrix in="dispBlue" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0" result="blue"/>' +
'<feBlend in="red" in2="green" mode="screen" result="rg"/>' +
'<feBlend in="rg" in2="blue" mode="screen" result="output"/>' +
'<feGaussianBlur in="output" stdDeviation="' + (displace || 0.7) + '"/>' +
'</filter></defs>';
var childNodes = Array.prototype.slice.call(el.childNodes);
var wrap = document.createElement("div");
wrap.className = "glass-surface__content";
childNodes.forEach(function (n) { wrap.appendChild(n); });
el.appendChild(filterSvg);
if (!svgSupported) {
var sheen = document.createElement("span");
sheen.className = "glass-surface__sheen";
sheen.setAttribute("aria-hidden", "true");
var rim = document.createElement("span");
rim.className = "glass-surface__rim";
rim.setAttribute("aria-hidden", "true");
el.appendChild(sheen);
el.appendChild(rim);
}
el.appendChild(wrap);
}
function applyGlassSurfaces(root) {
var base = root || document;
GLASS_TARGETS.forEach(function (target) {
base.querySelectorAll(target.selector).forEach(function (el) {
initGlassSurface(el, target.options);
});
});
}

View File

@@ -29,7 +29,6 @@ var ICONS = {
}; };
var THEMES_GENERAL = [ var THEMES_GENERAL = [
{ id: "auto", label: "Auto (seasonal)" },
{ id: "dark", label: "Dark" }, { id: "dark", label: "Dark" },
{ id: "light", label: "Light" }, { id: "light", label: "Light" },
{ id: "midnight", label: "Midnight" }, { id: "midnight", label: "Midnight" },
@@ -40,20 +39,9 @@ var THEMES_GENERAL = [
{ id: "cyberpunk", label: "Cyberpunk" } { id: "cyberpunk", label: "Cyberpunk" }
]; ];
var THEMES_SEASONAL = [
{ id: "halloween", label: "Halloween" },
{ id: "autumn", label: "Autumn" },
{ id: "winter", label: "Winter" },
{ id: "christmas", label: "Christmas" }
];
var THEME_VIDEOS = { var THEME_VIDEOS = {
halloween: "https://www.pexels.com/download/video/5652678/", dark: "https://www.pexels.com/download/video/39880903/",
autumn: "https://www.pexels.com/download/video/34463521/", light: "https://www.pexels.com/download/video/36600568/",
winter: "https://www.pexels.com/download/video/30181650/",
christmas: "https://www.pexels.com/download/video/35282426/",
dark: "https://www.pexels.com/download/video/31270356/",
light: "https://www.pexels.com/download/video/13956986/",
midnight: "https://www.pexels.com/download/video/15860507/", midnight: "https://www.pexels.com/download/video/15860507/",
nord: "https://www.pexels.com/download/video/31468607/", nord: "https://www.pexels.com/download/video/31468607/",
dracula: "https://www.pexels.com/download/video/8116002/", dracula: "https://www.pexels.com/download/video/8116002/",
@@ -237,11 +225,6 @@ function buildThemeControls() {
THEMES_GENERAL.forEach(function (t) { THEMES_GENERAL.forEach(function (t) {
html += '<button type="button" data-mode="' + t.id + '">' + icon(t.id) + '<span>' + esc(t.label) + '</span><i class="check">✓</i></button>'; html += '<button type="button" data-mode="' + t.id + '">' + icon(t.id) + '<span>' + esc(t.label) + '</span><i class="check">✓</i></button>';
}); });
html += '<div class="theme-menu-divider"></div>';
html += '<div class="theme-menu-label">Seasonal</div>';
THEMES_SEASONAL.forEach(function (t) {
html += '<button type="button" data-mode="' + t.id + '">' + icon(t.id) + '<span>' + esc(t.label) + '</span><i class="check">✓</i></button>';
});
menu.innerHTML = html; menu.innerHTML = html;
wrap.appendChild(menu); wrap.appendChild(menu);
menu.addEventListener("click", function (e) { menu.addEventListener("click", function (e) {
@@ -301,38 +284,6 @@ var THEME_COPY = {
greeting: "", greeting: "",
favicon: "", favicon: "",
confetti: null confetti: null
},
halloween: {
banner: "🎃 Happy Halloween!",
footer: "Stay spooky, keep streaming.",
notFound: "Something is lurking where this page should be. Let's get you back before the lights go out.",
greeting: "Spooky season is here.",
favicon: "🎃",
confetti: ["🎃", "🦇", "👻", "🕷️"]
},
autumn: {
banner: "🍂 Happy fall!",
footer: "Grab something warm and press play.",
notFound: "This page blew away with the leaves. Let's find you a better path.",
greeting: "Cozy season is here.",
favicon: "🍂",
confetti: ["🍂", "🍁", "🎃"]
},
winter: {
banner: "❄️ Stay warm!",
footer: "Cold outside, perfect for a movie night.",
notFound: "This page got buried in the snow. Let's dig you back out.",
greeting: "Perfect weather for staying in.",
favicon: "❄️",
confetti: ["❄️", "⛄", "✨"]
},
christmas: {
banner: "🎄 Happy holidays!",
footer: "Wishing you a quiet night and a great watchlist.",
notFound: "This page isn't on the nice list or the naughty list. Let's head home.",
greeting: "Happy holidays.",
favicon: "🎄",
confetti: ["🎄", "⭐", "🎁", "❄️"]
} }
}; };
@@ -340,19 +291,8 @@ var KONAMI = ["ArrowUp", "ArrowUp", "ArrowDown", "ArrowDown", "ArrowLeft", "Arro
var PROJECTS = ["home", "go", "TV", "vyla-sdk", "stream-api"]; var PROJECTS = ["home", "go", "TV", "vyla-sdk", "stream-api"];
var PROJECT_LABELS = { home: "Vyla Home", go: "Vyla Go", TV: "Vyla TV", "vyla-sdk": "Vyla SDK", "stream-api": "Stream API" }; var PROJECT_LABELS = { home: "Vyla Home", go: "Vyla Go", TV: "Vyla TV", "vyla-sdk": "Vyla SDK", "stream-api": "Stream API" };
function seasonalTheme() {
var d = new Date();
var m = d.getMonth();
if (m === 9) return "halloween";
if (m === 10) return "autumn";
if (m === 11) return "christmas";
if (m === 0 || m === 1) return "winter";
if (m === 8 && d.getDate() >= 22) return "autumn";
return "dark";
}
function resolveTheme(mode) { function resolveTheme(mode) {
return mode === "auto" ? seasonalTheme() : mode; return mode === "auto" ? "dark" : mode;
} }
function getPref(key, fallback) { function getPref(key, fallback) {
@@ -1266,6 +1206,94 @@ function navigateTo(path) {
loadPage(); loadPage();
} }
function initGlassSurface(el, opts) {
if (!el || el.getAttribute("data-glass")) return;
el.setAttribute("data-glass", "true");
opts = opts || {};
var distortionScale = opts.distortionScale !== undefined ? opts.distortionScale : -300;
var displace = opts.displace !== undefined ? opts.displace : 0;
var backgroundOpacity = opts.backgroundOpacity !== undefined ? opts.backgroundOpacity : 0.1;
var saturation = opts.saturation !== undefined ? opts.saturation : 1;
var redOffset = opts.redOffset !== undefined ? opts.redOffset : 0;
var greenOffset = opts.greenOffset !== undefined ? opts.greenOffset : 10;
var blueOffset = opts.blueOffset !== undefined ? opts.blueOffset : 20;
var borderWidth = opts.borderWidth !== undefined ? opts.borderWidth : 0.07;
var brightness = opts.brightness !== undefined ? opts.brightness : 50;
var opacity = opts.opacity !== undefined ? opts.opacity : 0.93;
var blur = opts.blur !== undefined ? opts.blur : 11;
var mixBlendMode = opts.mixBlendMode || "difference";
var uid = Math.random().toString(36).slice(2, 9);
var filterId = "glass-filter-" + uid;
var redGradId = "red-grad-" + uid;
var blueGradId = "blue-grad-" + uid;
var softId = "soft-" + uid;
var isWebkit = /Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent);
var isFirefox = /Firefox/.test(navigator.userAgent);
var div = document.createElement("div");
div.style.backdropFilter = "url(#" + filterId + ")";
var svgSupported = !isWebkit && !isFirefox && div.style.backdropFilter !== "";
var rect = el.getBoundingClientRect();
var w = Math.round(rect.width) || 160;
var h = Math.round(rect.height) || 44;
var r = Math.round(h / 2);
var edge = Math.min(w, h) * (borderWidth * 0.5);
var mapSvg = '<svg width="' + w + '" height="' + h + '" viewBox="0 0 ' + w + ' ' + h + '" xmlns="http://www.w3.org/2000/svg">' +
'<defs>' +
'<linearGradient id="' + redGradId + '" x1="100%" y1="0%" x2="0%" y2="0%"><stop offset="0%" stop-color="#0000"/><stop offset="100%" stop-color="red"/></linearGradient>' +
'<linearGradient id="' + blueGradId + '" x1="0%" y1="0%" x2="0%" y2="100%"><stop offset="0%" stop-color="#0000"/><stop offset="100%" stop-color="blue"/></linearGradient>' +
'<filter id="' + softId + '" filterUnits="userSpaceOnUse" x="0" y="0" width="' + w + '" height="' + h + '" color-interpolation-filters="sRGB"><feGaussianBlur stdDeviation="' + blur + '"/></filter>' +
'</defs>' +
'<rect x="0" y="0" width="' + w + '" height="' + h + '" fill="black"/>' +
'<rect x="0" y="0" width="' + w + '" height="' + h + '" rx="' + r + '" fill="url(#' + redGradId + ')"/>' +
'<rect x="0" y="0" width="' + w + '" height="' + h + '" rx="' + r + '" fill="url(#' + blueGradId + ')" style="mix-blend-mode:' + mixBlendMode + '"/>' +
'<rect x="' + edge + '" y="' + edge + '" width="' + (w - edge * 2) + '" height="' + (h - edge * 2) + '" rx="' + r + '" fill="hsl(0 0% ' + brightness + '% / ' + opacity + ')" filter="url(#' + softId + ')"/>' +
'</svg>';
var mapUrl = "data:image/svg+xml," + encodeURIComponent(mapSvg);
el.style.setProperty("--glass-frost", backgroundOpacity);
el.style.setProperty("--glass-saturation", saturation);
el.style.setProperty("--filter-id", "url(#" + filterId + ")");
el.classList.add(svgSupported ? "glass-surface--svg" : "glass-surface--fallback");
var filterSvg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
filterSvg.setAttribute("class", "glass-surface__filter");
filterSvg.innerHTML = '<defs>' +
'<filter id="' + filterId + '" color-interpolation-filters="sRGB" x="0%" y="0%" width="100%" height="100%">' +
'<feImage href="' + mapUrl + '" x="0" y="0" width="100%" height="100%" preserveAspectRatio="none" result="map"/>' +
'<feDisplacementMap in="SourceGraphic" in2="map" scale="' + (distortionScale + redOffset) + '" xChannelSelector="R" yChannelSelector="G" result="dispRed"/>' +
'<feColorMatrix in="dispRed" type="matrix" values="1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0" result="red"/>' +
'<feDisplacementMap in="SourceGraphic" in2="map" scale="' + (distortionScale + greenOffset) + '" xChannelSelector="R" yChannelSelector="G" result="dispGreen"/>' +
'<feColorMatrix in="dispGreen" type="matrix" values="0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0" result="green"/>' +
'<feDisplacementMap in="SourceGraphic" in2="map" scale="' + (distortionScale + blueOffset) + '" xChannelSelector="R" yChannelSelector="G" result="dispBlue"/>' +
'<feColorMatrix in="dispBlue" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0" result="blue"/>' +
'<feBlend in="red" in2="green" mode="screen" result="rg"/>' +
'<feBlend in="rg" in2="blue" mode="screen" result="output"/>' +
'<feGaussianBlur in="output" stdDeviation="' + (displace || 0.7) + '"/>' +
'</filter></defs>';
var childNodes = Array.prototype.slice.call(el.childNodes);
var wrap = document.createElement("div");
wrap.className = "glass-surface__content";
childNodes.forEach(function (n) { wrap.appendChild(n); });
el.appendChild(filterSvg);
if (!svgSupported) {
var sheen = document.createElement("span");
sheen.className = "glass-surface__sheen";
sheen.setAttribute("aria-hidden", "true");
var rim = document.createElement("span");
rim.className = "glass-surface__rim";
rim.setAttribute("aria-hidden", "true");
el.appendChild(sheen);
el.appendChild(rim);
}
el.appendChild(wrap);
}
function mountGreeting(root) { function mountGreeting(root) {
var content = root.querySelector(".header-content"); var content = root.querySelector(".header-content");
var title = root.querySelector(".header-title"); var title = root.querySelector(".header-title");
@@ -1286,6 +1314,9 @@ function mountGreeting(root) {
resume.textContent = "Continue: " + (last.title || last.path); resume.textContent = "Continue: " + (last.title || last.path);
actions.appendChild(resume); actions.appendChild(resume);
} }
if (typeof applyGlassSurfaces === "function") {
applyGlassSurfaces(root);
}
} }
function loadPage() { function loadPage() {
@@ -1892,72 +1923,4 @@ document.addEventListener("DOMContentLoaded", function () {
loadPage(); loadPage();
window.addEventListener("popstate", loadPage); window.addEventListener("popstate", loadPage);
document.addEventListener("click", function (e) {
var img = e.target.closest("main.prose img");
if (img && !img.closest(".spider-body") && !img.closest(".cobweb")) {
e.preventDefault();
openLightbox(img);
return;
}
var heading = e.target.closest("main.prose h1, main.prose h2, main.prose h3, main.prose h4");
if (heading && heading.id) {
var header = document.getElementById("header-container") || document.getElementById("navbar");
var offset = header ? header.offsetHeight + 16 : 80;
var topPos = heading.getBoundingClientRect().top + window.pageYOffset - offset;
window.scrollTo({ top: Math.max(0, topPos), behavior: "smooth" });
window.history.pushState(null, "", "#" + heading.id);
return;
}
var a = e.target.closest("a");
if (a) {
var href = a.getAttribute("href");
if (href && href.startsWith("#")) {
var targetId = href.slice(1);
var targetEl = document.getElementById(targetId);
if (!targetEl) {
var headings = document.querySelectorAll("h1, h2, h3, h4");
for (var h = 0; h < headings.length; h++) {
if (headings[h].textContent.trim().toLowerCase() === targetId.replace(/-/g, " ").toLowerCase()) {
targetEl = headings[h];
break;
}
}
}
if (targetEl) {
e.preventDefault();
var header = document.getElementById("header-container") || document.getElementById("navbar");
var offset = header ? header.offsetHeight + 16 : 80;
var topPos = targetEl.getBoundingClientRect().top + window.pageYOffset - offset;
window.scrollTo({ top: Math.max(0, topPos), behavior: "smooth" });
window.history.pushState(null, "", "#" + (targetEl.id || targetId));
}
return;
}
if (href && href.startsWith("/") && !href.startsWith("//") && a.target !== "_blank") {
e.preventDefault();
navigateTo(href);
return;
}
}
var sidebar = document.getElementById("sidebar");
var menu = document.getElementById("theme-menu");
var segMenu = document.getElementById("theme-seg-menu");
if (menu && !e.target.closest(".theme-wrap")) menu.classList.remove("open");
if (segMenu && !e.target.closest("#theme-seg")) segMenu.classList.remove("open");
if (
sidebar &&
sidebar.classList.contains("open") &&
!sidebar.contains(e.target) &&
!e.target.closest("#mobile-toggle") &&
!e.target.closest(".theme-wrap") &&
!e.target.closest("#theme-seg")
) {
sidebar.classList.remove("open");
document.body.classList.remove("nav-open");
}
});
}); });

View File

@@ -18,8 +18,6 @@ function syncSettingsUI() {
b.classList.toggle("on", b.getAttribute("data-v") === size); b.classList.toggle("on", b.getAttribute("data-v") === size);
}); });
settingsEl("set-video").checked = getPref("video", "on") !== "off"; settingsEl("set-video").checked = getPref("video", "on") !== "off";
settingsEl("set-motion").checked = getPref("motion", "on") !== "off";
settingsEl("set-deco").checked = getPref("deco", "on") !== "off";
} }
var saveTimer = null; var saveTimer = null;
@@ -73,7 +71,6 @@ function buildSettings() {
'<div class="st-scroll">' + '<div class="st-scroll">' +
'<section class="st-group"><h4 class="st-heading">Theme</h4><div class="st-card st-themes">' + '<section class="st-group"><h4 class="st-heading">Theme</h4><div class="st-card st-themes">' +
'<div class="st-sub">General</div><div class="st-theme-grid">' + themeChips(THEMES_GENERAL) + "</div>" + '<div class="st-sub">General</div><div class="st-theme-grid">' + themeChips(THEMES_GENERAL) + "</div>" +
'<div class="st-sub">Seasonal</div><div class="st-theme-grid">' + themeChips(THEMES_SEASONAL) + "</div>" +
"</div></section>" + "</div></section>" +
'<section class="st-group"><h4 class="st-heading">You</h4><div class="st-card">' + '<section class="st-group"><h4 class="st-heading">You</h4><div class="st-card">' +
'<label class="st-field"><span class="st-label">Your name</span><input id="set-name" class="st-input" type="text" maxlength="24" placeholder="Shown in the home greeting" autocomplete="off"></label>' + '<label class="st-field"><span class="st-label">Your name</span><input id="set-name" class="st-input" type="text" maxlength="24" placeholder="Shown in the home greeting" autocomplete="off"></label>' +
@@ -88,8 +85,6 @@ function buildSettings() {
"</div></section>" + "</div></section>" +
'<section class="st-group"><h4 class="st-heading">Experience</h4><div class="st-card">' + '<section class="st-group"><h4 class="st-heading">Experience</h4><div class="st-card">' +
switchRow("set-video", "Background video", "Looping video behind each theme.") + switchRow("set-video", "Background video", "Looping video behind each theme.") +
switchRow("set-motion", "Animations", "Transitions, falling decorations and effects.") +
switchRow("set-deco", "Decorations", "Spiders, snow, leaves and lights.") +
"</div></section>" + "</div></section>" +
"</div>" + "</div>" +
'<div class="st-bottom"><button type="button" class="sheet-btn-never st-reset">Reset</button><button type="button" class="sheet-btn-primary st-save">Save preferences</button></div>' + '<div class="st-bottom"><button type="button" class="sheet-btn-never st-reset">Reset</button><button type="button" class="sheet-btn-primary st-save">Save preferences</button></div>' +
@@ -197,7 +192,7 @@ function buildSettings() {
syncSettingsUI(); syncSettingsUI();
}); });
[["set-video", "video"], ["set-motion", "motion"], ["set-deco", "deco"]].forEach(function (pair) { [["set-video", "video"]].forEach(function (pair) {
settingsEl(pair[0]).addEventListener("change", function () { settingsEl(pair[0]).addEventListener("change", function () {
setPref(pair[1], this.checked ? null : "off"); setPref(pair[1], this.checked ? null : "off");
applyTheme(); applyTheme();