Landscape phone layout: compact donut, PWA support, safe-area insets
- Add compact donut mode for landscape phones (<=850px, landscape): wider radii (56%/93%/100%), no outside labels, bolder fonts - Refine landscape CSS: smaller header (h1:20px), 55/45 chart/details split, compact month previews (22px), tighter spacing - Add PWA standalone support: manifest.json, apple-mobile-web-app meta tags, viewport-fit=cover - Add safe-area-inset padding for Dynamic Island and home indicator Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
cc8b10dadb
commit
029e428bb4
24
app.js
24
app.js
@ -2765,21 +2765,23 @@ function adjustChartSize() {
|
|||||||
|
|
||||||
const screenWidth = window.innerWidth;
|
const screenWidth = window.innerWidth;
|
||||||
const isMobile = screenWidth <= 500;
|
const isMobile = screenWidth <= 500;
|
||||||
|
const isLandscapePhone = screenWidth <= 850 && window.innerHeight < window.innerWidth;
|
||||||
|
const isCompact = isMobile || isLandscapePhone;
|
||||||
|
|
||||||
// Mobile: extend layers to fill container, keeping same hole size as desktop
|
// Compact mode (portrait phones + landscape phones): extend layers to fill container
|
||||||
// Hole stays at 20%, layers scaled to fill remaining 80% (vs 55% on desktop)
|
// Hole stays at 20%, layers scaled to fill remaining 80% (vs 55% on desktop)
|
||||||
const level1Inner = '20%';
|
const level1Inner = '20%';
|
||||||
const level1Outer = isMobile ? '56%' : '45%';
|
const level1Outer = isCompact ? '56%' : '45%';
|
||||||
const level2Outer = isMobile ? '93%' : '70%';
|
const level2Outer = isCompact ? '93%' : '70%';
|
||||||
const level3Outer = isMobile ? '100%' : '75%';
|
const level3Outer = isCompact ? '100%' : '75%';
|
||||||
const outerRadius = isMobile ? '100%' : '95%';
|
const outerRadius = isCompact ? '100%' : '95%';
|
||||||
|
|
||||||
// Smaller font sizes on mobile, bolder for readability
|
// Smaller font sizes on compact, bolder for readability
|
||||||
const level1FontSize = isMobile ? 10 : 13;
|
const level1FontSize = isCompact ? 10 : 13;
|
||||||
const level1LineHeight = isMobile ? 12 : 15;
|
const level1LineHeight = isCompact ? 12 : 15;
|
||||||
const level1FontWeight = isMobile ? 600 : 500;
|
const level1FontWeight = isCompact ? 600 : 500;
|
||||||
const level2FontSize = isMobile ? 9 : 11;
|
const level2FontSize = isCompact ? 9 : 11;
|
||||||
const level2FontWeight = isMobile ? 600 : 400;
|
const level2FontWeight = isCompact ? 600 : 400;
|
||||||
|
|
||||||
// Update layer proportions
|
// Update layer proportions
|
||||||
option.series.levels[1].r0 = level1Inner;
|
option.series.levels[1].r0 = level1Inner;
|
||||||
|
|||||||
@ -2,7 +2,11 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
|
||||||
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
|
<meta name="apple-mobile-web-app-status-bar-style" content="default">
|
||||||
|
<meta name="apple-mobile-web-app-title" content="Траты">
|
||||||
|
<link rel="manifest" href="manifest.json">
|
||||||
<title>Spending Visualization</title>
|
<title>Spending Visualization</title>
|
||||||
<link rel="stylesheet" href="styles.css">
|
<link rel="stylesheet" href="styles.css">
|
||||||
<script src="https://cdn.jsdelivr.net/npm/echarts@5.6.0/dist/echarts.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/echarts@5.6.0/dist/echarts.min.js"></script>
|
||||||
|
|||||||
9
manifest.json
Normal file
9
manifest.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"name": "Семейные траты",
|
||||||
|
"short_name": "Траты",
|
||||||
|
"start_url": "/",
|
||||||
|
"display": "standalone",
|
||||||
|
"background_color": "#f5f5f5",
|
||||||
|
"theme_color": "#f5f5f5",
|
||||||
|
"orientation": "any"
|
||||||
|
}
|
||||||
61
styles.css
61
styles.css
@ -14,6 +14,7 @@ body {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
|
padding-top: calc(20px + env(safe-area-inset-top));
|
||||||
}
|
}
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
@ -613,6 +614,11 @@ body {
|
|||||||
|
|
||||||
/* Landscape phones: revert to desktop-like layout */
|
/* Landscape phones: revert to desktop-like layout */
|
||||||
@media (max-width: 850px) and (orientation: landscape) {
|
@media (max-width: 850px) and (orientation: landscape) {
|
||||||
|
h1 {
|
||||||
|
font-size: 20px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
.view-switcher {
|
.view-switcher {
|
||||||
position: static;
|
position: static;
|
||||||
background: none;
|
background: none;
|
||||||
@ -622,6 +628,7 @@ body {
|
|||||||
border-top: none;
|
border-top: none;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.view-switcher-btn {
|
.view-switcher-btn {
|
||||||
@ -630,6 +637,7 @@ body {
|
|||||||
padding: 4px 8px;
|
padding: 4px 8px;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
border-bottom: 2px solid transparent;
|
border-bottom: 2px solid transparent;
|
||||||
|
font-size: 13px;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
color: #999;
|
color: #999;
|
||||||
background: none;
|
background: none;
|
||||||
@ -642,20 +650,44 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
padding: 6px 12px;
|
padding: 4px 10px;
|
||||||
padding-bottom: 6px;
|
padding-top: calc(4px + env(safe-area-inset-top));
|
||||||
|
padding-bottom: 4px;
|
||||||
|
padding-left: calc(10px + env(safe-area-inset-left));
|
||||||
|
padding-right: calc(10px + env(safe-area-inset-right));
|
||||||
}
|
}
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 12px;
|
gap: 8px;
|
||||||
margin-bottom: 4px;
|
margin-bottom: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.month-navigator {
|
.month-navigator {
|
||||||
max-width: 60%;
|
max-width: 55%;
|
||||||
width: auto;
|
width: auto;
|
||||||
|
flex-shrink: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-btn {
|
||||||
|
padding: 2px 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-preview {
|
||||||
|
width: 22px;
|
||||||
|
height: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-label {
|
||||||
|
font-size: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-arrow {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content-wrapper {
|
.content-wrapper {
|
||||||
@ -663,24 +695,33 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.chart-wrapper {
|
.chart-wrapper {
|
||||||
width: 65%;
|
width: 55%;
|
||||||
height: calc(100dvh - 50px);
|
height: calc(100dvh - 38px);
|
||||||
}
|
}
|
||||||
|
|
||||||
#details-box {
|
#details-box {
|
||||||
position: relative;
|
position: relative;
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
width: 35%;
|
width: 45%;
|
||||||
min-width: auto;
|
min-width: auto;
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
max-height: calc(100dvh - 50px);
|
max-height: calc(100dvh - 38px);
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
padding: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.container.timeline-mode .chart-wrapper {
|
.container.timeline-mode .chart-wrapper {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: calc(100dvh - 50px);
|
height: calc(100dvh - 38px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.details-header {
|
||||||
|
padding: 6px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-item {
|
||||||
|
padding: 4px 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user