This commit is contained in:
2026-09-14 15:51:11 +02:00
parent ba5bc18b98
commit 22ffc3b51a
13 changed files with 3162 additions and 284 deletions
+595 -102
View File
@@ -701,39 +701,96 @@ html[theme='paper'] .metadata table th {
border-color: #e2e8f0;
}
/* Icons & GapRight - high contrast black colored */
/* Icons & GapRight - aligned with .input-actions button */
html[theme='light'] .gapRight i.iconset,
html[theme='light'] .gapRight svg.iconset,
html[theme='light'] .gapRight > .iconset,
html[theme='light'] .gapRight button,
html[theme='paper'] .gapRight i.iconset,
html[theme='paper'] .gapRight svg.iconset,
html[theme='paper'] .gapRight > .iconset {
color: #000 !important;
fill: #000 !important;
background: #f1f5f9 !important;
html[theme='paper'] .gapRight > .iconset,
html[theme='paper'] .gapRight button,
[theme='light'] .gapRight i.iconset,
[theme='light'] .gapRight svg.iconset,
[theme='light'] .gapRight > .iconset,
[theme='light'] .gapRight button,
[theme='paper'] .gapRight i.iconset,
[theme='paper'] .gapRight svg.iconset,
[theme='paper'] .gapRight > .iconset,
[theme='paper'] .gapRight button {
background: #ffffff !important;
border: 1px solid #cbd5e1 !important;
border-radius: 4px;
border-radius: 3px !important;
color: #334155 !important;
fill: #334155 !important;
}
html[theme='light'] .gapRight i.iconset:hover,
html[theme='light'] .gapRight svg.iconset:hover,
html[theme='light'] .gapRight > .iconset:hover,
html[theme='light'] .gapRight button:hover,
html[theme='paper'] .gapRight i.iconset:hover,
html[theme='paper'] .gapRight svg.iconset:hover {
background: #e2e8f0 !important;
color: #000 !important;
fill: #000 !important;
html[theme='paper'] .gapRight svg.iconset:hover,
html[theme='paper'] .gapRight > .iconset:hover,
html[theme='paper'] .gapRight button:hover,
[theme='light'] .gapRight i.iconset:hover,
[theme='light'] .gapRight svg.iconset:hover,
[theme='light'] .gapRight > .iconset:hover,
[theme='light'] .gapRight button:hover,
[theme='paper'] .gapRight i.iconset:hover,
[theme='paper'] .gapRight svg.iconset:hover,
[theme='paper'] .gapRight > .iconset:hover,
[theme='paper'] .gapRight button:hover,
html[theme='light'] .gapRight i.iconset.active,
html[theme='light'] .gapRight svg.iconset.active,
html[theme='light'] .gapRight > .iconset.active,
html[theme='light'] .gapRight button.active,
html[theme='paper'] .gapRight i.iconset.active,
html[theme='paper'] .gapRight svg.iconset.active,
html[theme='paper'] .gapRight > .iconset.active,
html[theme='paper'] .gapRight button.active,
[theme='light'] .gapRight i.iconset.active,
[theme='light'] .gapRight svg.iconset.active,
[theme='light'] .gapRight > .iconset.active,
[theme='light'] .gapRight button.active,
[theme='paper'] .gapRight i.iconset.active,
[theme='paper'] .gapRight svg.iconset.active,
[theme='paper'] .gapRight > .iconset.active,
[theme='paper'] .gapRight button.active,
html[theme='light'] .gapRight i.iconset.is-active,
html[theme='light'] .gapRight svg.iconset.is-active,
html[theme='light'] .gapRight > .iconset.is-active,
html[theme='light'] .gapRight button.is-active,
html[theme='paper'] .gapRight i.iconset.is-active,
html[theme='paper'] .gapRight svg.iconset.is-active,
html[theme='paper'] .gapRight > .iconset.is-active,
html[theme='paper'] .gapRight button.is-active,
[theme='light'] .gapRight i.iconset.is-active,
[theme='light'] .gapRight svg.iconset.is-active,
[theme='light'] .gapRight > .iconset.is-active,
[theme='light'] .gapRight button.is-active,
[theme='paper'] .gapRight i.iconset.is-active,
[theme='paper'] .gapRight svg.iconset.is-active,
[theme='paper'] .gapRight > .iconset.is-active,
[theme='paper'] .gapRight button.is-active {
background: #f1f5f9 !important;
border-color: var(--accent) !important;
color: var(--accent) !important;
fill: var(--accent) !important;
}
html[theme='light'] .gapRight #a_favo,
html[theme='paper'] .gapRight #a_favo {
html[theme='light'] .gapRight #a_favo.fa-solid,
html[theme='paper'] .gapRight #a_favo.fa-solid,
[theme='light'] .gapRight #a_favo.fa-solid,
[theme='paper'] .gapRight #a_favo.fa-solid {
color: #e11d48 !important;
fill: #e11d48 !important;
border-color: rgba(225, 29, 72, 0.4) !important;
}
html[theme='light'] i.iconset#a_oc,
html[theme='paper'] i.iconset#a_oc {
color: #000 !important;
fill: #000 !important;
color: inherit !important;
}
/* a_addtag and tag controls */
@@ -3155,23 +3212,41 @@ body.sidebar-right-hidden #sidebar-drag-zone {
}
.sidebar-media-placeholder.audio {
background: radial-gradient(circle at center, rgba(var(--accent-rgb, 153, 255, 0), 0.22) 0%, rgba(var(--accent-rgb, 153, 255, 0), 0.05) 70%), var(--nav-bg, #1e1e1e);
background: #000000;
color: var(--accent);
text-shadow: 0 0 16px rgba(var(--accent-rgb, 153, 255, 0), 0.35);
text-shadow: 0 0 16px color-mix(in srgb, var(--accent, #99ff00) 35%, transparent);
perspective: 800px;
overflow: hidden;
outline: none !important;
}
.sidebar-media-placeholder.audio.has-cover {
background: radial-gradient(circle at center, rgba(0, 0, 0, 0.45) 0%, rgba(0, 0, 0, 0.82) 85%), var(--nav-bg, #1e1e1e);
background: #000000;
}
.audio-reactive-bg {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 0;
opacity: 0;
transition: opacity 0.3s ease;
will-change: background, opacity;
}
.audio-cover-circle {
display: none;
display: flex;
align-items: center;
justify-content: center;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 155px;
height: 155px;
width: 125px;
height: 125px;
max-width: calc(100% - 40px);
max-height: calc(100% - 40px);
aspect-ratio: 1 / 1;
@@ -3179,31 +3254,63 @@ body.sidebar-right-hidden #sidebar-drag-zone {
background-size: cover;
background-position: center;
background-repeat: no-repeat;
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.88), 0 0 35px rgba(var(--accent-rgb, 153, 255, 0), 0.28), inset 0 0 20px rgba(0, 0, 0, 0.65);
border: 2px solid rgba(var(--accent-rgb, 153, 255, 0), 0.4);
overflow: hidden;
background-color: #000000;
background-image: none;
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.88), 0 0 150px color-mix(in srgb, var(--accent, #99ff00) 45%, transparent);
border: 2px solid color-mix(in srgb, var(--accent, #99ff00) 40%, transparent);
outline: none !important;
overflow: visible;
pointer-events: none;
z-index: 1;
will-change: transform, box-shadow, border-color;
}
.audio-cover-circle::after {
content: '';
.audio-eye-inner-canvas {
position: absolute;
inset: 0;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border-radius: 50%;
background: radial-gradient(circle at center, transparent 72%, rgba(0, 0, 0, 0.35) 92%, rgba(0, 0, 0, 0.75) 100%);
pointer-events: none;
z-index: 2;
}
.sidebar-media-placeholder.audio.has-cover .audio-cover-circle {
display: block;
.audio-cover-circle i {
font-size: 3.4rem;
color: var(--accent);
text-shadow: 0 0 16px color-mix(in srgb, var(--accent, #99ff00) 75%, transparent), 0 0 35px color-mix(in srgb, var(--accent, #99ff00) 40%, transparent);
z-index: 2;
position: relative;
pointer-events: none;
display: inline-block;
will-change: transform, filter;
transition: transform 0.04s linear;
}
.sidebar-media-placeholder.audio.has-cover i {
.sidebar-media-placeholder.audio.has-cover .audio-cover-circle i {
display: none !important;
}
.sidebar-media-placeholder.audio:has(.audio-cover-circle) > i {
display: none !important;
}
.sidebar-media-placeholder.audio .audio-cover-circle {
display: flex;
}
.thumb > .sidebar-media-placeholder .audio-cover-circle,
.album-thumb-item > .sidebar-media-placeholder .audio-cover-circle,
.item-preview .sidebar-media-placeholder .audio-cover-circle {
display: none !important;
}
.thumb > .sidebar-media-placeholder > i,
.album-thumb-item > .sidebar-media-placeholder > i,
.item-preview .sidebar-media-placeholder > i {
display: flex !important;
}
.sidebar-media-placeholder.hidden {
display: none !important;
}
@@ -3233,6 +3340,13 @@ body.sidebar-right-hidden #sidebar-drag-zone {
pointer-events: none;
font-size: clamp(2rem, 5.5vw, 3.8rem);
border-radius: inherit;
background: #000000 !important;
}
.album-gallery-container.is-audio-active,
.album-audio-wrapper,
.embed-responsive:has(.sidebar-media-placeholder.audio) {
background: #000000 !important;
}
.v0ck:fullscreen > .sidebar-media-placeholder.audio,
@@ -3252,6 +3366,13 @@ body.sidebar-right-hidden #sidebar-drag-zone {
max-height: calc(100% - 100px);
}
.v0ck:fullscreen .audio-cover-circle i,
.v0ck.v0ck_fullscreen .audio-cover-circle i,
#main:fullscreen .v0ck.v0ck_fullscreen .audio-cover-circle i,
#onara-modal:fullscreen .v0ck.v0ck_fullscreen .audio-cover-circle i {
font-size: clamp(5rem, 14vmin, 12rem);
}
.sidebar-media-placeholder.audio i {
position: relative;
z-index: 2;
@@ -3311,6 +3432,50 @@ body.sidebar-right-hidden #sidebar-drag-zone {
display: none !important;
}
/* Embedded in Right Sidebar */
.sidebar-tuner-container {
display: none;
flex: 1;
min-height: 0;
overflow-y: auto;
scrollbar-width: thin;
scrollbar-color: rgba(255, 255, 255, 0.15) transparent;
padding: 0;
touch-action: pan-y;
}
.sidebar-tuner-container::-webkit-scrollbar {
width: 5px;
}
.sidebar-tuner-container::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.15);
border-radius: 4px;
}
.sidebar-tuner-container.active {
display: block;
}
.f0ck-audio-tuner-panel.in-sidebar {
position: static;
width: 100%;
max-height: none;
overflow-y: visible;
background: transparent;
backdrop-filter: none;
-webkit-backdrop-filter: none;
border: none;
border-radius: 0;
box-shadow: none;
padding: 14px 14px 40px 14px;
box-sizing: border-box;
}
.f0ck-audio-tuner-panel.in-sidebar .f0ck-tuner-close {
display: none;
}
.f0ck-tuner-header {
display: flex;
justify-content: space-between;
@@ -3431,6 +3596,126 @@ body.sidebar-right-hidden #sidebar-drag-zone {
color: #fff;
}
.f0ck-tuner-presets-bar {
background: rgba(255, 255, 255, 0.04);
border: 1px solid rgba(255, 255, 255, 0.10);
border-radius: 8px;
padding: 10px;
margin-bottom: 14px;
display: flex;
flex-direction: column;
gap: 8px;
}
.f0ck-tuner-presets-select-wrap {
display: flex;
gap: 6px;
align-items: center;
}
.f0ck-tuner-preset-select {
flex: 1;
background: rgba(0, 0, 0, 0.45);
border: 1px solid rgba(255, 255, 255, 0.18);
border-radius: 6px;
color: #fff;
padding: 6px 8px;
font-size: 11px;
font-family: inherit;
cursor: pointer;
outline: none;
}
.f0ck-tuner-preset-select:focus {
border-color: var(--accent, #99ff00);
}
.f0ck-tuner-preset-select optgroup {
color: var(--accent, #99ff00);
background: #111;
font-weight: bold;
}
.f0ck-tuner-preset-select option {
color: #eee;
background: #181818;
}
.f0ck-tuner-btn-icon {
background: rgba(255, 255, 255, 0.06);
border: 1px solid rgba(255, 255, 255, 0.14);
color: #bbb;
border-radius: 6px;
padding: 6px 9px;
font-size: 11px;
cursor: pointer;
transition: all 0.15s ease;
display: flex;
align-items: center;
justify-content: center;
}
.f0ck-tuner-btn-icon:disabled {
opacity: 0.3;
cursor: not-allowed;
}
.f0ck-tuner-btn-icon:not(:disabled):hover {
background: rgba(255, 50, 50, 0.25);
border-color: rgba(255, 50, 50, 0.5);
color: #ff5555;
}
.f0ck-tuner-presets-actions {
display: flex;
gap: 6px;
align-items: center;
}
.f0ck-tuner-preset-input {
flex: 1;
background: rgba(0, 0, 0, 0.35);
border: 1px solid rgba(255, 255, 255, 0.14);
border-radius: 6px;
color: #fff;
padding: 5px 8px;
font-size: 11px;
font-family: inherit;
outline: none;
}
.f0ck-tuner-preset-input:focus {
border-color: var(--accent, #99ff00);
}
.f0ck-tuner-btn-save-preset,
.f0ck-tuner-btn-import-preset {
background: rgba(255, 255, 255, 0.08);
border: 1px solid rgba(255, 255, 255, 0.18);
color: #eee;
border-radius: 6px;
padding: 5px 10px;
font-size: 11px;
font-weight: 600;
cursor: pointer;
transition: all 0.15s ease;
display: flex;
align-items: center;
gap: 4px;
white-space: nowrap;
}
.f0ck-tuner-btn-save-preset:hover {
background: var(--accent, #99ff00);
border-color: var(--accent, #99ff00);
color: #000;
}
.f0ck-tuner-btn-import-preset:hover {
background: rgba(255, 255, 255, 0.2);
color: #fff;
}
.sidebar-video-details {
display: flex;
margin-top: 8px;
@@ -6725,8 +7010,10 @@ body.layout-modern.sidebar-right-hidden .pagination-container-fluid {
.gapRight {
align-items: center;
display: flex;
display: inline-flex;
gap: 6px;
flex-wrap: wrap;
vertical-align: middle;
}
.admin-lock-btn {
@@ -6938,7 +7225,8 @@ body:has(.index-container) > .pagewrapper > #main {
overflow-y: auto !important;
overflow-x: hidden !important;
-webkit-overflow-scrolling: touch;
overscroll-behavior-y: contain;
overscroll-behavior-y: auto;
overscroll-behavior-x: contain;
box-sizing: border-box;
padding: 5px 20px 75px 20px;
margin: 0;
@@ -7772,7 +8060,7 @@ a.removetag i {
background: transparent;
border: none;
padding: 0;
margin: 0;
margin: 0 0 0 5px;
cursor: pointer;
color: inherit;
display: inline-flex;
@@ -7783,44 +8071,15 @@ a.removetag i {
vertical-align: middle;
border-radius: 50%;
outline: none;
opacity: 0.85;
width: 14px;
max-width: 14px;
overflow: visible;
pointer-events: auto;
transform: scale(1);
transition: all 0.22s cubic-bezier(0.34, 1.56, 0.64, 1);
}
@media (hover: hover) {
.tag-badge:not(.tag-is-excluded) .tag-exclude-btn {
opacity: 0;
width: 0;
max-width: 0;
margin-left: 0;
overflow: hidden;
transform: scale(0.5);
pointer-events: none;
}
.tag-badge:hover .tag-exclude-btn,
.tag-badge:focus-within .tag-exclude-btn {
opacity: 0.85;
width: 14px;
max-width: 14px;
margin-left: 5px;
overflow: visible;
transform: scale(1);
pointer-events: auto;
}
}
@media (hover: none) {
.tag-badge .tag-exclude-btn {
opacity: 0.7;
width: 14px;
max-width: 14px;
margin-left: 4px;
overflow: visible;
pointer-events: auto;
transform: scale(1);
}
}
.tag-badge .tag-exclude-btn:hover,
.tag-badge .tag-exclude-btn:focus-visible {
opacity: 1;
@@ -7845,12 +8104,6 @@ a.removetag i {
.tag-badge.tag-is-excluded .tag-exclude-btn {
opacity: 0.95;
width: 14px;
max-width: 14px;
margin-left: 5px;
overflow: visible;
pointer-events: auto;
transform: scale(1);
color: #ff4757;
}
@@ -9674,15 +9927,18 @@ table img {
}
}
/* gapRight icon colors: white for all, pink for favorites */
.gapRight i.iconset {
color: #fff !important;
fill: #fff !important;
/* gapRight icon colors & active states */
.gapRight i.iconset,
.gapRight svg.iconset,
.gapRight button {
color: var(--white, #fff);
fill: var(--white, #fff);
}
.gapRight #a_favo {
.gapRight #a_favo.fa-solid {
color: #ff6b9d !important;
fill: #ff6b9d !important;
border-color: rgba(255, 107, 157, 0.4) !important;
}
/* pin icon */
@@ -9701,10 +9957,6 @@ table img {
transform: rotate(-45deg);
}
.iconset#subscribe-btn {
border-style: outset;
}
.imageDoor:hover:after {
content: "";
background-image: var(--hover-image);
@@ -14695,6 +14947,42 @@ body.layout-modern .tag-ac-input {
margin: 5px;
}
.item-preview .sidebar-thumb-link {
position: relative;
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 5px;
margin: 5px;
overflow: hidden;
flex-shrink: 0;
text-decoration: none;
}
.item-preview .sidebar-media-placeholder {
position: absolute;
inset: 0;
width: 32px;
height: 32px;
font-size: 14px;
border-radius: inherit;
display: flex;
align-items: center;
justify-content: center;
}
.item-preview .sidebar-media-placeholder.audio {
background: #000000;
color: var(--accent);
}
.item-preview .sidebar-media-placeholder.audio > i {
display: flex !important;
font-size: 14px;
}
/*
PRIVATE MESSAGES / DM SYSTEM
*/
@@ -16347,37 +16635,109 @@ span.gchat-post-card--loading {
.gapRight,
body.layout-modern .gapRight,
body.layout-legacy .gapRight {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 6px;
flex-wrap: wrap;
vertical-align: middle;
}
.gapRight>svg.iconset,
.gapRight>i.iconset,
.gapRight>button,
.gapRight>.iconset,
.gapRight i.iconset,
.gapRight svg.iconset,
.gapRight button,
body.layout-modern .gapRight>svg.iconset,
body.layout-modern .gapRight>i.iconset,
body.layout-modern .gapRight>button,
body.layout-modern .gapRight>.iconset,
body.layout-legacy .gapRight>svg.iconset,
body.layout-legacy .gapRight>i.iconset {
body.layout-legacy .gapRight>i.iconset,
body.layout-legacy .gapRight>button,
body.layout-legacy .gapRight>.iconset {
height: 30px;
min-width: 30px;
width: 30px;
margin: 5px;
padding: 5px;
right: 0px;
background: var(--badge-tag);
padding: 0;
box-sizing: border-box;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 18px;
box-sizing: border-box;
gap: 5px;
border-radius: 3px;
border: 1px solid var(--nav-border-color, rgba(255, 255, 255, 0.15));
background: var(--navigation-links-bg, rgba(255, 255, 255, 0.08));
color: var(--white, #fff);
fill: var(--white, #fff);
font-family: inherit;
font-size: 13px;
font-weight: bold;
line-height: 1;
cursor: pointer;
margin: 0;
position: static;
right: auto;
vertical-align: middle;
text-decoration: none;
transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease, opacity 0.15s ease;
}
.gapRight>svg.iconset:hover,
.gapRight>i.iconset:hover,
.gapRight>button:hover,
.gapRight>.iconset:hover,
.gapRight i.iconset:hover,
.gapRight svg.iconset:hover,
.gapRight button:hover,
.gapRight>svg.iconset.active,
.gapRight>i.iconset.active,
.gapRight>button.active,
.gapRight>.iconset.active,
.gapRight i.iconset.active,
.gapRight svg.iconset.active,
.gapRight button.active,
.gapRight>svg.iconset.is-active,
.gapRight>i.iconset.is-active,
.gapRight>button.is-active,
.gapRight>.iconset.is-active,
.gapRight i.iconset.is-active,
.gapRight svg.iconset.is-active,
.gapRight button.is-active,
body.layout-modern .gapRight>svg.iconset:hover,
body.layout-modern .gapRight>i.iconset:hover,
body.layout-modern .gapRight>button:hover,
body.layout-modern .gapRight>.iconset:hover,
body.layout-modern .gapRight>svg.iconset.active,
body.layout-modern .gapRight>i.iconset.active,
body.layout-modern .gapRight>button.active,
body.layout-modern .gapRight>.iconset.active,
body.layout-legacy .gapRight>svg.iconset:hover,
body.layout-legacy .gapRight>i.iconset:hover,
body.layout-legacy .gapRight>button:hover,
body.layout-legacy .gapRight>.iconset:hover,
body.layout-legacy .gapRight>svg.iconset.active,
body.layout-legacy .gapRight>i.iconset.active,
body.layout-legacy .gapRight>button.active,
body.layout-legacy .gapRight>.iconset.active {
background: var(--nav-link-hover-bg, rgba(255, 255, 255, 0.15)) !important;
border-color: var(--accent) !important;
color: var(--accent) !important;
fill: var(--accent) !important;
text-decoration: none;
}
.gapRight>.iconset#a_favo,
body.layout-legacy .gapRight>.iconset#a_favo {
fill: #ff009b;
fill: inherit;
}
/* OC Toggle Icon - now i element, color inherited from .gapRight i.iconset */
/* OC Toggle Icon - inherits from .gapRight i.iconset */
i.iconset#a_oc {
color: #fff !important;
fill: #fff !important;
color: inherit;
fill: inherit;
}
/* OC Feature */
@@ -20246,7 +20606,8 @@ body.onara-modal-open .admin-bar.open {
overflow-x: hidden !important;
-webkit-overflow-scrolling: touch;
scrollbar-width: none !important;
overscroll-behavior: contain !important;
overscroll-behavior-y: auto !important;
overscroll-behavior-x: contain !important;
box-sizing: border-box !important;
opacity: 0;
transform: scale(0.99);
@@ -21026,6 +21387,8 @@ div#flash,
.album-gallery-container {
position: relative;
overflow: hidden;
max-width: 100%;
box-sizing: border-box;
}
.album-active-image {
@@ -21082,7 +21445,8 @@ div#flash,
top: 14px;
left: 50%;
transform: translateX(-50%);
pointer-events: auto;
pointer-events: none;
opacity: 0;
background: rgba(16, 16, 20, 0.75);
border: 1px solid rgba(255, 255, 255, 0.2);
backdrop-filter: blur(12px);
@@ -21098,6 +21462,24 @@ div#flash,
box-shadow: 0 4px 14px rgba(0, 0, 0, 0.4);
letter-spacing: 0.03em;
user-select: none;
transition: opacity 0.25s cubic-bezier(0.4, 0, 0.2, 1), transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}
@media (hover: hover) {
.album-gallery-container:hover .album-counter-pill,
.album-gallery-container:focus-within .album-counter-pill {
opacity: 1;
pointer-events: auto;
}
}
.album-gallery-container.v0ck_hover .album-counter-pill,
.album-gallery-container.strip-peek .album-counter-pill,
.album-gallery-container:has(.v0ck.v0ck_hover) .album-counter-pill,
.album-counter-pill.is-visible,
.album-counter-pill.strip-peek {
opacity: 1;
pointer-events: auto;
}
.album-counter-pill i {
@@ -21111,6 +21493,7 @@ div#flash,
left: 50%;
transform: translateX(-50%) translateY(10px);
max-width: calc(100% - 32px);
box-sizing: border-box;
display: flex;
align-items: center;
gap: 8px;
@@ -21122,16 +21505,101 @@ div#flash,
border-radius: 12px;
z-index: 22;
overflow-x: auto;
overflow-y: hidden;
overscroll-behavior: contain;
overscroll-behavior-x: contain;
overscroll-behavior-y: none;
-webkit-overflow-scrolling: touch;
touch-action: pan-x;
scrollbar-width: none;
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.45);
opacity: 0;
pointer-events: none;
cursor: grab;
user-select: none;
-webkit-user-select: none;
scroll-behavior: smooth;
transition: opacity 0.25s cubic-bezier(0.4, 0, 0.2, 1), transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}
.album-gallery-container:hover .album-thumbnails-strip,
.album-gallery-container:focus-within .album-thumbnails-strip,
.album-thumbnails-strip.is-visible {
.album-thumbnails-strip.is-dragging {
cursor: grabbing !important;
scroll-behavior: auto !important;
}
.album-thumb-item {
cursor: pointer;
}
.album-thumb-item img {
-webkit-user-drag: none;
user-select: none;
}
/* Audio Track Info Badge (Artist & Song Title on top-left) */
.audio-track-info-badge {
position: absolute;
top: 5px;
left: 10px;
text-align: left;
z-index: 25;
pointer-events: none;
opacity: 0;
transition: opacity 0.2s ease;
}
.audio-track-info-badge.is-visible {
opacity: 1;
}
.audio-track-info-details {
display: flex;
flex-direction: column;
align-items: flex-start;
text-align: left;
min-width: 0;
line-height: 1.25;
}
.audio-track-artist {
font-size: 0.72rem;
font-weight: 700;
letter-spacing: 0.07em;
text-transform: uppercase;
color: var(--accent);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
text-align: left;
align-self: flex-start;
}
.audio-track-title {
font-size: 0.88rem;
font-weight: 700;
color: #fff;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
text-shadow: 0 1px 4px rgba(0, 0, 0, 0.8);
text-align: left;
align-self: flex-start;
}
@media (hover: hover) {
.album-gallery-container:hover .album-thumbnails-strip,
.album-gallery-container:focus-within .album-thumbnails-strip {
opacity: 1;
pointer-events: auto;
transform: translateX(-50%) translateY(0);
}
}
.album-gallery-container.v0ck_hover .album-thumbnails-strip,
.album-gallery-container.strip-peek .album-thumbnails-strip,
.album-gallery-container:has(.v0ck.v0ck_hover) .album-thumbnails-strip,
.album-thumbnails-strip.is-visible,
.album-thumbnails-strip.strip-peek {
opacity: 1;
pointer-events: auto;
transform: translateX(-50%) translateY(0);
@@ -21141,8 +21609,7 @@ div#flash,
display: none;
}
.album-video-wrapper,
.album-audio-wrapper {
.album-video-wrapper {
position: absolute;
inset: 0;
width: 100%;
@@ -21150,6 +21617,14 @@ div#flash,
background: #000;
}
.album-audio-wrapper {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
background: transparent;
}
.album-gallery-container.is-video-active .album-thumbnails-strip,
.album-gallery-container.is-audio-active .album-thumbnails-strip {
bottom: 58px;
@@ -21180,6 +21655,9 @@ div#flash,
padding: 0;
margin: 0;
background: #000;
touch-action: pan-x;
user-select: none;
-webkit-user-select: none;
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}
@@ -21261,5 +21739,20 @@ div#flash,
bottom: 8px;
padding: 4px 8px;
gap: 6px;
max-width: calc(100% - 16px);
box-sizing: border-box;
}
.audio-track-info-badge {
top: 8px;
left: 8px;
padding: 4px 8px;
gap: 6px;
max-width: calc(100% - 70px);
}
.audio-track-title {
font-size: 0.78rem;
}
.audio-track-artist {
font-size: 0.68rem;
}
}
+4 -4
View File
@@ -6,7 +6,7 @@
background-size: contain;
background-repeat: no-repeat;
background-position: center center;
touch-action: none; /* Prevent pull-to-refresh and scroll while interacting */
touch-action: pan-y;
z-index: 0;
}
@@ -556,8 +556,8 @@
transform: translate(-50%, 0);
}
/* Hide mouse cursor on inactivity in fullscreen */
.v0ck.v0ck_fullscreen:not(.v0ck_hover),
.v0ck.v0ck_fullscreen:not(.v0ck_hover) * {
/* Hide mouse cursor on inactivity when player controls auto-hide */
.v0ck:not(.v0ck_hover),
.v0ck:not(.v0ck_hover) * {
cursor: none !important;
}
+54 -8
View File
@@ -27,6 +27,8 @@ class CommentSystem {
if (this.displayMode === 1) this.sort = 'old';
this.customEmojis = CommentSystem.emojiCache || {};
this._selfPostedCommentIds = new Set();
this._pendingSelfCommentTexts = new Set();
this.icons = {
reply: `<i class="fa-solid fa-reply"></i>`,
@@ -472,6 +474,34 @@ class CommentSystem {
}
}
_isSelfComment(data) {
if (!data) return false;
if (data.id && this._selfPostedCommentIds?.has(data.id)) return true;
if (data.body && this._pendingSelfCommentTexts?.has(data.body)) return true;
const session = window.f0ckSession || {};
const currentUserId = session.id || session.user_id;
if (currentUserId && data.user_id && parseInt(data.user_id, 10) === parseInt(currentUserId, 10)) {
return true;
}
const currentUsername = session.user || this.user;
if (currentUsername && data.username && currentUsername.toLowerCase() === data.username.toLowerCase()) {
return true;
}
if (session.is_anon && data.is_anon) {
if (data.anon_fingerprint && session.fingerprint && data.anon_fingerprint === session.fingerprint) {
return true;
}
if (data.anon_short_fingerprint && session.fingerprint && session.fingerprint.includes(data.anon_short_fingerprint)) {
return true;
}
}
return false;
}
handleLiveComment(data) {
if (!this.container || !this.itemId) return;
// 1. Check if comment belongs to this item
@@ -537,14 +567,20 @@ class CommentSystem {
// Danmaku: fire one-shot for other users' comments.
// Own comment is handled by the optimistic submit path (fire + addItem).
// The _loadDanmaku re-render will add this comment to the items rotation.
const currentUser = window.f0ckSession?.user;
if (window.danmakuInstance && data.username !== currentUser) {
const isSelf = this._isSelfComment(data);
if (window.danmakuInstance && !isSelf) {
window.danmakuInstance.fire(
data.body,
data.display_name || data.username || '?',
data.username_color || null
);
window.danmakuInstance.addItem({
id: data.id,
content: data.body,
video_time: data.video_time ?? null,
display_name: data.display_name || data.username || '?',
username_color: data.username_color || null
});
}
// Update backlinks for live comment
@@ -3448,6 +3484,7 @@ class CommentSystem {
} else {
this.isMainSubmitting = true;
}
this._pendingSelfCommentTexts.add(text);
let retryCount = 0;
const maxRetries = 20; // Allow several minutes of retrying during restart
@@ -3534,7 +3571,7 @@ class CommentSystem {
// For 4xx errors, we stop and show the error to user (likely validation or auth)
const json = await res.json().catch(() => ({}));
alert('Error: ' + (json.message || `Status ${res.status}`));
this._finishSubmit(submitBtn, originalBtnHtml, parentId);
this._finishSubmit(submitBtn, originalBtnHtml, parentId, text);
return;
}
@@ -3692,6 +3729,11 @@ class CommentSystem {
poll: null
};
if (json.comment?.id) {
this._selfPostedCommentIds.add(json.comment.id);
}
this._pendingSelfCommentTexts.delete(text);
// Danmaku: fire immediately (one-shot) + add to future rotation
if (window.danmakuInstance) {
window.danmakuInstance.fire(
@@ -3700,6 +3742,7 @@ class CommentSystem {
session.username_color || null
);
window.danmakuInstance.addItem({
id: newComment.id,
content: text,
video_time: newComment.video_time ?? null,
display_name: session.display_name || currentUsername || '?',
@@ -3810,10 +3853,10 @@ class CommentSystem {
}
this._silentSync();
this._finishSubmit(submitBtn, originalBtnHtml, parentId);
this._finishSubmit(submitBtn, originalBtnHtml, parentId, text);
} else {
alert('Error: ' + json.message);
this._finishSubmit(submitBtn, originalBtnHtml, parentId);
this._finishSubmit(submitBtn, originalBtnHtml, parentId, text);
}
} catch (err) {
console.warn(`[CommentSystem] Submit attempt ${retryCount + 1} failed:`, err);
@@ -3825,7 +3868,7 @@ class CommentSystem {
setTimeout(attemptSubmit, delay);
} else {
alert('Failed to send comment after multiple attempts. Please check your connection.');
this._finishSubmit(submitBtn, originalBtnHtml, parentId);
this._finishSubmit(submitBtn, originalBtnHtml, parentId, text);
}
}
};
@@ -3857,7 +3900,10 @@ class CommentSystem {
console.log('[ensureBtn] done, button in DOM:', !!contentEl.querySelector('.load-full-comment-btn'));
}
_finishSubmit(btn, originalHtml, parentId) {
_finishSubmit(btn, originalHtml, parentId, submittedText = null) {
if (submittedText) {
this._pendingSelfCommentTexts?.delete(submittedText);
}
if (parentId) {
this.pendingSubmissions.delete(parentId);
} else {
+10
View File
@@ -195,6 +195,7 @@ class Danmaku {
const mapped = comments
.filter(c => !c.is_deleted && c.content)
.map(c => ({
id: c.id || null,
text: this._prepareText(c.content),
username: c.display_name || c.username || '?',
color: c.username_color || null,
@@ -288,6 +289,7 @@ class Danmaku {
*/
addItem(comment) {
if (!comment || !comment.content) return;
if (comment.id && this.items && this.items.some(i => i.id === comment.id)) return;
const duration = this.media.duration;
const hasDuration = isFinite(duration) && duration > 0;
@@ -307,6 +309,7 @@ class Danmaku {
}
const item = {
id: comment.id || null,
video_time: t,
text: this._prepareText(comment.content),
username: comment.display_name || comment.username || '?',
@@ -314,6 +317,13 @@ class Danmaku {
fired: true // mark as already fired — caller handles any immediate one-shot
};
if (this._synthClock && this._flashPool) {
if (!this._flashPool.some(i => (comment.id && i.id === comment.id) || (i.text === item.text && i.username === item.username))) {
this._flashPool.push(item);
}
return;
}
// Insert in sorted order
const idx = this.items.findIndex(i => i.video_time > t);
if (idx === -1) this.items.push(item);
+2255 -150
View File
File diff suppressed because it is too large Load Diff
+22 -3
View File
@@ -532,14 +532,32 @@
else if (rClass === 'sfw' && blurSfw) isBlurred = true;
else if (rClass === 'untagged' && blurUntagged) isBlurred = true;
let thumbUrl = `/t/${c.item_id}.webp`;
const mime = c.mime || c.item_mime || '';
const activeDest = c.item_dest || c.dest || '';
const isAudio = mime.startsWith('audio/') || (!mime && activeDest.match(/\.(mp3|wav|ogg|flac|m4a|aac|opus)$/i));
let thumbUrl = c.thumb || `/t/${c.item_id}.webp`;
if (isBlurred) {
thumbUrl = `/t/${c.item_id}_blur.webp`;
const baseThumb = thumbUrl.replace(/\.webp$/, '');
thumbUrl = `${baseThumb}_blur.webp`;
}
if (window.applyThumbCacheBust) thumbUrl = window.applyThumbCacheBust(thumbUrl);
mediaHtml = `<img src="${thumbUrl}" style="width: 32px; height: 32px; object-fit: cover; border-radius: 2px;" loading="lazy" onerror="this.style.display='none'" />`;
if (isAudio && !c.has_coverart) {
mediaHtml = `
<div class="sidebar-media-placeholder audio">
<i class="fa-solid fa-music"></i>
</div>
`;
} else {
mediaHtml = `
<img src="${thumbUrl}" style="width: 32px; height: 32px; object-fit: cover; border-radius: 2px;" loading="lazy" onerror="this.style.display='none'; if(this.nextElementSibling) this.nextElementSibling.classList.remove('hidden');" />
<div class="sidebar-media-placeholder ${isAudio ? 'audio' : ''} hidden">
<i class="${isAudio ? 'fa-solid fa-music' : 'fa-solid fa-image'}"></i>
</div>
`;
}
itemPreview = `
<div class="item-preview">
@@ -1869,6 +1887,7 @@
}
}
};
window.switchSidebarTab = switchSidebarTab;
const initSidebarTabs = () => {
const tabsContainer = document.querySelector('.sidebar-tabs');
+39 -8
View File
@@ -88,6 +88,8 @@ const updateHoverStates = () => {
const isOver = mouseX >= rect.left && mouseX <= rect.right &&
mouseY >= rect.top && mouseY <= rect.bottom;
p.classList.toggle("v0ck_hover", isOver);
const gal = p.closest('.album-gallery-container');
if (gal) gal.classList.toggle("v0ck_hover", isOver);
});
};
@@ -117,6 +119,8 @@ class v0ck {
if (mouseX >= rect.left && mouseX <= rect.right &&
mouseY >= rect.top && mouseY <= rect.bottom) {
parent.classList.add("v0ck_hover", "v0ck_no_transition");
const gal = parent.closest('.album-gallery-container');
if (gal) gal.classList.add("v0ck_hover");
// Remove no-transition after a frame
setTimeout(() => parent.classList.remove("v0ck_no_transition"), 50);
}
@@ -142,14 +146,24 @@ class v0ck {
if (!ph) {
ph = document.createElement('div');
ph.className = 'sidebar-media-placeholder audio';
ph.innerHTML = '<div class="audio-cover-circle"></div><i class="fa-solid fa-music"></i>';
ph.innerHTML = '<div class="audio-cover-circle"><i class="fa-solid fa-music"></i></div>';
player.prepend(ph);
}
let coverCircle = ph.querySelector('.audio-cover-circle');
if (!coverCircle) {
coverCircle = document.createElement('div');
coverCircle.className = 'audio-cover-circle';
coverCircle.innerHTML = '<i class="fa-solid fa-music"></i>';
ph.insertBefore(coverCircle, ph.firstChild);
} else {
if (!coverCircle.querySelector('i')) {
const existingI = ph.querySelector(':scope > i');
if (existingI) {
coverCircle.appendChild(existingI);
} else {
coverCircle.insertAdjacentHTML('beforeend', '<i class="fa-solid fa-music"></i>');
}
}
}
player.style.backgroundImage = 'none';
player.style.backgroundColor = 'transparent';
@@ -157,7 +171,7 @@ class v0ck {
coverCircle.style.backgroundImage = `url('${poster}')`;
ph.classList.add('has-cover');
} else {
coverCircle.style.backgroundImage = 'none';
coverCircle.style.backgroundImage = '';
ph.classList.remove('has-cover');
}
}
@@ -203,6 +217,23 @@ class v0ck {
let wasPausedWhenStarted = false;
// Mobile tap-to-show-controls: true when this touch revealed the controls bar
let controlsJustShown = false;
const setHover = (active) => {
if (active) {
player.classList.add('v0ck_hover');
const gal = player.closest('.album-gallery-container');
if (gal) gal.classList.add('v0ck_hover');
} else {
player.classList.remove('v0ck_hover');
const gal = player.closest('.album-gallery-container');
if (gal) {
gal.classList.remove('v0ck_hover');
gal.classList.remove('strip-peek');
const strip = gal.querySelector('.album-thumbnails-strip');
if (strip) strip.classList.remove('strip-peek');
}
}
};
const speedIndicator = player.querySelector('.v0ck_speed_indicator');
// (mouse position is now tracked via docMouseX/docMouseY in resetControlsTimer block)
@@ -343,7 +374,7 @@ class v0ck {
if (isMobile && controlsJustShown) {
// First tap: controls were just revealed by this touch — don't toggle play
controlsJustShown = false;
player.classList.add('v0ck_hover');
setHover(true);
return;
}
controlsJustShown = false;
@@ -353,7 +384,7 @@ class v0ck {
toggle.addEventListener('click', togglePlay);
overlay.addEventListener('click', e => {
e.stopPropagation();
player.classList.add('v0ck_hover');
setHover(true);
togglePlay();
});
video.addEventListener('play', updatePlayIcon);
@@ -831,7 +862,7 @@ class v0ck {
}
if (isMobile && !isInsidePlayer && !isFlashYankUI) {
player.classList.remove('v0ck_hover');
setHover(false);
}
});
@@ -928,7 +959,7 @@ class v0ck {
const isFullscreen = player.classList.contains('v0ck_fullscreen');
if (!video.paused || isFullscreen) {
controlsTimer = setTimeout(() => {
player.classList.remove('v0ck_hover');
setHover(false);
if (settingsMenu && !settingsMenu.classList.contains('v0ck_hidden')) {
settingsMenu.classList.add('v0ck_hidden');
document.dispatchEvent(new CustomEvent('v0ck_settings_closed'));
@@ -950,7 +981,7 @@ class v0ck {
docMouseX = e.clientX;
docMouseY = e.clientY;
}
player.classList.add('v0ck_hover');
setHover(true);
resetControlsTimer();
}
@@ -998,7 +1029,7 @@ class v0ck {
}
docMouseX = -1;
docMouseY = -1;
player.classList.remove('v0ck_hover');
setHover(false);
clearTimeout(controlsTimer);
});