mirror of
https://github.com/agent0ai/agent-zero.git
synced 2026-05-17 21:19:46 +00:00
Redesign the three messaging integration panels with a clearer, more guided setup flow and polished user experience. - simplify the email panel by surfacing the essentials first, moving advanced scheduling behind Advanced, and making connection checks more visible - redesign Telegram and WhatsApp as step-based setup flows with clearer status states, safer access warnings, richer test feedback, and more responsive layouts - add shared plugin-settings wizard footer support, extract WhatsApp state into its own store, and align test-connection messages with the new UX ux: ease Email connector setup and refresh copy - Redesign the Email connector settings around a guided first-run flow with a clearer empty state, provider presets, and much friendlier copy - Move server, routing, and scheduling power-user controls into an `Advanced` section while keeping the existing config model compatible - Improve connection-test messaging, add Exchange inbound validation, and refresh the dashboard Email card copy while keeping the card visible - Verify the updated setup flow in the browser on desktop and mobile update and simplify x-data based on established frontend patterns Update 10_discovery_cards.py further polishing and first-draft no-click model for email and telegram update whatsapp Update telegram-config-store.js
680 lines
No EOL
24 KiB
HTML
680 lines
No EOL
24 KiB
HTML
<html>
|
|
|
|
<head>
|
|
<title>Telegram Integration</title>
|
|
<script type="module">
|
|
import { store } from "/plugins/_telegram_integration/webui/telegram-config-store.js";
|
|
</script>
|
|
</head>
|
|
|
|
<body>
|
|
<div x-data x-init="$store.telegramConfig.init(config, context)" x-destroy="$store.telegramConfig.cleanup()">
|
|
<template x-if="config">
|
|
<div class="tg-page">
|
|
<div class="section-title">Telegram</div>
|
|
|
|
<template x-if="$store.telegramConfig.didInit && $store.telegramConfig.bots.length === 0">
|
|
<div class="tg-empty">
|
|
<div class="tg-empty-title">Start with one bot</div>
|
|
<div class="tg-empty-copy">
|
|
Most setups only need a bot token, one allowed user, and the default polling mode.
|
|
</div>
|
|
<button class="btn btn-field" @click="$store.telegramConfig.addBot()">
|
|
Connect a bot
|
|
</button>
|
|
</div>
|
|
</template>
|
|
|
|
<template x-for="(bot, idx) in $store.telegramConfig.bots" :key="idx">
|
|
<div class="tg-card">
|
|
<div class="tg-card-header" @click="$store.telegramConfig.toggleEditing(idx)">
|
|
<div class="tg-card-heading">
|
|
<div class="tg-card-title" x-text="$store.telegramConfig.botTitle(bot, idx)"></div>
|
|
<div class="tg-card-subtitle" x-text="$store.telegramConfig.botSubtitle(bot)"></div>
|
|
</div>
|
|
<div class="tg-card-actions">
|
|
<span class="tg-status-pill" :class="'tone-' + $store.telegramConfig.botStatusTone(bot)"
|
|
x-text="$store.telegramConfig.botStatusLabel(bot)"></span>
|
|
<button class="btn btn-action delete"
|
|
@click.stop="$confirmClick($event, () => $store.telegramConfig.removeBot(idx))" title="Remove bot">
|
|
<span class="material-symbols-outlined">delete</span>
|
|
</button>
|
|
<span class="material-symbols-outlined tg-card-chevron"
|
|
:class="{ 'is-open': $store.telegramConfig.editing === idx }">expand_more</span>
|
|
</div>
|
|
</div>
|
|
|
|
<template x-if="$store.telegramConfig.editing === idx">
|
|
<div class="tg-card-body">
|
|
<div class="tg-step-header">
|
|
<div class="tg-step-copy">
|
|
<div class="tg-step-title" x-text="$store.telegramConfig.currentStepMeta().title"></div>
|
|
<div class="tg-step-description" x-text="$store.telegramConfig.currentStepMeta().description"></div>
|
|
</div>
|
|
<div class="tg-step-dots" aria-hidden="true">
|
|
<template x-for="(step, stepIdx) in $store.telegramConfig.steps" :key="step.title">
|
|
<button type="button" class="tg-step-dot"
|
|
:class="{ 'is-active': $store.telegramConfig.currentStep === stepIdx }"
|
|
@click="$store.telegramConfig.setStep(stepIdx)"></button>
|
|
</template>
|
|
</div>
|
|
</div>
|
|
|
|
<template x-if="$store.telegramConfig.currentStep === 0">
|
|
<div class="tg-step-panel">
|
|
<div class="tg-token-row">
|
|
<div class="tg-qr-card">
|
|
<div class="tg-qr-title">Scan to open @BotFather</div>
|
|
<img class="tg-qr-image" :src="$store.telegramConfig.botFatherQr"
|
|
alt="Scan to open @BotFather" />
|
|
</div>
|
|
|
|
<div class="tg-token-card">
|
|
<div class="tg-token-steps">
|
|
<div class="tg-token-steps-title">Create your bot</div>
|
|
<ol class="tg-token-steps-list">
|
|
<li>Open <a href="https://t.me/BotFather" target="_blank" rel="noopener">@BotFather</a></li>
|
|
<li>Send <strong>/newbot</strong> and follow the prompts</li>
|
|
<li>Paste the token here</li>
|
|
</ol>
|
|
</div>
|
|
|
|
<div class="field">
|
|
<div class="field-label">
|
|
<div class="field-title">Bot token</div>
|
|
<div class="field-description">Paste the token you got from @BotFather.</div>
|
|
</div>
|
|
<div class="field-control">
|
|
<input type="password" x-model="bot.token"
|
|
placeholder="123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<template x-if="$store.telegramConfig.currentStep === 1">
|
|
<div class="tg-step-panel">
|
|
<div class="field">
|
|
<div class="field-label">
|
|
<div class="field-title">Turn on this bot</div>
|
|
<div class="field-description">Enable message polling when you are ready for the bot to go live.
|
|
</div>
|
|
</div>
|
|
<div class="field-control">
|
|
<label class="toggle">
|
|
<input type="checkbox" x-model="bot.enabled" />
|
|
<span class="toggler"></span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="field">
|
|
<div class="field-label">
|
|
<div class="field-title">Bot name</div>
|
|
<div class="field-description">A friendly internal label so you can tell bots apart.</div>
|
|
</div>
|
|
<div class="field-control">
|
|
<input type="text" x-model="bot.name" placeholder="support_bot" />
|
|
</div>
|
|
</div>
|
|
|
|
<div class="field">
|
|
<div class="field-label">
|
|
<div class="field-title">Delivery mode</div>
|
|
<div class="field-description">Polling is the simplest option. Webhook is for public HTTPS
|
|
setups.</div>
|
|
</div>
|
|
<div class="field-control">
|
|
<select x-model="bot.mode">
|
|
<option value="polling">Polling</option>
|
|
<option value="webhook">Webhook</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="field" x-show="bot.mode === 'webhook'">
|
|
<div class="field-label">
|
|
<div class="field-title">Webhook URL</div>
|
|
<div class="field-description">Your public Agent Zero base URL, for example
|
|
https://yourdomain.com.</div>
|
|
</div>
|
|
<div class="field-control">
|
|
<input type="text" x-model="bot.webhook_url" placeholder="https://yourdomain.com" />
|
|
</div>
|
|
</div>
|
|
|
|
<div class="field">
|
|
<div class="field-label">
|
|
<div class="field-title">Allowed users</div>
|
|
<div class="field-description">Comma-separated @usernames or numeric IDs. Leave empty only if
|
|
you truly want open access.</div>
|
|
</div>
|
|
<div class="field-control">
|
|
<input type="text" :value="$store.telegramConfig.whitelistText(bot)"
|
|
@input="$store.telegramConfig.setWhitelist(bot, $event.target.value)"
|
|
placeholder="@yourname, 123456789" />
|
|
</div>
|
|
</div>
|
|
|
|
<div class="tg-warning" x-show="$store.telegramConfig.accessWarning(bot)">
|
|
<span x-text="$store.telegramConfig.accessWarning(bot)"></span>
|
|
</div>
|
|
|
|
<div class="field">
|
|
<div class="field-label">
|
|
<div class="field-title">Default project</div>
|
|
<div class="field-description">Optional fallback project for conversations from this bot.</div>
|
|
</div>
|
|
<div class="field-control">
|
|
<select :value="bot.default_project" @change="bot.default_project = $event.target.value">
|
|
<option value="">No project</option>
|
|
<template x-for="proj in $store.telegramConfig.projects" :key="proj.name">
|
|
<option :value="proj.name" x-text="proj.title || proj.name"
|
|
:selected="bot.default_project === proj.name"></option>
|
|
</template>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<template x-if="$store.telegramConfig.currentStep === 2">
|
|
<div class="tg-step-panel">
|
|
<div class="field">
|
|
<div class="field-label">
|
|
<div class="field-title">Group behavior</div>
|
|
<div class="field-description">Choose whether the bot replies only when invited into the
|
|
conversation or to everything in a group.</div>
|
|
</div>
|
|
<div class="field-control">
|
|
<select x-model="bot.group_mode">
|
|
<option value="mention">Reply when @mentioned or replied to</option>
|
|
<option value="all">Reply to every group message</option>
|
|
<option value="off">Ignore group messages</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="field" x-show="bot.group_mode !== 'off'">
|
|
<div class="field-label">
|
|
<div class="field-title">Welcome new members</div>
|
|
<div class="field-description">Send a greeting when someone joins the group.</div>
|
|
</div>
|
|
<div class="field-control">
|
|
<label class="toggle">
|
|
<input type="checkbox" x-model="bot.welcome_enabled" />
|
|
<span class="toggler"></span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="field" x-show="bot.group_mode !== 'off' && bot.welcome_enabled">
|
|
<div class="field-label">
|
|
<div class="field-title">Welcome message</div>
|
|
<div class="field-description">Use {name} for the new member's name.</div>
|
|
</div>
|
|
<div class="field-control">
|
|
<input type="text" x-model="bot.welcome_message" placeholder="Welcome, {name}!" />
|
|
</div>
|
|
</div>
|
|
|
|
<div class="field">
|
|
<div class="field-label">
|
|
<div class="field-title">Agent instructions</div>
|
|
<div class="field-description">Extra guidance for how the agent should reply in Telegram chats.
|
|
</div>
|
|
</div>
|
|
<div class="field-control">
|
|
<textarea x-model="bot.agent_instructions" rows="3"
|
|
placeholder="Reply in a concise, mobile-friendly way."></textarea>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<div class="tg-test-panel">
|
|
<div class="tg-test-copy">
|
|
<div class="tg-test-title">Check the connection</div>
|
|
<div class="tg-test-description" x-text="$store.telegramConfig.testIntro()"></div>
|
|
</div>
|
|
<button class="btn btn-field" @click.stop="$store.telegramConfig.testConnection(idx)"
|
|
:disabled="$store.telegramConfig.testing === idx || !$store.telegramConfig.canTest(bot)">
|
|
<span x-text="$store.telegramConfig.testButtonLabel(bot, idx)"></span>
|
|
</button>
|
|
</div>
|
|
|
|
<template x-if="$store.telegramConfig.testResults && $store.telegramConfig.testResultsFor === idx">
|
|
<div class="tg-results" :class="{ 'is-error': !$store.telegramConfig.testResults.success }">
|
|
<template x-for="result in $store.telegramConfig.testResults.results"
|
|
:key="result.test + result.message">
|
|
<div class="tg-result-row">
|
|
<span class="tg-result-icon" x-text="result.ok ? '✓' : '✗'"></span>
|
|
<div class="tg-result-copy">
|
|
<div class="tg-result-title" x-text="$store.telegramConfig.resultTitle(result)"></div>
|
|
<div class="tg-result-message" x-text="$store.telegramConfig.resultMessage(result)"></div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</div>
|
|
</template>
|
|
|
|
<template x-if="$store.telegramConfig.currentStep > 0">
|
|
<details class="tg-advanced">
|
|
<summary>
|
|
<span>Advanced</span>
|
|
<span class="material-symbols-outlined tg-advanced-chevron"
|
|
aria-hidden="true">keyboard_arrow_down</span>
|
|
</summary>
|
|
<div class="tg-advanced-body">
|
|
<div class="field" x-show="bot.mode === 'webhook'">
|
|
<div class="field-label">
|
|
<div class="field-title">Webhook secret</div>
|
|
<div class="field-description">Optional shared secret for webhook verification.</div>
|
|
</div>
|
|
<div class="field-control">
|
|
<input type="password" x-model="bot.webhook_secret" />
|
|
</div>
|
|
</div>
|
|
|
|
<div class="field">
|
|
<div class="field-label">
|
|
<div class="field-title">Message notifications</div>
|
|
<div class="field-description">Show a WebUI notification for each incoming Telegram message.
|
|
</div>
|
|
</div>
|
|
<div class="field-control">
|
|
<label class="toggle">
|
|
<input type="checkbox" x-model="bot.notify_messages" />
|
|
<span class="toggler"></span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="field">
|
|
<div class="field-label">
|
|
<div class="field-title">User project mapping</div>
|
|
<div class="field-description">Map specific Telegram user IDs to projects with user_id=project
|
|
entries.</div>
|
|
</div>
|
|
<div class="field-control">
|
|
<input type="text" :value="$store.telegramConfig.userProjectsText(bot)"
|
|
@input="$store.telegramConfig.setUserProjects(bot, $event.target.value)"
|
|
placeholder="123456=my_project, 789012=other_project" />
|
|
</div>
|
|
</div>
|
|
|
|
<div class="field">
|
|
<div class="field-label">
|
|
<div class="field-title">Attachment max age</div>
|
|
<div class="field-description">How long to keep downloaded attachments. Use 0 to keep them
|
|
forever.</div>
|
|
</div>
|
|
<div class="field-control">
|
|
<input type="number" x-model.number="bot.attachment_max_age_hours" min="0" step="1"
|
|
placeholder="0" />
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</details>
|
|
</template>
|
|
</div>
|
|
</template>
|
|
</div>
|
|
</template>
|
|
|
|
<template x-if="$store.telegramConfig.bots.length > 0">
|
|
<button class="btn btn-field tg-add-btn" @click="$store.telegramConfig.addBot()">
|
|
Connect another bot
|
|
</button>
|
|
</template>
|
|
</div>
|
|
</template>
|
|
</div>
|
|
|
|
<style>
|
|
.tg-page {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.9rem;
|
|
}
|
|
|
|
.tg-advanced summary {
|
|
cursor: pointer;
|
|
list-style: none;
|
|
font-weight: 700;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.75rem;
|
|
}
|
|
|
|
.tg-advanced summary::-webkit-details-marker {
|
|
display: none;
|
|
}
|
|
|
|
.tg-guide-card,
|
|
.tg-empty,
|
|
.tg-card {
|
|
border-radius: 0.5rem;
|
|
}
|
|
|
|
.tg-empty-title,
|
|
.tg-step-title,
|
|
.tg-test-title,
|
|
.tg-qr-title {
|
|
font-weight: 700;
|
|
}
|
|
|
|
.tg-empty-copy,
|
|
.tg-step-description,
|
|
.tg-info-box,
|
|
.tg-test-description,
|
|
.tg-result-message,
|
|
.tg-card-subtitle {
|
|
color: var(--color-text-secondary);
|
|
line-height: 1.5;
|
|
}
|
|
|
|
.tg-empty {
|
|
padding: 1rem;
|
|
}
|
|
|
|
.tg-empty-copy {
|
|
margin-top: 0.35rem;
|
|
margin-bottom: 0.9rem;
|
|
}
|
|
|
|
.tg-card-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
gap: 1rem;
|
|
align-items: flex-start;
|
|
padding: var(--spacing-sm) 0;
|
|
border-bottom: 1px solid var(--color-border);
|
|
cursor: pointer;
|
|
}
|
|
|
|
.tg-card-heading {
|
|
min-width: 0;
|
|
flex: 1 1 auto;
|
|
}
|
|
|
|
.tg-card-title {
|
|
font-weight: 700;
|
|
line-height: 1.35;
|
|
overflow-wrap: anywhere;
|
|
}
|
|
|
|
.tg-card-subtitle {
|
|
margin-top: 0.3rem;
|
|
font-size: var(--font-size-small);
|
|
}
|
|
|
|
.tg-card-actions {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.45rem;
|
|
flex: 0 0 auto;
|
|
}
|
|
|
|
.tg-card-chevron {
|
|
transition: transform 0.18s ease;
|
|
opacity: 0.7;
|
|
}
|
|
|
|
.tg-card-chevron.is-open {
|
|
transform: rotate(180deg);
|
|
}
|
|
|
|
.tg-card-body {
|
|
border-top: 1px solid color-mix(in srgb, var(--color-border) 88%, white 12%);
|
|
}
|
|
|
|
.tg-step-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
gap: 1rem;
|
|
align-items: flex-start;
|
|
margin: 1rem 0;
|
|
}
|
|
|
|
.tg-step-dots {
|
|
display: flex;
|
|
gap: 0.5rem;
|
|
flex-wrap: wrap;
|
|
justify-content: flex-end;
|
|
align-items: center;
|
|
}
|
|
|
|
.tg-step-dot {
|
|
width: 0.85rem;
|
|
height: 0.85rem;
|
|
border-radius: 999px;
|
|
border: 1px solid var(--color-border);
|
|
background: transparent;
|
|
cursor: pointer;
|
|
padding: 0;
|
|
}
|
|
|
|
.tg-step-dot.is-active {
|
|
background: rgba(59, 130, 246, 0.9);
|
|
border-color: rgba(59, 130, 246, 0.9);
|
|
}
|
|
|
|
.tg-step-panel {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.2rem;
|
|
}
|
|
|
|
.tg-token-row {
|
|
display: grid;
|
|
grid-template-columns: minmax(12rem, 16rem) minmax(0, 1fr);
|
|
gap: 1rem;
|
|
align-items: stretch;
|
|
}
|
|
|
|
.tg-qr-card,
|
|
.tg-token-card {
|
|
border-radius: 0.5rem;
|
|
background: color-mix(in srgb, var(--color-background) 90%, white 10%);
|
|
padding: 1rem;
|
|
}
|
|
|
|
.tg-qr-card {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
text-align: center;
|
|
gap: 0.8rem;
|
|
}
|
|
|
|
.tg-qr-image {
|
|
width: 150px;
|
|
height: 150px;
|
|
border-radius: 0.5rem;
|
|
image-rendering: pixelated;
|
|
}
|
|
|
|
.tg-token-steps {
|
|
margin-bottom: 0.9rem;
|
|
}
|
|
|
|
.tg-token-steps-title {
|
|
font-weight: 700;
|
|
margin-bottom: 0.45rem;
|
|
}
|
|
|
|
.tg-token-steps-list {
|
|
margin: 0;
|
|
padding-left: 1.15rem;
|
|
color: var(--color-text-secondary);
|
|
line-height: 1.55;
|
|
}
|
|
|
|
.tg-token-steps-list a {
|
|
color: var(--color-highlight);
|
|
}
|
|
|
|
.tg-info-box,
|
|
.tg-warning {
|
|
margin-bottom: 0.9rem;
|
|
padding: 0.8rem 0.9rem;
|
|
border-radius: 12px;
|
|
font-size: var(--font-size-small);
|
|
}
|
|
|
|
.tg-info-box {
|
|
background: color-mix(in srgb, #3b82f6 12%, var(--color-background) 88%);
|
|
}
|
|
|
|
.tg-warning {
|
|
background: color-mix(in srgb, #f59e0b 14%, var(--color-background) 86%);
|
|
}
|
|
|
|
.tg-advanced {
|
|
margin-top: 0.95rem;
|
|
border: 1px solid color-mix(in srgb, var(--color-border) 88%, white 12%);
|
|
border-radius: 14px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.tg-advanced summary {
|
|
padding: 0.9rem 1rem;
|
|
background: color-mix(in srgb, var(--color-background) 88%, white 12%);
|
|
}
|
|
|
|
.tg-advanced-chevron {
|
|
margin-left: auto;
|
|
flex: 0 0 auto;
|
|
transition: transform 0.18s ease, opacity 0.18s ease;
|
|
opacity: 0.72;
|
|
}
|
|
|
|
.tg-advanced[open] .tg-advanced-chevron {
|
|
transform: rotate(180deg);
|
|
opacity: 1;
|
|
}
|
|
|
|
.tg-advanced-body {
|
|
padding: 1rem;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.2rem;
|
|
}
|
|
|
|
.tg-test-panel {
|
|
margin-top: 1rem;
|
|
padding: var(--spacing-xs) 0;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.tg-test-copy,
|
|
.tg-result-copy {
|
|
min-width: 0;
|
|
}
|
|
|
|
.tg-results {
|
|
margin-top: 0.9rem;
|
|
border-radius: 14px;
|
|
border: 1px solid color-mix(in srgb, #22c55e 28%, var(--color-border) 72%);
|
|
background: color-mix(in srgb, #22c55e 8%, var(--color-background) 92%);
|
|
padding: 0.35rem 0.9rem;
|
|
}
|
|
|
|
.tg-results.is-error {
|
|
border-color: color-mix(in srgb, #ef4444 28%, var(--color-border) 72%);
|
|
background: color-mix(in srgb, #ef4444 8%, var(--color-background) 92%);
|
|
}
|
|
|
|
.tg-result-row {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
gap: 0.8rem;
|
|
padding: 0.7rem 0;
|
|
}
|
|
|
|
.tg-result-row+.tg-result-row {
|
|
border-top: 1px solid color-mix(in srgb, var(--color-border) 85%, white 15%);
|
|
}
|
|
|
|
.tg-result-icon {
|
|
width: 1.25rem;
|
|
font-weight: 800;
|
|
line-height: 1.3;
|
|
}
|
|
|
|
.tg-result-title {
|
|
font-weight: 700;
|
|
margin-bottom: 0.18rem;
|
|
}
|
|
|
|
.tg-status-pill {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
min-width: 5.25rem;
|
|
padding: 0.35rem 0.7rem;
|
|
border-radius: 999px;
|
|
font-size: 0.8rem;
|
|
font-weight: 700;
|
|
}
|
|
|
|
.tg-status-pill.tone-success {
|
|
background: rgba(34, 197, 94, 0.14);
|
|
color: #7ee7a4;
|
|
}
|
|
|
|
.tg-status-pill.tone-ready {
|
|
background: rgba(59, 130, 246, 0.16);
|
|
color: #93c5fd;
|
|
}
|
|
|
|
.tg-status-pill.tone-warning {
|
|
background: rgba(245, 158, 11, 0.16);
|
|
color: #fcd34d;
|
|
}
|
|
|
|
.tg-status-pill.tone-muted {
|
|
background: rgba(148, 163, 184, 0.14);
|
|
color: #cbd5e1;
|
|
}
|
|
|
|
.tg-add-btn {
|
|
align-self: flex-start;
|
|
}
|
|
|
|
@media (max-width: 900px) {
|
|
.tg-token-row {
|
|
grid-template-columns: minmax(0, 1fr);
|
|
}
|
|
}
|
|
|
|
@media (max-width: 640px) {
|
|
|
|
.tg-card-header,
|
|
.tg-step-header,
|
|
.tg-test-panel {
|
|
flex-direction: column;
|
|
align-items: stretch;
|
|
}
|
|
|
|
.tg-card-actions,
|
|
.tg-step-dots {
|
|
width: 100%;
|
|
justify-content: space-between;
|
|
}
|
|
|
|
.tg-status-pill {
|
|
min-width: 0;
|
|
}
|
|
}
|
|
</style>
|
|
</body>
|
|
|
|
</html> |