refactor(stage-5): modularize style.css into domain stylesheets and update service worker precache

This commit is contained in:
Antigravity committed 2026-10-07 14:52:45 +03:00
1 parent dde87e5d6c
commit 6fb086a878
10 files changed
+8851 -8745

No files matched your search

+148
View File
@@ -0,0 +1,148 @@
/* ==========================================================================
1. Base Tokens, Typography, Reset & Global Safe Areas
========================================================================== */
/* Modern CSS Design System for Notes App */
:root {
--bg-main: #0f172a;
--bg-surface: #1e293b;
--bg-surface-hover: #334155;
--bg-card: #1e293b;
--bg-input: #0f172a;
--border-color: #334155;
--border-focus: #38bdf8;
--text-main: #f8fafc;
--text-muted: #94a3b8;
--text-dim: #64748b;
--primary: #38bdf8;
--primary-hover: #0ea5e9;
--primary-dim: rgba(56, 189, 248, 0.15);
--success: #10b981;
--success-hover: #059669;
--success-dim: rgba(16, 185, 129, 0.15);
--danger: #ef4444;
--danger-hover: #dc2626;
--danger-dim: rgba(239, 68, 68, 0.15);
--tag-bg: #293548;
--tag-text: #7dd3fc;
--radius-sm: 6px;
--radius-md: 10px;
--radius-lg: 14px;
--radius-full: 9999px;
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.2);
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.3), 0 2px 4px -2px rgba(0, 0, 0, 0.3);
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.4), 0 4px 6px -4px rgba(0, 0, 0, 0.4);
--font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
--transition: all 0.18s ease-in-out;
--sat: env(safe-area-inset-top, 0px);
--sar: env(safe-area-inset-right, 0px);
--sab: env(safe-area-inset-bottom, 0px);
--sal: env(safe-area-inset-left, 0px);
--navbar-height: 60px;
}
[data-theme="light"] {
--bg-main: #f1f5f9;
--bg-surface: #ffffff;
--bg-surface-hover: #f8fafc;
--bg-card: #ffffff;
--bg-input: #f8fafc;
--border-color: #cbd5e1;
--border-focus: #0284c7;
--text-main: #0f172a;
--text-muted: #475569;
--text-dim: #94a3b8;
--primary: #0284c7;
--primary-hover: #0369a1;
--primary-dim: rgba(2, 132, 199, 0.1);
--success: #059669;
--success-hover: #047857;
--success-dim: rgba(5, 150, 105, 0.1);
--tag-bg: #e2e8f0;
--tag-text: #0369a1;
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.08);
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html, body {
overflow-x: clip;
-webkit-tap-highlight-color: transparent;
}
body {
background-color: var(--bg-main);
color: var(--text-main);
font-family: var(--font-family);
line-height: 1.5;
-webkit-font-smoothing: antialiased;
min-height: 100vh;
min-height: 100dvh;
}
.hidden {
display: none !important;
}
/* Main Content */
.main-content {
max-width: 900px;
width: 100%;
margin: 0 auto;
padding: 32px 20px;
display: flex;
flex-direction: column;
gap: 36px;
}
/* --- Responsive Mobile Overrides (max-width: 768px) --- */
@media (max-width: 768px) {
/* 1. iOS Safari Auto-Zoom Fix (< 16px triggers zoom) */
input, select, textarea,
.input-styled, .search-input-box input, .form-group input,
.search-mini-box input, .reader-select {
font-size: 16px !important;
}
/* 2. Global Mobile App Container & Safe Areas */
html, body {
overflow-x: hidden;
-webkit-overflow-scrolling: touch;
min-height: 100dvh;
}
.app-shell {
min-height: 100dvh;
overflow-x: hidden;
}
.main-content,
.srs-view,
.reader-view {
padding-bottom: calc(74px + env(safe-area-inset-bottom, 0px)) !important;
}
}
File diff suppressed because it is too large. Load diff
+929
View File
@@ -0,0 +1,929 @@
/* ==========================================================================
3. Dictionary, Search, Word Cards, Collections & Tags
========================================================================== */
/* Search Box */
.search-box-wrapper {
display: flex;
flex-direction: column;
gap: 8px;
}
.search-input-box {
display: flex;
align-items: center;
background-color: var(--bg-surface);
border: 2px solid var(--border-color);
border-radius: var(--radius-md);
padding: 6px 10px 6px 16px;
transition: var(--transition);
box-shadow: var(--shadow-sm);
}
.search-input-box:focus-within {
border-color: var(--border-focus);
box-shadow: 0 0 0 4px var(--primary-dim);
}
.search-icon {
font-size: 18px;
color: var(--text-muted);
margin-right: 12px;
}
.search-input-box input {
flex: 1;
background: transparent;
border: none;
outline: none;
font-size: 17px;
color: var(--text-main);
padding: 8px 0;
}
.clear-btn {
background: transparent;
border: none;
color: var(--text-dim);
font-size: 16px;
cursor: pointer;
padding: 4px 8px;
border-radius: 50%;
}
.clear-btn:hover {
color: var(--text-main);
}
.translate-action-btn {
margin-left: 8px;
}
.hotkey-hints {
display: flex;
flex-wrap: wrap;
gap: 12px;
padding: 4px 8px;
font-size: 12px;
color: var(--text-dim);
}
.hotkey-hints kbd {
background-color: var(--bg-surface-hover);
border: 1px solid var(--border-color);
border-radius: 4px;
padding: 1px 5px;
font-family: monospace;
font-size: 11px;
color: var(--text-muted);
}
/* Live Result Card */
.result-card {
background-color: var(--bg-card);
border: 1px solid var(--border-color);
border-radius: var(--radius-lg);
padding: 24px;
box-shadow: var(--shadow-md);
animation: fadeIn 0.25s ease-out;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(6px); }
to { opacity: 1; transform: translateY(0); }
}
.result-header {
margin-bottom: 16px;
padding-bottom: 16px;
border-bottom: 1px solid var(--border-color);
}
.term-title-row {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 12px;
}
.res-term {
font-size: 28px;
font-weight: 800;
letter-spacing: -0.5px;
color: var(--text-main);
}
.badge-pill {
padding: 3px 10px;
border-radius: var(--radius-full);
font-size: 13px;
font-weight: 600;
}
.res-phonetic {
background-color: var(--primary-dim);
color: var(--primary);
font-family: monospace;
}
.res-pos {
background-color: var(--bg-surface-hover);
color: var(--text-muted);
}
.audio-btn {
background-color: var(--primary-dim);
border: 1px solid var(--primary);
color: var(--primary);
border-radius: var(--radius-full);
padding: 4px 12px;
font-size: 13px;
font-weight: 600;
cursor: pointer;
display: inline-flex;
align-items: center;
gap: 4px;
transition: var(--transition);
}
.audio-btn:hover {
background-color: var(--primary);
color: #0f172a;
}
.audio-xs-btn {
background-color: var(--primary-dim);
border: 1px solid var(--primary);
color: var(--primary);
border-radius: var(--radius-full);
padding: 2px 8px;
font-size: 11px;
font-weight: 600;
cursor: pointer;
display: inline-flex;
align-items: center;
gap: 4px;
transition: var(--transition);
}
.audio-xs-btn:hover {
background-color: var(--primary);
color: #0f172a;
}
.popup-sentence-audio-btn {
border-color: var(--border-color);
color: var(--text-muted);
}
.popup-sentence-audio-btn:hover {
border-color: var(--primary);
color: var(--primary);
background-color: var(--primary-dim);
}
.definition-box {
background-color: var(--bg-main);
border-left: 3px solid var(--primary);
padding: 12px 16px;
border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
margin-bottom: 20px;
}
.def-label {
font-size: 11px;
font-weight: 700;
text-transform: uppercase;
color: var(--primary);
letter-spacing: 0.5px;
margin-bottom: 4px;
}
.def-text {
font-size: 14px;
color: var(--text-main);
}
.card-edit-grid {
display: flex;
flex-direction: column;
gap: 16px;
margin-bottom: 24px;
}
.input-styled {
width: 100%;
padding: 10px 14px;
background-color: var(--bg-input);
border: 1px solid var(--border-color);
border-radius: var(--radius-sm);
color: var(--text-main);
font-size: 14px;
outline: none;
transition: var(--transition);
}
.input-styled:focus {
border-color: var(--border-focus);
box-shadow: 0 0 0 3px var(--primary-dim);
}
.field-group label {
display: block;
font-size: 12px;
font-weight: 600;
color: var(--text-muted);
margin-bottom: 5px;
}
.field-group .req {
color: var(--danger);
}
.field-row {
display: flex;
gap: 16px;
}
.flex-1 { flex: 1; }
.flex-2 { flex: 2; }
.suggestions-chips {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin-top: 6px;
}
.suggestion-chip {
font-size: 12px;
background-color: var(--bg-surface-hover);
color: var(--text-muted);
padding: 2px 8px;
border-radius: var(--radius-full);
cursor: pointer;
transition: var(--transition);
border: 1px solid transparent;
}
.suggestion-chip:hover {
border-color: var(--primary);
color: var(--primary);
}
.quick-tags {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin-top: 6px;
}
.tag-chip {
font-size: 11px;
background-color: var(--tag-bg);
color: var(--tag-text);
padding: 2px 8px;
border-radius: var(--radius-full);
cursor: pointer;
user-select: none;
transition: var(--transition);
}
.tag-chip:hover, .tag-chip.active {
background-color: var(--primary);
color: #0f172a;
font-weight: 600;
}
.result-actions {
display: flex;
justify-content: flex-end;
}
/* Vocabulary Section */
.vocabulary-section {
display: flex;
flex-direction: column;
gap: 16px;
}
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 12px;
}
.section-title-wrap {
display: flex;
align-items: baseline;
gap: 8px;
}
.section-title-wrap h3 {
font-size: 20px;
font-weight: 700;
}
.cards-count-label {
font-size: 13px;
color: var(--text-dim);
}
.list-controls {
display: flex;
align-items: center;
gap: 8px;
}
.batch-mode-btn {
white-space: nowrap;
flex-shrink: 0;
height: 35px;
display: inline-flex;
align-items: center;
justify-content: center;
}
.search-mini-box {
display: flex;
align-items: center;
}
.search-mini-box input {
background-color: var(--bg-surface);
border: 1px solid var(--border-color);
border-radius: var(--radius-sm);
padding: 8px 12px;
color: var(--text-main);
font-size: 13px;
outline: none;
min-width: 260px;
height: 35px;
box-sizing: border-box;
transition: var(--transition);
}
.search-mini-box input:focus {
border-color: var(--border-focus);
}
/* Tags Filter Bar */
.tags-filter-bar {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.filter-chip {
background-color: var(--bg-surface);
border: 1px solid var(--border-color);
color: var(--text-muted);
font-size: 12px;
font-weight: 600;
padding: 4px 12px;
border-radius: var(--radius-full);
cursor: pointer;
transition: var(--transition);
}
.filter-chip:hover {
border-color: var(--primary);
color: var(--primary);
}
.filter-chip.active {
background-color: var(--primary);
border-color: var(--primary);
color: #0f172a;
}
/* Cards List */
.cards-list {
display: flex;
flex-direction: column;
gap: 12px;
}
.vocab-card {
background-color: var(--bg-card);
border: 1px solid var(--border-color);
border-radius: var(--radius-md);
padding: 16px 20px;
box-shadow: var(--shadow-sm);
transition: var(--transition);
display: flex;
flex-direction: column;
gap: 10px;
}
.vocab-card:hover {
border-color: var(--border-focus);
box-shadow: var(--shadow-md);
}
.card-top {
display: flex;
justify-content: space-between;
align-items: flex-start;
}
.card-term-group {
display: flex;
align-items: center;
gap: 10px;
flex-wrap: wrap;
}
.card-term {
font-size: 18px;
font-weight: 700;
color: var(--text-main);
}
.card-phonetic {
font-size: 13px;
color: var(--primary);
font-family: monospace;
}
.card-pos {
font-size: 11px;
background-color: var(--bg-surface-hover);
color: var(--text-dim);
padding: 2px 6px;
border-radius: 4px;
}
.card-actions {
display: flex;
gap: 6px;
}
.card-translation {
font-size: 16px;
font-weight: 600;
color: var(--text-main);
}
.card-context {
font-size: 14px;
color: var(--text-muted);
font-style: italic;
background-color: var(--bg-main);
padding: 8px 12px;
border-radius: var(--radius-sm);
border-left: 2px solid var(--border-color);
}
.card-context mark {
background-color: var(--primary-dim);
color: var(--primary);
font-weight: 600;
padding: 0 4px;
border-radius: 2px;
}
.card-bottom {
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 8px;
font-size: 12px;
color: var(--text-dim);
}
.card-tags {
display: flex;
gap: 6px;
flex-wrap: wrap;
}
.card-tag {
background-color: var(--tag-bg);
color: var(--tag-text);
padding: 2px 8px;
border-radius: var(--radius-full);
font-size: 11px;
}
.card-notes {
font-size: 12px;
color: #fbbf24;
display: flex;
align-items: center;
gap: 4px;
}
/* Empty state */
.empty-state {
text-align: center;
padding: 48px 24px;
background-color: var(--bg-surface);
border: 1px dashed var(--border-color);
border-radius: var(--radius-md);
color: var(--text-muted);
}
.empty-icon {
font-size: 40px;
margin-bottom: 12px;
}
.empty-state h4 {
font-size: 16px;
color: var(--text-main);
margin-bottom: 6px;
}
.empty-state p {
font-size: 13px;
color: var(--text-dim);
}
/* Collections & Filters */
.collections-filter-wrap, .tags-filter-wrap {
display: flex;
flex-direction: column;
gap: 6px;
}
.filter-header-bar {
display: flex;
align-items: center;
justify-content: space-between;
}
.filter-title {
font-size: 12px;
font-weight: 700;
color: var(--text-muted);
text-transform: uppercase;
letter-spacing: 0.5px;
}
.filter-chips-row {
display: flex;
flex-wrap: wrap;
gap: 6px;
align-items: center;
}
.col-chip {
background-color: var(--bg-surface);
border: 1px solid var(--border-color);
color: var(--text-muted);
font-size: 12px;
font-weight: 600;
padding: 4px 12px;
border-radius: var(--radius-full);
cursor: pointer;
transition: var(--transition);
}
.col-chip:hover {
border-color: #a855f7;
color: #c084fc;
}
.col-chip.active {
background-color: #a855f7;
border-color: #a855f7;
color: #ffffff;
font-weight: 700;
}
.card-collection-badge {
font-size: 11px;
font-weight: 600;
background-color: rgba(168, 85, 247, 0.15);
color: #c084fc;
border: 1px solid rgba(168, 85, 247, 0.3);
padding: 2px 8px;
border-radius: var(--radius-full);
}
/* Batch Selection */
.batch-mode-btn.active {
background-color: var(--primary-dim);
border-color: var(--primary);
color: var(--primary);
}
.card-select-cell {
display: none;
margin-right: 12px;
align-items: center;
}
.batch-active .card-select-cell {
display: flex;
}
.card-select-checkbox {
width: 18px;
height: 18px;
cursor: pointer;
accent-color: var(--primary);
}
.vocab-card.is-selected {
border-color: var(--border-focus);
background-color: rgba(56, 189, 248, 0.05);
}
.batch-action-bar {
position: fixed;
bottom: 24px;
left: 50%;
transform: translateX(-50%);
width: calc(100% - 32px);
max-width: 760px;
background: rgba(30, 41, 59, 0.96);
backdrop-filter: blur(12px);
border: 1px solid var(--border-focus);
border-radius: var(--radius-lg);
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.6), 0 0 15px rgba(56, 189, 248, 0.2);
padding: 12px 20px;
display: flex;
justify-content: space-between;
align-items: center;
z-index: 900;
animation: slideUp 0.22s ease-out;
}
@keyframes slideUp {
from { transform: translate(-50%, 40px); opacity: 0; }
to { transform: translate(-50%, 0); opacity: 1; }
}
.batch-left {
display: flex;
align-items: center;
gap: 10px;
}
.batch-check-label {
display: flex;
align-items: center;
gap: 8px;
font-size: 14px;
font-weight: 600;
color: var(--text-main);
cursor: pointer;
}
.batch-master-checkbox {
width: 18px;
height: 18px;
accent-color: var(--primary);
cursor: pointer;
}
.batch-actions {
display: flex;
align-items: center;
gap: 8px;
}
.btn-secondary {
background-color: var(--bg-surface-hover);
color: var(--text-main);
border: 1px solid var(--border-color);
}
.btn-secondary:hover {
background-color: var(--border-color);
}
.btn-danger {
background-color: var(--danger);
color: #ffffff;
}
.btn-danger:hover {
background-color: var(--danger-hover);
}
.btn-ghost {
background: transparent;
border: none;
color: var(--primary);
cursor: pointer;
font-size: 13px;
padding: 4px 8px;
border-radius: var(--radius-sm);
}
.btn-ghost:hover {
background-color: var(--primary-dim);
}
.btn-xs {
padding: 2px 8px;
font-size: 11px;
}
/* Duplicate Warning Banner */
.duplicate-warning-box {
margin-top: 10px;
padding: 10px 14px;
background: rgba(234, 179, 8, 0.12);
border: 1px solid rgba(234, 179, 8, 0.35);
border-radius: var(--radius-md);
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
animation: fadeIn 0.2s ease-in-out;
}
.dup-left {
display: flex;
align-items: center;
gap: 8px;
font-size: 13px;
color: #facc15;
}
.dup-icon {
font-size: 16px;
}
/* 7. Bottom Sheet for Word Translation Popup on Mobile */
.reader-word-popup {
position: fixed !important;
top: auto !important;
bottom: calc(58px + env(safe-area-inset-bottom, 0px)) !important;
left: 8px !important;
right: 8px !important;
width: auto !important;
max-width: none !important;
border-radius: 18px !important;
box-shadow: 0 -8px 30px rgba(0, 0, 0, 0.5) !important;
border: 1px solid var(--border-focus) !important;
background-color: var(--bg-surface) !important;
z-index: 10005 !important;
padding: 14px 16px !important;
animation: slideUpSheet 0.22s cubic-bezier(0.16, 1, 0.3, 1) !important;
}
.reader-settings-panel {
position: fixed !important;
top: auto !important;
bottom: calc(58px + env(safe-area-inset-bottom, 0px)) !important;
left: 8px !important;
right: 8px !important;
width: auto !important;
max-height: calc(85dvh - 60px) !important;
overflow-y: auto !important;
-webkit-overflow-scrolling: touch !important;
border-radius: 20px !important;
box-shadow: 0 -8px 32px rgba(0, 0, 0, 0.55) !important;
border: 1px solid var(--border-focus) !important;
background-color: var(--bg-surface) !important;
color: var(--text-main) !important;
padding: 16px 18px 24px !important;
z-index: 10006 !important;
animation: slideUpSheet 0.22s cubic-bezier(0.16, 1, 0.3, 1) !important;
}
@keyframes slideUpSheet {
from {
transform: translateY(100%);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
/* --- Responsive Mobile Overrides (max-width: 768px) --- */
@media (max-width: 768px) {
/* 4. Dictionary & Search */
.main-content {
padding: 14px 12px calc(76px + env(safe-area-inset-bottom, 0px));
gap: 20px;
}
.search-input-box {
padding: 6px 8px 6px 12px;
}
.search-input-box input {
padding: 8px 0;
min-width: 0;
}
.translate-action-btn {
padding: 8px 14px;
font-size: 14px;
white-space: nowrap;
}
.hotkey-hints {
display: none !important;
}
.lookup-card {
padding: 16px 14px;
}
.lookup-header {
flex-direction: column;
align-items: flex-start;
gap: 8px;
}
.meta-inputs-grid .field-row {
flex-direction: column;
gap: 12px;
}
.result-actions .btn {
width: 100%;
justify-content: center;
min-height: 48px;
}
.result-actions .btn-subtext {
display: none;
}
/* Horizontal scrollable chips for collections and tags */
.filter-chips-row {
flex-wrap: nowrap;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
padding-bottom: 6px;
scrollbar-width: none;
}
.filter-chips-row::-webkit-scrollbar {
display: none;
}
.col-chip, .filter-chip {
flex-shrink: 0;
}
.list-controls {
width: 100%;
display: flex;
align-items: center;
gap: 8px;
margin-top: 10px;
}
.section-header {
flex-direction: column;
align-items: stretch;
}
.search-mini-box {
flex: 1;
min-width: 0;
}
.search-mini-box input {
width: 100%;
min-width: 0;
}
/* Cards */
.vocab-card {
padding: 14px;
gap: 8px;
}
.card-top {
gap: 8px;
}
.card-term {
font-size: 17px;
}
.card-actions .icon-btn {
min-width: 36px;
min-height: 36px;
display: flex;
align-items: center;
justify-content: center;
}
.card-bottom {
font-size: 11px;
}
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+32 -8743
View File
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -5,7 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
<title>Notes — Персональный тренажер и словарь английского языка</title>
<meta name="description" content="Защищённый персональный тренажёр и словарь английского языка с интервальными повторениями SRS SM-2, контекстным поиском и озвучкой">
<link rel="stylesheet" href="/static/css/style.css?v=6.4">
<link rel="stylesheet" href="/static/css/style.css?v=6.7">
<!-- PWA meta and icons -->
<link rel="manifest" href="/manifest.json">
+8 -1
View File
@@ -1,12 +1,19 @@
// Service Worker for Notes English PWA (Stage 2)
// Strategy: Cache-first for static assets, Network-first for API calls.
const CACHE_NAME = 'notes-v6.6';
const CACHE_NAME = 'notes-v6.7';
const OFFLINE_URL = '/';
const PRECACHE_URLS = [
'/',
'/static/css/style.css',
'/static/css/base.css',
'/static/css/components.css',
'/static/css/dictionary.css',
'/static/css/srs.css',
'/static/css/reader.css',
'/static/css/grammar_cefr.css',
'/static/css/lesson.css',
'/static/js/app.js',
'/static/js/modules/api.js',
'/static/js/modules/ui.js',