UNPKG

@papernote/ui

Version:

A modern React component library with a paper notebook aesthetic - minimal, professional, and expressive

589 lines (487 loc) 13.1 kB
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap'); /* Component styles */ @import '../components/Spreadsheet.css'; @tailwind base; @tailwind components; @tailwind utilities; @layer base { body { font-family: 'Inter', sans-serif; @apply bg-paper-100 text-ink-600; /* Desk-like background for page contrast */ } h1, h2, h3, h4, h5, h6 { @apply text-ink-900 font-medium; } h1 { @apply text-3xl tracking-tight; } h2 { @apply text-2xl tracking-tight; } h3 { @apply text-xl; } h4 { @apply text-lg; } } @layer components { /* Button Styles - Minimal & Professional */ .btn { @apply inline-flex items-center justify-center px-4 py-2.5 text-sm font-medium rounded-lg border transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-accent-400; } .btn-primary { @apply bg-accent-500 text-white border-accent-500 hover:bg-accent-600 hover:shadow-sm active:scale-[0.98]; } .btn-secondary { @apply bg-white text-ink-700 border-paper-300 hover:bg-paper-50 hover:border-paper-400 shadow-xs hover:shadow-sm; } .btn-ghost { @apply bg-transparent text-ink-600 border-transparent hover:text-ink-800 hover:bg-paper-100 active:bg-paper-200; } .btn:disabled { @apply opacity-40 cursor-not-allowed; } /* Input Styles - Comfortable & Clear */ .input { @apply block w-full px-4 py-2.5 border border-paper-300 rounded-lg text-sm text-ink-800 placeholder-ink-400 bg-white transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-accent-400 focus:border-accent-400 hover:border-paper-400; } .label { @apply flex items-center text-sm font-medium text-ink-700 mb-2; } /* Card Styles - Paper-like */ .card { @apply bg-white bg-subtle-grain rounded-xl shadow-card border border-paper-200 p-8 transition-shadow duration-200 hover:shadow-md; } .card-compact { @apply bg-white bg-subtle-grain rounded-lg shadow-card border border-paper-200 p-5; } /* Badge Styles - Muted & Professional */ .badge { @apply inline-flex items-center px-3 py-1 rounded-full text-xs font-medium; } .badge-success { @apply bg-success-50 text-success-700 border border-success-200; } .badge-warning { @apply bg-warning-50 text-warning-700 border border-warning-200; } .badge-error { @apply bg-error-50 text-error-700 border border-error-200; } .badge-info { @apply bg-primary-50 text-primary-700 border border-primary-200; } /* Table Styles - Clean & Minimal */ .table { @apply min-w-full divide-y divide-paper-200; } .table-header { @apply bg-paper-50; } .table-header-cell { @apply px-6 py-3 text-left text-xs font-medium text-ink-500 uppercase tracking-wider; } .table-cell { @apply px-6 py-4 whitespace-nowrap text-sm text-ink-700; } .table-row { @apply hover:bg-paper-50 transition-colors duration-150; } /* Navigation Styles - Notebook-like */ .nav-link { @apply flex items-center px-3 py-2.5 text-sm font-medium rounded-lg transition-all duration-200; } .nav-link-active { @apply bg-accent-50 text-accent-900 border-l-2 border-accent-500 pl-2.5; } .nav-link-inactive { @apply text-ink-600 hover:bg-paper-100 hover:text-ink-900; } /* Switch Toggle Styles - Refined */ .switch { @apply relative inline-block w-11 h-6; } .switch input { @apply opacity-0 w-0 h-0; } .slider { @apply absolute cursor-pointer top-0 left-0 right-0 bottom-0 bg-paper-300 rounded-full transition-all duration-200; } .slider:before { @apply absolute content-[''] h-5 w-5 left-0.5 bottom-0.5 bg-white rounded-full shadow-sm transition-all duration-200; } input:checked + .slider { @apply bg-accent-500; } input:checked + .slider:before { @apply transform translate-x-5; } /* Stat Card Styles - Paper-like */ .stat-card { @apply bg-white bg-subtle-grain rounded-xl border border-paper-200 p-6 hover:shadow-md hover:border-paper-300 transition-all duration-200; } .stat-card-icon { @apply h-10 w-10 mb-4 text-ink-600; } .stat-card-value { @apply text-3xl font-semibold text-ink-900 tracking-tight; } .stat-card-label { @apply text-sm text-ink-500 mt-2; } .stat-card-change { @apply text-sm font-medium mt-3; } .stat-card-change-positive { @apply text-success-600; } .stat-card-change-negative { @apply text-error-600; } /* Notebook Page Container - Creates bounded page effect NOTE: This class is deprecated - Page component now handles responsive layout via props Keeping for backward compatibility only */ .notebook-page { @apply bg-white bg-subtle-grain rounded-sm shadow-lg border-l-4 border-paper-300; max-width: 1400px; /* Responsive margins - fixed left/top, responsive right/bottom */ margin-top: 1rem; margin-left: 1rem; margin-right: 1rem; margin-bottom: 1rem; /* Responsive padding - fixed left/top, responsive right/bottom */ padding-top: 3rem; padding-left: 5rem; /* Extra left padding for binding margin */ padding-right: 1rem; padding-bottom: 1rem; min-height: calc(100vh - 2rem); position: relative; } /* Responsive padding/margin increases on larger screens */ @media (min-width: 640px) { .notebook-page { margin-right: 1.5rem; margin-bottom: 2rem; padding-right: 2rem; padding-bottom: 2rem; } } @media (min-width: 768px) { .notebook-page { margin-right: 2rem; margin-bottom: 2rem; padding-right: 3rem; padding-bottom: 3rem; } } @media (min-width: 1024px) { .notebook-page { margin-right: auto; /* Center on large screens */ padding-right: 4rem; padding-bottom: 4rem; } } /* Notebook binding effect on sidebar */ .notebook-binding { position: relative; } .notebook-binding::after { content: ''; position: absolute; right: 0; top: 0; bottom: 0; width: 3px; background: linear-gradient(to bottom, transparent 0%, rgba(0,0,0,0.03) 10%, rgba(0,0,0,0.05) 50%, rgba(0,0,0,0.03) 90%, transparent 100% ); box-shadow: 2px 0 4px rgba(0,0,0,0.04); } /* Ruled lines for notebook page (very subtle) */ .notebook-ruled { background-image: linear-gradient(transparent 0%, transparent calc(100% - 1px), rgba(231, 229, 228, 0.3) 100%); background-size: 100% 2rem; background-position: 0 1.5rem; } /* Left margin line for notebook page */ .notebook-margin { position: relative; } .notebook-margin::before { content: ''; position: absolute; left: 3rem; top: 0; bottom: 0; width: 1px; background-color: rgba(239, 68, 68, 0.05); /* Very subtle red margin line */ } /* Page Navigation / TOC - Sits in gutter between sidebar and page */ .page-nav { @apply fixed top-32 bottom-8; left: 16.5rem; /* Sidebar (16rem) + gutter offset */ width: 2rem; z-index: 5; pointer-events: none; } .page-nav-inner { @apply sticky top-32 flex flex-col gap-3; pointer-events: auto; } /* Tab-style navigation items */ .page-nav-item { @apply block w-full h-8 rounded-r-md border-r-2 border-transparent; @apply text-xs text-ink-400 hover:text-ink-700 hover:border-accent-400 hover:bg-paper-50; @apply transition-all duration-200; writing-mode: vertical-rl; text-orientation: mixed; padding: 0.5rem 0.25rem; text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-height: 8rem; } .page-nav-item.active { @apply border-accent-500 bg-accent-50 text-accent-900 font-medium; } /* Alternative: Dot navigation style (simpler) */ .page-nav-dots { @apply flex flex-col gap-2 items-center pointer-events-auto; } .page-nav-dot { @apply w-2 h-2 rounded-full bg-paper-300 transition-all duration-200 cursor-pointer pointer-events-auto; } .page-nav-dot:hover { @apply bg-accent-400; transform: scale(1.2); } .page-nav-dot.active { @apply bg-accent-500 w-2.5 h-2.5; } } @layer utilities { .line-clamp-1 { overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 1; } .line-clamp-2 { overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; } .line-clamp-3 { overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; } .scrollbar-hide { -ms-overflow-style: none; scrollbar-width: none; } .scrollbar-hide::-webkit-scrollbar { display: none; } .text-shadow { text-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); } .bg-gradient-primary { background: linear-gradient(135deg, #64748b, #475569); } .bg-gradient-success { background: linear-gradient(135deg, #10b981, #059669); } .bg-gradient-warning { background: linear-gradient(135deg, #f59e0b, #d97706); } .bg-gradient-accent { background: linear-gradient(135deg, #f59e0b, #d97706); } } /* Custom scrollbar - Subtle paper aesthetic */ ::-webkit-scrollbar { width: 8px; height: 8px; } ::-webkit-scrollbar-track { background: #fafaf9; } ::-webkit-scrollbar-thumb { background: #d6d3d1; border-radius: 4px; border: 2px solid #fafaf9; } ::-webkit-scrollbar-thumb:hover { background: #a8a29e; } /* Loading animations */ @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: .5; } } .animate-pulse { animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; } /* Table styles - Clean & minimal */ .table { @apply min-w-full divide-y divide-paper-200; } .table-header { @apply bg-paper-50; } .table-header-cell { @apply px-6 py-3 text-left text-xs font-medium text-ink-500 uppercase tracking-wider; } .table-row { @apply bg-white hover:bg-paper-50 transition-colors; } .table-cell { @apply px-6 py-4 whitespace-nowrap text-sm text-ink-700; } /* Prevent table layout shifts */ .table-fixed { table-layout: fixed !important; } .table-stable { @apply table-fixed; /* Removed min-height to allow content-based sizing for two-row layout */ } .table-stable thead { height: auto !important; } .table-stable thead th { position: sticky; top: 0; z-index: 10; background-color: #fafaf9; backdrop-filter: blur(8px); padding: 4px 8px !important; height: 28px !important; min-height: 28px !important; max-height: 28px !important; line-height: 1 !important; vertical-align: middle !important; overflow: hidden !important; box-sizing: border-box !important; font-size: 0.75rem !important; border-bottom: 1px solid #e7e5e4; } /* Primary rows with normal content */ .table-stable tbody tr { height: auto; /* Allow content-based sizing for two-row layout */ } /* Secondary rows should be compact */ .table-stable tbody tr.secondary-row { height: auto; } .table-stable tbody tr td { vertical-align: top; } /* Smooth loading overlay */ .table-loading-overlay { transition: opacity 0.3s ease-in-out; backdrop-filter: blur(1px); } /* Prevent content jumping during loading */ .loading-stable { min-height: inherit; visibility: visible; } .content-stable { transition: opacity 0.2s ease-in-out; } /* Custom tooltip for navigation dots using CSS */ .page-nav-dot { position: relative; } .page-nav-dot::after { content: attr(aria-label); position: absolute; left: 100%; top: 50%; transform: translateY(-50%); margin-left: 0.75rem; padding: 0.375rem 0.75rem; background-color: #1c1917; color: white; font-size: 0.75rem; font-weight: 500; border-radius: 0.375rem; opacity: 0; transition: opacity 200ms; pointer-events: none; white-space: nowrap; box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1); z-index: 50; } .page-nav-dot:hover::after { opacity: 1; } /* DataTable Expanded Row Animation */ @keyframes expandRow { from { opacity: 0; max-height: 0; transform: translateY(-10px); } to { opacity: 1; max-height: 1000px; transform: translateY(0); } } .animate-expand { animation: expandRow 0.3s ease-out forwards; overflow: hidden; } /* Drawer Slide Animations */ @keyframes slideInLeft { from { transform: translateX(-100%); } to { transform: translateX(0); } } @keyframes slideInRight { from { transform: translateX(100%); } to { transform: translateX(0); } } @keyframes slideInTop { from { transform: translateY(-100%); } to { transform: translateY(0); } } @keyframes slideInBottom { from { transform: translateY(100%); } to { transform: translateY(0); } } .animate-slide-in-left { animation: slideInLeft 0.3s ease-out; } .animate-slide-in-right { animation: slideInRight 0.3s ease-out; } .animate-slide-in-top { animation: slideInTop 0.3s ease-out; } .animate-slide-in-bottom { animation: slideInBottom 0.3s ease-out; }