diff --git a/web/package-lock.json b/web/package-lock.json index 0db28fe..fa95f94 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -8,7 +8,9 @@ "name": "qnote", "version": "0.0.1", "dependencies": { - "marked": "^15.0.7" + "highlight.js": "^11.11.1", + "marked": "^15.0.7", + "marked-highlight": "^2.2.1" }, "devDependencies": { "@sveltejs/adapter-auto": "^4.0.0", @@ -1552,6 +1554,15 @@ "dev": true, "license": "ISC" }, + "node_modules/highlight.js": { + "version": "11.11.1", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.1.tgz", + "integrity": "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/import-meta-resolve": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz", @@ -1882,6 +1893,15 @@ "node": ">= 18" } }, + "node_modules/marked-highlight": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/marked-highlight/-/marked-highlight-2.2.1.tgz", + "integrity": "sha512-SiCIeEiQbs9TxGwle9/OwbOejHCZsohQRaNTY2u8euEXYt2rYUFoiImUirThU3Gd/o6Q1gHGtH9qloHlbJpNIA==", + "license": "MIT", + "peerDependencies": { + "marked": ">=4 <16" + } + }, "node_modules/mini-svg-data-uri": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz", diff --git a/web/package.json b/web/package.json index f343cde..6c5c9d1 100644 --- a/web/package.json +++ b/web/package.json @@ -32,6 +32,8 @@ "vite": "^6.0.0" }, "dependencies": { - "marked": "^15.0.7" + "highlight.js": "^11.11.1", + "marked": "^15.0.7", + "marked-highlight": "^2.2.1" } } diff --git a/web/src/app.css b/web/src/app.css index 64c3164..70ac8dd 100644 --- a/web/src/app.css +++ b/web/src/app.css @@ -37,7 +37,6 @@ @layer base { body { - /* @apply bg-[var(--light-background)] text-[var(--light-text)] transition-colors duration-200; */ @apply bg-[var(--light-background)] text-[var(--light-text)]; } @@ -74,7 +73,7 @@ input, textarea, select { - @apply rounded-lg border border-[var(--light-text)]/20 bg-[var(--light-foreground)] px-3 py-2 text-[var(--light-text)] transition-colors duration-200; + @apply rounded-lg border px-3 py-2 transition-colors duration-200; } input:focus, @@ -82,449 +81,25 @@ @apply ring-2 ring-[var(--light-accent)] outline-none; } - .dark input, - .dark textarea, - .dark select { - @apply border-[var(--dark-text)]/20 bg-[var(--dark-foreground)] text-[var(--dark-text)]; - } - .dark input:focus, .dark select:focus { @apply ring-[var(--dark-accent)]; } button { - @apply cursor-pointer rounded-md bg-[var(--light-accent)] px-4 py-2 text-[var(--light-background)] transition-all duration-200 hover:bg-[var(--light-accent)]/80 focus:ring-2 focus:ring-[var(--light-accent)]/50 focus:outline-none disabled:opacity-50; + @apply cursor-pointer rounded-md bg-[var(--light-accent)] px-4 py-2 text-[var(--light-background)] transition-all duration-200 hover:bg-[var(--light-accent)]/80 focus:outline-none disabled:opacity-50; } .dark button { - @apply bg-[var(--dark-accent)] text-[var(--dark-background)] hover:bg-[var(--dark-accent)]/80 focus:ring-[var(--dark-accent)]/50; + @apply bg-[var(--dark-accent)] text-[var(--dark-background)] hover:bg-[var(--dark-accent)]/80; } } -/* Reusable component classes */ @layer components { - .card { - @apply rounded-lg bg-[var(--light-foreground)] p-6 shadow-md transition-colors duration-200; - } + /* * * * * * * * * * * * */ + /* Loading animation */ + /* * * * * * * * * * * * */ - .dark .card { - @apply bg-[var(--dark-foreground)]; - } - - .form-group { - @apply mb-4 space-y-2; - } - - .form-label { - @apply block text-sm font-medium text-[var(--light-text)]; - } - - .dark .form-label { - @apply text-[var(--dark-text)]; - } - - /* Error messages */ - .error { - @apply flex items-center justify-between rounded-lg bg-[var(--light-error-background)] p-3 text-sm text-[var(--light-error-text)]; - } - - .dark .error { - @apply bg-[var(--dark-error-background)] text-[var(--dark-error-text)]; - } - - /* Success messages */ - .success { - @apply flex items-center justify-between rounded-lg bg-[var(--light-success-background)] p-3 text-sm text-[var(--light-success-text)]; - } - - .dark .success { - @apply bg-[var(--dark-success-background)] text-[var(--dark-success-text)]; - } - - .btn-primary { - @apply rounded-lg bg-[var(--light-accent)] text-[var(--light-background)]; - } - - .dark .btn-primary { - @apply bg-[var(--dark-accent)] text-[var(--dark-background)]; - } - - .btn-secondary { - @apply rounded-lg border border-[var(--light-text)]/20 bg-[var(--light-foreground)] text-[var(--light-text)]; - } - - .dark .btn-secondary { - @apply border-[var(--dark-text)]/20 bg-[var(--dark-foreground)] text-[var(--dark-text)]; - } - - .container-page { - @apply mx-auto max-w-7xl px-4 sm:px-6 lg:px-8; - } - - /* Sidebar */ - @media (max-width: 768px) { - .sidebar { - @apply w-full max-w-full; - } - - body.sidebar-open { - @apply overflow-hidden; - } - } - - @media (min-width: 768px) { - .sidebar { - @apply w-64; - } - } - - .sidebar { - @apply fixed z-10 flex h-full flex-col overflow-hidden border-r border-[var(--light-foreground)] bg-[var(--light-foreground)] transition-all duration-300; - } - - .dark .sidebar { - @apply border-[var(--dark-foreground)] bg-[var(--dark-foreground)]; - } - - .sidebar-header, - .sidebar-footer { - /* Height should align with the navbar height for visual consistency */ - @apply flex h-20 items-center justify-center border-b border-[var(--light-text)]/20 p-2; - } - - .dark .sidebar-header, - .dark .sidebar-footer { - @apply border-[var(--dark-text)]/20; - } - - .sidebar-footer { - @apply border-t; - } - - .sidebar-item { - @apply cursor-pointer p-3 transition-colors hover:bg-[var(--light-background)]; - } - - .dark .sidebar-item { - @apply hover:bg-[var(--dark-background)]; - } - - .sidebar-item-active { - @apply bg-[var(--light-background)]; - } - - .dark .sidebar-item-active { - @apply bg-[var(--dark-background)]; - } - - .sidebar-item-content { - @apply flex flex-col; - } - - .sidebar-item-bottom-row { - @apply mt-1 flex items-center justify-between; - } - - .sidebar-item-text { - @apply text-xs text-[var(--light-text)]/60; - } - - .dark .sidebar-item-text { - @apply text-[var(--dark-text)]/60; - } - - .sidebar-item-delete { - @apply flex h-6.5 w-6.5 items-center justify-center rounded-lg border-1 border-[var(--light-accent)]/20 bg-transparent p-1 text-[var(--light-accent)]/50 hover:text-[var(--light-accent)]; - } - - .dark .sidebar-item-delete { - @apply border-[var(--dark-accent)]/20 text-[var(--dark-accent)]/50 hover:text-[var(--dark-accent)]; - } - - .sidebar-divider { - @apply divide-y divide-[var(--light-text)]/20; - } - - .dark .sidebar-divider { - @apply divide-[var(--dark-text)]/20; - } - - .search-bar { - @apply w-full rounded-lg py-2.5 pr-4 pl-11; - } - - .search-bar-icon { - @apply absolute top-3 left-8 h-5 w-5 text-[var(--light-text)]/60; - } - - .dark .search-bar-icon { - @apply text-[var(--dark-text)]/60; - } - - .general-sidebar-icon { - @apply h-4 w-4 text-[var(--light-text)]/60; - } - - .dark .general-sidebar-icon { - @apply text-[var(--dark-text)]/60; - } - - /* Versions dropdown */ - .versions-dropdown { - @apply absolute right-0 z-10 mt-2 w-52 origin-top-right space-y-0.5 rounded-md bg-[var(--light-foreground)] shadow-lg ring-1 ring-[var(--light-foreground)]/10 focus:outline-none; - } - - .dark .versions-dropdown { - @apply bg-[var(--dark-foreground)] ring-[var(--dark-foreground)]/10; - } - - .versions-dropdown-item { - @apply w-full bg-[var(--light-foreground)] p-3 transition-colors hover:bg-[var(--light-background)]; - } - - .dark .versions-dropdown-item { - @apply bg-[var(--dark-foreground)] hover:bg-[var(--dark-background)]; - } - - .versions-dropdown-item-active { - @apply bg-[var(--light-accent)]/20; - } - - .dark .versions-dropdown-item-active { - @apply bg-[var(--dark-accent)]/20; - } - - .versions-dropdown-item-text { - @apply text-xs text-[var(--light-text)]/60; - } - - .dark .versions-dropdown-item-text { - @apply text-[var(--dark-text)]/60; - } - - .versions-dropdown-divider { - @apply divide-y divide-[var(--light-text)]/20; - } - - .dark .versions-dropdown-divider { - @apply divide-[var(--dark-text)]/20; - } - - /* Note editor */ - .note-title-container { - @apply mb-4; - } - - .note-title-input { - @apply w-full rounded-2xl border-b border-[var(--light-text)]/20 bg-transparent pb-2 text-2xl font-bold focus:border-[var(--light-accent)]; - } - - .dark .note-title-input { - @apply border-[var(--dark-text)]/20 focus:border-[var(--dark-accent)]; - } - - .note-char-count { - @apply mt-2 text-xs text-[var(--light-text)]/60; - } - - .dark .note-char-count { - @apply text-[var(--dark-text)]/60; - } - - .note-editor-container { - @apply flex min-h-0 flex-1 flex-col overflow-auto; - } - - .note-editor-wrapper { - @apply flex h-full flex-col; - } - - .note-editor-content { - @apply flex h-full flex-col; - } - - .note-textarea { - @apply h-full max-h-full min-h-1/2 w-full resize-none rounded-2xl bg-transparent p-3.5 font-mono outline-none focus:border-4 focus:border-[var(--light-accent)]/60; - } - - .dark .note-textarea { - @apply focus:border-[var(--dark-accent)]/60; - } - - .note-save-button { - @apply fixed right-10 bottom-10 z-10; - } - - /* Markdown preview */ - .markdown-preview h1 { - @apply mt-6 mb-4 border-b border-[var(--light-foreground)] pb-3 text-3xl; - } - - .dark .markdown-preview h1 { - @apply border-[var(--dark-foreground)]; - } - - .markdown-preview h2 { - @apply mt-6 mb-4 text-2xl; - } - - .markdown-preview h3 { - @apply mt-5 mb-3 text-xl; - } - - .markdown-preview p { - @apply my-4; - } - - .markdown-preview ul, - .markdown-preview ol { - @apply my-4 pl-5; - } - - .markdown-preview ul { - @apply list-disc; - } - - .markdown-preview ol { - @apply list-decimal; - } - - .markdown-preview li > ul, - .markdown-preview li > ol, - .markdown-preview ul > ul, - .markdown-preview ul > ol, - .markdown-preview ol > ol, - .markdown-preview ol > ul { - @apply my-1; /* Reduced vertical spacing for nested lists */ - } - - .markdown-preview ul ul:has(> li > input[type="checkbox"]) { - @apply pl-11; - } - - .markdown-preview ul ul ul:has(> li > input[type="checkbox"]) { - @apply pl-11; - } - - .markdown-preview li span { - @apply ml-1.5; - } - - .markdown-preview li:has(> input[type="checkbox"]) { - /* Bullet removal */ - @apply -ml-4.5 list-none; - } - - .markdown-preview input[type="checkbox"] { - /* Actual checkbox styling */ - @apply mr-1 h-4 w-4 appearance-none rounded-full border-[var(--light-text)]/30 bg-[var(--light-foreground)] p-0 align-middle; - } - - .dark .markdown-preview input[type="checkbox"] { - @apply border-[var(--dark-text)]/30 bg-[var(--dark-foreground)]; - } - - .markdown-preview input[type="checkbox"]:checked { - @apply border-[var(--light-accent)] bg-[var(--light-accent)]; - } - - .dark .markdown-preview input[type="checkbox"]:checked { - @apply border-[var(--dark-accent)] bg-[var(--dark-accent)]; - } - - .markdown-preview hr { - @apply border-[var(--light-text)]/20; - } - - .dark .markdown-preview hr { - @apply border-[var(--dark-text)]/20; - } - - .markdown-preview code { - @apply rounded bg-[var(--light-foreground)] px-1 py-0.5 font-mono; - } - - .dark .markdown-preview code { - @apply bg-[var(--dark-foreground)]; - } - - .markdown-preview pre { - @apply overflow-x-auto rounded-2xl bg-[var(--light-foreground)] p-3; - } - - .dark .markdown-preview pre { - @apply bg-[var(--dark-foreground)]; - } - - .markdown-preview blockquote { - @apply my-4 border-l-4 border-[var(--light-accent)] pl-4 text-[var(--light-text)] opacity-70; - } - - .dark .markdown-preview blockquote { - @apply border-[var(--dark-accent)] text-[var(--dark-text)]; - } - - .markdown-preview a { - @apply text-[var(--light-accent)] underline; - } - - .dark .markdown-preview a { - @apply text-[var(--dark-accent)]; - } - - .markdown-preview table { - @apply my-4 w-full border-collapse; - } - - .markdown-preview th, - .markdown-preview td { - @apply border border-[var(--light-text)]/20 p-2 text-left; - } - - .dark .markdown-preview th, - .dark .markdown-preview td { - @apply border-[var(--dark-text)]/20; - } - - .markdown-preview th { - @apply bg-[var(--light-foreground)]; - } - - .dark .markdown-preview th { - @apply bg-[var(--dark-foreground)]; - } - - /* Settings modal */ - .modal-backdrop { - @apply fixed inset-0 z-40 flex items-center justify-center backdrop-blur-xs; - } - - .modal-content { - @apply mx-4 max-h-[90vh] w-full max-w-md overflow-y-auto rounded-lg border-2 border-[var(--light-accent)]/10 bg-[var(--light-background)] shadow-lg; - } - - .dark .modal-content { - @apply border-[var(--dark-accent)]/10 bg-[var(--dark-background)]; - } - - .modal-section { - @apply border-b border-[var(--light-text)]/20 p-4; - } - - .dark .modal-section { - @apply border-[var(--dark-text)]/20; - } - - .modal-close-button { - @apply h-8 w-8 items-center justify-center rounded-md border-1 border-[var(--light-accent)]/20 bg-transparent p-1 text-[var(--light-accent)]/50 hover:text-[var(--light-accent)]; - } - - .dark .modal-close-button { - @apply border-[var(--dark-accent)]/20 text-[var(--dark-accent)]/50 hover:text-[var(--dark-accent)]; - } - - /* Loading spinner */ .loading-container { @apply pointer-events-none flex h-screen w-full items-center justify-center; } @@ -567,7 +142,54 @@ } } - /* Main layout */ + /* * * * * * * * * * * * * */ + /* Authentication view */ + /* * * * * * * * * * * * * */ + + .auth-card { + @apply rounded-lg bg-[var(--light-foreground)] p-6 shadow-md transition-colors duration-200; + } + + .auth-input-field { + @apply w-full rounded-lg border border-[var(--light-accent)]/20 bg-transparent; + } + + .dark .auth-input-field { + @apply border-[var(--dark-accent)]/20; + } + + .auth-button { + @apply w-full rounded-lg border border-[var(--light-accent)]/20 bg-[var(--light-accent)]/70 text-[var(--light-background)]; + } + + .dark .auth-button { + @apply border-[var(--dark-accent)]/20 bg-[var(--dark-accent)]/70 text-[var(--dark-background)]; + } + + .dark .auth-card { + @apply bg-[var(--dark-foreground)]; + } + + /* * * * * * */ + /* Forms */ + /* * * * * * */ + + .form-group { + @apply mb-4 space-y-2; + } + + .form-label { + @apply block text-sm font-medium text-[var(--light-text)]; + } + + .dark .form-label { + @apply text-[var(--dark-text)]; + } + + /* * * * * * * * * * * * * */ + /* Primary view layout */ + /* * * * * * * * * * * * * */ + .main-layout-container { @apply flex h-screen w-full bg-[var(--light-background)]; } @@ -576,20 +198,9 @@ @apply bg-[var(--dark-background)]; } - .content-wrapper { - @apply flex h-screen flex-1 flex-col overflow-hidden; - } - - .note-content-fixed-width { - @apply mx-auto flex w-full max-w-[800px] flex-col px-8 py-0; - height: calc(100% - 5rem); - } - - @media (max-width: 768px) { - .note-content-fixed-width { - @apply max-w-full px-4 py-0; - } - } + /* * * * * * * * * * */ + /* Notifications */ + /* * * * * * * * * * */ .main-info-popup { /* Z-value should be set so that this is on top of the modal's background blur */ @@ -600,18 +211,225 @@ @apply ml-2 h-4 w-4 items-center justify-center rounded-md bg-transparent p-0 text-inherit; } - .main-header { - /* - Should have higher z-value than the contents, but still less than the sidebar - (otherwise the navbar and the sidebar shadows will seem uneven). - */ - @apply z-5 flex h-20 items-center justify-between bg-[var(--light-foreground)] p-4 shadow-sm; + /* Error notifications */ + + .error { + @apply flex items-center justify-between rounded-lg bg-[var(--light-error-background)] p-3 text-sm text-[var(--light-error-text)]; } - .dark .main-header { - @apply bg-[var(--dark-foreground)]; + .dark .error { + @apply bg-[var(--dark-error-background)] text-[var(--dark-error-text)]; } + /* Success notifications */ + + .success { + @apply flex items-center justify-between rounded-lg bg-[var(--light-success-background)] p-3 text-sm text-[var(--light-success-text)]; + } + + .dark .success { + @apply bg-[var(--dark-success-background)] text-[var(--dark-success-text)]; + } + + /* * * * * * * */ + /* Buttons */ + /* * * * * * * */ + + .btn-primary { + @apply rounded-lg bg-[var(--light-accent)] text-[var(--light-background)]; + } + + .dark .btn-primary { + @apply bg-[var(--dark-accent)] text-[var(--dark-background)]; + } + + .btn-secondary { + @apply rounded-lg border border-[var(--light-text)]/20 bg-[var(--light-foreground)] text-[var(--light-text)]; + } + + .dark .btn-secondary { + @apply border-[var(--dark-text)]/20 bg-[var(--dark-foreground)] text-[var(--dark-text)]; + } + + /* * * * * * * * * * * * */ + /* Content container */ + /* * * * * * * * * * * * */ + + .container-page { + @apply mx-auto max-w-7xl px-4 sm:px-6 lg:px-8; + } + + /* * * * * * * * * */ + /* Sidebar */ + /* * * * * * * * * */ + + .mini-sidebar { + @apply flex w-14 flex-col items-center border-r border-[var(--light-accent)]/20 bg-[var(--light-foreground)] py-4; + } + + .dark .mini-sidebar { + @apply border-[var(--dark-accent)]/20 bg-[var(--dark-foreground)]; + } + + .sidebar-button { + @apply flex h-8 w-8 items-center justify-center rounded-lg border border-[var(--light-accent)] bg-transparent p-0 text-[var(--light-text)] hover:bg-[var(--light-background)]/80; + } + + .dark .sidebar-button { + @apply border-[var(--dark-accent)]/50 text-[var(--dark-text)] hover:bg-[var(--dark-background)]/80; + } + + .sidebar { + @apply z-10 flex h-full flex-col overflow-hidden border-r border-[var(--light-accent)]/20 bg-[var(--light-foreground)] transition-all duration-300 ease-in-out; + } + + .dark .sidebar { + @apply border-[var(--dark-accent)]/20 bg-[var(--dark-foreground)]; + } + + /* Take up full screen width on mobile */ + @media (max-width: 768px) { + .sidebar { + /* Max width must take into account width of "mini sidebar" */ + @apply w-[calc(100vw-3.5rem)]; + } + + body.sidebar-open { + @apply overflow-hidden; + } + } + + /* 16rem width on desktop or equivalent screens */ + @media (min-width: 768px) { + .sidebar { + @apply w-64; + } + } + + .sidebar-header-container { + @apply flex items-center px-2.5 py-4.5; + } + + .sidebar-header-link { + @apply flex items-center text-inherit no-underline; + } + + .sidebar-header-logo { + @apply ml-2 h-7 w-7; + } + + .sidebar-header-text { + @apply font-copernicus ml-2.5 text-center text-lg text-[var(--light-text)]; + } + + .dark .sidebar-header-text { + @apply text-[var(--dark-text)]; + } + + .sidebar-section-divider { + @apply mx-4 border-t border-[var(--light-text)]/20; + } + + .dark .sidebar-section-divider { + @apply border-[var(--dark-text)]/20; + } + + .sidebar-action-button { + @apply flex items-center rounded-lg border border-[var(--light-text)]/10 bg-transparent px-3 py-2 text-sm text-[var(--light-text)] hover:bg-[var(--light-background)]/50; + } + + .dark .sidebar-action-button { + @apply border-[var(--dark-text)]/10 text-[var(--dark-text)] hover:bg-[var(--dark-background)]/80; + } + + .sidebar-search-bar { + @apply w-full rounded-lg border border-[var(--light-text)]/10 bg-transparent py-2 pr-4 pl-11 text-sm text-[var(--light-text)] hover:bg-[var(--light-background)]/80; + } + + .dark .sidebar-search-bar { + @apply border-[var(--dark-text)]/10 text-[var(--dark-text)] hover:bg-[var(--dark-background)]/80; + } + + .sidebar-search-bar-icon { + @apply absolute top-3 left-6 h-4 w-4 text-[var(--light-text)]/60; + } + + .dark .sidebar-search-bar-icon { + @apply text-[var(--dark-text)]/60; + } + + .sidebar-list { + @apply flex cursor-pointer flex-col rounded-lg border border-[var(--light-text)]/10 bg-transparent px-3 py-2 text-sm text-[var(--light-text)] hover:bg-[var(--light-background)]/50; + } + + .dark .sidebar-list { + @apply border-[var(--dark-text)]/10 bg-transparent text-[var(--dark-text)] hover:bg-[var(--dark-background)]/80; + } + + .sidebar-list-active { + @apply border-[var(--light-accent)]; + } + + .dark .sidebar-list-active { + @apply border-[var(--dark-accent)]; + } + + .sidebar-list-item-title { + @apply font-copernicus truncate text-sm text-[var(--light-text)]; + } + + .dark .sidebar-list-item-title { + @apply text-[var(--dark-text)]; + } + + .sidebar-list-item-delete-button { + @apply ml-1 h-5.5 w-5.5 flex-shrink-0 border-[var(--light-accent)]/40 hover:bg-[var(--light-accent)]/20; + } + + .dark .sidebar-list-item-delete-button { + @apply border-[var(--dark-accent)]/40 hover:bg-[var(--dark-accent)]/20; + } + + .sidebar-list-item-metadata { + @apply mt-1 truncate text-xs text-[var(--light-text)]/40; + } + + .dark .sidebar-list-item-metadata { + @apply text-[var(--dark-text)]/40; + } + + .sidebar-search-info { + @apply p-4 text-center text-sm text-[var(--light-text)]/60; + } + + .dark .sidebar-search-info { + @apply text-[var(--dark-text)]/60; + } + + .sidebar-user-button-content-container { + @apply flex w-full items-center; + } + + .sidebar-user-button-username-container { + @apply max-w-full flex-grow justify-center overflow-hidden px-2; + } + + .sidebar-user-button-username-text { + @apply line-clamp-2 block max-w-full overflow-hidden text-ellipsis; + } + + .sidebar-user-dropdown { + @apply absolute bottom-full left-2 mb-0 w-[95%] rounded-lg border border-[var(--light-accent)]/20 bg-[var(--light-foreground)] shadow-lg; + } + + .dark .sidebar-user-dropdown { + @apply border-[var(--dark-accent)]/20 bg-[var(--dark-foreground)]; + } + + /* * * * * * * * * * * * */ + /* Primary workspace */ + /* * * * * * * * * * * * */ + .main-content { @apply flex min-h-0 flex-1 flex-col overflow-auto bg-[var(--light-background)] p-6; } @@ -620,6 +438,35 @@ @apply bg-[var(--dark-background)]; } + /* Minimize wasted screen height on short displays */ + @media (max-width: 768px) { + .main-content { + @apply pb-2; + } + } + + .content-wrapper { + @apply flex h-screen flex-1 flex-col overflow-hidden py-12; + } + + .note-content-fixed-width { + @apply mx-auto flex h-full w-full max-w-[800px] flex-col px-8 py-0; + } + + @media (max-width: 768px) { + .content-wrapper { + @apply py-0; + } + + .note-content-fixed-width { + @apply max-w-full px-0 py-0; + } + } + + /* * * * * * * * * * * */ + /* User greetings */ + /* * * * * * * * * * * */ + .greeting-container { @apply flex h-full flex-col items-center justify-center; } @@ -629,10 +476,442 @@ } .greeting-bottom-link { - @apply cursor-pointer text-[var(--light-accent)] transition-colors duration-200 hover:underline; + @apply cursor-pointer text-[var(--light-accent)]/70 transition-colors duration-200 hover:underline; } - .greeting-bottom-link { + .dark .greeting-bottom-link { @apply text-[var(--dark-accent)]; } + + /* * * * * * * * * * * * * */ + /* Note editor/viewer */ + /* * * * * * * * * * * * * */ + + .note-editor-content { + @apply flex h-full flex-col; + } + + .note-title-container { + @apply mb-4; + } + + .note-title-display { + @apply font-copernicus max-w-full pb-1 text-2xl wrap-break-word; + } + + /* Limit title (display as input is always only one row tall) to max. 4 rows tall on short screens */ + @media (max-width: 768px) { + .note-title-display { + @apply max-h-24 overflow-y-auto; + line-height: 1.2; + } + } + + .note-title-input { + @apply w-full rounded-lg border-[var(--light-text)]/20 bg-transparent pb-2 text-2xl hover:bg-[var(--light-foreground)]/50 focus:border-1 focus:border-[var(--light-accent)]/50; + } + + .dark .note-title-input { + @apply border-[var(--dark-text)]/20 hover:bg-[var(--dark-foreground)]/80 focus:border-[var(--dark-accent)]/50; + } + + .note-char-count { + @apply my-2 text-xs text-[var(--light-text)]/50; + } + + .dark .note-char-count { + @apply text-[var(--dark-text)]/50; + } + + .note-action-container { + @apply mb-2.5 flex flex-wrap items-center justify-start space-x-2 gap-y-2 border-t border-[var(--light-text)]/10 pt-2.5; + } + + .dark .note-action-container { + @apply border-[var(--dark-text)]/10; + } + + .note-action-button { + @apply flex h-9 items-center justify-center rounded-lg border border-[var(--light-text)]/10 bg-transparent text-sm text-[var(--light-text)] hover:bg-[var(--light-foreground)]/50; + } + + .dark .note-action-button { + @apply border-[var(--dark-text)]/10 text-[var(--dark-text)] hover:bg-[var(--dark-foreground)]/80; + } + + .note-action-icon-button { + @apply flex h-9 w-9 items-center justify-center rounded-lg border border-[var(--light-text)]/10 bg-transparent p-0 text-[var(--light-text)] hover:bg-[var(--light-foreground)]/80; + } + + .dark .note-action-icon-button { + @apply border-[var(--dark-text)]/10 text-[var(--dark-text)] hover:bg-[var(--dark-foreground)]/80; + } + + .note-mobile-save-button { + @apply fixed right-4 bottom-4 z-10 hidden h-10 w-10 items-center justify-center border border-[var(--light-accent)] bg-[var(--light-foreground)] p-0 text-[var(--light-text)]/80 shadow-lg; + } + + .dark .note-mobile-save-button { + @apply border-[var(--dark-accent)]/50 bg-[var(--dark-foreground)] text-[var(--dark-text)]/80; + } + + /* Modified save button positioning on short screens */ + @media (max-width: 768px) { + .note-mobile-save-button { + @apply flex; + } + + .note-action-icon-button { + @apply hidden; + } + } + + .note-versions-dropdown { + @apply absolute top-9 right-0 z-10 mt-2 w-58 origin-top-right overflow-hidden rounded-lg border border-[var(--light-accent)]/20 bg-[var(--light-foreground)] shadow-lg; + } + + .dark .note-versions-dropdown { + @apply border-[var(--dark-accent)]/20 bg-[var(--dark-foreground)]; + } + + .versions-dropdown-item-text { + @apply font-copernicus w-full justify-end truncate px-0 text-[var(--light-text)]/90; + letter-spacing: -0.02em; + } + + .dark .versions-dropdown-item-text { + @apply text-[var(--dark-text)]/90; + } + + .versions-dropdown-item-meta { + @apply text-xs text-[var(--light-text)]/60; + } + + .dark .versions-dropdown-item-meta { + @apply text-[var(--dark-text)]/60; + } + + .versions-dropdown-active-version { + @apply border-[var(--light-accent)]; + } + + .dark .versions-dropdown-active-version { + @apply border-[var(--dark-accent)]; + } + + .note-editor-container { + @apply flex min-h-0 flex-1 flex-col overflow-auto; + } + + .note-editor-wrapper { + @apply flex h-full flex-col; + } + + .note-textarea { + @apply h-full max-h-full min-h-1/2 w-full resize-none rounded-lg border-1 border-[var(--light-text)]/20 bg-transparent p-3.5 font-mono outline-none hover:bg-[var(--light-foreground)]/50 focus:border-3 focus:border-[var(--light-accent)]/70; + } + + .dark .note-textarea { + @apply border-[var(--dark-text)]/20 hover:bg-[var(--dark-foreground)]/80 focus:border-[var(--dark-accent)]/80; + } + + .note-save-button { + @apply fixed right-10 bottom-10 z-10; + } + + /* * * * * * * * * * * * * */ + /* Rendered Markdown */ + /* * * * * * * * * * * * * */ + + .markdown-preview h1, + h2, + h3, + h4 { + @apply font-copernicus; + } + + /* Headings */ + + .markdown-preview h1 { + @apply mt-6 mb-4 border-b border-[var(--light-foreground)] pb-3 text-3xl; + } + + .dark .markdown-preview h1 { + @apply border-[var(--dark-foreground)]; + } + + .markdown-preview h2 { + @apply mt-6 mb-4 text-2xl; + } + + .markdown-preview h3 { + @apply mt-5 mb-3 text-xl; + } + + /* Regular text */ + + .markdown-preview p { + @apply my-4; + } + + /* Regular lists */ + + .markdown-preview ul, + .markdown-preview ol { + @apply pl-5; + } + + .markdown-preview ul { + @apply list-disc; + } + + .markdown-preview ol { + @apply list-decimal; + } + + /* Checkboxes ('todo items') */ + + .markdown-preview input[type="checkbox"] { + @apply mr-1 h-4 w-4 appearance-none rounded-md border-[var(--light-text)]/30 bg-[var(--light-foreground)] p-0 align-text-bottom; + } + + .dark .markdown-preview input[type="checkbox"] { + @apply border-[var(--dark-text)]/30 bg-[var(--dark-foreground)]; + } + + .markdown-preview input[type="checkbox"]:checked { + @apply border-[var(--light-accent)] bg-[var(--light-accent)]; + } + + .dark .markdown-preview input[type="checkbox"]:checked { + @apply border-[var(--dark-accent)] bg-[var(--dark-accent)]/80; + } + + /* Horizontal rules */ + + .markdown-preview hr { + @apply my-4 border-[var(--light-text)]/20; + } + + .dark .markdown-preview hr { + @apply border-[var(--dark-text)]/20; + } + + /* Inline code snippets */ + + .markdown-preview code { + @apply rounded-lg bg-[var(--light-foreground)] px-1 py-0.5 font-mono; + } + + .dark .markdown-preview code { + @apply bg-[var(--dark-foreground)]; + } + + /* Code blocks & blockquotes */ + + .markdown-preview pre code { + @apply block bg-transparent px-0 py-0; + } + + .markdown-preview pre { + @apply overflow-x-auto rounded-lg bg-[var(--light-foreground)] p-2; + } + + .dark .markdown-preview pre { + @apply bg-[var(--dark-foreground)]; + } + + .markdown-preview blockquote { + @apply my-4 rounded-none border-l-4 border-[var(--light-accent)] pl-4 text-[var(--light-text)] opacity-70; + } + + .dark .markdown-preview blockquote { + @apply border-[var(--dark-accent)] text-[var(--dark-text)]; + } + + /* Links */ + + .markdown-preview a { + @apply text-[var(--light-accent)] underline; + } + + .dark .markdown-preview a { + @apply text-[var(--dark-accent)]; + } + + /* Tables & their contents */ + + .markdown-preview table { + @apply my-4 w-full border-collapse; + } + + .markdown-preview th, + .markdown-preview td { + @apply border border-[var(--light-text)]/20 p-2 text-left; + } + + .dark .markdown-preview th, + .dark .markdown-preview td { + @apply border-[var(--dark-text)]/20; + } + + .markdown-preview th { + @apply bg-[var(--light-foreground)]; + } + + .dark .markdown-preview th { + @apply bg-[var(--dark-foreground)]; + } + + /* Codeblock syntax highlighting (highlight.js) */ + + .hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + background: transparent; + color: var(--light-text); + } + + .dark .hljs { + color: var(--dark-text); + } + + /* Keywords */ + + .hljs-keyword, + .hljs-selector-tag, + .hljs-subst { + color: #8959a8; + } + + .dark .hljs-keyword, + .dark .hljs-selector-tag, + .dark .hljs-subst { + color: #c792ea; + } + + /* Strings */ + + .hljs-string, + .hljs-doctag, + .hljs-regexp { + color: #3c8548; + } + + .dark .hljs-string, + .dark .hljs-doctag, + .dark .hljs-regexp { + color: #89ca78; + } + + /* Numbers & booleans */ + + .hljs-number, + .hljs-literal { + color: #f5871f; + } + + .dark .hljs-number, + .dark .hljs-literal { + color: #f78c6c; + } + + /* Function names */ + + .hljs-title, + .hljs-section, + .hljs-selector-id { + color: #4271ae; + } + + .dark .hljs-title, + .dark .hljs-section, + .dark .hljs-selector-id { + color: #82aaff; + } + + /* Comments */ + + .hljs-comment { + color: #8e908c; + } + + .dark .hljs-comment { + color: #676e95; + } + + /* Variables */ + + .hljs-variable, + .hljs-template-variable { + color: #c82829; + } + + .dark .hljs-variable, + .dark .hljs-template-variable { + color: #ff5874; + } + + /* Class names */ + + .hljs-class .hljs-title { + color: #4271ae; + } + + .dark .hljs-class .hljs-title { + color: #ffcb6b; + } + + /* * * * * * * */ + /* Modals */ + /* * * * * * * */ + + .modal-backdrop { + @apply fixed inset-0 z-40 flex items-center justify-center backdrop-blur-xs; + } + + .modal-content { + @apply mx-4 max-h-[90vh] w-full max-w-[90vw] overflow-y-auto rounded-lg border-2 border-[var(--light-accent)]/10 bg-[var(--light-background)] shadow-lg; + } + + .dark .modal-content { + @apply border-[var(--dark-accent)]/10 bg-[var(--dark-background)]; + } + + .modal-section { + @apply border-b border-[var(--light-text)]/20 p-4; + } + + .dark .modal-section { + @apply border-[var(--dark-text)]/20; + } + + .modal-section-title { + @apply mb-4 text-lg; + } + + .modal-table { + @apply w-full table-auto border-collapse; + } + + .modal-table-row { + @apply border border-[var(--light-text)]/10; + } + + .dark .modal-table-row { + @apply border-[var(--dark-text)]/10; + } + + .modal-table-row-item { + @apply overflow-x-auto px-4 py-3 text-wrap; + } + + .modal-table-head { + @apply text-left font-semibold text-[var(--light-text)]/80; + } + + .dark .modal-table-head { + @apply text-[var(--dark-text)]/80; + } } diff --git a/web/src/app.html b/web/src/app.html index 718fae9..9eef4bd 100644 --- a/web/src/app.html +++ b/web/src/app.html @@ -21,6 +21,7 @@ localStorage.setItem("darkMode", darkMode) +