feat: Implement mobile responsiveness for marketing pages with adaptive layouts and a sidebar toggle.

This commit is contained in:
Ho Ngoc Hai
2026-02-12 22:37:10 +07:00
parent ba57eb7e03
commit e3915aee9e
7 changed files with 227 additions and 22 deletions

View File

@@ -80,6 +80,10 @@
@* ═══ MAIN AREA / VÙNG NỘI DUNG ═══ *@
<main class="mkt-main">
@* Mobile toggle button — visible only on ≤768px *@
<button class="mkt-mobile-toggle" @onclick="ToggleSidebar" style="position:fixed;top:12px;left:12px;z-index:998;">
<i data-lucide="menu"></i>
</button>
@Body
</main>
</div>

View File

@@ -10,9 +10,9 @@
<PageTitle>AI Chatbot — tMarketing</PageTitle>
<div style="display:flex;flex:1;min-height:0;">
<div class="mkt-aibot-layout" style="display:flex;flex:1;min-height:0;">
@* ═══ LEFT: Scenario List ═══ *@
<div style="width:260px;background:var(--mkt-bg-card);border-right:1px solid var(--mkt-border);display:flex;flex-direction:column;">
<div class="mkt-scenario-list" style="width:260px;background:var(--mkt-bg-card);border-right:1px solid var(--mkt-border);display:flex;flex-direction:column;">
<div style="padding:16px;border-bottom:1px solid var(--mkt-border);display:flex;align-items:center;justify-content:space-between;">
<div style="display:flex;align-items:center;gap:8px;">
<i data-lucide="brain" style="width:16px;height:16px;color:var(--mkt-yellow-primary);"></i>
@@ -48,7 +48,7 @@
</div>
@* ═══ CENTER: Scenario Detail ═══ *@
<div style="flex:1;display:flex;flex-direction:column;background:var(--mkt-bg-page);">
<div class="mkt-aibot-main" style="flex:1;display:flex;flex-direction:column;background:var(--mkt-bg-page);">
@* Header *@
<div style="padding:16px 20px;background:var(--mkt-bg-card);border-bottom:1px solid var(--mkt-border);display:flex;align-items:center;justify-content:space-between;">
<div style="display:flex;flex-direction:column;gap:2px;">
@@ -68,7 +68,7 @@
</div>
@* Scenario content *@
<div style="flex:1;display:flex;gap:20px;padding:20px;overflow-y:auto;">
<div class="mkt-aibot-panels" style="flex:1;display:flex;gap:20px;padding:20px;overflow-y:auto;">
@* Training Data Panel *@
<div class="mkt-panel" style="flex:1;">
<div class="mkt-panel__header">

View File

@@ -29,7 +29,7 @@
</div>
@* ═══ CONTENT ═══ *@
<div style="display:flex;gap:0;flex:1;min-height:0;padding:0 28px 28px;">
<div class="mkt-content-split" style="display:flex;gap:0;flex:1;min-height:0;padding:0 28px 28px;">
@* ── LEFT: Calendar + Upcoming ── *@
<div style="flex:1;display:flex;flex-direction:column;gap:20px;padding-right:20px;">
@* Content Calendar *@

View File

@@ -52,7 +52,7 @@
</div>
@* ── ROW 2: Engagement Chart + Top Content ── *@
<div style="display:flex;gap:20px;">
<div class="mkt-analytics-row" style="display:flex;gap:20px;">
@* Engagement Chart (placeholder) *@
<div class="mkt-panel" style="flex:1;">
<div class="mkt-panel__header">
@@ -113,7 +113,7 @@
</h3>
</div>
<div class="mkt-panel__body">
<div style="display:flex;gap:16px;">
<div class="mkt-channel-cards" style="display:flex;gap:16px;">
@foreach (var channel in _channelPerf)
{
<div style="flex:1;display:flex;flex-direction:column;gap:8px;padding:16px;background:var(--mkt-bg-page);border-radius:8px;">

View File

@@ -10,9 +10,9 @@
<PageTitle>Chatbot Automation — tMarketing</PageTitle>
<div style="display:flex;flex:1;min-height:0;">
<div class="mkt-chatbot-layout" style="display:flex;flex:1;min-height:0;">
@* ═══ LEFT: Flow List ═══ *@
<div style="width:280px;background:var(--mkt-bg-card);border-right:1px solid var(--mkt-border);display:flex;flex-direction:column;">
<div class="mkt-flow-list" style="width:280px;background:var(--mkt-bg-card);border-right:1px solid var(--mkt-border);display:flex;flex-direction:column;">
<div style="padding:16px;border-bottom:1px solid var(--mkt-border);display:flex;align-items:center;justify-content:space-between;">
<div style="display:flex;align-items:center;gap:8px;">
<i data-lucide="git-branch" style="width:16px;height:16px;color:var(--mkt-yellow-primary);"></i>
@@ -41,7 +41,7 @@
</div>
@* ═══ CENTER: Flow Builder Canvas ═══ *@
<div style="flex:1;display:flex;flex-direction:column;background:var(--mkt-bg-page);">
<div class="mkt-flow-canvas" style="flex:1;display:flex;flex-direction:column;background:var(--mkt-bg-page);">
@* Header *@
<div style="padding:16px 20px;background:var(--mkt-bg-card);border-bottom:1px solid var(--mkt-border);display:flex;align-items:center;justify-content:space-between;">
<div style="display:flex;flex-direction:column;gap:2px;">
@@ -101,7 +101,7 @@
</div>
@* ═══ RIGHT: Node Palette ═══ *@
<div style="width:260px;background:var(--mkt-bg-card);border-left:1px solid var(--mkt-border);display:flex;flex-direction:column;">
<div class="mkt-node-palette" style="width:260px;background:var(--mkt-bg-card);border-left:1px solid var(--mkt-border);display:flex;flex-direction:column;">
<div style="padding:16px;border-bottom:1px solid var(--mkt-border);display:flex;align-items:center;gap:8px;">
<i data-lucide="box" style="width:16px;height:16px;color:var(--mkt-yellow-primary);"></i>
<span style="font-size:13px;font-weight:700;color:var(--mkt-text-primary);letter-spacing:0.5px;">ADD NODE</span>

View File

@@ -31,7 +31,7 @@
@* ═══ CONTENT ═══ *@
<div class="mkt-content">
@* ── ROW 1: Platform Status + Quick Actions ── *@
<div style="display:flex;gap:20px;">
<div class="mkt-hub-columns" style="display:flex;gap:20px;">
@* Platform Status *@
<div class="mkt-panel" style="flex:1;">
<div class="mkt-panel__header" style="border-bottom:none;padding-bottom:8px;">

View File

@@ -585,7 +585,24 @@
display: none;
}
/* ── Mobile hamburger button ── */
.mkt-mobile-toggle {
display: none;
width: 36px;
height: 36px;
border-radius: 6px;
background: var(--mkt-bg-card);
border: 1px solid var(--mkt-border);
color: var(--mkt-text-primary);
align-items: center;
justify-content: center;
cursor: pointer;
flex-shrink: 0;
}
@media (max-width: 768px) {
/* ── Sidebar hide/show ── */
.mkt-sidebar {
position: fixed;
left: -260px;
@@ -607,27 +624,211 @@
z-index: 999;
}
.mkt-kpi-row {
.mkt-mobile-toggle {
display: flex;
}
/* ── Topbar ── */
.mkt-topbar {
padding: 12px 16px;
gap: 8px;
}
.mkt-topbar__title {
font-size: 16px;
}
.mkt-topbar__subtitle {
font-size: 11px;
}
.mkt-topbar__right {
flex-wrap: wrap;
gap: 6px;
}
/* ── Content area ── */
.mkt-content {
padding: 0 12px 16px;
gap: 16px;
}
/* ── KPI row → 2x2 grid ── */
.mkt-kpi-row {
display: grid !important;
grid-template-columns: 1fr 1fr;
gap: 10px !important;
}
.mkt-kpi-card {
min-width: calc(50% - 8px);
min-width: 0;
}
.mkt-topbar {
padding: 16px;
.mkt-kpi-card__value {
font-size: 20px;
}
.mkt-content {
padding: 0 16px 16px;
/* ── Table → horizontal scroll ── */
.mkt-panel:has(.mkt-table) .mkt-panel__body,
.mkt-table-wrap {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
.mkt-chat-info {
display: none;
.mkt-table {
min-width: 600px;
}
/* ── Search → smaller ── */
.mkt-search {
min-width: 120px;
}
/* ═══ LIVECHAT — single column ═══ */
.mkt-chat-layout {
flex-direction: column !important;
}
.mkt-chat-list {
width: 100%;
width: 100% !important;
max-height: 220px;
border-right: none !important;
border-bottom: 1px solid var(--mkt-border);
}
}
.mkt-chat-main {
min-height: 300px;
}
.mkt-chat-info {
display: none !important;
}
/* ═══ SOCIAL HUB — stack sections ═══ */
.mkt-hub-columns {
flex-direction: column !important;
gap: 16px !important;
}
.mkt-hub-columns>div {
width: 100% !important;
}
.mkt-platform-grid {
flex-direction: column !important;
gap: 10px !important;
}
.mkt-platform-grid>div {
width: 100% !important;
}
/* ═══ AI CONTENT STUDIO — stack calendar + AI panel ═══ */
.mkt-content-split {
flex-direction: column !important;
padding: 0 12px 16px !important;
}
.mkt-content-split>div {
width: 100% !important;
padding-right: 0 !important;
}
.mkt-calendar-grid {
font-size: 11px;
}
/* ═══ ANALYTICS — stack chart + top content ═══ */
.mkt-analytics-row {
flex-direction: column !important;
gap: 16px !important;
}
.mkt-analytics-row>.mkt-panel {
width: 100% !important;
flex: none !important;
}
.mkt-channel-cards {
flex-direction: column !important;
gap: 10px !important;
}
.mkt-channel-cards>div {
width: 100% !important;
}
/* ═══ CHATBOT — stack flows + canvas ═══ */
.mkt-chatbot-layout {
flex-direction: column !important;
}
.mkt-chatbot-layout>.mkt-flow-list {
width: 100% !important;
max-height: 200px;
border-right: none !important;
border-bottom: 1px solid var(--mkt-border);
overflow-y: auto;
}
.mkt-chatbot-layout>.mkt-flow-canvas {
min-height: 300px;
}
.mkt-node-palette {
position: static !important;
width: 100% !important;
right: auto !important;
top: auto !important;
bottom: auto !important;
display: flex !important;
flex-direction: row !important;
overflow-x: auto !important;
gap: 8px !important;
padding: 12px !important;
border-top: 1px solid var(--mkt-border);
}
.mkt-node-palette>div {
min-width: 140px;
flex-shrink: 0;
}
/* ═══ AI CHATBOT — stack scenarios + panels ═══ */
.mkt-aibot-layout {
flex-direction: column !important;
}
.mkt-aibot-layout>.mkt-scenario-list {
width: 100% !important;
max-height: 200px;
border-right: none !important;
border-bottom: 1px solid var(--mkt-border);
overflow-y: auto;
}
.mkt-aibot-layout>.mkt-aibot-main {
width: 100% !important;
}
.mkt-aibot-panels {
flex-direction: column !important;
gap: 16px !important;
}
.mkt-aibot-panels>div {
width: 100% !important;
}
/* ═══ Panel footer actions → wrap ═══ */
.mkt-panel-footer {
flex-wrap: wrap;
gap: 8px;
}
.mkt-panel-footer .mkt-btn-ghost,
.mkt-panel-footer .mkt-btn-primary {
font-size: 11px;
padding: 6px 10px;
}
}