Upload 3 files
Browse files- static/app.js +61 -3
- static/index.html +2 -2
- static/style.css +95 -21
static/app.js
CHANGED
|
@@ -67,6 +67,14 @@ const snippetQueue = [];
|
|
| 67 |
const snippetCache = new Map();
|
| 68 |
const snippetControllers = new Set();
|
| 69 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 70 |
function themeIcon(isDark) {
|
| 71 |
const shape = isDark
|
| 72 |
? '<path d="M20 15.5A8 8 0 1 1 8.5 4 6.5 6.5 0 0 0 20 15.5Z"/>'
|
|
@@ -464,11 +472,18 @@ function updateFilterVisibility() {
|
|
| 464 |
}
|
| 465 |
|
| 466 |
function showToast(message, duration = 2000) {
|
|
|
|
|
|
|
|
|
|
| 467 |
DOM.toast.textContent = message;
|
| 468 |
DOM.toast.style.display = "";
|
| 469 |
-
clearTimeout(showToast._timer);
|
| 470 |
showToast._timer = setTimeout(() => {
|
| 471 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 472 |
}, duration);
|
| 473 |
}
|
| 474 |
|
|
@@ -534,9 +549,19 @@ function applyTheme() {
|
|
| 534 |
}
|
| 535 |
|
| 536 |
function toggleTheme() {
|
|
|
|
|
|
|
| 537 |
STATE.isDark = !STATE.isDark;
|
| 538 |
applyTheme();
|
| 539 |
localStorage.setItem("theme", STATE.isDark ? "dark" : "light");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 540 |
}
|
| 541 |
|
| 542 |
function applyMobileMode() {
|
|
@@ -765,6 +790,7 @@ async function applyInitialSearch(sequence) {
|
|
| 765 |
STATE.results = data.results || [];
|
| 766 |
STATE.isLoading = false;
|
| 767 |
DOM.resultsLoading.style.display = "none";
|
|
|
|
| 768 |
renderResults();
|
| 769 |
updateStatus();
|
| 770 |
DOM.resultsContainer.scrollTop = 0;
|
|
@@ -810,6 +836,12 @@ function prefetchNextPage() {
|
|
| 810 |
});
|
| 811 |
}
|
| 812 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 813 |
async function doSearch() {
|
| 814 |
if (STATE.searchController) STATE.searchController.abort();
|
| 815 |
abortSearchPrefetch();
|
|
@@ -828,6 +860,7 @@ async function doSearch() {
|
|
| 828 |
STATE.searchController = controller;
|
| 829 |
STATE.isLoading = true;
|
| 830 |
DOM.resultsLoading.style.display = "flex";
|
|
|
|
| 831 |
if (STATE.page === 1) {
|
| 832 |
STATE.suppressAutoLoad = true;
|
| 833 |
DOM.previewPanel.style.display = "none";
|
|
@@ -859,6 +892,7 @@ async function doSearch() {
|
|
| 859 |
STATE.searchController = null;
|
| 860 |
STATE.isLoading = false;
|
| 861 |
DOM.resultsLoading.style.display = "none";
|
|
|
|
| 862 |
requestAnimationFrame(() => { STATE.suppressAutoLoad = false; });
|
| 863 |
prefetchNextPage();
|
| 864 |
}
|
|
@@ -902,6 +936,7 @@ function appendResults(items) {
|
|
| 902 |
if (!items.length) return;
|
| 903 |
DOM.emptyState.style.display = "none";
|
| 904 |
DOM.resultsList.insertAdjacentHTML("beforeend", items.map(resultItemHtml).join(""));
|
|
|
|
| 905 |
DOM.multiActionBar.style.display = STATE.multiSelect ? "" : "none";
|
| 906 |
observeResultSnippets();
|
| 907 |
}
|
|
@@ -917,10 +952,23 @@ function renderResults() {
|
|
| 917 |
}
|
| 918 |
DOM.emptyState.style.display = "none";
|
| 919 |
DOM.resultsList.innerHTML = STATE.results.map(resultItemHtml).join("");
|
|
|
|
| 920 |
DOM.multiActionBar.style.display = STATE.multiSelect ? "" : "none";
|
| 921 |
observeResultSnippets();
|
| 922 |
}
|
| 923 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 924 |
function resetSnippetObserver() {
|
| 925 |
if (snippetObserver) snippetObserver.disconnect();
|
| 926 |
snippetObserver = null;
|
|
@@ -1036,6 +1084,14 @@ async function openPreview(docId, keyword, options = {}) {
|
|
| 1036 |
else previewBody.textContent = rawText;
|
| 1037 |
DOM.previewPanel.style.display = STATE.isMobile ? "flex" : "block";
|
| 1038 |
document.body.classList.add("preview-open");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1039 |
STATE.previewDocId = docId;
|
| 1040 |
if (options.scroll !== false) DOM.previewPanel.scrollIntoView({ behavior: "smooth", block: "start" });
|
| 1041 |
} catch (error) {
|
|
@@ -1282,6 +1338,7 @@ function renderFolderTreeRows(animation = {}) {
|
|
| 1282 |
container.innerHTML = "";
|
| 1283 |
renderFolderNodes(container, STATE.folderTree, 0);
|
| 1284 |
refreshFolderTreeSelectionState();
|
|
|
|
| 1285 |
const newRows = container.querySelectorAll(".filter-folder-item[data-folder-path]");
|
| 1286 |
newRows.forEach((row) => {
|
| 1287 |
const path = row.dataset.folderPath;
|
|
@@ -1327,7 +1384,8 @@ function renderFolderTreeRows(animation = {}) {
|
|
| 1327 |
function animateFolderCollapse(nodePath, exitingPaths) {
|
| 1328 |
const container = DOM.filterFolderTree;
|
| 1329 |
if (!container) return 200;
|
| 1330 |
-
const duration = 200;
|
|
|
|
| 1331 |
const glyph = container.querySelector(`.filter-folder-item[data-folder-path="${CSS.escape(nodePath)}"] .tree-toggle-glyph`);
|
| 1332 |
if (glyph) {
|
| 1333 |
glyph.animate([
|
|
|
|
| 67 |
const snippetCache = new Map();
|
| 68 |
const snippetControllers = new Set();
|
| 69 |
|
| 70 |
+
function motionAllowed() {
|
| 71 |
+
return !window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
function motionDuration(duration) {
|
| 75 |
+
return motionAllowed() ? duration : 0;
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
function themeIcon(isDark) {
|
| 79 |
const shape = isDark
|
| 80 |
? '<path d="M20 15.5A8 8 0 1 1 8.5 4 6.5 6.5 0 0 0 20 15.5Z"/>'
|
|
|
|
| 472 |
}
|
| 473 |
|
| 474 |
function showToast(message, duration = 2000) {
|
| 475 |
+
clearTimeout(showToast._timer);
|
| 476 |
+
clearTimeout(showToast._hideTimer);
|
| 477 |
+
DOM.toast.classList.remove("is-leaving");
|
| 478 |
DOM.toast.textContent = message;
|
| 479 |
DOM.toast.style.display = "";
|
|
|
|
| 480 |
showToast._timer = setTimeout(() => {
|
| 481 |
+
const exitDuration = motionDuration(140);
|
| 482 |
+
if (exitDuration) DOM.toast.classList.add("is-leaving");
|
| 483 |
+
showToast._hideTimer = setTimeout(() => {
|
| 484 |
+
DOM.toast.style.display = "none";
|
| 485 |
+
DOM.toast.classList.remove("is-leaving");
|
| 486 |
+
}, exitDuration);
|
| 487 |
}, duration);
|
| 488 |
}
|
| 489 |
|
|
|
|
| 549 |
}
|
| 550 |
|
| 551 |
function toggleTheme() {
|
| 552 |
+
const animate = motionAllowed();
|
| 553 |
+
if (animate) document.body.classList.add("theme-transitioning");
|
| 554 |
STATE.isDark = !STATE.isDark;
|
| 555 |
applyTheme();
|
| 556 |
localStorage.setItem("theme", STATE.isDark ? "dark" : "light");
|
| 557 |
+
if (animate) {
|
| 558 |
+
document.body.classList.remove("theme-switching");
|
| 559 |
+
void document.body.offsetWidth;
|
| 560 |
+
document.body.classList.add("theme-switching");
|
| 561 |
+
window.setTimeout(() => {
|
| 562 |
+
document.body.classList.remove("theme-transitioning", "theme-switching");
|
| 563 |
+
}, 280);
|
| 564 |
+
}
|
| 565 |
}
|
| 566 |
|
| 567 |
function applyMobileMode() {
|
|
|
|
| 790 |
STATE.results = data.results || [];
|
| 791 |
STATE.isLoading = false;
|
| 792 |
DOM.resultsLoading.style.display = "none";
|
| 793 |
+
setSearchMotion(false);
|
| 794 |
renderResults();
|
| 795 |
updateStatus();
|
| 796 |
DOM.resultsContainer.scrollTop = 0;
|
|
|
|
| 836 |
});
|
| 837 |
}
|
| 838 |
|
| 839 |
+
function setSearchMotion(loading, refreshing = false) {
|
| 840 |
+
DOM.resultsContainer.classList.toggle("is-searching", loading);
|
| 841 |
+
DOM.resultsContainer.classList.toggle("is-refreshing", loading && refreshing);
|
| 842 |
+
DOM.resultsContainer.setAttribute("aria-busy", loading ? "true" : "false");
|
| 843 |
+
}
|
| 844 |
+
|
| 845 |
async function doSearch() {
|
| 846 |
if (STATE.searchController) STATE.searchController.abort();
|
| 847 |
abortSearchPrefetch();
|
|
|
|
| 860 |
STATE.searchController = controller;
|
| 861 |
STATE.isLoading = true;
|
| 862 |
DOM.resultsLoading.style.display = "flex";
|
| 863 |
+
setSearchMotion(true, STATE.page === 1 && STATE.results.length > 0);
|
| 864 |
if (STATE.page === 1) {
|
| 865 |
STATE.suppressAutoLoad = true;
|
| 866 |
DOM.previewPanel.style.display = "none";
|
|
|
|
| 892 |
STATE.searchController = null;
|
| 893 |
STATE.isLoading = false;
|
| 894 |
DOM.resultsLoading.style.display = "none";
|
| 895 |
+
setSearchMotion(false);
|
| 896 |
requestAnimationFrame(() => { STATE.suppressAutoLoad = false; });
|
| 897 |
prefetchNextPage();
|
| 898 |
}
|
|
|
|
| 936 |
if (!items.length) return;
|
| 937 |
DOM.emptyState.style.display = "none";
|
| 938 |
DOM.resultsList.insertAdjacentHTML("beforeend", items.map(resultItemHtml).join(""));
|
| 939 |
+
animateResultRows(Array.from(DOM.resultsList.children).slice(-items.length));
|
| 940 |
DOM.multiActionBar.style.display = STATE.multiSelect ? "" : "none";
|
| 941 |
observeResultSnippets();
|
| 942 |
}
|
|
|
|
| 952 |
}
|
| 953 |
DOM.emptyState.style.display = "none";
|
| 954 |
DOM.resultsList.innerHTML = STATE.results.map(resultItemHtml).join("");
|
| 955 |
+
animateResultRows(Array.from(DOM.resultsList.children).slice(0, 8));
|
| 956 |
DOM.multiActionBar.style.display = STATE.multiSelect ? "" : "none";
|
| 957 |
observeResultSnippets();
|
| 958 |
}
|
| 959 |
|
| 960 |
+
function animateResultRows(rows) {
|
| 961 |
+
if (!motionAllowed()) return;
|
| 962 |
+
rows.slice(0, 8).forEach((row, index) => {
|
| 963 |
+
row.style.setProperty("--result-enter-delay", `${index * 14}ms`);
|
| 964 |
+
row.classList.add("result-enter");
|
| 965 |
+
row.addEventListener("animationend", () => {
|
| 966 |
+
row.classList.remove("result-enter");
|
| 967 |
+
row.style.removeProperty("--result-enter-delay");
|
| 968 |
+
}, { once: true });
|
| 969 |
+
});
|
| 970 |
+
}
|
| 971 |
+
|
| 972 |
function resetSnippetObserver() {
|
| 973 |
if (snippetObserver) snippetObserver.disconnect();
|
| 974 |
snippetObserver = null;
|
|
|
|
| 1084 |
else previewBody.textContent = rawText;
|
| 1085 |
DOM.previewPanel.style.display = STATE.isMobile ? "flex" : "block";
|
| 1086 |
document.body.classList.add("preview-open");
|
| 1087 |
+
if (motionAllowed()) {
|
| 1088 |
+
DOM.previewPanel.classList.remove("preview-enter");
|
| 1089 |
+
void DOM.previewPanel.offsetWidth;
|
| 1090 |
+
DOM.previewPanel.classList.add("preview-enter");
|
| 1091 |
+
DOM.previewPanel.addEventListener("animationend", () => {
|
| 1092 |
+
DOM.previewPanel.classList.remove("preview-enter");
|
| 1093 |
+
}, { once: true });
|
| 1094 |
+
}
|
| 1095 |
STATE.previewDocId = docId;
|
| 1096 |
if (options.scroll !== false) DOM.previewPanel.scrollIntoView({ behavior: "smooth", block: "start" });
|
| 1097 |
} catch (error) {
|
|
|
|
| 1338 |
container.innerHTML = "";
|
| 1339 |
renderFolderNodes(container, STATE.folderTree, 0);
|
| 1340 |
refreshFolderTreeSelectionState();
|
| 1341 |
+
if (!motionAllowed()) return;
|
| 1342 |
const newRows = container.querySelectorAll(".filter-folder-item[data-folder-path]");
|
| 1343 |
newRows.forEach((row) => {
|
| 1344 |
const path = row.dataset.folderPath;
|
|
|
|
| 1384 |
function animateFolderCollapse(nodePath, exitingPaths) {
|
| 1385 |
const container = DOM.filterFolderTree;
|
| 1386 |
if (!container) return 200;
|
| 1387 |
+
const duration = motionDuration(200);
|
| 1388 |
+
if (!duration) return 0;
|
| 1389 |
const glyph = container.querySelector(`.filter-folder-item[data-folder-path="${CSS.escape(nodePath)}"] .tree-toggle-glyph`);
|
| 1390 |
if (glyph) {
|
| 1391 |
glyph.animate([
|
static/index.html
CHANGED
|
@@ -68,7 +68,7 @@
|
|
| 68 |
<button id="multi-zip-download" class="multi-action-btn primary">合并下载</button>
|
| 69 |
<span id="multi-selected-count" class="multi-selected-count"></span>
|
| 70 |
</div>
|
| 71 |
-
<div id="results-container" class="results-container">
|
| 72 |
<div id="results-list" class="results-list"></div>
|
| 73 |
<div id="results-loading" class="loading-spinner" style="display:none"><div class="spinner"></div></div>
|
| 74 |
<div id="empty-state" class="empty-state" style="display:none">
|
|
@@ -145,7 +145,7 @@
|
|
| 145 |
|
| 146 |
</footer>
|
| 147 |
<div id="overlay" class="overlay" style="display:none"></div>
|
| 148 |
-
<div id="toast" class="toast" style="display:none"></div>
|
| 149 |
|
| 150 |
<script>if ("serviceWorker" in navigator) { navigator.serviceWorker.register("/sw.js", { scope: "/" }); }</script>
|
| 151 |
<script src="/static/app.js"></script>
|
|
|
|
| 68 |
<button id="multi-zip-download" class="multi-action-btn primary">合并下载</button>
|
| 69 |
<span id="multi-selected-count" class="multi-selected-count"></span>
|
| 70 |
</div>
|
| 71 |
+
<div id="results-container" class="results-container" aria-busy="false">
|
| 72 |
<div id="results-list" class="results-list"></div>
|
| 73 |
<div id="results-loading" class="loading-spinner" style="display:none"><div class="spinner"></div></div>
|
| 74 |
<div id="empty-state" class="empty-state" style="display:none">
|
|
|
|
| 145 |
|
| 146 |
</footer>
|
| 147 |
<div id="overlay" class="overlay" style="display:none"></div>
|
| 148 |
+
<div id="toast" class="toast" role="status" aria-live="polite" style="display:none"></div>
|
| 149 |
|
| 150 |
<script>if ("serviceWorker" in navigator) { navigator.serviceWorker.register("/sw.js", { scope: "/" }); }</script>
|
| 151 |
<script src="/static/app.js"></script>
|
static/style.css
CHANGED
|
@@ -35,7 +35,9 @@
|
|
| 35 |
--shadow-sm: 0 1px 2px rgba(0,0,0,0.3);
|
| 36 |
--shadow-md: 0 2px 8px rgba(0,0,0,0.4);
|
| 37 |
--shadow-lg: 0 4px 16px rgba(0,0,0,0.5);
|
| 38 |
-
--transition:
|
|
|
|
|
|
|
| 39 |
--sidebar-w: 280px;
|
| 40 |
--sidebar-expanded-w: min(50vw, 720px);
|
| 41 |
color-scheme: dark;
|
|
@@ -279,6 +281,13 @@ ul, li {
|
|
| 279 |
max-height: 320px;
|
| 280 |
overflow-y: auto;
|
| 281 |
padding: 4px 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 282 |
}
|
| 283 |
|
| 284 |
.search-history-dropdown .history-item {
|
|
@@ -461,6 +470,15 @@ ul, li {
|
|
| 461 |
overflow: hidden;
|
| 462 |
}
|
| 463 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 464 |
body.preview-open {
|
| 465 |
user-select: none;
|
| 466 |
-webkit-user-select: none;
|
|
@@ -518,6 +536,15 @@ body.preview-open #preview-panel .preview-header {
|
|
| 518 |
display: block;
|
| 519 |
}
|
| 520 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 521 |
.preview-title {
|
| 522 |
font-size: 15px;
|
| 523 |
font-weight: 600;
|
|
@@ -607,7 +634,7 @@ body.preview-open #preview-panel .preview-header {
|
|
| 607 |
}
|
| 608 |
|
| 609 |
.sidebar.collapsed {
|
| 610 |
-
width: 0 !important;
|
| 611 |
border-right: none;
|
| 612 |
}
|
| 613 |
|
|
@@ -1154,6 +1181,40 @@ body.mobile .multi-toggle { padding: 1px 4px; font-size: 11px; }
|
|
| 1154 |
flex: 1;
|
| 1155 |
overflow-y: auto;
|
| 1156 |
overflow-x: hidden;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1157 |
}
|
| 1158 |
|
| 1159 |
.snippet-loading {
|
|
@@ -1174,6 +1235,16 @@ body.mobile .multi-toggle { padding: 1px 4px; font-size: 11px; }
|
|
| 1174 |
transition: background var(--transition);
|
| 1175 |
}
|
| 1176 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1177 |
.result-item:nth-child(even) {
|
| 1178 |
background: var(--surface-variant);
|
| 1179 |
}
|
|
@@ -1762,6 +1833,10 @@ body.mobile .mobile-selected-count {
|
|
| 1762 |
animation: toast-in 0.2s ease;
|
| 1763 |
}
|
| 1764 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1765 |
@keyframes toast-in {
|
| 1766 |
from {
|
| 1767 |
opacity: 0;
|
|
@@ -1774,6 +1849,11 @@ body.mobile .mobile-selected-count {
|
|
| 1774 |
}
|
| 1775 |
}
|
| 1776 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1777 |
body.mobile .sidebar {
|
| 1778 |
position: fixed;
|
| 1779 |
top: var(--header-h);
|
|
@@ -1781,7 +1861,7 @@ body.mobile .sidebar {
|
|
| 1781 |
z-index: 95;
|
| 1782 |
width: 85vw !important;
|
| 1783 |
max-width: 320px;
|
| 1784 |
-
transition: transform var(--
|
| 1785 |
will-change: transform;
|
| 1786 |
}
|
| 1787 |
|
|
@@ -1868,6 +1948,15 @@ body.mobile .preview-panel {
|
|
| 1868 |
background: var(--reader-bg);
|
| 1869 |
}
|
| 1870 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1871 |
body.light.mobile .preview-panel {
|
| 1872 |
--reader-bg: #f7f3e8;
|
| 1873 |
--reader-header: #f0ecdf;
|
|
@@ -1921,7 +2010,7 @@ body.mobile .preview-path {
|
|
| 1921 |
z-index: 95;
|
| 1922 |
width: 85vw !important;
|
| 1923 |
max-width: 320px;
|
| 1924 |
-
transition: transform var(--
|
| 1925 |
will-change: transform;
|
| 1926 |
}
|
| 1927 |
|
|
@@ -2033,26 +2122,11 @@ input[type="checkbox"]:indeterminate {
|
|
| 2033 |
accent-color: var(--primary);
|
| 2034 |
}
|
| 2035 |
|
|
|
|
| 2036 |
body.theme-transitioning *,
|
| 2037 |
body.theme-transitioning *::before,
|
| 2038 |
body.theme-transitioning *::after {
|
| 2039 |
-
transition: background-color
|
| 2040 |
-
}
|
| 2041 |
-
|
| 2042 |
-
.theme-ripple {
|
| 2043 |
-
position: fixed;
|
| 2044 |
-
border-radius: 50%;
|
| 2045 |
-
pointer-events: none;
|
| 2046 |
-
z-index: 9999;
|
| 2047 |
-
width: 0;
|
| 2048 |
-
height: 0;
|
| 2049 |
-
animation: theme-ripple-expand 0.6s ease-out forwards;
|
| 2050 |
-
}
|
| 2051 |
-
|
| 2052 |
-
@keyframes theme-ripple-expand {
|
| 2053 |
-
0% { width: 0; height: 0; opacity: 0.6; }
|
| 2054 |
-
|
| 2055 |
-
100% { width: 300vmax; height: 300vmax; opacity: 0; transform: translate(-150vmax, -150vmax); }
|
| 2056 |
}
|
| 2057 |
|
| 2058 |
@media (prefers-reduced-motion: reduce) {
|
|
|
|
| 35 |
--shadow-sm: 0 1px 2px rgba(0,0,0,0.3);
|
| 36 |
--shadow-md: 0 2px 8px rgba(0,0,0,0.4);
|
| 37 |
--shadow-lg: 0 4px 16px rgba(0,0,0,0.5);
|
| 38 |
+
--transition: 160ms cubic-bezier(0.2, 0, 0, 1);
|
| 39 |
+
--motion-standard: 180ms cubic-bezier(0.2, 0, 0, 1);
|
| 40 |
+
--motion-emphasized: 220ms cubic-bezier(0.2, 0, 0, 1);
|
| 41 |
--sidebar-w: 280px;
|
| 42 |
--sidebar-expanded-w: min(50vw, 720px);
|
| 43 |
color-scheme: dark;
|
|
|
|
| 281 |
max-height: 320px;
|
| 282 |
overflow-y: auto;
|
| 283 |
padding: 4px 0;
|
| 284 |
+
transform-origin: top center;
|
| 285 |
+
animation: menu-enter var(--motion-standard);
|
| 286 |
+
}
|
| 287 |
+
|
| 288 |
+
@keyframes menu-enter {
|
| 289 |
+
from { opacity: 0; transform: translateY(-4px) scaleY(0.98); }
|
| 290 |
+
to { opacity: 1; transform: translateY(0) scaleY(1); }
|
| 291 |
}
|
| 292 |
|
| 293 |
.search-history-dropdown .history-item {
|
|
|
|
| 470 |
overflow: hidden;
|
| 471 |
}
|
| 472 |
|
| 473 |
+
.preview-panel.preview-enter {
|
| 474 |
+
animation: preview-enter var(--motion-emphasized);
|
| 475 |
+
}
|
| 476 |
+
|
| 477 |
+
@keyframes preview-enter {
|
| 478 |
+
from { opacity: 0; transform: translateY(6px) scale(0.995); }
|
| 479 |
+
to { opacity: 1; transform: translateY(0) scale(1); }
|
| 480 |
+
}
|
| 481 |
+
|
| 482 |
body.preview-open {
|
| 483 |
user-select: none;
|
| 484 |
-webkit-user-select: none;
|
|
|
|
| 536 |
display: block;
|
| 537 |
}
|
| 538 |
|
| 539 |
+
body.theme-switching .theme-icon-svg {
|
| 540 |
+
animation: theme-icon-turn 280ms cubic-bezier(0.2, 0, 0, 1);
|
| 541 |
+
}
|
| 542 |
+
|
| 543 |
+
@keyframes theme-icon-turn {
|
| 544 |
+
from { opacity: 0.35; transform: rotate(-80deg) scale(0.82); }
|
| 545 |
+
to { opacity: 1; transform: rotate(0) scale(1); }
|
| 546 |
+
}
|
| 547 |
+
|
| 548 |
.preview-title {
|
| 549 |
font-size: 15px;
|
| 550 |
font-weight: 600;
|
|
|
|
| 634 |
}
|
| 635 |
|
| 636 |
.sidebar.collapsed {
|
| 637 |
+
width: 0 !important;
|
| 638 |
border-right: none;
|
| 639 |
}
|
| 640 |
|
|
|
|
| 1181 |
flex: 1;
|
| 1182 |
overflow-y: auto;
|
| 1183 |
overflow-x: hidden;
|
| 1184 |
+
position: relative;
|
| 1185 |
+
}
|
| 1186 |
+
|
| 1187 |
+
.results-container::before {
|
| 1188 |
+
content: "";
|
| 1189 |
+
position: sticky;
|
| 1190 |
+
top: 0;
|
| 1191 |
+
z-index: 6;
|
| 1192 |
+
display: block;
|
| 1193 |
+
width: 100%;
|
| 1194 |
+
height: 2px;
|
| 1195 |
+
margin-bottom: -2px;
|
| 1196 |
+
background: linear-gradient(90deg, transparent, var(--primary), transparent);
|
| 1197 |
+
opacity: 0;
|
| 1198 |
+
transform: translateX(-100%);
|
| 1199 |
+
pointer-events: none;
|
| 1200 |
+
}
|
| 1201 |
+
|
| 1202 |
+
.results-container.is-searching::before {
|
| 1203 |
+
opacity: 1;
|
| 1204 |
+
animation: search-progress 1.15s ease-in-out infinite;
|
| 1205 |
+
}
|
| 1206 |
+
|
| 1207 |
+
.results-container.is-refreshing .results-list {
|
| 1208 |
+
opacity: 0.56;
|
| 1209 |
+
}
|
| 1210 |
+
|
| 1211 |
+
.results-list {
|
| 1212 |
+
transition: opacity var(--motion-standard);
|
| 1213 |
+
}
|
| 1214 |
+
|
| 1215 |
+
@keyframes search-progress {
|
| 1216 |
+
from { transform: translateX(-100%); }
|
| 1217 |
+
to { transform: translateX(100%); }
|
| 1218 |
}
|
| 1219 |
|
| 1220 |
.snippet-loading {
|
|
|
|
| 1235 |
transition: background var(--transition);
|
| 1236 |
}
|
| 1237 |
|
| 1238 |
+
.result-item.result-enter {
|
| 1239 |
+
animation: result-enter var(--motion-standard) both;
|
| 1240 |
+
animation-delay: var(--result-enter-delay, 0ms);
|
| 1241 |
+
}
|
| 1242 |
+
|
| 1243 |
+
@keyframes result-enter {
|
| 1244 |
+
from { opacity: 0; transform: translateY(4px); }
|
| 1245 |
+
to { opacity: 1; transform: translateY(0); }
|
| 1246 |
+
}
|
| 1247 |
+
|
| 1248 |
.result-item:nth-child(even) {
|
| 1249 |
background: var(--surface-variant);
|
| 1250 |
}
|
|
|
|
| 1833 |
animation: toast-in 0.2s ease;
|
| 1834 |
}
|
| 1835 |
|
| 1836 |
+
.toast.is-leaving {
|
| 1837 |
+
animation: toast-out 140ms ease-in forwards;
|
| 1838 |
+
}
|
| 1839 |
+
|
| 1840 |
@keyframes toast-in {
|
| 1841 |
from {
|
| 1842 |
opacity: 0;
|
|
|
|
| 1849 |
}
|
| 1850 |
}
|
| 1851 |
|
| 1852 |
+
@keyframes toast-out {
|
| 1853 |
+
from { opacity: 1; transform: translateX(-50%) translateY(0); }
|
| 1854 |
+
to { opacity: 0; transform: translateX(-50%) translateY(6px); }
|
| 1855 |
+
}
|
| 1856 |
+
|
| 1857 |
body.mobile .sidebar {
|
| 1858 |
position: fixed;
|
| 1859 |
top: var(--header-h);
|
|
|
|
| 1861 |
z-index: 95;
|
| 1862 |
width: 85vw !important;
|
| 1863 |
max-width: 320px;
|
| 1864 |
+
transition: transform var(--motion-emphasized), opacity var(--motion-standard);
|
| 1865 |
will-change: transform;
|
| 1866 |
}
|
| 1867 |
|
|
|
|
| 1948 |
background: var(--reader-bg);
|
| 1949 |
}
|
| 1950 |
|
| 1951 |
+
body.mobile .preview-panel.preview-enter {
|
| 1952 |
+
animation-name: preview-enter-mobile;
|
| 1953 |
+
}
|
| 1954 |
+
|
| 1955 |
+
@keyframes preview-enter-mobile {
|
| 1956 |
+
from { opacity: 0.7; transform: translateX(18px); }
|
| 1957 |
+
to { opacity: 1; transform: translateX(0); }
|
| 1958 |
+
}
|
| 1959 |
+
|
| 1960 |
body.light.mobile .preview-panel {
|
| 1961 |
--reader-bg: #f7f3e8;
|
| 1962 |
--reader-header: #f0ecdf;
|
|
|
|
| 2010 |
z-index: 95;
|
| 2011 |
width: 85vw !important;
|
| 2012 |
max-width: 320px;
|
| 2013 |
+
transition: transform var(--motion-emphasized), opacity var(--motion-standard);
|
| 2014 |
will-change: transform;
|
| 2015 |
}
|
| 2016 |
|
|
|
|
| 2122 |
accent-color: var(--primary);
|
| 2123 |
}
|
| 2124 |
|
| 2125 |
+
body.theme-transitioning,
|
| 2126 |
body.theme-transitioning *,
|
| 2127 |
body.theme-transitioning *::before,
|
| 2128 |
body.theme-transitioning *::after {
|
| 2129 |
+
transition: background-color 180ms ease, color 180ms ease, border-color 180ms ease, box-shadow 180ms ease !important;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2130 |
}
|
| 2131 |
|
| 2132 |
@media (prefers-reduced-motion: reduce) {
|