diff --git a/css/item-catalog.css b/css/item-catalog.css index 21264b1..f973362 100644 --- a/css/item-catalog.css +++ b/css/item-catalog.css @@ -107,6 +107,10 @@ @media (max-width: 540px) { .item-catalog-grid { grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); } .item-catalog-toolbar .form-select { flex: 1 1 100%; } + /* Keep supporting text legible on phones. */ + .item-catalog-name { font-size: .88rem; } + .item-catalog-details { font-size: .72rem; } + .item-catalog-support { font-size: .68rem; } } .inventory-mode-switch { display: flex; diff --git a/css/styles.css b/css/styles.css index 08647d6..ee6b4cf 100644 --- a/css/styles.css +++ b/css/styles.css @@ -4499,3 +4499,474 @@ input:checked + .slider:before { .substat-option:hover:not(:disabled), .substat-option:focus-visible { background: #263d59; } .substat-option:disabled { opacity: .4; cursor: not-allowed; } @media (max-width: 600px) { .add-relic-set-grid { grid-template-columns: repeat(auto-fill, minmax(105px, 1fr)); max-height: 230px; } } + +/* ========================================================================== + Mobile / responsive pass + Breakpoints: 900 (tablet), 768 (large phone), 640 (phone), 480 (small + phone), 360 (compact). Desktop layout above 900px is left untouched. + ========================================================================== */ + +/* --- Shell: header, tab bar, page padding ------------------------------- */ +@media (max-width: 768px) { + /* The tab bar becomes the sticky element so phones keep vertical space + for content instead of pinning a tall header. */ + .app-header { + position: static; + flex-wrap: wrap; + gap: 0.6rem; + padding: 0.6rem 0.85rem; + } + + .brand { min-width: 0; } + .brand-logo-img { width: 36px; height: 36px; } + .brand-title { font-size: 1.1rem; } + .brand-subtitle { font-size: 0.62rem; } + + .header-controls { + width: 100%; + align-items: center; + gap: 0.45rem; + } + + .server-mode-badge, + .connection-pill { + min-height: 36px; + padding: 0.32rem 0.6rem; + font-size: 0.75rem; + } + + /* Two tidy rows on phones: [server mode] [status] / [language] [refresh] */ + .server-mode-badge { order: 1; } + .connection-pill { order: 2; } + #lang-select { + order: 3; + width: auto; + max-width: 46vw; + min-height: 36px; + padding: 0.3rem 0.6rem; + } + #btn-quick-ping { order: 4; } + + .nav-tabs { + top: 0; + padding: 0.4rem 0.55rem; + gap: 0.25rem; + scroll-snap-type: x proximity; + scrollbar-width: none; + -webkit-overflow-scrolling: touch; + mask-image: linear-gradient(90deg, transparent 0, #000 12px, #000 calc(100% - 12px), transparent 100%); + -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 12px, #000 calc(100% - 12px), transparent 100%); + } + + .nav-tabs::-webkit-scrollbar { display: none; } + + .tab-btn { + min-height: 40px; + gap: 0.35rem; + padding: 0.5rem 0.75rem; + font-size: 0.8rem; + scroll-snap-align: start; + } + + .main-container { padding: 0.9rem 0.8rem 1.4rem; } + + /* Touch targets */ + .btn { min-height: 40px; } + .btn-sm { min-height: 36px; } + + /* iOS zooms the page when a focused field is smaller than 16px. */ + input, + select, + textarea { font-size: 16px; } + + .form-input, + .form-select { + min-height: 44px; + padding: 0.6rem 0.75rem; + font-size: 16px; + } + + .form-label { font-size: 0.72rem; } + + /* Toasts: keep clear of screen edges and the home indicator. */ + .toast-container { + left: 0.75rem; + right: 0.75rem; + bottom: calc(0.9rem + env(safe-area-inset-bottom, 0px)); + align-items: stretch; + } + + .toast { + width: 100%; + min-width: 0; + max-width: none; + } +} + +@media (max-width: 480px) { + .brand-subtitle { display: none; } + + .header-controls { gap: 0.4rem; } + + .tab-btn { + padding: 0.45rem 0.65rem; + font-size: 0.76rem; + } +} + +/* --- Layout grids ------------------------------------------------------- */ +/* The desktop grids use fixed minmax floors (320/280/250px) which no longer + fit phone content boxes; allow them to collapse instead of overflowing. + Page-level grids collapse to one column, while field grids inside dialogs + may still show two compact columns. */ +@media (max-width: 640px) { + .grid-2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr)); } + .grid-3 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr)); } + .grid-4 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 250px), 1fr)); } + + .modal-content .grid-2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 160px), 1fr)); } + + /* Dashboard counters: three compact tiles instead of three full-width cards. */ + #tab-dashboard > .grid-3 { + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 0.5rem; + } + + #tab-dashboard > .grid-3 .stat-box { + padding: 0.65rem 0.6rem; + gap: 0.2rem; + } + + #tab-dashboard > .grid-3 .stat-number { font-size: 1.55rem; } + + #tab-dashboard > .grid-3 .stat-label { + font-size: 0.66rem; + line-height: 1.25; + letter-spacing: 0.03em; + } +} + +/* --- Dialogs as phone bottom sheets ------------------------------------- */ +@media (max-width: 640px) { + .modal-overlay { + padding: 0; + align-items: flex-end; + } + + .modal-content { + width: 100%; + max-width: 100%; + max-height: calc(100dvh - 0.5rem); + padding: 1rem 0.9rem calc(1rem + env(safe-area-inset-bottom, 0px)); + border-width: 1px 0 0; + border-radius: 18px 18px 0 0; + } + + .modal-content .modal-header { + margin-bottom: 0.9rem; + padding-bottom: 0.6rem; + } + + .assign-picker-modal { + width: 100% !important; + max-width: 100% !important; + max-height: calc(100dvh - 0.5rem) !important; + border-radius: 18px 18px 0 0 !important; + } + + .modal-content .grid-2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 160px), 1fr)); } +} + +/* --- Equipment: tiles, subtabs, inspector ------------------------------- */ +@media (max-width: 900px) { + /* The side inspector was a 320px sticky column; on narrow screens it moves + under the tile grid instead of squeezing it to nothing. */ + .eq-layout { flex-wrap: wrap; } + #eq-inspector-card { + width: 100% !important; + position: static !important; + } + .eq-tiles-grid { max-height: 50vh; } +} + +@media (max-width: 640px) { + /* The server-mode -
+ +
@@ -1888,6 +1888,6 @@
- + diff --git a/js/app.js b/js/app.js index 0c2a067..e2000e6 100644 --- a/js/app.js +++ b/js/app.js @@ -4,7 +4,7 @@ import { LIGHTCONE_METADATA, RELIC_SET_METADATA, getLightconeInfo, getRelicSetIn import { initializeItemCatalog } from './item-catalog.js?v=5'; import { initializeUnstuck } from './unstuck.js?v=4'; import { PRYDWEN_BUILD_GUIDES } from './build-guides-data.js'; -import { SUPPORTED_LANGUAGES, TRANSLATIONS, getCurrentLanguage, setLanguage, t, translateElement, translatePath } from './i18n.js?v=2.21'; +import { SUPPORTED_LANGUAGES, TRANSLATIONS, getCurrentLanguage, setLanguage, t, translateElement, translatePath } from './i18n.js?v=2.22'; import { getAvatarIconUrl, getLightconeArtUrl, diff --git a/js/avatars-data.js b/js/avatars-data.js index 1752fa0..b0f9b61 100644 --- a/js/avatars-data.js +++ b/js/avatars-data.js @@ -1,4 +1,4 @@ -import { getCurrentLanguage, translateElement, translatePath } from "./i18n.js?v=2.21"; +import { getCurrentLanguage, translateElement, translatePath } from "./i18n.js?v=2.22"; export const AVATAR_METADATA = { "1001": { diff --git a/js/equipment-data.js b/js/equipment-data.js index 805cba7..242dd00 100644 --- a/js/equipment-data.js +++ b/js/equipment-data.js @@ -1,4 +1,4 @@ -import { getCurrentLanguage, translatePath } from "./i18n.js?v=2.21"; +import { getCurrentLanguage, translatePath } from "./i18n.js?v=2.22"; export const LIGHTCONE_METADATA = { "20000": { diff --git a/js/i18n.js b/js/i18n.js index f4ff2d5..ff840a2 100644 --- a/js/i18n.js +++ b/js/i18n.js @@ -7177,6 +7177,10 @@ const MODAL_AND_TOOL_TRANSLATIONS = { copyCardLevel: 'เลเวล', copyCardEidolon: 'Eidolon', copyCardLightCone: 'กรวยแสง', + inventoryViewsLabel: 'มุมมองกระเป๋าไอเทม', + relicSetSearchLabel: 'ค้นหาชุดรีลิกส์', + relicSetSearchPlaceholder: '🔍 ค้นหาชุดรีลิกส์...', + relicSetGridLabel: 'ชุดรีลิกส์', analystDamageAvPlaceholder: "เฉลี่ยต่อรอบ: -", analystCyclesPlaceholder: "0 รอบ", analystTurnsPlaceholder: "0 เทิร์น", analystAutoTurnsPlaceholder: "เทิร์นอัตโนมัติ: 0", analystDamageAvPlaceholder: "Avg per cycle: -", analystCyclesPlaceholder: "0 Cycles", analystTurnsPlaceholder: "0 Turns", analystAutoTurnsPlaceholder: "Auto Turns: 0", analystDamageAvPlaceholder: "ラウンド平均: -", analystCyclesPlaceholder: "0 ラウンド", analystTurnsPlaceholder: "0 ターン", analystAutoTurnsPlaceholder: "オートターン: 0", analystDamageAvPlaceholder: "라운드당 평균: -", analystCyclesPlaceholder: "0 라운드", analystTurnsPlaceholder: "0 턴", analystAutoTurnsPlaceholder: "자동 턴: 0", analystDamageAvPlaceholder: "Trung bình mỗi vòng: -", analystCyclesPlaceholder: "0 vòng", analystTurnsPlaceholder: "0 lượt", analystAutoTurnsPlaceholder: "Lượt tự động: 0", analystDamageAvPlaceholder: "Rata-rata per siklus: -", analystCyclesPlaceholder: "0 Siklus", analystTurnsPlaceholder: "0 Giliran", analystAutoTurnsPlaceholder: "Giliran otomatis: 0", analystDamageAvPlaceholder: "Promedio por ciclo: -", analystCyclesPlaceholder: "0 ciclos", analystTurnsPlaceholder: "0 turnos", analystAutoTurnsPlaceholder: "Turnos automáticos: 0", analystDamageAvPlaceholder: "Moyenne par cycle : -", analystCyclesPlaceholder: "0 cycle", analystTurnsPlaceholder: "0 tour", analystAutoTurnsPlaceholder: "Tours auto : 0", analystDamageAvPlaceholder: "Durchschnitt pro Zyklus: -", analystCyclesPlaceholder: "0 Zyklen", analystTurnsPlaceholder: "0 Züge", analystAutoTurnsPlaceholder: "Auto-Züge: 0", analystDamageAvPlaceholder: "В среднем за цикл: -", analystCyclesPlaceholder: "0 циклов", analystTurnsPlaceholder: "0 ходов", analystAutoTurnsPlaceholder: "Авто-ходы: 0", analystDamageAvPlaceholder: "Média por ciclo: -", analystCyclesPlaceholder: "0 ciclos", analystTurnsPlaceholder: "0 turnos", analystAutoTurnsPlaceholder: "Turnos automáticos: 0", miniViewFullAnalystTooltip: "เปิดหน้า Damage Analyst ตัวเต็ม", miniViewFullAnalystTooltip: "Open full Damage Analyst", miniViewFullAnalystTooltip: "完全なダメージ分析を開く", miniViewFullAnalystTooltip: "전체 데미지 분석 열기", miniViewFullAnalystTooltip: "Mở Trình phân tích sát thương đầy đủ", miniViewFullAnalystTooltip: "Buka Analis Kerusakan Lengkap", miniViewFullAnalystTooltip: "Abrir analizador de daño completo", miniViewFullAnalystTooltip: "Ouvrir l'analyseur de dégâts complet", miniViewFullAnalystTooltip: "Vollständigen Schadensanalysten öffnen", miniViewFullAnalystTooltip: "Открыть полный анализ урона", miniViewFullAnalystTooltip: "Abrir analisador de dano completo", copyCardGenerated: 'สร้างโดย GaCy-Srtool' }, en: { @@ -7308,6 +7312,10 @@ const MODAL_AND_TOOL_TRANSLATIONS = { copyCardLevel: 'Level', copyCardEidolon: 'Eidolon', copyCardLightCone: 'Light Cone', + inventoryViewsLabel: 'Inventory views', + relicSetSearchLabel: 'Search relic sets', + relicSetSearchPlaceholder: '🔍 Search relic sets...', + relicSetGridLabel: 'Relic sets', copyCardGenerated: 'Generated via GaCy-Srtool' } }; diff --git a/js/item-catalog.js b/js/item-catalog.js index e6a12f3..ad919ad 100644 --- a/js/item-catalog.js +++ b/js/item-catalog.js @@ -1,4 +1,4 @@ -import { getCurrentLanguage, t, translatePath } from './i18n.js?v=2.21'; +import { getCurrentLanguage, t, translatePath } from './i18n.js?v=2.22'; const CATALOG_URL = new URL('../assets/item-catalog.json?v=2', import.meta.url); const PAGE_SIZE = 48; diff --git a/js/unstuck.js b/js/unstuck.js index 663426d..715b4c3 100644 --- a/js/unstuck.js +++ b/js/unstuck.js @@ -1,4 +1,4 @@ -import { getCurrentLanguage } from './i18n.js?v=2.21'; +import { getCurrentLanguage } from './i18n.js?v=2.22'; const strings = { en: {