This commit is contained in:
Devin Bot
2026-10-25 14:53:50 -07:00
parent 6080df1456
commit e31ae53518
41 changed files with 442 additions and 431 deletions

72
src/assets/css/404.css Normal file
View File

@@ -0,0 +1,72 @@
body.is-404 #sidebar,
body.is-404 #toc,
body.is-404 #mobile-bar,
body.is-404 .footer-nav {
display: none !important;
}
body.is-404 #content-wrapper {
padding: 0 !important;
margin: 0 auto !important;
max-width: 100% !important;
width: 100% !important;
}
body.is-404 #content-col,
body.is-404 #main-wrap,
body.is-404 #main-content {
max-width: 100% !important;
width: 100% !important;
margin: 0 !important;
}
body.is-404 .error-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: calc(80vh - 120px);
padding: 40px 20px;
box-sizing: border-box;
text-align: center;
}
body.is-404 .error-code {
margin: 0 0 16px;
color: var(--text);
font-size: clamp(74px, 14vw, 112px);
font-weight: 700;
line-height: 1;
letter-spacing: -2px;
}
body.is-404 .error-title {
margin: 0 0 24px;
color: var(--text);
font-size: 18px;
font-weight: 800;
letter-spacing: 0.12em;
text-transform: uppercase;
}
body.is-404 .error-desc {
max-width: 440px;
margin: 0 0 32px;
color: var(--muted);
font-size: 15.5px;
line-height: 1.6;
}
body.is-404 .btn-home {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 10px 28px;
border-radius: 9999px;
background: var(--btn-home-bg);
color: var(--btn-home-text) !important;
font-size: 14.5px;
font-weight: 500;
text-decoration: none !important;
transition: background 0.2s ease, border-color 0.2s ease, color 0.2s ease;
}

View File

@@ -0,0 +1,327 @@
.ico {
width: 16px;
height: 16px;
flex-shrink: 0;
}
#search-trigger {
position: absolute;
left: 50%;
transform: translateX(-50%);
display: flex;
align-items: center;
gap: 10px;
background: var(--search-bg);
width: min(440px, 40vw);
height: 36px;
padding: 0 12px;
border: none;
border-radius: 100px;
color: var(--muted);
font: inherit;
font-size: 14px;
cursor: pointer;
}
#search-trigger kbd {
margin-left: auto;
font: 600 11px var(--font);
color: inherit;
}
.code-wrap {
position: relative;
}
.code-wrap .copy-btn {
position: absolute;
top: 12px;
right: 12px;
display: flex;
padding: 6px;
border: none;
border-radius: 8px;
background: none;
color: var(--muted);
cursor: pointer;
}
.code-wrap .copy-btn:hover {
background: var(--hover-bg);
}
.code-group {
position: relative;
margin: 16px 0;
border-radius: 20px;
background: var(--code-group-bg);
padding: 6px 4px 4px;
}
.code-group-tabs {
display: flex;
align-items: center;
gap: 16px;
padding: 4px 6px 6px;
}
.code-group-tab {
position: relative;
padding: 6px 2px 8px;
font-family: var(--font);
font-size: 13px;
font-weight: 600;
line-height: 16px;
border: none;
background: none;
cursor: pointer;
color: var(--muted);
}
.code-group-tab.active {
color: var(--code-tab-active);
}
.code-group-tab.active::after {
content: "";
position: absolute;
left: 0;
right: 0;
bottom: 0;
height: 2px;
background: var(--code-tab-active);
border-radius: 2px;
}
.code-group-panels {
background: var(--code-group-panel-bg);
border-radius: 14px;
overflow: hidden;
}
.cg-copy-btn {
position: absolute;
top: 10px;
right: 14px;
display: flex;
align-items: center;
justify-content: center;
padding: 4px;
border: none;
border-radius: 6px;
background: none;
color: var(--muted);
cursor: pointer;
}
.cg-copy-btn:hover {
color: var(--text);
}
.code-group-panel {
display: none;
}
.code-group-panel.active {
display: block;
}
main.prose .code-group pre {
margin: 0;
padding: 16px 20px;
border: none;
border-radius: 0;
background: transparent;
color: inherit;
}
main.prose .code-group pre code {
color: inherit;
}
main.prose blockquote {
margin: 16px 0;
padding: 4px 0 4px 16px;
border-left: 3px solid var(--border);
color: var(--muted);
}
main.prose blockquote p {
margin: 0;
color: inherit;
}
.skeleton-wrap {
width: 100%;
}
.skeleton-line,
.skeleton-media {
background: linear-gradient(90deg, var(--skeleton-pulse-1) 25%, var(--skeleton-pulse-2) 37%, var(--skeleton-pulse-1) 63%);
background-size: 400% 100%;
animation: skeletonPulse 1.3s cubic-bezier(0.4, 0, 0.6, 1) infinite;
border-radius: 8px;
}
@keyframes skeletonPulse {
0% {
background-position: 100% 50%;
}
100% {
background-position: 0 50%;
}
}
.skeleton-eyebrow {
width: 90px;
height: 16px;
margin-bottom: 12px;
}
.skeleton-title {
width: 65%;
height: 38px;
margin-bottom: 18px;
border-radius: 10px;
}
.skeleton-desc {
width: 85%;
height: 22px;
margin-bottom: 24px;
}
.skeleton-media {
width: 100%;
height: 320px;
border-radius: 24px;
margin: 24px 0;
}
.skeleton-text {
height: 16px;
margin: 12px 0;
}
.w-100 {
width: 100%;
}
.w-90 {
width: 90%;
}
.w-85 {
width: 85%;
}
.w-75 {
width: 75%;
}
.content-animate>* {
animation: smoothBlurReveal 0.44s cubic-bezier(0.22, 1, 0.36, 1) both;
will-change: filter, opacity, transform;
}
.content-animate>*:nth-child(1) {
animation-delay: 0ms;
}
.content-animate>*:nth-child(2) {
animation-delay: 35ms;
}
.content-animate>*:nth-child(3) {
animation-delay: 70ms;
}
.content-animate>*:nth-child(4) {
animation-delay: 105ms;
}
.content-animate>*:nth-child(5) {
animation-delay: 140ms;
}
.content-animate>*:nth-child(6) {
animation-delay: 175ms;
}
.content-animate>*:nth-child(7) {
animation-delay: 210ms;
}
.content-animate>*:nth-child(8) {
animation-delay: 245ms;
}
.content-animate>*:nth-child(9) {
animation-delay: 280ms;
}
.content-animate>*:nth-child(n+10) {
animation-delay: 315ms;
}
.content-animate.caught-up>* {
animation: none !important;
opacity: 1 !important;
filter: none !important;
transform: none !important;
}
@keyframes smoothBlurReveal {
0% {
opacity: 0;
filter: blur(8px);
transform: translateY(6px);
}
100% {
opacity: 1;
filter: blur(0px);
transform: translateY(0);
}
}
@media (prefers-reduced-motion: reduce) {
.content-animate>* {
animation: none !important;
}
.skeleton-line,
.skeleton-media {
animation: none !important;
}
}
@media (max-width: 900px) {
#search-trigger {
order: 2;
position: static;
transform: none;
width: auto;
padding: 8px;
background: transparent;
}
#search-trigger .ico {
font-weight: 900;
width: 1.53rem;
height: 1.3rem;
}
#search-trigger span,
#search-trigger kbd {
display: none;
}
}
main.prose h1,
main.prose h2,
main.prose h3,
main.prose h4 {
cursor: pointer;
}

262
src/assets/css/features.css Normal file
View File

@@ -0,0 +1,262 @@
.bm-btn {
display: flex;
align-items: center;
justify-content: center;
width: 30px;
height: 30px;
padding: 0;
border: none;
border-radius: 50%;
background: none;
color: var(--muted);
cursor: pointer;
transition: color 0.15s ease, background 0.15s ease;
}
.bm-btn .ico {
width: 18px;
height: 18px;
}
.bm-btn:hover {
background: var(--hover-bg);
color: var(--text);
}
.bm-btn.on {
color: var(--text);
}
.bm-btn.on .ico {
fill: currentColor;
}
.personal-card {
margin: 18px 0 8px;
padding: 16px 18px;
border-radius: 22px;
background: var(--callout-note-bg);
}
.personal-card label {
display: block;
margin-bottom: 10px;
font-size: 14px;
font-weight: 600;
color: var(--text);
}
.pc-row {
display: flex;
gap: 8px;
}
.pc-row input {
flex: 1;
min-width: 0;
height: 36px;
padding: 0 14px;
border: 1px solid var(--border);
border-radius: 100px;
background: var(--search-bg);
color: var(--text);
font: inherit;
font-size: 13.5px;
outline: none;
}
.pc-row input.bad {
border-color: #ef4444;
}
.pc-btn {
height: 36px;
padding: 0 18px;
border: none;
border-radius: 100px;
background: var(--btn-primary-bg);
color: var(--btn-primary-text);
font: inherit;
font-size: 13.5px;
font-weight: 600;
cursor: pointer;
}
main.prose .pc-hint {
margin: 8px 0 0;
font-size: 12.5px;
line-height: 1.5;
color: var(--muted);
}
.rec-badge {
display: inline-flex;
align-items: center;
margin-left: 8px;
padding: 2px 10px;
border-radius: 100px;
background: var(--btn-primary-bg);
color: var(--btn-primary-text);
font-size: 11.5px;
font-weight: 700;
letter-spacing: 0.02em;
vertical-align: middle;
white-space: nowrap;
}
tbody tr.rec-row td {
background: var(--hover-bg);
}
tbody tr.rec-row td:first-child {
padding-left: 12px;
border-top-left-radius: 12px;
border-bottom-left-radius: 12px;
}
tbody tr.rec-row td:last-child {
padding-right: 12px;
border-top-right-radius: 12px;
border-bottom-right-radius: 12px;
}
#footer-note {
margin: 0 0 16px;
font-size: 13.5px;
color: var(--muted);
}
.changelog,
.contributors {
margin: 20px 0;
}
.contributors {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
main.prose .muted-line {
margin: 0;
color: var(--muted);
}
.cl-item {
padding: 16px 0;
border-bottom: 1px solid var(--border-subtle);
}
.cl-meta {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 10px;
font-size: 12.5px;
color: var(--muted);
}
.cl-tag {
padding: 2px 10px;
border-radius: 100px;
background: var(--hover-bg);
color: var(--text);
font-weight: 600;
}
.cl-title {
margin-top: 8px;
font-size: 16px;
font-weight: 700;
color: var(--text);
}
main.prose .cl-notes {
margin: 6px 0 0;
font-size: 14px;
}
.cl-link {
display: inline-block;
margin-top: 8px;
font-size: 13px;
}
.ct-chip {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 0px 14px 0px 5px;
border-radius: 100px;
background: var(--hover-bg);
color: var(--text);
;
font-size: 13.5px;
margin-right: 10px;
height: 40px;
align-items: center;
}
.ct-chip em {
font-style: normal;
font-size: 12px;
color: var(--muted);
}
.ct-avatar {
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
background: var(--btn-primary-bg);
color: var(--btn-primary-text);
font-size: 12px;
font-weight: 700;
}
.ct-avatar-img {
width: 26px;
height: 26px;
}
.confetti-canvas {
position: fixed;
inset: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 3000;
}
body:not(.is-home) main.prose {
zoom: var(--text-scale, 1);
}
body.no-deco .cobweb,
body.no-deco .spider-container,
body.no-deco .snowfall,
body.no-deco .leaf-fall,
body.no-deco .light-string {
display: none !important;
}
body.no-video .video-bg,
body.no-video .body-blurred-video,
body.no-video .header-video {
display: none !important;
}
body.no-motion *,
body.no-motion *::before,
body.no-motion *::after {
animation: none !important;
transition: none !important;
scroll-behavior: auto !important;
}
@media (max-width: 900px) {
.rec-badge {
margin-left: 0 !important;
margin-top: 10px !important;
}
}

View File

@@ -0,0 +1,72 @@
pre[class*="language-"],
code[class*="language-"] {
color: var(--code-text);
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: var(--hl-comment);
font-style: italic;
}
.token.punctuation {
color: var(--hl-punct);
}
.token.function,
.token.function-name {
color: var(--hl-func);
font-weight: 500;
}
.token.keyword,
.token.selector {
color: var(--hl-keyword);
font-weight: 600;
}
.token.string,
.token.url {
color: var(--hl-string);
}
.token.variable,
.token.attr-name,
.token.property {
color: var(--hl-var);
}
.token.operator,
.token.entity {
color: var(--hl-op);
}
.token.number,
.token.boolean,
.token.constant {
color: var(--hl-num);
}
.token.parameter {
color: var(--hl-param);
}
.token.class-name {
color: var(--hl-class);
}
.token.tag {
color: var(--hl-tag);
}
.token.deleted {
color: var(--hl-deleted-color);
background-color: var(--hl-deleted-bg);
}
.token.inserted {
color: var(--hl-inserted-color);
background-color: var(--hl-inserted-bg);
}

1007
src/assets/css/layout.css Normal file

File diff suppressed because it is too large Load Diff

858
src/assets/css/overlay.css Normal file
View File

@@ -0,0 +1,858 @@
#search-modal {
position: fixed;
inset: 0;
z-index: 100;
display: none;
}
#search-modal.open {
display: block;
}
.search-panel {
position: relative;
width: min(640px, calc(100vw - 24px));
margin: 52px auto 0;
border-radius: 20px;
overflow: hidden;
background: var(--search-panel-bg) !important;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.4);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
}
.search-input-row {
display: flex;
align-items: center;
gap: 12px;
padding: 18px 20px;
}
.search-input-row .ico {
width: 18px;
height: 18px;
color: var(--muted);
}
#search-input {
flex: 1;
border: none;
outline: none;
background: transparent;
color: var(--text);
font: inherit;
font-size: 18px;
}
#search-results {
max-height: 40vh;
overflow-y: auto;
padding: 0 6px 8px;
}
.search-label {
padding: 8px 14px;
font-size: 12px;
color: var(--muted);
}
.sr {
display: flex;
align-items: flex-start;
gap: 12px;
padding: 8px 12px;
border-radius: 12px;
}
.sr>.ico {
margin-top: 3px;
color: var(--muted);
}
.sr.on {
background: var(--hover-bg);
}
.sr-body {
min-width: 0;
}
.sr .t {
font-size: 14px;
font-weight: 600;
line-height: 1.35;
color: var(--text);
}
.sr .s {
display: -webkit-box;
margin-top: 2px;
font-size: 12.5px;
line-height: 1.4;
color: var(--muted);
overflow: hidden;
-webkit-line-clamp: 2;
line-clamp: 2;
-webkit-box-orient: vertical;
}
.sr .p {
margin-top: 2px;
font-size: 12px;
line-height: 1.35;
color: var(--muted);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.sr .sep {
margin: 0 6px;
opacity: 0.7;
}
.sr .hit {
font-weight: 700;
color: var(--text);
}
.search-footer {
display: flex;
gap: 18px;
padding: 12px 20px;
font-size: 12px;
color: var(--muted);
border-top: 1px solid var(--border-subtle);
}
.search-footer .close-hint {
margin-left: auto;
}
.search-footer kbd {
margin-right: 4px;
padding: 1px 5px;
border-radius: 4px;
font: 11px var(--font);
}
@media (max-width: 900px) {
.search-panel {
margin-top: 50px;
border-radius: 30px;
}
.search-footer {
display: none;
}
}
.sheet-overlay {
position: fixed;
inset: 0;
z-index: 1000;
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
pointer-events: none;
transition: opacity 0.35s cubic-bezier(0.16, 1, 0.3, 1);
}
.sheet-overlay.active {
opacity: 1;
pointer-events: auto;
}
.sheet-backdrop {
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.65);
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
}
.sheet-panel {
position: relative;
width: min(500px, calc(100vw - 32px));
background: var(--bg-modal);
border-radius: 28px;
backdrop-filter: blur(24px);
-webkit-backdrop-filter: blur(24px);
padding: 32px 28px 28px;
box-sizing: border-box;
transform: scale(0.92) translateY(16px);
transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1);
display: flex;
flex-direction: column;
}
.sheet-overlay.active .sheet-panel {
transform: scale(1) translateY(0);
}
.sheet-handle-bar {
display: none;
}
.sheet-title {
font-size: 22px;
font-weight: 700;
color: var(--text);
margin: 0 0 10px;
line-height: 1.3;
text-align: center;
}
.sheet-desc {
font-size: 14.5px;
color: var(--muted);
line-height: 1.6;
margin: 0 0 24px;
text-align: center;
}
.sheet-actions {
display: flex;
align-items: center;
gap: 12px;
justify-content: center;
}
.sheet-btn-primary {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 10px 22px;
border-radius: 100px;
background: var(--btn-primary-bg);
color: var(--btn-primary-text) !important;
font-size: 14px;
font-weight: 600;
text-decoration: none !important;
transition: transform 0.15s ease, opacity 0.15s ease;
}
.sheet-btn-primary:hover {
opacity: 0.9;
transform: translateY(-1px);
}
.sheet-btn-never {
padding: 10px 18px;
border: none;
background: none;
color: var(--muted);
font: inherit;
font-size: 13.5px;
font-weight: 500;
cursor: pointer;
border-radius: 100px;
transition: color 0.15s ease, background 0.15s ease;
}
.sheet-btn-never:hover {
color: var(--text);
background: var(--hover-bg);
}
@media (max-width: 900px) {
.sheet-overlay {
align-items: flex-end;
}
.sheet-panel {
width: 100%;
max-width: 100%;
border-radius: 28px 28px 0 0;
border-bottom: none;
padding: 14px 22px 32px;
transform: translateY(100%);
transition: transform 0.45s cubic-bezier(0.32, 0.72, 0, 1);
touch-action: none;
max-height: 90vh;
}
.sheet-panel.dragging {
transition: none !important;
}
.sheet-overlay.active .sheet-panel {
transform: translateY(0);
}
.sheet-handle-bar {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
padding: 6px 0 16px;
cursor: grab;
}
.sheet-handle {
width: 40px;
height: 5px;
border-radius: 999px;
background: var(--muted);
opacity: 0.45;
}
.sheet-actions {
flex-direction: column;
width: 100%;
gap: 8px;
}
.sheet-btn-primary {
width: 100%;
}
.sheet-btn-never {
width: 100%;
text-align: center;
}
}
@media (orientation: landscape) and (max-height: 550px) {
.sheet-panel {
max-height: 94vh;
overflow-y: auto;
padding: 10px max(24px, env(safe-area-inset-right)) 16px max(24px, env(safe-area-inset-left));
}
.sheet-title {
font-size: 18px;
margin-bottom: 6px;
}
.sheet-desc {
font-size: 13px;
margin-bottom: 12px;
line-height: 1.45;
}
.sheet-actions {
flex-direction: row;
gap: 10px;
}
.sheet-btn-primary,
.sheet-btn-never {
width: auto;
padding: 8px 18px;
font-size: 13px;
}
}
.image-lightbox {
position: fixed;
inset: 0;
z-index: 2000;
background: transparent;
backdrop-filter: blur(0px);
-webkit-backdrop-filter: blur(0px);
opacity: 0;
pointer-events: none;
transition: background 0.42s cubic-bezier(0.2, 0.9, 0.3, 1),
backdrop-filter 0.42s cubic-bezier(0.2, 0.9, 0.3, 1),
opacity 0.25s ease;
}
.image-lightbox.active {
background: var(--bg-modal);
backdrop-filter: blur(24px);
-webkit-backdrop-filter: blur(24px);
opacity: 1;
pointer-events: auto;
}
.lightbox-controls {
position: fixed;
top: max(16px, env(safe-area-inset-top));
right: max(16px, env(safe-area-inset-right));
display: flex;
align-items: center;
gap: 3px;
z-index: 2003;
background: var(--bg-menu);
border-radius: 100px;
padding: 3px 6px;
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
opacity: 0;
transform: translateY(-8px) scale(0.96);
transition: opacity 0.3s cubic-bezier(0.16, 1, 0.3, 1) 0.08s,
transform 0.3s cubic-bezier(0.16, 1, 0.3, 1) 0.08s;
}
.image-lightbox.active .lightbox-controls {
opacity: 1;
transform: translateY(0) scale(1);
}
.lightbox-btn {
display: flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
border: none;
border-radius: 50%;
background: transparent;
color: var(--muted);
font-family: var(--font);
font-size: 16px;
line-height: 1;
cursor: pointer;
transition: background 0.15s ease, color 0.15s ease;
}
.lightbox-btn:hover {
background: var(--hover-bg);
color: var(--text);
}
.lightbox-btn svg {
display: block;
width: 16px;
height: 16px;
fill: currentColor;
flex-shrink: 0;
}
.lightbox-img {
position: fixed;
object-fit: contain;
border-radius: 16px;
transition: top 0.44s cubic-bezier(0.2, 0.9, 0.3, 1),
left 0.44s cubic-bezier(0.2, 0.9, 0.3, 1),
width 0.44s cubic-bezier(0.2, 0.9, 0.3, 1),
height 0.44s cubic-bezier(0.2, 0.9, 0.3, 1),
border-radius 0.44s cubic-bezier(0.2, 0.9, 0.3, 1),
transform 0.25s ease;
z-index: 2002;
transform-origin: center center;
will-change: top, left, width, height, transform;
}
main.prose img {
cursor: zoom-in;
transition: opacity 0.2s ease, transform 0.2s ease;
}
main.prose img:hover {
opacity: 0.95;
}
#settings-trigger,
.side-settings {
display: flex;
align-items: center;
justify-content: center;
width: 36px;
height: 36px;
padding: 0;
border: none;
border-radius: 10px;
background: none;
color: var(--muted);
cursor: pointer;
}
#settings-trigger .ico,
.side-settings .ico {
width: 18px;
height: 18px;
}
#settings-trigger:hover,
.side-settings:hover {
background: var(--hover-bg);
color: var(--text);
}
.settings-panel {
position: relative;
display: flex;
flex-direction: column;
padding: 0;
overflow: hidden;
}
.st-top,
.st-bottom {
position: absolute;
left: 0;
right: 0;
z-index: 3;
isolation: isolate;
}
.st-top::before,
.st-bottom::before {
content: "";
position: absolute;
inset: 0;
z-index: -1;
pointer-events: none;
backdrop-filter: blur(18px) saturate(1.2);
-webkit-backdrop-filter: blur(18px) saturate(1.2);
}
.st-top {
top: 0;
padding: 26px 28px 30px;
}
.st-top::before {
background: linear-gradient(to bottom, var(--bg-menu) 40%, transparent);
background: linear-gradient(to bottom, color-mix(in srgb, var(--bg-menu) 94%, transparent), color-mix(in srgb, var(--bg-menu) 80%, transparent) 60%, transparent);
-webkit-mask-image: linear-gradient(to bottom, #000 55%, transparent);
mask-image: linear-gradient(to bottom, #000 55%, transparent);
}
.st-top .sheet-title {
margin: 0 0 6px;
font-size: 20px;
}
.st-top .sheet-desc {
margin: 0;
font-size: 13.5px;
line-height: 1.5;
}
.st-bottom {
bottom: 0;
display: flex;
align-items: center;
justify-content: flex-end;
gap: 10px;
padding: 36px 28px calc(20px + env(safe-area-inset-bottom));
}
.st-bottom::before {
background: linear-gradient(to top, var(--bg-menu) 40%, transparent);
background: linear-gradient(to top, color-mix(in srgb, var(--bg-menu) 94%, transparent), color-mix(in srgb, var(--bg-menu) 80%, transparent) 60%, transparent);
-webkit-mask-image: linear-gradient(to top, #000 55%, transparent);
mask-image: linear-gradient(to top, #000 55%, transparent);
}
.st-bottom .sheet-btn-primary {
border: none;
font-family: inherit;
cursor: pointer;
}
.st-bottom .sheet-btn-primary.done {
opacity: 0.85;
}
.st-scroll {
flex: 1;
min-height: 0;
padding: var(--st-top, 110px) 28px var(--st-bottom, 84px);
overflow-y: auto;
overscroll-behavior: contain;
touch-action: pan-y;
scrollbar-width: thin;
scrollbar-color: var(--border) transparent;
}
.st-group {
margin-bottom: 18px;
}
.st-heading {
margin: 0 0 8px 6px;
font-size: 11px;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--muted);
}
.st-card {
border-radius: 20px;
background: var(--hover-bg);
overflow: hidden;
}
.st-row,
.st-field {
display: flex;
gap: 14px;
padding: 14px 16px;
border-top: 1px solid var(--border-subtle);
cursor: default;
}
.st-card>:first-child {
border-top: none;
}
.st-row {
align-items: center;
justify-content: space-between;
}
.st-row.stack {
flex-direction: column;
align-items: stretch;
}
label.st-row {
cursor: pointer;
}
.st-field {
flex-direction: column;
align-items: stretch;
gap: 8px;
}
.st-text {
display: flex;
flex-direction: column;
gap: 2px;
min-width: 0;
}
.st-label {
font-size: 14px;
font-weight: 600;
line-height: 1.35;
color: var(--text);
}
.st-hint {
font-size: 12.5px;
line-height: 1.45;
color: var(--muted);
}
.st-hint.err {
color: #ef4444;
}
.st-input {
width: 100%;
height: 40px;
padding: 0 16px;
border: none;
border-radius: 100px;
background: var(--search-bg);
color: var(--text);
font: inherit;
font-size: 14px;
outline: none;
transition: border-color 0.15s ease;
}
.st-input::placeholder {
color: var(--muted);
opacity: 0.8;
}
.st-input:focus {
border-color: var(--text);
}
.st-input.bad {
border-color: #ef4444;
}
.st-swatches {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 12px;
}
.st-swatch {
display: block;
position: relative;
flex-shrink: 0;
width: 26px;
height: 26px;
padding: 0;
border: none;
border-radius: 50%;
background: var(--sw, var(--hover-bg));
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.2);
cursor: pointer;
transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.st-swatch:hover {
transform: scale(1.12);
}
.st-swatch.on {
box-shadow: 0 0 0 2px var(--bg-menu), 0 0 0 4px var(--text);
;
}
.st-swatch.reset {
background: linear-gradient(135deg, transparent 46%, var(--muted) 46%, var(--muted) 54%, transparent 54%), var(--search-bg);
box-shadow: inset 0 0 0 1.5px var(--muted);
}
.st-swatch.reset.on {
box-shadow: inset 0 0 0 1.5px var(--muted), 0 0 0 2px var(--bg-menu), 0 0 0 4px var(--text);
;
}
.st-swatch.custom {
background: conic-gradient(from 0deg, #ff5c5c, #f4b942, #5fd68f, #8ad1ff, #c084fc, #ff5c5c);
}
.st-swatch.custom input {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
padding: 0;
border: none;
opacity: 0;
cursor: pointer;
}
.st-seg {
display: flex;
gap: 2px;
padding: 3px;
border-radius: 100px;
background: var(--search-bg);
}
.st-seg button {
flex: 1;
height: 32px;
padding: 0 10px;
border: none;
border-radius: 100px;
background: none;
color: var(--muted);
font: inherit;
font-size: 13px;
font-weight: 600;
cursor: pointer;
transition: background 0.15s ease, color 0.15s ease;
}
.st-seg button:hover {
color: var(--text);
}
.st-seg button.on {
background: var(--btn-primary-bg);
color: var(--btn-primary-text);
}
.st-switch {
position: relative;
flex-shrink: 0;
width: 44px;
height: 26px;
}
.st-switch input {
position: absolute;
inset: 0;
z-index: 1;
width: 100%;
height: 100%;
margin: 0;
opacity: 0;
cursor: pointer;
}
.st-track {
position: absolute;
inset: 0;
border: 1px solid var(--border);
border-radius: 100px;
background: var(--search-bg);
transition: background 0.2s ease, border-color 0.2s ease;
}
.st-track::after {
content: "";
position: absolute;
top: 2px;
left: 2px;
width: 20px;
height: 20px;
border-radius: 50%;
background: var(--muted);
transition: transform 0.25s cubic-bezier(0.16, 1, 0.3, 1), background 0.2s ease;
}
.st-switch input:checked+.st-track {
border-color: transparent;
background: var(--btn-primary-bg);
}
.st-switch input:checked+.st-track::after {
transform: translateX(18px);
background: var(--btn-primary-text);
}
.st-switch input:focus-visible+.st-track {
outline: 2px solid var(--text);
outline-offset: 2px;
}
@media (min-width: 901px) {
.settings-panel {
width: min(540px, calc(100vw - 32px));
max-height: min(88vh, 780px);
}
}
@media (max-width: 900px) {
.st-top {
padding: 8px 22px 28px;
}
.st-scroll {
padding-left: 22px;
padding-right: 22px;
}
.st-bottom {
padding: 36px 22px calc(18px + env(safe-area-inset-bottom));
}
.st-bottom .sheet-btn-primary {
flex: 1;
width: auto;
}
.st-bottom .sheet-btn-never {
flex: 0 0 auto;
width: auto;
}
}
@media (orientation: landscape) and (max-height: 550px) {
.settings-panel {
max-height: 94vh;
}
.st-top {
padding: 14px 24px 22px;
}
.st-top .sheet-title {
font-size: 17px;
margin-bottom: 0;
}
.st-top .sheet-desc {
display: none;
}
}

305
src/assets/css/prose.css Normal file
View File

@@ -0,0 +1,305 @@
main.prose {
flex: 1;
min-width: 0;
max-width: 100%;
width: 100%;
box-sizing: border-box;
}
main.prose .eyebrow {
font-size: 14px;
font-weight: 600;
margin: 0 0 8px;
color: var(--text);
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
}
main.prose h1 {
font-size: 30px;
font-weight: 700;
letter-spacing: 0;
margin: 0 0 6px;
color: var(--text);
}
main.prose .page-description {
color: var(--muted);
font-size: 18px;
margin: 0 0 32px;
}
main.prose h2 {
font-size: 22px;
font-weight: 700;
margin: 40px 0 14px;
padding-top: 6px;
}
main.prose h2:first-child {
border-top: none;
padding-top: 0;
}
main.prose h3 {
font-size: 17px;
font-weight: 700;
margin: 26px 0 10px;
}
main.prose h2,
main.prose h3 {
scroll-margin-top: 130px;
color: var(--text);
}
main.prose p,
main.prose li {
color: var(--muted);
line-height: 1.75;
}
main.prose strong {
color: var(--text);
}
main.prose a {
color: var(--text);
;
font-weight: 600;
text-decoration: underline;
}
main.prose ul,
main.prose ol {
padding-left: 22px;
}
main.prose li {
margin: 4px 0;
}
main.prose img {
max-width: 100%;
border-radius: 16px;
display: block;
margin: 20px 0;
}
main.prose img.vyla-banner {
width: 100%;
}
main.prose hr {
border: none;
}
main.prose code {
background: var(--code-inline-bg);
color: var(--text);
font-family: var(--mono);
font-size: 13px;
padding: 2px 6px;
border-radius: 5px;
}
main.prose pre {
margin: 16px 0;
padding: 16px 20px;
border-radius: 25px;
overflow-x: auto;
background: var(--bg-code);
color: var(--code-text);
--fade-l: 0px;
--fade-r: 0px;
scrollbar-width: none;
-webkit-mask-image: linear-gradient(to right, transparent 0, #000 var(--fade-l), #000 calc(100% - var(--fade-r)), transparent 100%);
mask-image: linear-gradient(to right, transparent 0, #000 var(--fade-l), #000 calc(100% - var(--fade-r)), transparent 100%);
}
main.prose pre code {
background: none;
padding: 0;
font-size: 13px;
color: inherit;
}
.table-wrap {
--fade-l: 0px;
--fade-r: 0px;
max-width: 100%;
margin: 20px 0;
overflow-x: auto;
scrollbar-width: thin;
border-radius: 14px;
-webkit-mask-image: linear-gradient(to right, transparent 0, #000 var(--fade-l), #000 calc(100% - var(--fade-r)), transparent 100%);
mask-image: linear-gradient(to right, transparent 0, #000 var(--fade-l), #000 calc(100% - var(--fade-r)), transparent 100%);
}
.table-wrap table {
margin: 0;
}
table {
width: 100%;
border-collapse: separate;
border-spacing: 0;
margin: 0;
font-size: 13.5px;
line-height: 1.55;
text-align: left;
}
th {
padding: 12px 5px;
font-size: 11.5px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--muted);
white-space: nowrap;
}
td {
padding: 14px 5px;
vertical-align: top;
border-bottom: 1px solid var(--border-subtle);
color: var(--text);
;
}
tbody tr:last-child td {
border-bottom: none;
}
tbody tr {
transition: background 0.15s ease;
}
tbody tr:hover {
background: var(--hover-bg);
}
td code {
white-space: nowrap;
font-size: 12.5px;
}
.callout {
display: flex;
gap: 12px;
padding: 14px 11px;
border-radius: 25px;
font-size: 14px;
}
.callout-content {
flex: 1;
}
.callout-content> :first-child {
margin-top: 0;
}
.callout-content> :last-child {
margin-bottom: 0;
}
.callout-note {
background: var(--callout-note-bg);
}
.callout-info {
background: var(--callout-info-bg);
}
.callout-warning {
background: var(--callout-warning-bg) !important;
color: var(--callout-warning-text) !important;
}
.callout-warning p,
.callout-warning strong {
color: inherit !important;
}
aside#toc {
width: var(--toc-width);
flex-shrink: 0;
display: none;
border-radius: 12px;
padding-left: 10px;
height: fit-content;
max-height: calc(100vh - var(--header-height) - 40px);
padding-bottom: 10px;
overflow-y: auto;
position: sticky;
top: calc(var(--header-height) + 40px);
}
@media (min-width: 1100px) {
aside#toc {
display: block;
}
}
aside#toc .toc-title {
display: flex;
align-items: center;
gap: 8px;
font-size: 14px;
font-weight: 600;
line-height: 20px;
color: var(--text);
margin-bottom: 2px;
}
aside#toc .toc-title::before {
content: "";
width: 16px;
height: 16px;
background: currentColor;
-webkit-mask: var(--ico-toc-mask) center / contain no-repeat;
mask: var(--ico-toc-mask) center / contain no-repeat;
}
aside#toc ul {
list-style: none;
margin: 0;
padding: 0;
}
aside#toc li a {
display: block;
padding: 6px 0;
font-size: 14px;
line-height: 20px;
color: var(--muted);
}
aside#toc li a:hover {
color: var(--text);
}
aside#toc li a.active {
color: var(--text);
font-weight: 600;
}
@media (max-width: 900px) {
aside#toc {
display: none;
}
}
@supports (-webkit-touch-callout: none) {
#main-wrap {
margin-top: max(130px, env(safe-area-inset-top));
}
body.is-home {
margin-top: 0px !important;
}
}

519
src/assets/css/roots.css Normal file
View File

@@ -0,0 +1,519 @@
@import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap");
:root,
:root[data-theme="dark"] {
--bg: #000000;
--text: #f3f3f3;
--text: #ffffff;
--muted: #a3a3a3;
--border: #2b2b2b98;
--bg-elevated: rgba(255, 255, 255, 0.08);
--bg-card: rgba(25, 25, 25, 0.2);
--bg-card-hover: rgba(28, 28, 28, 0.8);
--bg-code: #050505;
--code-inline-bg: #050505;
--code-inline-text: #f3f3f3;
--code-text: #abb2bf;
--bg-menu: #000000;
--bg-modal: rgba(10, 10, 10, 0.35);
--hover-bg: rgba(120, 120, 120, 0.05);
--search-bg: rgba(50, 50, 50, 0.1);
--search-panel-bg: rgba(10, 10, 10, 0.6);
--code-group-bg: #0d0d0d;
--code-group-panel-bg: #000000;
--code-tab-active: #ffffff;
--footer-border: rgba(255, 255, 255, 0.08);
--border-subtle: rgba(255, 255, 255, 0.05);
--btn-primary-bg: #ffffff;
--btn-primary-text: #000000;
--btn-home-bg: #ffffff;
--btn-home-text: #000000;
--callout-note-bg: rgba(50, 50, 50, 0.1);
--callout-info-bg: rgba(39, 39, 39, 0.08);
--callout-warning-bg: rgba(180, 120, 0, 0.18);
--callout-warning-text: #fde047;
--body-radial-tint: rgba(0, 0, 0, 0.7);
--skeleton-pulse-1: rgba(255, 255, 255, 0.05);
--skeleton-pulse-2: rgba(255, 255, 255, 0.12);
--spider-display: none;
--cobweb-display: none;
--spider-thread: rgba(255, 255, 255, 0.3);
--snow-display: none;
--leaf-display: none;
--lights-display: none;
--hl-comment: #5c6370;
--hl-punct: #abb2bf;
--hl-func: #61afef;
--hl-keyword: #c678dd;
--hl-string: #98c379;
--hl-var: #e06c75;
--hl-op: #56b6c2;
--hl-num: #d19a66;
--hl-param: #d19a66;
--hl-class: #e5c07b;
--hl-tag: #e06c75;
--hl-deleted-color: #e06c75;
--hl-deleted-bg: rgba(224, 108, 117, 0.15);
--hl-inserted-color: #98c379;
--hl-inserted-bg: rgba(152, 195, 121, 0.15);
--sidebar-width: 150px;
--toc-width: 240px;
--header-height: 148px;
--font: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
--mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
--ico-toc-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M4 6h16M4 12h10M4 18h14'/%3E%3C/svg%3E");
--ico-check-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E");
--ico-chevron-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
--ico-search-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.35-4.35'/%3E%3C/svg%3E");
--ico-close-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='6' x2='6' y2='18'/%3E%3Cline x1='6' y1='6' x2='18' y2='18'/%3E%3C/svg%3E");
}
:root[data-theme="light"] {
--bg: #ffffff;
--text: #0b0b0c;
--text: #111827;
--muted: #6b7280;
--border: #e5e7eb;
--bg-elevated: rgba(0, 0, 0, 0.05);
--bg-card: rgba(240, 240, 240, 0.85);
--bg-card-hover: rgba(225, 225, 225, 0.95);
--bg-code: #fafafa;
--code-inline-bg: rgba(240, 240, 240, 0.8);
--code-inline-text: #0b0b0c;
--code-text: #24292e;
--bg-menu: #ffffff;
--bg-modal: rgba(240, 240, 240);
--hover-bg: rgba(0, 0, 0, 0.05);
--search-bg: rgba(0, 0, 0, 0.05);
--search-panel-bg: rgba(255, 255, 255, 0.85);
--code-group-bg: #f4f4f5;
--code-group-panel-bg: #ffffff;
--code-tab-active: #0b0b0c;
--footer-border: rgba(0, 0, 0, 0.08);
--border-subtle: rgba(0, 0, 0, 0.05);
--btn-primary-bg: #000000;
--btn-primary-text: #ffffff;
--btn-home-bg: #000000;
--btn-home-text: #ffffff;
--callout-note-bg: rgba(5, 5, 5, 0.06);
--callout-info-bg: rgba(39, 39, 39, 0.06);
--callout-warning-bg: #fefce8;
--callout-warning-text: #854d0e;
--body-radial-tint: rgba(255, 255, 255, 0.7);
--skeleton-pulse-1: rgba(0, 0, 0, 0.05);
--skeleton-pulse-2: rgba(0, 0, 0, 0.12);
--spider-display: none;
--cobweb-display: none;
--spider-thread: rgba(0, 0, 0, 0.3);
--hl-comment: #6a737d;
--hl-punct: #24292e;
--hl-func: #6f42c1;
--hl-keyword: #d73a49;
--hl-string: #22863a;
--hl-var: #e36209;
--hl-op: #d73a49;
--hl-num: #005cc5;
--hl-param: #b08800;
--hl-class: #6f42c1;
--hl-tag: #22863a;
--hl-deleted-color: #b31d28;
--hl-deleted-bg: #ffeef0;
--hl-inserted-color: #22863a;
--hl-inserted-bg: #f0fff4;
}
:root[data-theme="midnight"] {
--bg: #070913;
--text: #e2e8f0;
--text: #f8fafc;
--muted: #7f8ea3;
--border: #1a2234;
--bg-elevated: rgba(30, 41, 59, 0.5);
--bg-card: rgba(15, 23, 42, 0.55);
--bg-card-hover: rgba(30, 41, 59, 0.7);
--bg-code: #0b1120;
--code-inline-bg: #0f172a;
--code-inline-text: #38bdf8;
--code-text: #cbd5e1;
--bg-menu: #0b1120;
--bg-modal: rgba(11, 17, 32, 0.75);
--hover-bg: rgba(56, 189, 248, 0.08);
--search-bg: rgba(30, 41, 59, 0.4);
--search-panel-bg: rgba(11, 17, 32, 0.85);
--code-group-bg: #0b1329;
--code-group-panel-bg: #070913;
--code-tab-active: #38bdf8;
--footer-border: #1e293b;
--border-subtle: rgba(255, 255, 255, 0.06);
--btn-primary-bg: #38bdf8;
--btn-primary-text: #020617;
--btn-home-bg: #38bdf8;
--btn-home-text: #020617;
--callout-note-bg: rgba(56, 189, 248, 0.1);
--callout-info-bg: rgba(99, 102, 241, 0.12);
--callout-warning-bg: rgba(245, 158, 11, 0.15);
--callout-warning-text: #fbbf24;
--body-radial-tint: rgba(7, 9, 19, 0.85);
--skeleton-pulse-1: rgba(56, 189, 248, 0.05);
--skeleton-pulse-2: rgba(56, 189, 248, 0.15);
--spider-display: none;
--cobweb-display: none;
--spider-thread: rgba(56, 189, 248, 0.3);
--hl-comment: #64748b;
--hl-punct: #94a3b8;
--hl-func: #38bdf8;
--hl-keyword: #818cf8;
--hl-string: #34d399;
--hl-var: #f472b6;
--hl-op: #38bdf8;
--hl-num: #fbbf24;
--hl-param: #cbd5e1;
--hl-class: #67e8f9;
--hl-tag: #818cf8;
--hl-deleted-color: #f87171;
--hl-deleted-bg: rgba(248, 113, 113, 0.15);
--hl-inserted-color: #34d399;
--hl-inserted-bg: rgba(52, 211, 153, 0.15);
}
:root[data-theme="nord"] {
--bg: #2e3440;
--text: #eceff4;
--text: #88c0d0;
--muted: #d8dee9;
--border: #3b4252;
--bg-elevated: rgba(67, 76, 94, 0.5);
--bg-card: rgba(59, 66, 82, 0.5);
--bg-card-hover: rgba(67, 76, 94, 0.7);
--bg-code: #242933;
--code-inline-bg: #3b4252;
--code-inline-text: #eceff4;
--code-text: #d8dee9;
--bg-menu: #2e3440;
--bg-modal: rgba(46, 52, 64, 0.8);
--hover-bg: rgba(136, 192, 208, 0.1);
--search-bg: rgba(59, 66, 82, 0.5);
--search-panel-bg: rgba(46, 52, 64, 0.9);
--code-group-bg: #3b4252;
--code-group-panel-bg: #2e3440;
--code-tab-active: #88c0d0;
--footer-border: #3b4252;
--border-subtle: rgba(255, 255, 255, 0.05);
--btn-primary-bg: #88c0d0;
--btn-primary-text: #2e3440;
--btn-home-bg: #88c0d0;
--btn-home-text: #2e3440;
--callout-note-bg: rgba(129, 161, 193, 0.15);
--callout-info-bg: rgba(136, 192, 208, 0.15);
--callout-warning-bg: rgba(235, 203, 139, 0.15);
--callout-warning-text: #ebcb8b;
--body-radial-tint: rgba(46, 52, 64, 0.8);
--skeleton-pulse-1: rgba(216, 222, 233, 0.05);
--skeleton-pulse-2: rgba(216, 222, 233, 0.12);
--spider-display: none;
--cobweb-display: none;
--spider-thread: rgba(236, 239, 244, 0.3);
--hl-comment: #616e88;
--hl-punct: #d8dee9;
--hl-func: #88c0d0;
--hl-keyword: #81a1c1;
--hl-string: #a3be8c;
--hl-var: #d08770;
--hl-op: #81a1c1;
--hl-num: #b48ead;
--hl-param: #d8dee9;
--hl-class: #8fbcbb;
--hl-tag: #81a1c1;
--hl-deleted-color: #bf616a;
--hl-deleted-bg: rgba(191, 97, 106, 0.15);
--hl-inserted-color: #a3be8c;
--hl-inserted-bg: rgba(163, 190, 140, 0.15);
}
:root[data-theme="dracula"] {
--bg: #282a36;
--text: #f8f8f2;
--text: #bd93f9;
--muted: #6272a4;
--border: #44475a;
--bg-elevated: rgba(68, 71, 90, 0.5);
--bg-card: rgba(68, 71, 90, 0.4);
--bg-card-hover: rgba(68, 71, 90, 0.7);
--bg-code: #1e1f29;
--code-inline-bg: #44475a;
--code-inline-text: #ff79c6;
--code-text: #f8f8f2;
--bg-menu: #282a36;
--bg-modal: rgba(40, 42, 54, 0.85);
--hover-bg: rgba(189, 147, 249, 0.12);
--search-bg: rgba(68, 71, 90, 0.5);
--search-panel-bg: rgba(40, 42, 54, 0.9);
--code-group-bg: #44475a;
--code-group-panel-bg: #282a36;
--code-tab-active: #ff79c6;
--footer-border: #44475a;
--border-subtle: rgba(255, 255, 255, 0.07);
--btn-primary-bg: #bd93f9;
--btn-primary-text: #282a36;
--btn-home-bg: #bd93f9;
--btn-home-text: #282a36;
--callout-note-bg: rgba(189, 147, 249, 0.15);
--callout-info-bg: rgba(139, 233, 253, 0.15);
--callout-warning-bg: rgba(241, 250, 140, 0.15);
--callout-warning-text: #f1fa8c;
--body-radial-tint: rgba(40, 42, 54, 0.85);
--skeleton-pulse-1: rgba(98, 114, 164, 0.08);
--skeleton-pulse-2: rgba(98, 114, 164, 0.2);
--spider-display: none;
--cobweb-display: none;
--spider-thread: rgba(189, 147, 249, 0.3);
--hl-comment: #6272a4;
--hl-punct: #f8f8f2;
--hl-func: #50fa7b;
--hl-keyword: #ff79c6;
--hl-string: #f1fa8c;
--hl-var: #ffb86c;
--hl-op: #ff79c6;
--hl-num: #bd93f9;
--hl-param: #ffb86c;
--hl-class: #8be9fd;
--hl-tag: #ff79c6;
--hl-deleted-color: #ff5555;
--hl-deleted-bg: rgba(255, 85, 85, 0.15);
--hl-inserted-color: #50fa7b;
--hl-inserted-bg: rgba(80, 250, 123, 0.15);
}
:root[data-theme="forest"] {
--bg: #0d1612;
--text: #e2ede5;
--text: #86efac;
--muted: #739481;
--border: #1a2f24;
--bg-elevated: rgba(34, 76, 56, 0.35);
--bg-card: rgba(20, 42, 31, 0.45);
--bg-card-hover: rgba(28, 59, 44, 0.65);
--bg-code: #080f0c;
--code-inline-bg: #142a1f;
--code-inline-text: #86efac;
--code-text: #d1fae5;
--bg-menu: #0d1612;
--bg-modal: rgba(13, 22, 18, 0.85);
--hover-bg: rgba(134, 239, 172, 0.08);
--search-bg: rgba(26, 47, 36, 0.6);
--search-panel-bg: rgba(13, 22, 18, 0.9);
--code-group-bg: #15271e;
--code-group-panel-bg: #0d1612;
--code-tab-active: #86efac;
--footer-border: #1a2f24;
--border-subtle: rgba(255, 255, 255, 0.05);
--btn-primary-bg: #4ade80;
--btn-primary-text: #052e16;
--btn-home-bg: #4ade80;
--btn-home-text: #052e16;
--callout-note-bg: rgba(74, 222, 128, 0.12);
--callout-info-bg: rgba(45, 212, 191, 0.12);
--callout-warning-bg: rgba(250, 204, 21, 0.15);
--callout-warning-text: #fde047;
--body-radial-tint: rgba(13, 22, 18, 0.85);
--skeleton-pulse-1: rgba(134, 239, 172, 0.05);
--skeleton-pulse-2: rgba(134, 239, 172, 0.12);
--spider-display: none;
--cobweb-display: none;
--spider-thread: rgba(134, 239, 172, 0.3);
--hl-comment: #527561;
--hl-punct: #d1fae5;
--hl-func: #4ade80;
--hl-keyword: #2dd4bf;
--hl-string: #a7f3d0;
--hl-var: #fcd34d;
--hl-op: #34d399;
--hl-num: #fbbf24;
--hl-param: #e2ede5;
--hl-class: #6ee7b7;
--hl-tag: #2dd4bf;
--hl-deleted-color: #f87171;
--hl-deleted-bg: rgba(248, 113, 113, 0.15);
--hl-inserted-color: #4ade80;
--hl-inserted-bg: rgba(74, 222, 128, 0.15);
}
:root[data-theme="sunset"] {
--bg: #180d18;
--text: #fce7f3;
--text: #fb7185;
--muted: #a77c98;
--border: #3b1d36;
--bg-elevated: rgba(80, 30, 70, 0.35);
--bg-card: rgba(50, 20, 45, 0.5);
--bg-card-hover: rgba(75, 30, 68, 0.65);
--bg-code: #120712;
--code-inline-bg: #3b1d36;
--code-inline-text: #fda4af;
--code-text: #fbcfe8;
--bg-menu: #180d18;
--bg-modal: rgba(24, 13, 24, 0.85);
--hover-bg: rgba(251, 113, 133, 0.1);
--search-bg: rgba(59, 29, 54, 0.5);
--search-panel-bg: rgba(24, 13, 24, 0.9);
--code-group-bg: #2d1329;
--code-group-panel-bg: #180d18;
--code-tab-active: #fb7185;
--footer-border: #3b1d36;
--border-subtle: rgba(255, 255, 255, 0.05);
--btn-primary-bg: #f43f5e;
--btn-primary-text: #ffffff;
--btn-home-bg: #f43f5e;
--btn-home-text: #ffffff;
--callout-note-bg: rgba(251, 113, 133, 0.15);
--callout-info-bg: rgba(192, 132, 252, 0.15);
--callout-warning-bg: rgba(251, 146, 60, 0.15);
--callout-warning-text: #fdba74;
--body-radial-tint: rgba(24, 13, 24, 0.85);
--skeleton-pulse-1: rgba(251, 113, 133, 0.05);
--skeleton-pulse-2: rgba(251, 113, 133, 0.15);
--spider-display: none;
--cobweb-display: none;
--spider-thread: rgba(251, 113, 133, 0.3);
--hl-comment: #835b77;
--hl-punct: #fbcfe8;
--hl-func: #fb7185;
--hl-keyword: #c084fc;
--hl-string: #f472b6;
--hl-var: #fb923c;
--hl-op: #f43f5e;
--hl-num: #facc15;
--hl-param: #fce7f3;
--hl-class: #e879f9;
--hl-tag: #c084fc;
--hl-deleted-color: #f87171;
--hl-deleted-bg: rgba(248, 113, 113, 0.15);
--hl-inserted-color: #4ade80;
--hl-inserted-bg: rgba(74, 222, 128, 0.15);
}
:root[data-theme="cyberpunk"] {
--bg: #050508;
--text: #00ffcc;
--text: #ffe600;
--muted: #5e7a75;
--border: #1a2a26;
--bg-elevated: rgba(0, 255, 204, 0.08);
--bg-card: rgba(10, 20, 20, 0.7);
--bg-card-hover: rgba(20, 40, 35, 0.85);
--bg-code: #020204;
--code-inline-bg: rgba(0, 255, 204, 0.12);
--code-inline-text: #ffe600;
--code-text: #00ffcc;
--bg-menu: #08080f;
--bg-modal: rgba(5, 5, 8, 0.9);
--hover-bg: rgba(0, 255, 204, 0.1);
--search-bg: rgba(0, 255, 204, 0.08);
--search-panel-bg: rgba(8, 8, 15, 0.95);
--code-group-bg: #0e121a;
--code-group-panel-bg: #050508;
--code-tab-active: #ffe600;
--footer-border: #1a2a26;
--border-subtle: rgba(0, 255, 204, 0.15);
--btn-primary-bg: #ffe600;
--btn-primary-text: #000000;
--btn-home-bg: #00ffcc;
--btn-home-text: #000000;
--callout-note-bg: rgba(0, 255, 204, 0.12);
--callout-info-bg: rgba(255, 0, 128, 0.15);
--callout-warning-bg: rgba(255, 230, 0, 0.15);
--callout-warning-text: #ffe600;
--body-radial-tint: rgba(5, 5, 8, 0.9);
--skeleton-pulse-1: rgba(0, 255, 204, 0.05);
--skeleton-pulse-2: rgba(255, 230, 0, 0.12);
--spider-display: none;
--cobweb-display: none;
--spider-thread: rgba(0, 255, 204, 0.3);
--hl-comment: #3f5e58;
--hl-punct: #00ffcc;
--hl-func: #ffe600;
--hl-keyword: #ff007f;
--hl-string: #00f0ff;
--hl-var: #ff5500;
--hl-op: #ff007f;
--hl-num: #00ffcc;
--hl-param: #ffffff;
--hl-class: #ffe600;
--hl-tag: #ff007f;
--hl-deleted-color: #ff0055;
--hl-deleted-bg: rgba(255, 0, 85, 0.2);
--hl-inserted-color: #00ffcc;
--hl-inserted-bg: rgba(0, 255, 204, 0.2);
}
body.banner-dismissed {
--header-height: 109px;
}
* {
box-sizing: border-box;
}
html {
margin: 0;
height: 100%;
overflow-x: hidden;
scrollbar-width: none;
-ms-overflow-style: none;
}
body {
min-height: 100%;
min-height: -webkit-fill-available;
margin: 0;
font-family: var(--font);
background: var(--bg);
color: var(--text);
;
line-height: 1.65;
overflow-x: hidden;
-ms-overflow-style: none;
scrollbar-width: none;
padding-left: env(safe-area-inset-left);
padding-right: env(safe-area-inset-right);
}
html::-webkit-scrollbar,
body::-webkit-scrollbar {
display: none;
width: 0;
height: 0;
}
body::before {
content: "";
position: fixed;
inset: 0;
pointer-events: none;
z-index: -1;
background: radial-gradient(ellipse at center, transparent 35%, var(--body-radial-tint) 100%);
}
.video-bg {
position: fixed;
inset: 0;
width: 100%;
height: 100%;
object-fit: cover;
z-index: -2;
}
a {
color: inherit;
text-decoration: none;
}

574
src/assets/css/themes.css Normal file
View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1016 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 441 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 360 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 652 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
src/assets/images/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 698 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 MiB

View File

@@ -0,0 +1,84 @@
function renderChangelog() {
var box = document.getElementById("changelog");
if (!box) return;
box.innerHTML = '<p class="muted-line">Loading releases...</p>';
Promise.all(PROJECTS.map(function (p) {
return fetchProjectReleases(p).then(function (list) {
return list.map(function (r) { return { project: p, rel: r }; });
});
})).then(function (groups) {
var all = [].concat.apply([], groups).sort(function (a, b) {
return new Date(b.rel.released_at || b.rel.created_at) - new Date(a.rel.released_at || a.rel.created_at);
}).slice(0, 15);
if (!all.length) {
box.innerHTML = '<p class="muted-line">No releases found yet.</p>';
return;
}
box.innerHTML = all.map(function (entry) {
var r = entry.rel;
var d = new Date(r.released_at || r.created_at);
var date = isNaN(d) ? "" : d.toLocaleDateString(undefined, { year: "numeric", month: "short", day: "numeric" });
var notes = String(r.description || "").replace(/[#*`>_\[\]]/g, "").replace(/\s+/g, " ").trim().slice(0, 280);
var url = r._links && typeof r._links.self === "string" && /^https?:\/\//.test(r._links.self) ? r._links.self : "";
return '<article class="cl-item"><div class="cl-meta"><span class="cl-tag">' + esc(PROJECT_LABELS[entry.project] || entry.project) + "</span><span>" + esc(r.tag_name || "") + "</span><span>" + esc(date) + "</span></div>" +
(r.name && r.name !== r.tag_name ? '<div class="cl-title">' + esc(r.name) + "</div>" : "") +
(notes ? '<p class="cl-notes">' + esc(notes) + "</p>" : "") +
(url ? '<a class="cl-link" href="' + esc(url) + '" target="_blank" rel="noopener">View on GitLab</a>' : "") +
"</article>";
}).join("");
});
}
function fetchContributors(project) {
var url = "https://gitlab.com/api/v4/projects/vyla-entertainment%2F" + encodeURIComponent(project) + "/repository/contributors?order_by=commits&sort=desc&per_page=100";
return fetch(url)
.then(function (res) {
if (!res.ok) throw new Error();
return res.json();
})
.then(function (data) { return Array.isArray(data) ? data : []; })
.catch(function () { return []; });
}
function renderContributors() {
var box = document.getElementById("contributors");
if (!box) return;
box.innerHTML = '<p class="muted-line">Loading contributors...</p>';
Promise.all(PROJECTS.map(fetchContributors)).then(function (groups) {
var totals = {};
[].concat.apply([], groups).forEach(function (c) {
var name = String(c.name || "").trim();
if (!name || name.toLowerCase() === "devin bot") return;
var key = name.toLowerCase();
if (!totals[key]) totals[key] = { name: name, commits: 0 };
totals[key].commits += Number(c.commits) || 0;
});
var people = Object.keys(totals)
.map(function (k) { return totals[k]; })
.sort(function (a, b) { return b.commits - a.commits; });
if (!people.length) {
box.innerHTML = '<p class="muted-line">Contributors will show up here.</p>';
return;
}
box.innerHTML = people.map(function (p) {
var avatar;
if (p.name.toLowerCase() === "alwaysmesmerizingyou") {
avatar = '<img class="ct-avatar-img" src="https://secure.gravatar.com/avatar/f7a5dfd997d0aa0e81331fd1804d962099056d0b01d60d686e02deb3f8d9751c?s=80&d=identicon" alt="' + esc(p.name) + '" />';
} else if (p.name.toLowerCase() === "zstrike") {
avatar = '<img class="ct-avatar-img" src="https://secure.gravatar.com/avatar/50dccff77795ed47ea2afe0d67823fbde6e0a6c39d7b6cc3af41a08bd159611d?s=1600&d=identicon" alt="' + esc(p.name) + '" />';
} else {
avatar = '<span class="ct-avatar">' + esc(p.name.charAt(0).toUpperCase()) + "</span>";
}
return '<span class="ct-chip">' + avatar + esc(p.name) + " <em>" + p.commits + "</em></span>";
}).join("");
});
}

View File

@@ -0,0 +1,50 @@
function resolveLatestDownloads() {
var path = window.location.pathname;
var project = null;
if (path.indexOf("/products/home") !== -1) project = "home";
else if (path.indexOf("/products/go") !== -1) project = "go";
else if (path.indexOf("/products/tv") !== -1) project = "TV";
if (!project) return;
fetchProjectReleases(project).then(function (releases) {
markRecommended(project);
if (!releases.length) return;
var links = document.querySelectorAll("#main-content a");
links.forEach(function (a) {
var text = a.textContent.toLowerCase();
var href = a.getAttribute("href") || "";
if (project === "home") {
if (text.indexOf(".exe") !== -1 || text.indexOf("windows") !== -1) {
var matchExe = findAssetInReleases(releases, "exe");
if (matchExe) {
a.href = matchExe.url;
a.textContent = "Download: " + matchExe.tag + " (.exe)";
a.setAttribute("target", "_blank");
a.setAttribute("rel", "noopener");
}
} else if (text.indexOf(".dmg") !== -1 || text.indexOf("macos") !== -1) {
var matchDmg = findAssetInReleases(releases, "dmg");
if (matchDmg) {
a.href = matchDmg.url;
a.textContent = "Download: " + matchDmg.tag + " (.dmg)";
a.setAttribute("target", "_blank");
a.setAttribute("rel", "noopener");
}
}
} else if (project === "go" || project === "TV") {
if (text.indexOf(".apk") !== -1 || href.indexOf("releases") !== -1) {
var matchApk = findAssetInReleases(releases, "apk");
if (matchApk) {
a.href = matchApk.url;
a.textContent = "Download: " + matchApk.tag + " (.apk)";
a.setAttribute("target", "_blank");
a.setAttribute("rel", "noopener");
}
}
}
});
});
}

View File

@@ -0,0 +1,42 @@
var RELEASE_CACHE = {};
function fetchProjectReleases(project) {
if (RELEASE_CACHE[project]) return Promise.resolve(RELEASE_CACHE[project]);
var url = "https://gitlab.com/api/v4/projects/vyla-entertainment%2F" + encodeURIComponent(project) + "/releases";
return fetch(url)
.then(function (res) {
if (!res.ok) throw new Error();
return res.json();
})
.then(function (data) {
RELEASE_CACHE[project] = Array.isArray(data) ? data : [];
return RELEASE_CACHE[project];
})
.catch(function () {
return [];
});
}
function findAssetInReleases(releases, ext) {
for (var r = 0; r < releases.length; r++) {
var rel = releases[r];
var tag = rel.tag_name || "";
var links = (rel.assets && rel.assets.links) || [];
for (var i = 0; i < links.length; i++) {
var l = links[i];
var name = (l.name || "").toLowerCase();
var url = (l.url || "").toLowerCase();
if (name.indexOf(ext) !== -1 || url.indexOf(ext) !== -1) {
return { tag: tag, url: l.direct_asset_url || l.url };
}
}
if (rel.description) {
var reg = new RegExp("\\[([^\\]]+)\\]\\((https?:[^)]+\\." + ext + "[^)]*)\\)", "i");
var match = rel.description.match(reg);
if (match) return { tag: tag, url: match[2] };
var rawMatch = rel.description.match(new RegExp("(https?:\\S+\\." + ext + ")", "i"));
if (rawMatch) return { tag: tag, url: rawMatch[1] };
}
}
return null;
}

1963
src/assets/js/main.js Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,230 @@
function syncSettingsUI() {
var m = settingsEl("settings-modal");
if (!m) return;
settingsEl("set-name").value = getPref("name", "");
settingsEl("set-api").value = getPref("api", "");
settingsEl("set-api").classList.remove("bad");
setApiHint("");
var accent = String(getPref("accent", "") || "").toLowerCase();
var validAccent = /^#[0-9a-f]{6}$/.test(accent);
m.querySelectorAll(".st-swatch[data-color]").forEach(function (b) {
b.classList.toggle("on", validAccent && b.getAttribute("data-color") === accent);
});
m.querySelector(".st-swatch.reset").classList.toggle("on", !validAccent);
m.querySelector(".st-swatch.custom").classList.toggle("on", validAccent && ACCENT_PRESETS.indexOf(accent) === -1);
settingsEl("set-accent").value = validAccent ? accent : "#ffffff";
var size = String(parseInt(getPref("text", "100"), 10) || 100);
m.querySelectorAll(".st-seg button").forEach(function (b) {
b.classList.toggle("on", b.getAttribute("data-v") === size);
});
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;
function measureSettings() {
var m = settingsEl("settings-modal");
if (!m) return;
var panel = m.querySelector(".sheet-panel");
var top = m.querySelector(".st-top");
var bottom = m.querySelector(".st-bottom");
if (top) panel.style.setProperty("--st-top", Math.max(0, top.offsetHeight - 10) + "px");
if (bottom) panel.style.setProperty("--st-bottom", Math.max(0, bottom.offsetHeight - 10) + "px");
}
function openSettings() {
var m = settingsEl("settings-modal");
if (!m) return;
syncSettingsUI();
m.querySelector(".sheet-panel").style.transform = "";
m.classList.add("active");
measureSettings();
document.body.style.overflow = "hidden";
}
function closeSettings() {
var m = settingsEl("settings-modal");
if (!m || !m.classList.contains("active")) return;
m.querySelector(".sheet-panel").style.transform = "";
m.classList.remove("active");
document.body.style.overflow = "";
}
function buildSettings() {
var trigger = settingsEl("settings-trigger");
if (trigger) trigger.innerHTML = icon("sliders");
var modal = document.createElement("div");
modal.id = "settings-modal";
modal.className = "sheet-overlay settings-overlay";
var swatches = ACCENT_PRESETS.map(function (c) {
return '<button type="button" class="st-swatch" data-color="' + c + '" style="--sw:' + c + '" aria-label="Accent color ' + c + '"></button>';
}).join("");
var sizes = TEXT_STEPS.map(function (s) {
return '<button type="button" data-v="' + s.v + '">' + s.l + "</button>";
}).join("");
modal.innerHTML =
'<div class="sheet-backdrop"></div>' +
'<div class="sheet-panel settings-panel" role="dialog" aria-modal="true" aria-label="Personalize">' +
'<div class="st-top"><div class="sheet-handle-bar"><div class="sheet-handle"></div></div>' +
'<h3 class="sheet-title">Make it yours</h3>' +
'<p class="sheet-desc">Saved only in this browser. Nothing leaves your device.</p></div>' +
'<div class="st-scroll">' +
'<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">Seasonal</div><div class="st-theme-grid">' + themeChips(THEMES_SEASONAL) + "</div>" +
"</div></section>" +
'<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">Stream API URL</span><input id="set-api" class="st-input" type="url" placeholder="https://your-server.example.com" autocomplete="off" spellcheck="false"><span id="set-api-hint" class="st-hint"></span></label>' +
"</div></section>" +
'<section class="st-group"><h4 class="st-heading">Appearance</h4><div class="st-card">' +
'<div class="st-row stack"><span class="st-text"><span class="st-label">Accent color</span><span class="st-hint">Headings, buttons and highlights.</span></span>' +
'<span class="st-swatches"><button type="button" class="st-swatch reset" aria-label="Use theme color" title="Theme default"></button>' + swatches +
'<label class="st-swatch custom" title="Custom color"><input id="set-accent" type="color" value="#ffffff" aria-label="Custom accent color"></label></span></div>' +
'<div class="st-row stack"><span class="st-text"><span class="st-label">Text size</span><span class="st-hint">Applies to documentation pages.</span></span>' +
'<div class="st-seg">' + sizes + "</div></div>" +
"</div></section>" +
'<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-motion", "Animations", "Transitions, falling decorations and effects.") +
switchRow("set-deco", "Decorations", "Spiders, snow, leaves and lights.") +
"</div></section>" +
"</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>";
document.body.appendChild(modal);
refreshThemeUI();
measureSettings();
if (window.ResizeObserver) {
var settingsRO = new ResizeObserver(measureSettings);
settingsRO.observe(modal.querySelector(".st-top"));
settingsRO.observe(modal.querySelector(".st-bottom"));
}
var panel = modal.querySelector(".sheet-panel");
var handle = modal.querySelector(".st-top");
modal.addEventListener("click", function (e) {
if (e.target.closest(".sheet-backdrop")) {
closeSettings();
return;
}
var saveBtn = e.target.closest(".st-save");
if (saveBtn) {
var apiBox = settingsEl("set-api");
var apiRaw = apiBox.value.trim();
commitApi();
if (apiRaw && !cleanApiUrl(apiRaw)) {
apiBox.focus();
return;
}
saveBtn.textContent = "Saved";
saveBtn.classList.add("done");
clearTimeout(saveTimer);
saveTimer = setTimeout(function () {
closeSettings();
saveBtn.textContent = "Save preferences";
saveBtn.classList.remove("done");
}, 450);
return;
}
var tb = e.target.closest(".st-theme");
if (tb) {
setTheme(tb.getAttribute("data-mode"));
return;
}
var sw = e.target.closest(".st-swatch[data-color]");
if (sw) {
var color = sw.getAttribute("data-color");
setPref("accent", color);
applyAccent(color);
syncSettingsUI();
return;
}
if (e.target.closest(".st-swatch.reset")) {
setPref("accent", null);
applyAccent("");
syncSettingsUI();
return;
}
var seg = e.target.closest(".st-seg button");
if (seg) {
var v = seg.getAttribute("data-v");
setPref("text", v === "100" ? null : v);
applyPreferences();
syncSettingsUI();
return;
}
if (e.target.closest(".st-reset")) {
Object.keys(PREF_KEYS).forEach(function (k) { setPref(k, null); });
applyTheme();
syncSettingsUI();
refreshPersonalPages();
}
});
settingsEl("set-name").addEventListener("input", function () {
setPref("name", this.value.trim());
});
function commitApi() {
var input = settingsEl("set-api");
var raw = input.value.trim();
var clean = cleanApiUrl(raw);
if (raw && !clean) {
input.classList.add("bad");
setApiHint("Enter a full URL starting with http:// or https://", true);
return;
}
input.classList.remove("bad");
setPref("api", clean);
input.value = clean;
setApiHint(clean ? "Saved. Docs examples now use your server." : "");
refreshPersonalPages();
}
settingsEl("set-api").addEventListener("change", commitApi);
settingsEl("set-api").addEventListener("keydown", function (e) {
if (e.key === "Enter") commitApi();
});
settingsEl("set-accent").addEventListener("input", function () {
var color = this.value.toLowerCase();
setPref("accent", color);
applyAccent(color);
syncSettingsUI();
});
[["set-video", "video"], ["set-motion", "motion"], ["set-deco", "deco"]].forEach(function (pair) {
settingsEl(pair[0]).addEventListener("change", function () {
setPref(pair[1], this.checked ? null : "off");
applyTheme();
});
});
var drag = null;
handle.addEventListener("touchstart", function (e) {
if (window.innerWidth > 900) return;
drag = { y: e.touches[0].clientY, d: 0 };
panel.classList.add("dragging");
}, { passive: true });
window.addEventListener("touchmove", function (e) {
if (!drag) return;
drag.d = Math.max(0, e.touches[0].clientY - drag.y);
panel.style.transform = "translateY(" + drag.d + "px)";
}, { passive: true });
window.addEventListener("touchend", function () {
if (!drag) return;
var d = drag.d;
drag = null;
panel.classList.remove("dragging");
if (d > 110) closeSettings();
else panel.style.transform = "";
});
document.addEventListener("keydown", function (e) {
if (e.key === "Escape" && modal.classList.contains("active")) closeSettings();
});
}