- Add useInlineEdit hook for per-field editing (double-click to edit) - Add useDirtyFields hook for tracking unsaved changes - Add NotionFieldRow component with CSS Grid layout (140px label + 1fr value) - Add StickyActionBar component (fixed bottom bar with Save/Cancel) - Remove editModeBar from top (was shifting content down) - Replace field flex layout with notion-field-row grid - Add unified input styles (h-8, centered text) in CSS - Add safe-area-bottom for iOS PWA - Buttons now appear at bottom only when fields are dirty Refs: TaskTitan CRM UI refactor
518 lines
13 KiB
CSS
518 lines
13 KiB
CSS
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
|
|
@import url('https://fonts.googleapis.com/css2?family=DM+Mono:wght@400;500&display=swap');
|
|
@import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;500;600;700&display=swap');
|
|
@import './themes/styles/generated-skins.css';
|
|
|
|
@tailwind base;
|
|
@tailwind components;
|
|
@tailwind utilities;
|
|
|
|
/*
|
|
* Fallback переменные для случая, когда data-skin/data-theme ещё не применены
|
|
* (например, во время гидратации). Основные значения берутся из generated-skins.css.
|
|
*/
|
|
:root {
|
|
--background: hsl(0 0% 100%);
|
|
--foreground: hsl(220 10% 15%);
|
|
--card: hsl(0 0% 100%);
|
|
--card-foreground: hsl(220 10% 15%);
|
|
--popover: hsl(0 0% 100%);
|
|
--popover-foreground: hsl(220 10% 15%);
|
|
--primary: hsl(220 10% 15%);
|
|
--primary-foreground: hsl(0 0% 100%);
|
|
--secondary: hsl(220 5% 96%);
|
|
--secondary-foreground: hsl(220 10% 15%);
|
|
--muted: hsl(220 5% 96%);
|
|
--muted-foreground: hsl(220 5% 45%);
|
|
--accent: hsl(220 5% 93%);
|
|
--accent-foreground: hsl(220 10% 15%);
|
|
--destructive: hsl(0 72% 51%);
|
|
--destructive-foreground: hsl(0 0% 100%);
|
|
--border: hsl(220 5% 90%);
|
|
--input: hsl(0 0% 100%);
|
|
--ring: hsl(220 10% 15%);
|
|
|
|
--status-done: hsl(142 50% 45%);
|
|
--status-progress: hsl(45 90% 50%);
|
|
--status-overdue: hsl(0 70% 55%);
|
|
--status-paused: hsl(220 5% 60%);
|
|
|
|
--chart-1: hsl(220 10% 25%);
|
|
--chart-2: hsl(142 50% 45%);
|
|
--chart-3: hsl(45 90% 50%);
|
|
--chart-4: hsl(200 70% 50%);
|
|
--chart-5: hsl(0 70% 55%);
|
|
|
|
--sidebar: hsl(0 0% 100%);
|
|
--sidebar-foreground: hsl(220 10% 15%);
|
|
--sidebar-primary: hsl(220 10% 15%);
|
|
--sidebar-primary-foreground: hsl(0 0% 100%);
|
|
--sidebar-accent: hsl(220 5% 96%);
|
|
--sidebar-accent-foreground: hsl(220 10% 15%);
|
|
--sidebar-border: hsl(220 5% 92%);
|
|
--sidebar-ring: hsl(220 10% 15%);
|
|
|
|
--font-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
--font-mono: "DM Mono", "SF Mono", "Monaco", "Inconsolata", monospace;
|
|
|
|
--radius: 0.25rem;
|
|
|
|
--shadow-2xs: none;
|
|
--shadow-xs: none;
|
|
--shadow-sm: none;
|
|
--shadow: none;
|
|
--shadow-md: 0 1px 2px 0 rgba(0, 0, 0, 0.03);
|
|
--shadow-lg: 0 1px 3px 0 rgba(0, 0, 0, 0.05);
|
|
--shadow-xl: 0 2px 4px 0 rgba(0, 0, 0, 0.05);
|
|
--shadow-2xl: 0 4px 6px -1px rgba(0, 0, 0, 0.05);
|
|
|
|
--tracking-normal: -0.01em;
|
|
--spacing: 0.25rem;
|
|
|
|
--elevate-1: rgba(0, 0, 0, 0.03);
|
|
--elevate-2: rgba(0, 0, 0, 0.08);
|
|
}
|
|
|
|
.dark {
|
|
--elevate-1: rgba(255, 255, 255, 0.03);
|
|
--elevate-2: rgba(255, 255, 255, 0.08);
|
|
--background: hsl(220 10% 8%);
|
|
--foreground: hsl(220 5% 92%);
|
|
--card: hsl(220 10% 10%);
|
|
--card-foreground: hsl(220 5% 92%);
|
|
--popover: hsl(220 10% 10%);
|
|
--popover-foreground: hsl(220 5% 92%);
|
|
--primary: hsl(0 0% 100%);
|
|
--primary-foreground: hsl(220 10% 8%);
|
|
--secondary: hsl(220 10% 14%);
|
|
--secondary-foreground: hsl(220 5% 92%);
|
|
--muted: hsl(220 10% 14%);
|
|
--muted-foreground: hsl(220 5% 55%);
|
|
--accent: hsl(220 10% 16%);
|
|
--accent-foreground: hsl(220 5% 92%);
|
|
--destructive: hsl(0 70% 55%);
|
|
--destructive-foreground: hsl(0 0% 100%);
|
|
--border: hsl(220 10% 18%);
|
|
--input: hsl(220 10% 12%);
|
|
--ring: hsl(0 0% 100%);
|
|
|
|
--status-done: hsl(142 50% 55%);
|
|
--status-progress: hsl(45 90% 55%);
|
|
--status-overdue: hsl(0 70% 60%);
|
|
--status-paused: hsl(220 5% 55%);
|
|
|
|
--chart-1: hsl(220 5% 70%);
|
|
--chart-2: hsl(142 50% 55%);
|
|
--chart-3: hsl(45 90% 55%);
|
|
--chart-4: hsl(200 70% 55%);
|
|
--chart-5: hsl(0 70% 60%);
|
|
|
|
--sidebar: hsl(220 10% 8%);
|
|
--sidebar-foreground: hsl(220 5% 92%);
|
|
--sidebar-primary: hsl(0 0% 100%);
|
|
--sidebar-primary-foreground: hsl(220 10% 8%);
|
|
--sidebar-accent: hsl(220 10% 14%);
|
|
--sidebar-accent-foreground: hsl(220 5% 92%);
|
|
--sidebar-border: hsl(220 10% 16%);
|
|
--sidebar-ring: hsl(0 0% 100%);
|
|
|
|
--radius: 0.25rem;
|
|
|
|
--shadow-md: 0 1px 2px 0 rgba(0, 0, 0, 0.15);
|
|
--shadow-lg: 0 2px 4px 0 rgba(0, 0, 0, 0.2);
|
|
--shadow-xl: 0 4px 6px -1px rgba(0, 0, 0, 0.2);
|
|
--shadow-2xl: 0 8px 10px -2px rgba(0, 0, 0, 0.25);
|
|
}
|
|
|
|
@layer base {
|
|
* {
|
|
@apply border-border;
|
|
}
|
|
|
|
body {
|
|
@apply font-sans antialiased bg-background text-foreground;
|
|
font-size: 13px;
|
|
line-height: 1.5;
|
|
letter-spacing: -0.01em;
|
|
font-feature-settings: "cv11", "ss01";
|
|
}
|
|
|
|
/* Clean typography */
|
|
h1 {
|
|
@apply text-xl font-semibold tracking-tight;
|
|
}
|
|
|
|
h2 {
|
|
@apply text-lg font-medium tracking-tight;
|
|
}
|
|
|
|
h3 {
|
|
@apply text-base font-medium;
|
|
}
|
|
|
|
h4 {
|
|
@apply text-sm font-medium;
|
|
}
|
|
|
|
/* Fast transitions */
|
|
button, a, input, select, textarea {
|
|
@apply transition-colors duration-100 ease-out;
|
|
}
|
|
}
|
|
|
|
@layer components {
|
|
/* Page container */
|
|
.page-container {
|
|
@apply max-w-6xl mx-auto;
|
|
}
|
|
|
|
/* Page header */
|
|
.page-header {
|
|
@apply flex items-center justify-between mb-4 pb-3 border-b border-border;
|
|
}
|
|
|
|
.page-title {
|
|
@apply text-lg font-medium text-foreground;
|
|
}
|
|
|
|
/* Compact buttons */
|
|
.btn-compact {
|
|
@apply h-7 px-2.5 text-xs font-medium;
|
|
}
|
|
|
|
.btn-small {
|
|
@apply h-6 px-2 text-xs;
|
|
}
|
|
|
|
.btn-icon {
|
|
@apply h-7 w-7 p-0;
|
|
}
|
|
|
|
/* Compact inputs */
|
|
.input-compact {
|
|
@apply h-7 px-2 text-xs;
|
|
}
|
|
|
|
/* Clean table */
|
|
.table-minimal {
|
|
@apply w-full text-xs;
|
|
}
|
|
|
|
.table-minimal thead {
|
|
@apply border-b border-border;
|
|
}
|
|
|
|
.table-minimal th {
|
|
@apply py-2 px-3 text-left font-medium text-muted-foreground uppercase tracking-wider text-[10px];
|
|
}
|
|
|
|
.table-minimal td {
|
|
@apply py-2 px-3 border-b border-border/50;
|
|
}
|
|
|
|
.table-minimal tbody tr:hover {
|
|
@apply bg-muted/30;
|
|
}
|
|
|
|
/* Card minimal */
|
|
.card-minimal {
|
|
@apply border border-border rounded bg-card p-3;
|
|
}
|
|
|
|
/* Badge minimal */
|
|
.badge-minimal {
|
|
@apply inline-flex items-center px-1.5 py-0.5 text-[10px] font-medium rounded;
|
|
}
|
|
|
|
/* Status colors */
|
|
.status-badge {
|
|
@apply inline-flex items-center gap-1.5 px-2 py-0.5 text-xs rounded-full;
|
|
}
|
|
|
|
.status-badge-done {
|
|
background-color: color-mix(in srgb, var(--status-done) 12%, transparent);
|
|
color: var(--status-done);
|
|
}
|
|
|
|
.status-badge-progress {
|
|
background-color: color-mix(in srgb, var(--status-progress) 12%, transparent);
|
|
color: var(--status-progress);
|
|
}
|
|
|
|
.status-badge-overdue {
|
|
background-color: color-mix(in srgb, var(--status-overdue) 12%, transparent);
|
|
color: var(--status-overdue);
|
|
}
|
|
|
|
/* Nav item */
|
|
.nav-item {
|
|
@apply flex items-center gap-2 px-2 py-1.5 text-xs font-medium text-muted-foreground rounded hover:bg-muted hover:text-foreground transition-colors;
|
|
}
|
|
|
|
.nav-item-active {
|
|
@apply bg-muted text-foreground;
|
|
}
|
|
|
|
/* Section header */
|
|
.section-header {
|
|
@apply text-[10px] font-medium text-muted-foreground uppercase tracking-wider px-2 py-1.5;
|
|
}
|
|
|
|
/* Toolbar */
|
|
.toolbar {
|
|
@apply flex items-center gap-1.5 p-1.5 border-b border-border bg-background;
|
|
}
|
|
|
|
/* Empty state */
|
|
.empty-state {
|
|
@apply flex flex-col items-center justify-center py-12 text-center text-muted-foreground;
|
|
}
|
|
|
|
/* Form grid */
|
|
.form-grid {
|
|
@apply grid gap-3;
|
|
}
|
|
|
|
.form-row {
|
|
@apply flex items-center gap-2;
|
|
}
|
|
|
|
.form-label {
|
|
@apply text-xs font-medium text-muted-foreground;
|
|
}
|
|
|
|
/* List item */
|
|
.list-item {
|
|
@apply flex items-center gap-3 px-3 py-2 border-b border-border/50 hover:bg-muted/30 cursor-pointer;
|
|
}
|
|
|
|
.list-item:last-child {
|
|
@apply border-b-0;
|
|
}
|
|
}
|
|
|
|
@layer utilities {
|
|
/* Status badge utilities */
|
|
.status-done {
|
|
background-color: hsl(var(--status-done));
|
|
}
|
|
|
|
.status-progress {
|
|
background-color: hsl(var(--status-progress));
|
|
}
|
|
|
|
.status-overdue {
|
|
background-color: hsl(var(--status-overdue));
|
|
}
|
|
|
|
.status-paused {
|
|
background-color: hsl(var(--status-paused));
|
|
}
|
|
|
|
/* Text utilities */
|
|
.text-caption {
|
|
@apply text-[10px] text-muted-foreground;
|
|
}
|
|
|
|
.text-label {
|
|
@apply text-xs font-medium;
|
|
}
|
|
|
|
/* Truncate utilities */
|
|
.line-clamp-1 {
|
|
overflow: hidden;
|
|
display: -webkit-box;
|
|
-webkit-box-orient: vertical;
|
|
-webkit-line-clamp: 1;
|
|
}
|
|
|
|
/* Finance elevation */
|
|
.hover-elevate {
|
|
position: relative;
|
|
}
|
|
.hover-elevate::after {
|
|
content: "";
|
|
position: absolute;
|
|
inset: 0;
|
|
border-radius: inherit;
|
|
pointer-events: none;
|
|
opacity: 0;
|
|
background: var(--elevate-1);
|
|
transition: opacity 0.15s ease;
|
|
}
|
|
.hover-elevate:hover::after {
|
|
opacity: 1;
|
|
}
|
|
|
|
.hover-elevate-2 {
|
|
position: relative;
|
|
}
|
|
.hover-elevate-2::after {
|
|
content: "";
|
|
position: absolute;
|
|
inset: 0;
|
|
border-radius: inherit;
|
|
pointer-events: none;
|
|
opacity: 0;
|
|
background: var(--elevate-2);
|
|
transition: opacity 0.15s ease;
|
|
}
|
|
.hover-elevate-2:hover::after {
|
|
opacity: 1;
|
|
}
|
|
|
|
.active-elevate:active::after {
|
|
opacity: 1;
|
|
}
|
|
.active-elevate-2:active::after {
|
|
opacity: 1;
|
|
}
|
|
|
|
.toggle-elevate[data-state="on"]::after,
|
|
.toggle-elevate-2[data-state="on"]::after {
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
/* jspreadsheet formula cell highlight */
|
|
td.formula-highlight {
|
|
background-color: var(--tw-background-transparent-secondary) !important;
|
|
border: 1px solid var(--tw-border-strong) !important;
|
|
}
|
|
|
|
/* Mobile bottom navigation safe area */
|
|
.safe-area-bottom {
|
|
padding-bottom: env(safe-area-inset-bottom, 0);
|
|
}
|
|
|
|
/* Fix: Tailwind utility .flex overrides preflight [hidden] rule.
|
|
Radix primitives (Tabs, Dialog, Accordion, etc.) use hidden attr for inactive/unmounted content.
|
|
Ensure [hidden] always hides even when combined with flex/grid/display utilities. */
|
|
[hidden] {
|
|
display: none !important;
|
|
}
|
|
|
|
/* Fix Radix ScrollArea display:table horizontal overflow in chats */
|
|
.chat-scroll-area [data-radix-scroll-area-viewport] > div {
|
|
display: block !important;
|
|
min-width: 0 !important;
|
|
}
|
|
|
|
/* Scrollbar minimal */
|
|
::-webkit-scrollbar {
|
|
width: 6px;
|
|
height: 6px;
|
|
}
|
|
|
|
::-webkit-scrollbar-track {
|
|
background: transparent;
|
|
}
|
|
|
|
::-webkit-scrollbar-thumb {
|
|
background: var(--tw-border-strong);
|
|
border-radius: 3px;
|
|
}
|
|
|
|
::-webkit-scrollbar-thumb:hover {
|
|
background: var(--tw-font-extra-light);
|
|
}
|
|
|
|
/* Focus visible — removed per user request */
|
|
@layer base {
|
|
*:focus-visible {
|
|
outline: none;
|
|
--tw-ring-offset-shadow: none;
|
|
--tw-ring-shadow: none;
|
|
box-shadow: none;
|
|
}
|
|
}
|
|
|
|
/* Selection */
|
|
::selection {
|
|
background-color: var(--tw-background-transparent-secondary);
|
|
}
|
|
|
|
/* ============================================================
|
|
Notion-Style Task Detail — Inline Edit System
|
|
Added: 2026-07-16
|
|
============================================================ */
|
|
|
|
@layer components {
|
|
/* --- Unified field grid: label + value --- */
|
|
.notion-field-row {
|
|
@apply grid gap-x-3 gap-y-1 py-1.5 px-2 -mx-2 rounded transition-colors;
|
|
grid-template-columns: 1fr; /* mobile: stacked */
|
|
}
|
|
|
|
@media (min-width: 768px) {
|
|
.notion-field-row {
|
|
grid-template-columns: minmax(120px, 140px) 1fr;
|
|
align-items: start;
|
|
}
|
|
}
|
|
|
|
/* Editable hover state */
|
|
.notion-field-row[data-editable="true"]:not([data-editing="true"]):hover {
|
|
@apply bg-muted/40;
|
|
}
|
|
|
|
/* --- Label column --- */
|
|
.notion-field-label {
|
|
@apply flex items-center gap-1;
|
|
}
|
|
|
|
@media (min-width: 768px) {
|
|
.notion-field-label {
|
|
@apply justify-end text-right;
|
|
padding-top: 2px;
|
|
}
|
|
}
|
|
|
|
/* --- Value column --- */
|
|
.notion-field-value {
|
|
@apply min-w-0;
|
|
}
|
|
|
|
/* --- Sticky bottom action bar --- */
|
|
.sticky-action-bar {
|
|
@apply sticky bottom-0 z-40 bg-background/95 backdrop-blur-sm border-t;
|
|
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05);
|
|
}
|
|
|
|
/* --- Inline editor inputs (unified height) --- */
|
|
.inline-input {
|
|
@apply border border-input rounded-md bg-background px-2 text-[13px];
|
|
@apply focus:outline-none focus:ring-1 focus:ring-primary focus:border-primary;
|
|
height: 32px;
|
|
line-height: 30px;
|
|
padding-top: 0;
|
|
padding-bottom: 0;
|
|
}
|
|
|
|
.inline-textarea {
|
|
@apply border border-input rounded-md bg-background px-2 py-1.5 text-[13px];
|
|
@apply focus:outline-none focus:ring-1 focus:ring-primary focus:border-primary;
|
|
min-height: 32px;
|
|
line-height: 1.5;
|
|
}
|
|
|
|
.inline-select {
|
|
@apply inline-input w-full appearance-none;
|
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%236B7280' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
|
|
background-repeat: no-repeat;
|
|
background-position: right 8px center;
|
|
padding-right: 28px;
|
|
}
|
|
}
|
|
|
|
/* --- PWA Safe Area --- */
|
|
.safe-area-bottom {
|
|
padding-bottom: env(safe-area-inset-bottom, 0);
|
|
}
|
|
|
|
@supports (padding-bottom: env(safe-area-inset-bottom)) {
|
|
.safe-area-bottom {
|
|
padding-bottom: max(12px, env(safe-area-inset-bottom));
|
|
}
|
|
}
|