- Added new API endpoints for admin features: `GET /api/admin/me`, `GET /api/admin/users`, and `PATCH /api/admin/duties/:id` to manage user duties. - Introduced `UserForAdmin` and `AdminDutyReassignBody` schemas for handling admin-related data. - Updated documentation to include Mini App design guidelines and admin panel functionalities. - Enhanced tests for admin API to ensure proper access control and functionality. - Improved error handling and localization for admin actions.
11 KiB
Mini App Design Guideline
This document defines the design rules for the Duty Teller Mini App (Next.js frontend in webapp-next/). It aligns with Telegram’s official Mini App design guidelines (Color Schemes and Design Guidelines) and codifies the current implementation (calendar, duty list, admin) as the reference for new screens and components.
1. Telegram design principles
Telegram’s guidelines state:
- Mobile-first: All elements must be responsive and designed for mobile first.
- Consistency: Interactive elements should match the style, behaviour, and intent of existing Telegram UI components.
- Performance: Animations should be smooth, ideally 60fps.
- Accessibility: Inputs and images must have labels.
- Theme: The app must use the dynamic theme-based colors provided by the API (Day/Night and custom themes).
- Safe areas: The interface must respect the safe area and content safe area so content does not overlap system or Telegram UI, especially in fullscreen.
- Android: On Android, use the extra User-Agent data (e.g. performance class) and reduce animations and effects on low-performance devices for smooth operation.
Color schemes: Mini Apps receive the user’s current theme in real time. Use the ThemeParams object and the CSS variables Telegram exposes (e.g. --tg-theme-bg-color, --tg-theme-text-color) so the UI adapts when the user switches Day/Night or custom themes.
2. Theme and colors
2.1 Sources
Theme is resolved in this order:
- Hash parameters:
tgWebAppColorScheme,tgWebAppThemeParams(parsed in the inline script inwebapp-next/src/app/layout.tsx). - At runtime:
Telegram.WebApp.colorSchemeandTelegram.WebApp.themeParamsviause-telegram-theme.tsandTelegramProvider.
The inline script in the layout maps all Telegram theme keys to --tg-theme-* CSS variables on the document root. The hook sets data-theme (light / dark) and applies Mini App background/header colors.
2.2 Mapping (ThemeParams → app tokens)
In webapp-next/src/app/globals.css, :root and [data-theme="light"] / [data-theme="dark"] map Telegram’s ThemeParams to internal design tokens:
| Telegram ThemeParam (CSS var) | App token / usage |
|---|---|
--tg-theme-bg-color |
--bg (background) |
--tg-theme-secondary-bg-color |
--surface (cards, panels) |
--tg-theme-text-color |
--text (primary text) |
--tg-theme-hint-color, --tg-theme-subtitle-text-color |
--muted (secondary text) |
--tg-theme-link-color |
--accent (links, secondary actions) |
--tg-theme-header-bg-color |
--header-bg |
--tg-theme-section-bg-color |
--card (sections) |
--tg-theme-section-header-text-color |
--section-header |
--tg-theme-section-separator-color |
--border |
--tg-theme-button-color |
--primary |
--tg-theme-button-text-color |
--primary-foreground |
--tg-theme-destructive-text-color |
--error |
--tg-theme-accent-text-color |
--accent-text |
Tailwind/shadcn semantic tokens are wired to these: --background → --bg, --foreground → --text, --primary, --secondary → --surface, etc.
2.3 Domain colors
Duty-specific semantics (fixed per theme, not from ThemeParams):
--duty— duty shift (e.g. green).--unavailable— unavailable (e.g. amber).--vacation— vacation (e.g. blue).--today— “today” highlight; tied to--tg-theme-accent-text-color/--tg-theme-link-color.
Use Tailwind classes such as bg-duty, border-l-unavailable, text-today, bg-today, etc.
2.4 Derived tokens (color-mix)
Prefer these instead of ad-hoc color mixes:
--surface-hover,--surface-hover-10— hover states for surfaces.--surface-today-tint,--surface-muted-tint— subtle tints.--today-hover,--today-border,--today-border-selected,--today-gradient-end— today state.--muted-fade,--shadow-card, etc.
Defined in globals.css; use via var(--surface-hover) in classes (e.g. hover:bg-[var(--surface-hover)]).
2.5 Rule for new work
Use only these tokens and Tailwind/shadcn aliases (bg-background, text-muted, bg-surface, text-accent, border-l-duty, bg-today, etc.). Do not hardcode hex or RGB in new components or screens.
3. Layout and safe areas
3.1 Width
- Token:
--max-width-app: 420px(in@themeinglobals.css). - Usage: Page wrapper uses
max-w-[var(--max-width-app)](e.g. inpage.tsx,CalendarPage.tsx,admin/page.tsx). Content is centred withmx-auto.
3.2 Height
- Viewport: Prefer
min-h-[var(--tg-viewport-stable-height,100vh)]for the main content area so the Mini App fills the visible height correctly when expanded/collapsed. Fallback100vhwhen not in Telegram. - Body: In
globals.css,bodyalready hasmin-height: var(--tg-viewport-stable-height, 100vh)andbackground: var(--bg).
3.3 Safe area and content safe area
- Class
.content-safe(inglobals.css): Applies:padding-top: var(--tg-viewport-content-safe-area-inset-top, env(safe-area-inset-top, 0))padding-bottom: var(--tg-viewport-content-safe-area-inset-bottom, env(safe-area-inset-bottom, 0))
- Use
.content-safeon the root container of each page so content is not covered by the Telegram header or bottom bar (Bot API 8.0+). - Lists that extend to the bottom should also account for bottom inset (e.g.
padding-bottom: var(--tg-viewport-content-safe-area-inset-bottom, 12px)in.container-app).
3.4 Sheets and modals
Bottom sheets and modals that sit at the bottom of the screen must add safe area to their padding, e.g.:
pb-[calc(24px+env(safe-area-inset-bottom,0px))]
See webapp-next/src/components/day-detail/DayDetail.tsx for the Sheet content.
4. Typography and spacing
4.1 Font
- Family:
system-ui, -apple-system, sans-serif(set inglobals.cssand Tailwind theme).
4.2 Patterns from the calendar and duty list
| Element | Classes / tokens |
|---|---|
| Month title | text-[1.1rem] / sm:text-[1.25rem], font-semibold |
| Year (above month) | text-xs, text-muted |
| Nav buttons (prev/next month) | size-10, rounded-[10px] |
| Calendar day cell | text-[0.85rem], rounded-lg, p-1 |
| Duty timeline card | px-2.5 py-2, rounded-lg |
4.3 Page and block spacing
- Page container:
px-3 pb-6in addition to.content-safe. - Between sections:
mb-3,mb-4as appropriate. - Grids:
gap-1for tight layouts (e.g. calendar grid), larger gaps where needed.
5. Component patterns
5.1 Buttons
- Primary: Use the default Button variant:
bg-primary text-primary-foreground(fromwebapp-next/src/components/ui/button.tsx). - Secondary icon buttons (e.g. calendar nav):
bg-surface text-accent hover:bg-[var(--surface-hover)] focus-visible:outline-accent active:scale-95
withsize-10androunded-[10px]. - Keep focus visible (e.g.
focus-visible:outline-accentor ring); do not remove outline without a visible replacement.
5.2 Cards
- Background:
bg-surfaceorbg-card(both resolve to theme tokens). - Borders:
border,--border(section separator color). - Emphasis:
var(--shadow-card)for highlighted cards (e.g. current duty). - Left stripe by type:
border-l-[3px]with:border-l-duty,border-l-unavailable,border-l-vacationfor event types;border-l-todayfor “current duty” (see.border-l-todayinglobals.css).
5.3 Calendar grid
- Structure: 7 columns × 6 rows; use
role="grid"on the container androle="gridcell"on each cell. - Layout:
min-h-[var(--calendar-grid-min-height)], cellsaspect-squarewithmin-h-8,rounded-lg,gap-1. - Today:
bg-today text-[var(--bg)]; hoverhover:bg-[var(--today-hover)]. - Other month:
opacity-40,pointer-events-none,bg-[var(--surface-muted-tint)].
5.4 Timeline list (duties)
- Dates: Horizontal line and vertical tick from shared CSS in
globals.css:
.duty-timeline-date,.duty-timeline-date--today(with::before/::after). - Cards: Same card rules as above;
border-l-[3px]+ type class; optional flip card for contacts (seeDutyTimelineCard.tsx).
6. Motion and performance
6.1 Timing
- Tokens:
--transition-fast: 0.15s,--transition-normal: 0.25s,--ease-out: cubic-bezier(0.32, 0.72, 0, 1). - Use these for transitions and short animations so behaviour is consistent and predictable.
6.2 Reduced motion
- Rule:
@media (prefers-reduced-motion: reduce)inglobals.cssshortens animation and transition durations globally. New animations should remain optional or short so they degrade gracefully when reduced.
6.3 Android low-performance devices
- Detection:
webapp-next/src/lib/telegram-android-perf.tsreads Telegram’s User-Agent and setsdata-perf="low"on the document root when the device performance class is LOW. - CSS:
[data-perf="low"] *inglobals.cssminimizes animation/transition duration. Avoid adding heavy or long animations without considering this; prefer simple or no animation on low-end devices.
7. Accessibility
- Focus: Use
focus-visible:outline-accent(or equivalent ring) on interactive elements; do not remove focus outline without a visible alternative. - Calendar: Use
role="grid"androle="gridcell",aria-labelon nav buttons (e.g. “Previous month”), and a compositearia-labelon each day cell (date + event types). Seewebapp-next/src/components/calendar/CalendarDay.tsx. - Images and inputs: Always provide labels (per Telegram’s guidelines and WCAG).
8. Telegram integration
- Header and background: On init (layout script and
use-telegram-theme.ts), call:setBackgroundColor('bg_color')setHeaderColor('bg_color')setBottomBarColor('bottom_bar_bg_color')when available (Bot API 7.10+).
- Surface contrast: When
--surfaceequals--bg(e.g. some iOS OLED themes),fixSurfaceContrast()inuse-telegram-theme.tsadjusts--surfaceusing ThemeParams or a light color-mix so cards and panels remain visible.
9. Checklist for new screens and components
Use this for review when adding or changing UI:
- Use only design tokens from
globals.cssand Tailwind/shadcn aliases; no hardcoded colours. - Page wrapper has
.content-safe,max-w-[var(--max-width-app)], and appropriate min-height (viewport-stable-height ormin-h-screenwith fallback). - Buttons and cards follow the patterns above (variants, surfaces, border-l by type).
- Safe area is respected for bottom padding and for sheets/modals.
- Interactive elements and grids/lists have appropriate
aria-labels and roles. - New animations respect
prefers-reduced-motionanddata-perf="low"(short or minimal on low-end Android).