Skip to content

Instantly share code, notes, and snippets.

@tutorgaming
Created May 18, 2026 05:01
Show Gist options
  • Select an option

  • Save tutorgaming/12d7f1aef7419f2fac83e54bd11c0ce6 to your computer and use it in GitHub Desktop.

Select an option

Save tutorgaming/12d7f1aef7419f2fac83e54bd11c0ce6 to your computer and use it in GitHub Desktop.
Health Dashboard Example
<!DOCTYPE html>
<html lang="th">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="theme-color" content="#1a7d8f">
<meta name="apple-mobile-web-app-title" content="สุขภาพหลัก">
<title>แดชบอร์ดสุขภาพหลัก</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans+Thai:wght@300;400;500;600;700&family=Prompt:wght@400;500;600;700;800;900&display=swap" rel="stylesheet">
<style>
:root {
--teal-900: #0d4a56;
--teal-800: #146676;
--teal-700: #1a7d8f;
--teal-600: #2596a8;
--teal-500: #3aaabd;
--teal-400: #5cc1d1;
--teal-300: #8bd6e1;
--teal-200: #b8e6ec;
--teal-100: #d9f0f4;
--teal-50: #ebf7f9;
--navy-900: #0a2540;
--navy-700: #1a3a5f;
--ink: #0f2a3b;
--ink-soft: #4a6b7c;
--ink-mute: #8aa3b0;
--paper: #f5f7f8;
--paper-2: #ffffff;
--accent-red: #d94545;
--accent-amber: #f0a830;
--accent-green: #4caf7d;
--accent-violet: #6e5cd6;
--shadow-tile: 0 10px 24px -8px rgba(13,74,86,0.45), 0 4px 8px -4px rgba(13,74,86,0.25);
--shadow-card: 0 8px 28px -6px rgba(13,74,86,0.18);
--shadow-soft: 0 2px 12px rgba(13,74,86,0.08);
--r-lg: 22px;
--r-md: 16px;
--r-sm: 10px;
/* Safe areas for iOS notch and home indicator */
--safe-top: env(safe-area-inset-top, 0px);
--safe-bottom: env(safe-area-inset-bottom, 0px);
--safe-left: env(safe-area-inset-left, 0px);
--safe-right: env(safe-area-inset-right, 0px);
/* Real viewport height accounting for mobile browser chrome */
--vh: 100vh;
}
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html, body {
height: 100%;
width: 100%;
font-family: 'IBM Plex Sans Thai', 'Prompt', system-ui, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: var(--ink);
background: var(--paper);
overflow: hidden;
overscroll-behavior: none;
-webkit-tap-highlight-color: transparent;
-webkit-touch-callout: none;
touch-action: manipulation;
}
body {
position: fixed;
inset: 0;
}
/* App container — fills the entire viewport */
.app {
position: fixed;
inset: 0;
width: 100%;
height: 100vh;
height: 100dvh; /* dynamic viewport height for modern mobile browsers */
background: var(--paper);
overflow: hidden;
display: flex;
flex-direction: column;
}
/* The status bar area in the hero now respects the iOS notch via safe-area */
.pages {
flex: 1;
position: relative;
overflow: hidden;
}
.page {
position: absolute;
inset: 0;
overflow-y: auto;
overflow-x: hidden;
transform: translateX(100%);
transition: transform 0.32s cubic-bezier(0.4, 0, 0.2, 1);
-webkit-overflow-scrolling: touch;
scrollbar-width: none;
/* Account for bottom tab bar height + safe area */
padding-bottom: calc(72px + var(--safe-bottom));
}
.page::-webkit-scrollbar { display: none; }
.page.active { transform: translateX(0); }
/* HOME */
.home-hero {
background:
radial-gradient(ellipse at 50% 100%, rgba(255,255,255,0.35) 0%, transparent 60%),
linear-gradient(160deg, var(--teal-700) 0%, var(--teal-600) 55%, var(--teal-500) 100%);
padding: calc(var(--safe-top) + 16px) 20px 110px;
position: relative;
overflow: hidden;
}
.hero-deco {
position: absolute;
inset: 0;
opacity: 0.10;
pointer-events: none;
overflow: hidden;
}
.hero-deco svg { position: absolute; fill: white; }
.hero-waves {
position: absolute;
bottom: 50px;
left: 0; right: 0;
height: 100px;
opacity: 0.45;
pointer-events: none;
}
.hero-top {
display: flex;
align-items: center;
gap: 12px;
position: relative;
z-index: 5;
}
.avatar-wrap {
position: relative;
flex-shrink: 0;
}
.avatar {
width: 46px; height: 46px;
border-radius: 50%;
background: linear-gradient(135deg, #ffe1c4, #ffc89a);
border: 2.5px solid rgba(255,255,255,0.85);
display: grid;
place-items: center;
font-size: 24px;
overflow: hidden;
box-shadow: 0 4px 10px rgba(0,0,0,0.15);
}
.avatar-tag {
position: absolute;
bottom: -8px; left: 50%;
transform: translateX(-50%);
background: var(--teal-900);
color: #fff;
font-size: 8.5px;
font-weight: 600;
padding: 1.5px 7px;
border-radius: 8px;
white-space: nowrap;
letter-spacing: 0.2px;
}
.hero-title-wrap {
flex: 1;
color: white;
font-family: 'Prompt', sans-serif;
min-width: 0;
}
.hero-title {
font-size: 19px;
font-weight: 700;
letter-spacing: -0.3px;
line-height: 1.1;
}
.bell-btn {
width: 42px; height: 42px;
border-radius: 50%;
background: rgba(255,255,255,0.20);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border: 1.5px solid rgba(255,255,255,0.3);
display: grid;
place-items: center;
cursor: pointer;
position: relative;
transition: transform 0.15s, background 0.15s;
flex-shrink: 0;
}
.bell-btn:active { transform: scale(0.92); background: rgba(255,255,255,0.30); }
.bell-btn svg { width: 20px; height: 20px; fill: white; }
.bell-dot {
position: absolute;
top: 8px; right: 10px;
width: 9px; height: 9px;
background: #ff4757;
border: 2px solid var(--teal-600);
border-radius: 50%;
}
.hero-subtitle {
text-align: center;
color: white;
margin-top: 18px;
position: relative;
z-index: 5;
font-family: 'Prompt', sans-serif;
}
.hero-subtitle h2 {
font-size: 26px;
font-weight: 700;
letter-spacing: -0.5px;
}
.hero-subtitle .en {
font-size: 18px;
font-weight: 500;
opacity: 0.92;
letter-spacing: 0.2px;
}
.score-wrap {
position: relative;
width: 220px;
height: 220px;
margin: 24px auto 0;
z-index: 5;
cursor: pointer;
}
.score-svg { width: 100%; height: 100%; transform: rotate(-90deg); }
.ring-track { stroke: rgba(255,255,255,0.25); }
.ring-progress {
stroke: url(#ringGrad);
stroke-linecap: round;
stroke-dasharray: 565;
stroke-dashoffset: 565;
animation: ringDraw 1.4s cubic-bezier(0.4, 0, 0.2, 1) 0.4s forwards;
filter: drop-shadow(0 0 8px rgba(255,255,255,0.4));
}
@keyframes ringDraw {
to { stroke-dashoffset: 85; }
}
.score-inner {
position: absolute;
inset: 16px;
background: radial-gradient(circle at 30% 30%, #ffffff, #f5fbfc 70%, #e8f5f8);
border-radius: 50%;
box-shadow: inset 0 -8px 24px rgba(13,74,86,0.10), 0 10px 30px rgba(13,74,86,0.18);
display: grid;
place-items: center;
transition: transform 0.2s;
}
.score-wrap:active .score-inner { transform: scale(0.97); }
.score-content {
text-align: center;
font-family: 'Prompt', sans-serif;
}
.score-num {
font-size: 72px;
font-weight: 800;
color: var(--navy-900);
line-height: 0.9;
letter-spacing: -3px;
animation: countUp 1.6s ease forwards;
}
.score-label {
font-size: 18px;
font-weight: 700;
color: var(--navy-900);
margin-top: 6px;
letter-spacing: -0.2px;
}
@keyframes countUp {
0% { opacity: 0; transform: scale(0.5) translateY(20px); }
60% { opacity: 1; transform: scale(1.08) translateY(-4px); }
100% { opacity: 1; transform: scale(1) translateY(0); }
}
.home-sheet {
background: var(--paper);
border-radius: 30px 30px 0 0;
margin-top: -90px;
padding: 20px 16px 20px;
position: relative;
}
.summary-card {
background: white;
border-radius: var(--r-lg);
padding: 14px 16px;
box-shadow: var(--shadow-card);
display: grid;
grid-template-columns: 130px 1fr;
gap: 14px;
align-items: center;
margin-bottom: 18px;
cursor: pointer;
transition: transform 0.18s ease;
animation: slideUp 0.5s 0.1s both;
position: relative;
}
.summary-card:active { transform: scale(0.98); }
.chart-area { position: relative; }
.chart-area h3 {
font-size: 11px;
font-weight: 600;
color: var(--ink-soft);
margin-bottom: 4px;
font-family: 'Prompt', sans-serif;
}
.chart-canvas { width: 100%; height: 70px; }
.chart-days {
display: flex;
justify-content: space-around;
margin-top: 2px;
padding: 0 4px;
}
.chart-days span {
font-size: 9px;
color: var(--ink-mute);
font-weight: 500;
}
.summary-text { font-family: 'Prompt', sans-serif; }
.summary-text .l1 { font-size: 13px; font-weight: 600; color: var(--ink); line-height: 1.4; }
.summary-text .l2 { font-size: 12px; color: var(--ink-soft); margin-top: 2px; }
.summary-text .l3 {
color: var(--accent-red);
font-size: 13px;
font-weight: 700;
margin-top: 4px;
display: flex;
align-items: center;
gap: 4px;
}
.l3-emoji { font-size: 14px; }
.ribbon {
position: absolute;
top: -6px; right: 8px;
background: linear-gradient(135deg, #c8d0d6, #8b95a1);
color: white;
font-size: 9px;
font-weight: 700;
width: 30px;
text-align: center;
padding: 3px 0 5px;
border-radius: 4px 4px 0 0;
box-shadow: 0 3px 6px rgba(0,0,0,0.15);
font-family: 'Prompt', sans-serif;
}
.tiles {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 12px;
}
.tile {
background: linear-gradient(150deg, var(--teal-700) 0%, var(--teal-600) 100%);
border-radius: var(--r-lg);
padding: 18px 16px;
min-height: 130px;
color: white;
cursor: pointer;
position: relative;
overflow: hidden;
box-shadow: var(--shadow-tile);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 8px;
transition: transform 0.16s ease, box-shadow 0.16s ease;
animation: slideUp 0.5s both;
text-align: center;
border: none;
font-family: 'Prompt', sans-serif;
}
.tile:nth-child(1) { animation-delay: 0.15s; }
.tile:nth-child(2) { animation-delay: 0.20s; }
.tile:nth-child(3) { animation-delay: 0.25s; }
.tile:nth-child(4) { animation-delay: 0.30s; }
.tile:active { transform: scale(0.97); }
.tile::before {
content: '';
position: absolute;
top: -40%; right: -30%;
width: 140%; height: 140%;
background: radial-gradient(circle, rgba(255,255,255,0.18) 0%, transparent 50%);
pointer-events: none;
}
.tile-icon-wrap {
width: 52px;
height: 52px;
display: grid;
place-items: center;
}
.tile-icon-wrap svg { width: 100%; height: 100%; }
.tile-label {
font-size: 15px;
font-weight: 600;
line-height: 1.25;
letter-spacing: -0.2px;
}
@keyframes slideUp {
from { opacity: 0; transform: translateY(18px); }
to { opacity: 1; transform: translateY(0); }
}
/* Tab bar — anchored to bottom of viewport with safe area */
.tabbar {
position: fixed;
bottom: 0; left: 0; right: 0;
background: rgba(255,255,255,0.96);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
padding: 8px 6px calc(8px + var(--safe-bottom));
display: flex;
justify-content: space-around;
align-items: center;
border-top: 1px solid rgba(13,74,86,0.06);
z-index: 60;
}
.tab {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
gap: 3px;
padding: 6px 0;
cursor: pointer;
position: relative;
transition: color 0.15s;
font-family: 'Prompt', sans-serif;
}
.tab svg { width: 22px; height: 22px; fill: var(--ink-mute); transition: fill 0.15s; }
.tab .label { font-size: 10.5px; font-weight: 500; color: var(--ink-mute); transition: color 0.15s; }
.tab.active svg { fill: var(--teal-700); }
.tab.active .label { color: var(--teal-700); font-weight: 700; }
.tab.active::before {
content: '';
position: absolute;
top: -8px;
width: 28px; height: 3px;
background: var(--teal-700);
border-radius: 0 0 3px 3px;
}
/* Inner pages */
.inner-page { background: var(--paper); }
.inner-header {
background: linear-gradient(160deg, var(--teal-700) 0%, var(--teal-600) 100%);
padding: calc(var(--safe-top) + 16px) 20px 28px;
color: white;
border-radius: 0 0 28px 28px;
position: relative;
}
.inner-top {
display: flex;
align-items: center;
gap: 10px;
}
.back-btn {
width: 38px; height: 38px;
border-radius: 50%;
background: rgba(255,255,255,0.18);
border: none;
display: grid;
place-items: center;
cursor: pointer;
color: white;
font-size: 18px;
transition: background 0.15s, transform 0.12s;
flex-shrink: 0;
}
.back-btn:active { background: rgba(255,255,255,0.3); transform: scale(0.92); }
.inner-title {
font-size: 18px;
font-weight: 700;
font-family: 'Prompt', sans-serif;
}
.inner-subtitle {
font-size: 12px;
opacity: 0.85;
margin-top: 2px;
}
.inner-content {
padding: 18px 16px;
}
.info-row {
background: white;
border-radius: var(--r-md);
padding: 14px 16px;
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 10px;
box-shadow: var(--shadow-soft);
cursor: pointer;
transition: transform 0.15s;
font-family: 'Prompt', sans-serif;
}
.info-row:active { transform: scale(0.98); }
.info-row .icon-bubble {
width: 42px; height: 42px;
border-radius: 12px;
display: grid; place-items: center;
background: var(--teal-100);
color: var(--teal-700);
flex-shrink: 0;
font-size: 20px;
}
.info-row .icon-bubble svg { width: 22px; height: 22px; fill: currentColor; }
.info-row .row-content { flex: 1; min-width: 0; }
.info-row .row-title { font-size: 14px; font-weight: 600; color: var(--ink); }
.info-row .row-sub { font-size: 12px; color: var(--ink-soft); margin-top: 2px; }
.info-row .row-value { font-size: 16px; font-weight: 700; color: var(--teal-700); }
.info-row .row-value.warn { color: var(--accent-red); font-size: 13px; }
.section-h {
font-size: 12px;
font-weight: 700;
color: var(--ink-soft);
text-transform: uppercase;
letter-spacing: 0.5px;
margin: 16px 4px 8px;
font-family: 'Prompt', sans-serif;
}
/* Meals */
.meal-card {
background: white;
border-radius: var(--r-md);
padding: 14px;
margin-bottom: 10px;
box-shadow: var(--shadow-soft);
display: grid;
grid-template-columns: 56px 1fr auto;
gap: 12px;
align-items: center;
font-family: 'Prompt', sans-serif;
}
.meal-emoji {
width: 56px; height: 56px;
border-radius: 14px;
background: linear-gradient(135deg, var(--teal-100), var(--teal-50));
display: grid; place-items: center;
font-size: 28px;
}
.meal-info .meal-time { font-size: 11px; color: var(--ink-mute); font-weight: 500; }
.meal-info .meal-name { font-size: 14px; font-weight: 600; color: var(--ink); margin-top: 1px; }
.meal-info .meal-kcal { font-size: 12px; color: var(--accent-amber); font-weight: 600; margin-top: 2px; }
.meal-check {
width: 28px; height: 28px;
border-radius: 50%;
border: 2px solid var(--teal-300);
background: white;
cursor: pointer;
transition: all 0.2s;
display: grid; place-items: center;
flex-shrink: 0;
}
.meal-check.done {
background: var(--teal-600);
border-color: var(--teal-600);
}
.meal-check.done::after {
content: '✓';
color: white;
font-weight: 700;
font-size: 14px;
}
/* Doctor */
.doctor-card {
background: white;
border-radius: var(--r-md);
padding: 14px;
margin-bottom: 10px;
box-shadow: var(--shadow-soft);
display: flex;
gap: 12px;
align-items: center;
font-family: 'Prompt', sans-serif;
}
.doctor-avatar {
width: 54px; height: 54px;
border-radius: 50%;
background: linear-gradient(135deg, var(--teal-300), var(--teal-500));
display: grid; place-items: center;
font-size: 26px;
color: white;
position: relative;
flex-shrink: 0;
}
.doctor-avatar::after {
content: '';
position: absolute;
bottom: 0; right: 0;
width: 14px; height: 14px;
background: var(--accent-green);
border-radius: 50%;
border: 2.5px solid white;
}
.doctor-info { flex: 1; min-width: 0; }
.doctor-name { font-size: 14px; font-weight: 700; color: var(--ink); }
.doctor-spec { font-size: 11.5px; color: var(--ink-soft); margin-top: 1px; }
.doctor-meta { font-size: 10.5px; color: var(--accent-green); margin-top: 3px; font-weight: 600; }
.call-btn {
background: var(--teal-600);
color: white;
border: none;
padding: 9px 16px;
border-radius: 20px;
font-size: 12px;
font-weight: 600;
cursor: pointer;
transition: transform 0.15s, background 0.15s;
font-family: 'Prompt', sans-serif;
flex-shrink: 0;
}
.call-btn:active { transform: scale(0.94); background: var(--teal-700); }
/* Rewards */
.reward-card {
background: white;
border-radius: var(--r-md);
padding: 16px;
margin-bottom: 10px;
box-shadow: var(--shadow-soft);
display: flex;
align-items: center;
gap: 14px;
position: relative;
overflow: hidden;
font-family: 'Prompt', sans-serif;
}
.reward-discount {
width: 70px;
text-align: center;
border-right: 2px dashed var(--teal-200);
padding-right: 12px;
flex-shrink: 0;
}
.reward-pct { font-size: 24px; font-weight: 800; color: var(--teal-700); line-height: 1; }
.reward-off { font-size: 10px; color: var(--ink-soft); margin-top: 2px; }
.reward-info { flex: 1; min-width: 0; }
.reward-title { font-size: 13.5px; font-weight: 700; color: var(--ink); }
.reward-sub { font-size: 11px; color: var(--ink-soft); margin-top: 3px; line-height: 1.4; }
.reward-use {
background: var(--teal-700);
color: white;
border: none;
border-radius: 14px;
padding: 8px 14px;
font-size: 11px;
font-weight: 700;
cursor: pointer;
flex-shrink: 0;
font-family: 'Prompt', sans-serif;
}
.reward-use:active { transform: scale(0.94); }
/* Scanner */
.scanner-frame {
margin: 24px auto;
width: 240px;
height: 240px;
max-width: 60vw;
max-height: 60vw;
border-radius: 24px;
position: relative;
background: linear-gradient(135deg, #0d4a56, #146676);
display: grid; place-items: center;
overflow: hidden;
box-shadow: 0 20px 40px -15px rgba(13,74,86,0.4);
}
.scan-line {
position: absolute;
top: 0; left: 0; right: 0;
height: 3px;
background: linear-gradient(90deg, transparent, var(--teal-300), transparent);
box-shadow: 0 0 12px var(--teal-300);
animation: scanLine 2.4s ease-in-out infinite;
}
@keyframes scanLine {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(237px); }
}
.scanner-frame > svg {
width: 90px; height: 90px;
fill: rgba(255,255,255,0.9);
position: relative;
z-index: 2;
}
.corner {
position: absolute;
width: 26px; height: 26px;
border: 3px solid var(--teal-300);
}
.corner.tl { top: 12px; left: 12px; border-right: none; border-bottom: none; border-radius: 8px 0 0 0; }
.corner.tr { top: 12px; right: 12px; border-left: none; border-bottom: none; border-radius: 0 8px 0 0; }
.corner.bl { bottom: 12px; left: 12px; border-right: none; border-top: none; border-radius: 0 0 0 8px; }
.corner.br { bottom: 12px; right: 12px; border-left: none; border-top: none; border-radius: 0 0 8px 0; }
.scan-cta {
text-align: center;
font-family: 'Prompt', sans-serif;
margin-bottom: 16px;
}
.scan-cta .big {
font-size: 18px;
font-weight: 700;
color: var(--ink);
}
.scan-cta .small {
font-size: 12.5px;
color: var(--ink-soft);
margin-top: 4px;
line-height: 1.5;
}
.pill-btn {
width: 100%;
background: var(--teal-700);
color: white;
border: none;
border-radius: 16px;
padding: 14px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
font-family: 'Prompt', sans-serif;
transition: transform 0.15s, background 0.15s;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
}
.pill-btn:active { transform: scale(0.98); background: var(--teal-800); }
.pill-btn.ghost {
background: transparent;
color: var(--teal-700);
border: 1.5px solid var(--teal-200);
margin-top: 10px;
}
/* Notif sheet */
.notif-sheet {
position: fixed;
inset: 0;
background: rgba(10,37,64,0.5);
backdrop-filter: blur(6px);
z-index: 200;
display: flex;
align-items: flex-end;
justify-content: center;
opacity: 0;
pointer-events: none;
transition: opacity 0.25s;
}
.notif-sheet.open { opacity: 1; pointer-events: all; }
.notif-content {
width: 100%;
background: white;
border-radius: 28px 28px 0 0;
padding: 24px 18px calc(36px + var(--safe-bottom));
max-height: 70%;
overflow-y: auto;
transform: translateY(100%);
transition: transform 0.32s cubic-bezier(0.34, 1.36, 0.64, 1);
}
.notif-sheet.open .notif-content { transform: translateY(0); }
.sheet-handle {
width: 38px; height: 4px;
background: #ddd;
border-radius: 2px;
margin: 0 auto 16px;
}
.sheet-title {
font-family: 'Prompt', sans-serif;
font-size: 17px;
font-weight: 700;
color: var(--ink);
margin-bottom: 14px;
}
.notif-item {
display: flex;
gap: 12px;
padding: 12px;
border-radius: 14px;
margin-bottom: 8px;
background: var(--paper);
cursor: pointer;
transition: background 0.15s;
font-family: 'Prompt', sans-serif;
}
.notif-item:active { background: var(--teal-50); }
.notif-item .ni-icon {
width: 36px; height: 36px;
border-radius: 12px;
background: var(--teal-100);
color: var(--teal-700);
display: grid; place-items: center;
flex-shrink: 0;
font-size: 18px;
}
.notif-item .ni-text { flex: 1; }
.notif-item .ni-title { font-size: 13px; font-weight: 600; color: var(--ink); }
.notif-item .ni-body { font-size: 11.5px; color: var(--ink-soft); margin-top: 2px; line-height: 1.4; }
.notif-item .ni-time { font-size: 10px; color: var(--ink-mute); margin-top: 3px; }
/* Toast */
.toast {
position: fixed;
bottom: calc(90px + var(--safe-bottom));
left: 50%;
transform: translateX(-50%) translateY(20px);
background: var(--navy-900);
color: white;
padding: 10px 20px;
border-radius: 24px;
font-size: 13px;
font-family: 'Prompt', sans-serif;
font-weight: 600;
box-shadow: 0 8px 24px rgba(0,0,0,0.3);
opacity: 0;
pointer-events: none;
transition: opacity 0.25s, transform 0.25s;
z-index: 300;
white-space: nowrap;
max-width: 80%;
}
.toast.show {
opacity: 1;
transform: translateX(-50%) translateY(0);
}
.bar-norm { fill: var(--teal-400); }
/* Larger viewport — center the app and add some max width for tablets/desktop preview */
@media (min-width: 600px) {
body {
background: linear-gradient(135deg, #e0f0f4, #cfe6ec);
}
.app {
max-width: 440px;
margin: 0 auto;
box-shadow: 0 20px 60px rgba(13,74,86,0.2);
}
.tabbar {
max-width: 440px;
left: 50%;
transform: translateX(-50%);
}
.notif-sheet {
max-width: 440px;
left: 50%;
transform: translateX(-50%);
}
.toast {
max-width: 320px;
}
}
</style>
</head>
<body>
<div class="app">
<div class="pages">
<!-- HOME -->
<section class="page active" id="page-home">
<div class="home-hero">
<div class="hero-deco">
<svg style="top:80px;left:14px;width:32px;height:32px;" viewBox="0 0 24 24"><path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"/></svg>
<svg style="top:110px;left:60px;width:24px;height:24px;" viewBox="0 0 24 24"><path d="M19 8h-2v3h-3v2h3v3h2v-3h3v-2h-3zM4 8a3 3 0 116 0 3 3 0 01-6 0zm3 5c-2.67 0-8 1.34-8 4v3h16v-3c0-2.66-5.33-4-8-4z"/></svg>
<svg style="top:60px;right:30px;width:26px;height:26px;" viewBox="0 0 24 24"><path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-7 14h-2v-4H6v-2h4V7h2v4h4v2h-4v4z"/></svg>
<svg style="bottom:90px;left:25px;width:28px;height:28px;" viewBox="0 0 24 24"><path d="M9 11.75c-.69 0-1.25.56-1.25 1.25s.56 1.25 1.25 1.25 1.25-.56 1.25-1.25-.56-1.25-1.25-1.25zm6 0c-.69 0-1.25.56-1.25 1.25s.56 1.25 1.25 1.25 1.25-.56 1.25-1.25-.56-1.25-1.25-1.25zM12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2z"/></svg>
<svg style="bottom:110px;right:40px;width:30px;height:30px;" viewBox="0 0 24 24"><path d="M20.5 11H19V7c0-1.1-.9-2-2-2h-4V3.5C13 2.12 11.88 1 10.5 1S8 2.12 8 3.5V5H4c-1.1 0-1.99.9-1.99 2v3.8H3.5c1.49 0 2.7 1.21 2.7 2.7s-1.21 2.7-2.7 2.7H2V20c0 1.1.9 2 2 2h3.8v-1.5c0-1.49 1.21-2.7 2.7-2.7s2.7 1.21 2.7 2.7V22H17c1.1 0 2-.9 2-2v-4h1.5c1.38 0 2.5-1.12 2.5-2.5S21.88 11 20.5 11z"/></svg>
<svg style="top:160px;right:80px;width:22px;height:22px;" viewBox="0 0 24 24"><path d="M19 8l-4 4h3c0 3.31-2.69 6-6 6-1.01 0-1.97-.25-2.8-.7l-1.46 1.46C8.97 19.54 10.43 20 12 20c4.42 0 8-3.58 8-8h3l-4-4z"/></svg>
</div>
<svg class="hero-waves" viewBox="0 0 400 100" preserveAspectRatio="none">
<path d="M0,50 C80,20 160,80 240,50 C320,20 360,70 400,40" stroke="white" stroke-width="1.5" fill="none"/>
<path d="M0,60 C100,30 200,80 280,55 C340,35 380,60 400,50" stroke="#ffcb70" stroke-width="1.2" fill="none" opacity="0.7"/>
<path d="M0,40 C60,65 140,30 220,50 C300,70 360,40 400,55" stroke="#ff7070" stroke-width="1.2" fill="none" opacity="0.7"/>
</svg>
<div class="hero-top">
<div class="avatar-wrap">
<div class="avatar">👩🏻</div>
<span class="avatar-tag">Demo User</span>
</div>
<div class="hero-title-wrap">
<div class="hero-title">แดชบอร์ดสุขภาพหลัก</div>
</div>
<button class="bell-btn" onclick="openNotifSheet()" aria-label="การแจ้งเตือน">
<svg viewBox="0 0 24 24"><path d="M12 22c1.1 0 2-.9 2-2h-4c0 1.1.89 2 2 2zm6-6v-5c0-3.07-1.64-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68C7.63 5.36 6 7.92 6 11v5l-2 2v1h16v-1l-2-2z"/></svg>
<span class="bell-dot"></span>
</button>
</div>
<div class="hero-subtitle">
<h2>ศูนย์รวมข้อมูลสุขภาพ</h2>
<div class="en">All Member &amp; Bio-data</div>
</div>
<div class="score-wrap" onclick="openPage('page-summary')">
<svg class="score-svg" viewBox="0 0 200 200">
<defs>
<linearGradient id="ringGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#5cc1d1"/>
<stop offset="50%" stop-color="#3aaabd"/>
<stop offset="100%" stop-color="#0d4a56"/>
</linearGradient>
</defs>
<circle class="ring-track" cx="100" cy="100" r="90" fill="none" stroke-width="14"/>
<circle class="ring-progress" cx="100" cy="100" r="90" fill="none" stroke-width="14"/>
</svg>
<div class="score-inner">
<div class="score-content">
<div class="score-num">85</div>
<div class="score-label">สุขภาพดีมาก</div>
</div>
</div>
</div>
</div>
<div class="home-sheet">
<div class="summary-card" onclick="openPage('page-summary')">
<div class="ribbon">★</div>
<div class="chart-area">
<h3>Weekly nutrient summary</h3>
<svg class="chart-canvas" viewBox="0 0 200 80" preserveAspectRatio="none">
<g font-size="6" fill="#8aa3b0">
<text x="0" y="10">100</text>
<text x="0" y="28">175</text>
<text x="0" y="46">50</text>
<text x="0" y="64">25</text>
<text x="0" y="76">0</text>
</g>
<g>
<rect class="bar-norm" x="28" y="40" width="14" height="32" rx="2" opacity="0.5"/>
<rect class="bar-norm" x="28" y="48" width="14" height="24" rx="2"/>
<rect class="bar-norm" x="62" y="26" width="14" height="46" rx="2" opacity="0.5"/>
<rect class="bar-norm" x="62" y="36" width="14" height="36" rx="2"/>
<rect class="bar-norm" x="96" y="20" width="14" height="52" rx="2" opacity="0.5"/>
<rect class="bar-norm" x="96" y="30" width="14" height="42" rx="2"/>
<rect class="bar-norm" x="130" y="14" width="14" height="58" rx="2" opacity="0.5"/>
<rect class="bar-norm" x="130" y="22" width="14" height="50" rx="2"/>
<rect class="bar-norm" x="164" y="44" width="14" height="28" rx="2" opacity="0.5"/>
<rect class="bar-norm" x="164" y="50" width="14" height="22" rx="2"/>
</g>
<polyline points="35,42 69,28 103,18 137,12 171,46"
fill="none" stroke="#d94545" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
<g fill="#d94545">
<circle cx="35" cy="42" r="2"/>
<circle cx="69" cy="28" r="2"/>
<circle cx="103" cy="18" r="2"/>
<circle cx="137" cy="12" r="2"/>
<circle cx="171" cy="46" r="2"/>
</g>
</svg>
<div class="chart-days">
<span>Mon</span><span>Tue</span><span>Wed</span><span>Thu</span><span>Fri</span>
</div>
</div>
<div class="summary-text">
<div class="l1">สรุปสารอาหารรายสัปดาห์</div>
<div class="l2">ได้รับโซเดียมสูงกว่าเกณฑ์</div>
<div class="l3">+20% (ลดเค็ม) <span class="l3-emoji">🥦💊</span></div>
</div>
</div>
<div class="tiles">
<button class="tile" onclick="openPage('page-scan')">
<div class="tile-icon-wrap">
<svg viewBox="0 0 64 64" fill="none">
<path d="M8 8 V14 H4 V8 H8 Z M56 8 V14 H60 V8 H56 Z M8 56 V50 H4 V56 H8 Z M56 56 V50 H60 V56 H56 Z" fill="white"/>
<path d="M14 32 H22 L26 22 L32 42 L36 30 H42" stroke="white" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
<rect x="44" y="20" width="14" height="22" rx="1.5" stroke="white" stroke-width="2.4" fill="none"/>
<line x1="47" y1="26" x2="55" y2="26" stroke="white" stroke-width="1.6" stroke-linecap="round"/>
<line x1="47" y1="30" x2="55" y2="30" stroke="white" stroke-width="1.6" stroke-linecap="round"/>
<line x1="47" y1="34" x2="52" y2="34" stroke="white" stroke-width="1.6" stroke-linecap="round"/>
</svg>
</div>
<div class="tile-label">สแกนสุขภาพ<br>&amp; ใบเสร็จ</div>
</button>
<button class="tile" onclick="openPage('page-meal')">
<div class="tile-icon-wrap">
<svg viewBox="0 0 64 64" fill="none">
<path d="M16 8 V28 M12 8 V20 Q12 24 16 24 Q20 24 20 20 V8 M16 28 V56" stroke="white" stroke-width="2.8" stroke-linecap="round" fill="none"/>
<ellipse cx="40" cy="34" rx="14" ry="6" stroke="white" stroke-width="2.8" fill="none"/>
<circle cx="40" cy="32" r="6" stroke="white" stroke-width="2.5" fill="none"/>
<path d="M56 8 Q60 12 60 22 V36 M56 36 V56" stroke="white" stroke-width="2.8" stroke-linecap="round" fill="none"/>
</svg>
</div>
<div class="tile-label">ดูแผนอาหารวันนี้</div>
</button>
<button class="tile" onclick="openPage('page-doctor')">
<div class="tile-icon-wrap">
<svg viewBox="0 0 64 64" fill="none">
<rect x="8" y="20" width="36" height="24" rx="4" fill="white"/>
<path d="M44 28 L56 22 V42 L44 36 Z" fill="white"/>
</svg>
</div>
<div class="tile-label">ปรึกษาหมอ</div>
</button>
<button class="tile" onclick="openPage('page-rewards')">
<div class="tile-icon-wrap">
<svg viewBox="0 0 64 64" fill="none">
<g stroke="white" stroke-width="2" stroke-linecap="round">
<line x1="22" y1="12" x2="22" y2="20"/>
<line x1="18" y1="16" x2="26" y2="16"/>
<line x1="32" y1="6" x2="32" y2="14"/>
<line x1="28" y1="10" x2="36" y2="10"/>
<line x1="42" y1="12" x2="42" y2="20"/>
<line x1="38" y1="16" x2="46" y2="16"/>
</g>
<path d="M10 40 Q10 30 18 30 L28 30 Q32 30 32 34 L42 34 Q46 34 46 38 Q50 38 50 42 Q52 42 52 46 L46 52 Q42 56 36 56 H22 Q12 56 10 46 Z" fill="white"/>
</svg>
</div>
<div class="tile-label">สิทธิพิเศษ</div>
</button>
</div>
</div>
</section>
<!-- SCAN -->
<section class="page inner-page" id="page-scan">
<div class="inner-header">
<div class="inner-top">
<button class="back-btn" onclick="goBack()">←</button>
<div>
<div class="inner-title">สแกนสุขภาพ &amp; ใบเสร็จ</div>
<div class="inner-subtitle">Scan health data &amp; receipts</div>
</div>
</div>
</div>
<div class="inner-content">
<div class="scanner-frame">
<span class="scan-line"></span>
<span class="corner tl"></span>
<span class="corner tr"></span>
<span class="corner bl"></span>
<span class="corner br"></span>
<svg viewBox="0 0 64 64">
<rect x="12" y="18" width="40" height="32" rx="4" stroke="white" stroke-width="3" fill="none"/>
<circle cx="32" cy="34" r="9" stroke="white" stroke-width="3" fill="none"/>
<circle cx="32" cy="34" r="4" fill="white"/>
<rect x="26" y="14" width="12" height="6" rx="1.5" fill="white"/>
</svg>
</div>
<div class="scan-cta">
<div class="big">นำกล้องส่องไปที่ใบเสร็จ</div>
<div class="small">รองรับใบเสร็จจาก 7-Eleven, Lotus's, BigC<br>และร้านอาหารทั่วไป</div>
</div>
<button class="pill-btn" onclick="showToast('📸 เริ่มสแกน...')">
<svg width="20" height="20" viewBox="0 0 24 24" fill="white"><path d="M9.4 10.5l4.77-8.26C13.47 2.09 12.75 2 12 2c-2.4 0-4.6.85-6.32 2.25l3.66 6.35.06-.1zM21.54 9c-.92-2.92-3.15-5.26-6-6.34L11.88 9h9.66zm.26 1h-7.49l.29.5 4.76 8.25C21 16.97 22 14.61 22 12c0-.69-.07-1.35-.2-2z"/></svg>
เปิดกล้องสแกน
</button>
<button class="pill-btn ghost" onclick="showToast('📁 เลือกรูปจากแกลเลอรี่')">เลือกจากแกลเลอรี่</button>
<div class="section-h">ประวัติการสแกนล่าสุด</div>
<div class="info-row" onclick="showToast('ใบเสร็จ 7-Eleven วันนี้')">
<div class="icon-bubble">🧾</div>
<div class="row-content">
<div class="row-title">7-Eleven สาขาอโศก</div>
<div class="row-sub">วันนี้ 14:32 · 4 รายการ</div>
</div>
<div class="row-value warn">⚠ Na สูง</div>
</div>
<div class="info-row" onclick="showToast('ใบเสร็จ Lotus เมื่อวาน')">
<div class="icon-bubble">🧾</div>
<div class="row-content">
<div class="row-title">Lotus's Express</div>
<div class="row-sub">เมื่อวาน 09:15 · 6 รายการ</div>
</div>
<div class="row-value">✓ ดี</div>
</div>
<div class="info-row" onclick="showToast('ใบเสร็จ BigC วันก่อน')">
<div class="icon-bubble">🧾</div>
<div class="row-content">
<div class="row-title">BigC Mini</div>
<div class="row-sub">2 วันก่อน · 3 รายการ</div>
</div>
<div class="row-value">✓ ดี</div>
</div>
</div>
</section>
<!-- MEAL -->
<section class="page inner-page" id="page-meal">
<div class="inner-header">
<div class="inner-top">
<button class="back-btn" onclick="goBack()">←</button>
<div>
<div class="inner-title">แผนอาหารวันนี้</div>
<div class="inner-subtitle">Today's meal plan</div>
</div>
</div>
</div>
<div class="inner-content">
<div class="info-row" style="background: linear-gradient(135deg, var(--teal-50), white);">
<div class="icon-bubble" style="background: var(--teal-600); color: white;">
<svg viewBox="0 0 24 24"><path d="M11 9H9V2H7v7H5V2H3v7c0 2.12 1.66 3.84 3.75 3.97V22h2.5v-9.03C11.34 12.84 13 11.12 13 9V2h-2v7zm5-3v8h2.5v8H21V2c-2.76 0-5 2.24-5 4z"/></svg>
</div>
<div class="row-content">
<div class="row-title">เป้าหมายวันนี้</div>
<div class="row-sub">1,800 kcal · โซเดียม &lt; 2,000mg</div>
</div>
<div class="row-value">68%</div>
</div>
<div class="section-h">มื้อวันนี้</div>
<div class="meal-card">
<div class="meal-emoji">🍳</div>
<div class="meal-info">
<div class="meal-time">เช้า · 07:30</div>
<div class="meal-name">ข้าวต้มปลา + ไข่ลวก</div>
<div class="meal-kcal">320 kcal · Na 520mg</div>
</div>
<div class="meal-check done" onclick="toggleMeal(this)"></div>
</div>
<div class="meal-card">
<div class="meal-emoji">🥗</div>
<div class="meal-info">
<div class="meal-time">กลางวัน · 12:30</div>
<div class="meal-name">สลัดอกไก่</div>
<div class="meal-kcal">480 kcal · Na 380mg</div>
</div>
<div class="meal-check done" onclick="toggleMeal(this)"></div>
</div>
<div class="meal-card">
<div class="meal-emoji">🍵</div>
<div class="meal-info">
<div class="meal-time">ของว่าง · 15:00</div>
<div class="meal-name">โยเกิร์ต + บลูเบอร์รี่</div>
<div class="meal-kcal">180 kcal · Na 80mg</div>
</div>
<div class="meal-check" onclick="toggleMeal(this)"></div>
</div>
<div class="meal-card">
<div class="meal-emoji">🐟</div>
<div class="meal-info">
<div class="meal-time">เย็น · 18:30</div>
<div class="meal-name">ปลานึ่งมะนาว + ผักลวก</div>
<div class="meal-kcal">420 kcal · Na 620mg</div>
</div>
<div class="meal-check" onclick="toggleMeal(this)"></div>
</div>
<button class="pill-btn" style="margin-top:14px;" onclick="showToast('✓ เพิ่มมื้ออาหาร')">
+ เพิ่มมื้ออาหาร
</button>
</div>
</section>
<!-- DOCTOR -->
<section class="page inner-page" id="page-doctor">
<div class="inner-header">
<div class="inner-top">
<button class="back-btn" onclick="goBack()">←</button>
<div>
<div class="inner-title">ปรึกษาแพทย์</div>
<div class="inner-subtitle">Video consultation</div>
</div>
</div>
</div>
<div class="inner-content">
<div class="info-row" style="background: linear-gradient(135deg, #e8f7f1, white);">
<div class="icon-bubble" style="background: var(--accent-green); color: white;">
<svg viewBox="0 0 24 24"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/></svg>
</div>
<div class="row-content">
<div class="row-title">แพทย์ออนไลน์ขณะนี้</div>
<div class="row-sub">รอคิวเฉลี่ย 5-10 นาที</div>
</div>
<div class="row-value" style="color: var(--accent-green);">12 คน</div>
</div>
<div class="section-h">แพทย์ที่แนะนำ</div>
<div class="doctor-card">
<div class="doctor-avatar">👨‍⚕️</div>
<div class="doctor-info">
<div class="doctor-name">นพ. สมชาย ใจดี</div>
<div class="doctor-spec">อายุรกรรม · โภชนบำบัด</div>
<div class="doctor-meta">● ออนไลน์ · ⭐ 4.9 (320)</div>
</div>
<button class="call-btn" onclick="showToast('🎥 กำลังเชื่อมต่อ...')">เริ่มคุย</button>
</div>
<div class="doctor-card">
<div class="doctor-avatar" style="background: linear-gradient(135deg, #f5a623, #e87a3b);">👩‍⚕️</div>
<div class="doctor-info">
<div class="doctor-name">พญ. ปนัดดา สุขสม</div>
<div class="doctor-spec">โรคหัวใจ · ความดัน</div>
<div class="doctor-meta">● ออนไลน์ · ⭐ 4.8 (215)</div>
</div>
<button class="call-btn" onclick="showToast('🎥 กำลังเชื่อมต่อ...')">เริ่มคุย</button>
</div>
<div class="doctor-card">
<div class="doctor-avatar" style="background: linear-gradient(135deg, #8e6cd6, #6e5cd6);">👨‍⚕️</div>
<div class="doctor-info">
<div class="doctor-name">นพ. ธนากร เจริญสุข</div>
<div class="doctor-spec">เบาหวาน · ต่อมไร้ท่อ</div>
<div class="doctor-meta">● ออนไลน์ · ⭐ 4.9 (188)</div>
</div>
<button class="call-btn" onclick="showToast('🎥 กำลังเชื่อมต่อ...')">เริ่มคุย</button>
</div>
<button class="pill-btn ghost" onclick="showToast('🔍 ดูแพทย์ทั้งหมด')">ดูแพทย์ทั้งหมด</button>
</div>
</section>
<!-- REWARDS -->
<section class="page inner-page" id="page-rewards">
<div class="inner-header">
<div class="inner-top">
<button class="back-btn" onclick="goBack()">←</button>
<div>
<div class="inner-title">สิทธิพิเศษ</div>
<div class="inner-subtitle">Your member benefits</div>
</div>
</div>
</div>
<div class="inner-content">
<div style="background: linear-gradient(135deg, var(--teal-700), var(--teal-500)); border-radius: var(--r-lg); padding: 20px; color: white; margin-bottom: 18px; font-family: 'Prompt', sans-serif; position: relative; overflow: hidden;">
<div style="position: absolute; top: -30px; right: -30px; width: 120px; height: 120px; border-radius: 50%; background: rgba(255,255,255,0.1);"></div>
<div style="font-size: 12px; opacity: 0.85;">คะแนนสะสมของคุณ</div>
<div style="font-size: 36px; font-weight: 800; letter-spacing: -1px; margin-top: 4px;">2,450 <span style="font-size: 14px; opacity: 0.85;">คะแนน</span></div>
<div style="font-size: 11.5px; opacity: 0.85; margin-top: 4px;">ระดับ Gold · หมดอายุ 31 ธ.ค. 2026</div>
</div>
<div class="section-h">สิทธิประโยชน์</div>
<div class="reward-card">
<div class="reward-discount"><div class="reward-pct">20%</div><div class="reward-off">OFF</div></div>
<div class="reward-info">
<div class="reward-title">ส่วนลดยาตามใบสั่งแพทย์</div>
<div class="reward-sub">ที่ร้านขายยาเครือข่าย · ถึง 30 มิ.ย.</div>
</div>
<button class="reward-use" onclick="showToast('🎟 ใช้คูปอง 20%')">ใช้</button>
</div>
<div class="reward-card">
<div class="reward-discount"><div class="reward-pct">FREE</div><div class="reward-off">3 ครั้ง</div></div>
<div class="reward-info">
<div class="reward-title">ปรึกษาแพทย์ฟรี</div>
<div class="reward-sub">วิดีโอคอล · เหลือ 2 ครั้ง</div>
</div>
<button class="reward-use" onclick="showToast('🎟 ใช้สิทธิ์ปรึกษาฟรี')">ใช้</button>
</div>
<div class="reward-card">
<div class="reward-discount"><div class="reward-pct">฿100</div><div class="reward-off">ส่วนลด</div></div>
<div class="reward-info">
<div class="reward-title">ตรวจสุขภาพประจำปี</div>
<div class="reward-sub">โรงพยาบาลในเครือ · ทั่วประเทศ</div>
</div>
<button class="reward-use" onclick="showToast('🎟 จองคิวตรวจสุขภาพ')">จอง</button>
</div>
<div class="reward-card">
<div class="reward-discount"><div class="reward-pct">2X</div><div class="reward-off">คะแนน</div></div>
<div class="reward-info">
<div class="reward-title">สแกนใบเสร็จรับ 2 เท่า</div>
<div class="reward-sub">วันนี้เท่านั้น · จนถึง 23:59</div>
</div>
<button class="reward-use" onclick="openPage('page-scan')">รับ</button>
</div>
</div>
</section>
<!-- SUMMARY -->
<section class="page inner-page" id="page-summary">
<div class="inner-header">
<div class="inner-top">
<button class="back-btn" onclick="goBack()">←</button>
<div>
<div class="inner-title">สรุปสารอาหาร</div>
<div class="inner-subtitle">Weekly nutrient summary</div>
</div>
</div>
</div>
<div class="inner-content">
<div class="info-row" style="background: linear-gradient(135deg, #ffe4e4, white); border-left: 4px solid var(--accent-red);">
<div class="icon-bubble" style="background: var(--accent-red); color: white;">⚠️</div>
<div class="row-content">
<div class="row-title">โซเดียมสูงกว่าเกณฑ์</div>
<div class="row-sub">+20% จากค่าแนะนำสัปดาห์นี้</div>
</div>
<div class="row-value warn">+20%</div>
</div>
<div class="section-h">สารอาหารรายวัน</div>
<div class="info-row">
<div class="icon-bubble">🧂</div>
<div class="row-content">
<div class="row-title">โซเดียม (Sodium)</div>
<div class="row-sub">เฉลี่ย 2,400mg/วัน · เกิน 400mg</div>
</div>
<div class="row-value warn">⚠</div>
</div>
<div class="info-row">
<div class="icon-bubble">🍞</div>
<div class="row-content">
<div class="row-title">คาร์โบไฮเดรต</div>
<div class="row-sub">เฉลี่ย 240g/วัน · ปกติ</div>
</div>
<div class="row-value">✓</div>
</div>
<div class="info-row">
<div class="icon-bubble">🍗</div>
<div class="row-content">
<div class="row-title">โปรตีน</div>
<div class="row-sub">เฉลี่ย 62g/วัน · ดี</div>
</div>
<div class="row-value">✓</div>
</div>
<div class="info-row">
<div class="icon-bubble">🥑</div>
<div class="row-content">
<div class="row-title">ไขมัน</div>
<div class="row-sub">เฉลี่ย 58g/วัน · ปกติ</div>
</div>
<div class="row-value">✓</div>
</div>
<div class="section-h">คำแนะนำ</div>
<div class="info-row">
<div class="icon-bubble" style="background: #fff3e0; color: var(--accent-amber);">💡</div>
<div class="row-content">
<div class="row-title">ลดอาหารแปรรูปและน้ำจิ้ม</div>
<div class="row-sub">เป็นแหล่งโซเดียมหลัก</div>
</div>
</div>
<div class="info-row">
<div class="icon-bubble" style="background: #e8f7f1; color: var(--accent-green);">🥗</div>
<div class="row-content">
<div class="row-title">เพิ่มผักใบเขียวและผลไม้</div>
<div class="row-sub">ช่วยขับโซเดียมส่วนเกิน</div>
</div>
</div>
</div>
</section>
<!-- ACTIVITY -->
<section class="page inner-page" id="page-activity">
<div class="inner-header">
<div class="inner-top">
<div style="width:38px;"></div>
<div>
<div class="inner-title">กิจกรรม</div>
<div class="inner-subtitle">Activities &amp; challenges</div>
</div>
</div>
</div>
<div class="inner-content">
<div class="section-h">กำลังดำเนินอยู่</div>
<div class="info-row">
<div class="icon-bubble">🚶</div>
<div class="row-content">
<div class="row-title">เดิน 10,000 ก้าว</div>
<div class="row-sub">วันนี้: 6,842 / 10,000 ก้าว</div>
</div>
<div class="row-value">68%</div>
</div>
<div class="info-row">
<div class="icon-bubble">💧</div>
<div class="row-content">
<div class="row-title">ดื่มน้ำ 8 แก้ว</div>
<div class="row-sub">วันนี้: 5 / 8 แก้ว</div>
</div>
<div class="row-value">62%</div>
</div>
<div class="info-row">
<div class="icon-bubble">😴</div>
<div class="row-content">
<div class="row-title">นอน 8 ชั่วโมง</div>
<div class="row-sub">เมื่อคืน: 7 ชม. 20 นาที</div>
</div>
<div class="row-value">92%</div>
</div>
<div class="section-h">ชาเลนจ์</div>
<div class="info-row">
<div class="icon-bubble" style="background: #fff3e0; color: var(--accent-amber);">🏆</div>
<div class="row-content">
<div class="row-title">7 วันลดเค็ม</div>
<div class="row-sub">วันที่ 3 / 7 · รับ 500 คะแนน</div>
</div>
<button class="call-btn" onclick="showToast('🏆 ทำต่อ!')">ทำต่อ</button>
</div>
</div>
</section>
<!-- SHOP -->
<section class="page inner-page" id="page-shop">
<div class="inner-header">
<div class="inner-top">
<div style="width:38px;"></div>
<div>
<div class="inner-title">ร้านค้า</div>
<div class="inner-subtitle">Health products</div>
</div>
</div>
</div>
<div class="inner-content">
<div class="section-h">หมวดหมู่</div>
<div style="display:grid; grid-template-columns: 1fr 1fr; gap: 10px;">
<div class="info-row" style="flex-direction: column; align-items: flex-start; padding: 18px 14px;" onclick="showToast('💊 ยาและวิตามิน')">
<div class="icon-bubble" style="margin-bottom: 8px;">💊</div>
<div class="row-title">ยาและวิตามิน</div>
<div class="row-sub">120+ รายการ</div>
</div>
<div class="info-row" style="flex-direction: column; align-items: flex-start; padding: 18px 14px;" onclick="showToast('🩺 อุปกรณ์การแพทย์')">
<div class="icon-bubble" style="margin-bottom: 8px;">🩺</div>
<div class="row-title">อุปกรณ์การแพทย์</div>
<div class="row-sub">45+ รายการ</div>
</div>
<div class="info-row" style="flex-direction: column; align-items: flex-start; padding: 18px 14px;" onclick="showToast('🥗 อาหารสุขภาพ')">
<div class="icon-bubble" style="margin-bottom: 8px;">🥗</div>
<div class="row-title">อาหารสุขภาพ</div>
<div class="row-sub">80+ รายการ</div>
</div>
<div class="info-row" style="flex-direction: column; align-items: flex-start; padding: 18px 14px;" onclick="showToast('🧪 ตรวจสุขภาพ')">
<div class="icon-bubble" style="margin-bottom: 8px;">🧪</div>
<div class="row-title">ตรวจสุขภาพ</div>
<div class="row-sub">25+ แพ็คเกจ</div>
</div>
</div>
</div>
</section>
<!-- COMMUNITY -->
<section class="page inner-page" id="page-community">
<div class="inner-header">
<div class="inner-top">
<div style="width:38px;"></div>
<div>
<div class="inner-title">ชุมชน</div>
<div class="inner-subtitle">Health community</div>
</div>
</div>
</div>
<div class="inner-content">
<div class="section-h">กระทู้ยอดนิยม</div>
<div class="info-row" onclick="showToast('📖 เปิดบทความ...')">
<div class="icon-bubble">🥗</div>
<div class="row-content">
<div class="row-title">เมนูลดเค็มที่ทำง่าย 5 สูตร</div>
<div class="row-sub">คุณหมอเมย์ · 234 likes</div>
</div>
</div>
<div class="info-row" onclick="showToast('📖 เปิดบทความ...')">
<div class="icon-bubble">🏃</div>
<div class="row-content">
<div class="row-title">เริ่มวิ่งยังไงไม่บาดเจ็บ</div>
<div class="row-sub">โค้ชต้อม · 189 likes</div>
</div>
</div>
<div class="info-row" onclick="showToast('📖 เปิดบทความ...')">
<div class="icon-bubble">💤</div>
<div class="row-content">
<div class="row-title">นอนหลับลึกใน 30 นาที</div>
<div class="row-sub">Dr.Sleep · 156 likes</div>
</div>
</div>
<div class="info-row" onclick="showToast('📖 เปิดบทความ...')">
<div class="icon-bubble">🧘</div>
<div class="row-content">
<div class="row-title">โยคะคลายเครียดสำหรับมือใหม่</div>
<div class="row-sub">ครูแอน · 124 likes</div>
</div>
</div>
</div>
</section>
<!-- PROFILE -->
<section class="page inner-page" id="page-profile">
<div class="inner-header">
<div class="inner-top">
<div style="width:38px;"></div>
<div>
<div class="inner-title">โปรไฟล์ของฉัน</div>
<div class="inner-subtitle">My profile</div>
</div>
</div>
<div style="display: flex; align-items: center; gap: 14px; margin-top: 14px;">
<div style="width: 64px; height: 64px; border-radius: 50%; background: linear-gradient(135deg, #ffe1c4, #ffc89a); display: grid; place-items: center; font-size: 32px; border: 3px solid rgba(255,255,255,0.4);">👩🏻</div>
<div style="font-family: 'Prompt', sans-serif;">
<div style="font-size: 17px; font-weight: 700; color: white;">Demo User</div>
<div style="font-size: 12px; color: rgba(255,255,255,0.85); margin-top: 2px;">สมาชิก Gold · ตั้งแต่ 2024</div>
</div>
</div>
</div>
<div class="inner-content">
<div class="section-h">บัญชี</div>
<div class="info-row" onclick="showToast('👤 ข้อมูลส่วนตัว')">
<div class="icon-bubble">👤</div>
<div class="row-content"><div class="row-title">ข้อมูลส่วนตัว</div></div>
<span style="color: var(--ink-mute);">›</span>
</div>
<div class="info-row" onclick="showToast('🩺 ประวัติสุขภาพ')">
<div class="icon-bubble">🩺</div>
<div class="row-content"><div class="row-title">ประวัติสุขภาพ</div></div>
<span style="color: var(--ink-mute);">›</span>
</div>
<div class="info-row" onclick="openNotifSheet()">
<div class="icon-bubble">🔔</div>
<div class="row-content"><div class="row-title">การแจ้งเตือน</div></div>
<span style="color: var(--ink-mute);">›</span>
</div>
<div class="section-h">การตั้งค่า</div>
<div class="info-row" onclick="showToast('🌐 เปลี่ยนภาษา')">
<div class="icon-bubble">🌐</div>
<div class="row-content"><div class="row-title">ภาษา</div></div>
<span style="color: var(--ink-soft); font-size: 13px;">ไทย ›</span>
</div>
<div class="info-row" onclick="showToast('🌙 โหมดมืด (เร็วๆ นี้)')">
<div class="icon-bubble">🌙</div>
<div class="row-content"><div class="row-title">โหมดมืด</div></div>
<span style="color: var(--ink-soft); font-size: 13px;">ปิด ›</span>
</div>
<div class="info-row" onclick="showToast('👋 ออกจากระบบ')" style="margin-top: 10px;">
<div class="icon-bubble" style="background: #ffe4e4; color: var(--accent-red);">🚪</div>
<div class="row-content"><div class="row-title" style="color: var(--accent-red);">ออกจากระบบ</div></div>
</div>
</div>
</section>
</div>
<!-- Tab bar -->
<div class="tabbar">
<div class="tab active" data-page="page-home" onclick="switchTab(this)">
<svg viewBox="0 0 24 24"><path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/></svg>
<span class="label">หน้าหลัก</span>
</div>
<div class="tab" data-page="page-activity" onclick="switchTab(this)">
<svg viewBox="0 0 24 24"><path d="M19 5h-2V3H7v2H5c-1.1 0-2 .9-2 2v1c0 2.55 1.92 4.63 4.39 4.94.63 1.5 1.98 2.63 3.61 2.96V19H7v2h10v-2h-4v-3.1c1.63-.33 2.98-1.46 3.61-2.96C19.08 12.63 21 10.55 21 8V7c0-1.1-.9-2-2-2zM5 8V7h2v3.82C5.84 10.4 5 9.3 5 8zm14 0c0 1.3-.84 2.4-2 2.82V7h2v1z"/></svg>
<span class="label">กิจกรรม</span>
</div>
<div class="tab" data-page="page-shop" onclick="switchTab(this)">
<svg viewBox="0 0 24 24"><path d="M19 6h-2c0-2.76-2.24-5-5-5S7 3.24 7 6H5c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm-7-3c1.66 0 3 1.34 3 3H9c0-1.66 1.34-3 3-3zm0 10c-2.76 0-5-2.24-5-5h2c0 1.66 1.34 3 3 3s3-1.34 3-3h2c0 2.76-2.24 5-5 5z"/></svg>
<span class="label">ร้านค้า</span>
</div>
<div class="tab" data-page="page-community" onclick="switchTab(this)">
<svg viewBox="0 0 24 24"><path d="M16 11c1.66 0 2.99-1.34 2.99-3S17.66 5 16 5c-1.66 0-3 1.34-3 3s1.34 3 3 3zm-8 0c1.66 0 2.99-1.34 2.99-3S9.66 5 8 5C6.34 5 5 6.34 5 8s1.34 3 3 3zm0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5z"/></svg>
<span class="label">ชุมชน</span>
</div>
<div class="tab" data-page="page-profile" onclick="switchTab(this)">
<svg viewBox="0 0 24 24"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/></svg>
<span class="label">ฉัน</span>
</div>
</div>
<!-- Notif sheet -->
<div class="notif-sheet" id="notifSheet" onclick="closeNotifSheet(event)">
<div class="notif-content" onclick="event.stopPropagation()">
<div class="sheet-handle"></div>
<div class="sheet-title">การแจ้งเตือน 🔔</div>
<div class="notif-item" onclick="document.getElementById('notifSheet').classList.remove('open'); openPage('page-summary');">
<div class="ni-icon">⚠️</div>
<div class="ni-text">
<div class="ni-title">โซเดียมเกินเกณฑ์</div>
<div class="ni-body">คุณได้รับโซเดียม +20% สัปดาห์นี้</div>
<div class="ni-time">5 นาทีที่แล้ว</div>
</div>
</div>
<div class="notif-item">
<div class="ni-icon">💊</div>
<div class="ni-text">
<div class="ni-title">ถึงเวลาทานยา</div>
<div class="ni-body">ยาความดันโลหิต - 1 เม็ดหลังอาหาร</div>
<div class="ni-time">2 ชั่วโมงที่แล้ว</div>
</div>
</div>
<div class="notif-item" onclick="document.getElementById('notifSheet').classList.remove('open'); openPage('page-rewards');">
<div class="ni-icon">🎁</div>
<div class="ni-text">
<div class="ni-title">รับคะแนนพิเศษ</div>
<div class="ni-body">สแกนใบเสร็จวันนี้รับคะแนน 2 เท่า</div>
<div class="ni-time">เช้านี้</div>
</div>
</div>
<div class="notif-item" onclick="document.getElementById('notifSheet').classList.remove('open'); openPage('page-doctor');">
<div class="ni-icon">🩺</div>
<div class="ni-text">
<div class="ni-title">นัดหมายแพทย์</div>
<div class="ni-body">นพ. สมชาย ตอบกลับข้อความแล้ว</div>
<div class="ni-time">เมื่อวาน</div>
</div>
</div>
</div>
</div>
<div class="toast" id="toast"></div>
</div>
<script>
const pages = document.querySelectorAll('.page');
const tabs = document.querySelectorAll('.tab');
const history = ['page-home'];
function openPage(id) {
pages.forEach(p => p.classList.remove('active'));
const target = document.getElementById(id);
target.classList.add('active');
target.scrollTop = 0;
if (history[history.length - 1] !== id) history.push(id);
const tabPages = ['page-home', 'page-activity', 'page-shop', 'page-community', 'page-profile'];
if (tabPages.includes(id)) {
tabs.forEach(t => t.classList.toggle('active', t.dataset.page === id));
}
}
function goBack() {
if (history.length > 1) {
history.pop();
const prev = history[history.length - 1];
pages.forEach(p => p.classList.remove('active'));
document.getElementById(prev).classList.add('active');
} else {
openPage('page-home');
}
}
function switchTab(el) {
const pageId = el.dataset.page;
tabs.forEach(t => t.classList.remove('active'));
el.classList.add('active');
pages.forEach(p => p.classList.remove('active'));
const target = document.getElementById(pageId);
target.classList.add('active');
target.scrollTop = 0;
history.length = 0;
history.push(pageId);
}
function openNotifSheet() {
document.getElementById('notifSheet').classList.add('open');
}
function closeNotifSheet(e) {
if (!e || e.target.id === 'notifSheet') {
document.getElementById('notifSheet').classList.remove('open');
}
}
let toastTimer;
function showToast(msg) {
const t = document.getElementById('toast');
t.textContent = msg;
t.classList.add('show');
clearTimeout(toastTimer);
toastTimer = setTimeout(() => t.classList.remove('show'), 2000);
}
function toggleMeal(el) {
el.classList.toggle('done');
showToast(el.classList.contains('done') ? '✓ บันทึกแล้ว' : '↩ ยกเลิก');
}
// Prevent pull-to-refresh and bounce scrolling on iOS
document.addEventListener('touchmove', function(e) {
const scrollable = e.target.closest('.page, .notif-content');
if (!scrollable) {
e.preventDefault();
}
}, { passive: false });
// Handle Android back button via History API
window.addEventListener('popstate', function(e) {
if (document.getElementById('notifSheet').classList.contains('open')) {
closeNotifSheet();
history.pushState(null, '', '');
return;
}
if (window.history && window.history.state !== 'home') {
goBack();
window.history.pushState(null, '', '');
}
});
window.history.pushState('home', '', '');
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment