-
- {/* Main Timer Section */}
-
- {/* Timer Circle */}
-
- { /* Pomodoro Timer Component */ }
-
-
- {/* Today's Progress */}
-
-
- Today's Progress
-
-
-
-
- Sessions Completed
-
-
- {completedToday.length}
-
-
-
-
- Focus Time
-
-
- {formatFocusTime(todayFocusTime)}
-
-
-
-
- Completion Rate
-
-
- {completionRate}%
-
-
-
-
-
-
-
- {/* Duration Selector & Settings */}
+
+
- {/* Duration Presets */}
+
-
- {/* Quick Actions */}
-
-
- Quick Actions
-
-
-
-
-
-
-
diff --git a/client/src/styles/Home.module.scss b/client/src/styles/Home.module.scss
new file mode 100644
index 0000000..6362864
--- /dev/null
+++ b/client/src/styles/Home.module.scss
@@ -0,0 +1,38 @@
+.container {
+ padding: 1.5rem;
+ max-width: 64rem;
+ margin: 0 auto;
+ display: flex;
+ flex-direction: column;
+ gap: 2rem;
+ animation: fadeIn 0.3s ease-in-out;
+}
+
+.grid {
+ display: grid;
+ grid-template-columns: 1fr;
+ gap: 2rem;
+}
+
+@media (min-width: 768px) {
+ .grid {
+ grid-template-columns: 35% 1fr;
+ }
+}
+
+@media (min-width: 1024px) {
+ .grid {
+ grid-template-columns: 30% 1fr;
+ }
+}
+
+@keyframes fadeIn {
+ from {
+ opacity: 0;
+ transform: translateY(10px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
diff --git a/client/src/styles/QuickActions.module.scss b/client/src/styles/QuickActions.module.scss
new file mode 100644
index 0000000..af85a71
--- /dev/null
+++ b/client/src/styles/QuickActions.module.scss
@@ -0,0 +1,61 @@
+.card {
+ // Card container styles
+}
+
+.cardContent {
+ display: flex;
+ flex-direction: column;
+ gap: 0.75rem;
+}
+
+.actionButton {
+ width: 100%;
+ justify-content: flex-start;
+ gap: 0.75rem;
+ height: auto;
+ padding: 0.75rem;
+ min-height: 5rem;
+ transition: all 0.2s ease;
+}
+
+.soundButton {
+ &:hover {
+ border-color: hsl(var(--accent));
+ background-color: hsl(var(--accent) / 0.05);
+ }
+}
+
+.exportButton {
+ &:hover {
+ border-color: hsl(var(--chart-2));
+ background-color: hsl(var(--chart-2) / 0.05);
+ }
+}
+
+.buttonContent {
+ text-align: left;
+ flex: 1;
+ min-width: 0;
+}
+
+.buttonTitle {
+ font-weight: 500;
+ word-break: break-words;
+}
+
+.buttonDescription {
+ font-size: 0.875rem;
+ color: hsl(var(--muted-foreground));
+ word-break: break-words;
+ line-height: 1.5;
+}
+
+.soundIcon {
+ color: hsl(var(--accent));
+ flex-shrink: 0;
+}
+
+.exportIcon {
+ color: hsl(var(--chart-2));
+ flex-shrink: 0;
+}
diff --git a/client/src/styles/TaskCard.module.scss b/client/src/styles/TaskCard.module.scss
new file mode 100644
index 0000000..c3e9e57
--- /dev/null
+++ b/client/src/styles/TaskCard.module.scss
@@ -0,0 +1,123 @@
+.card {
+ cursor: pointer !important;
+ transition: all 0.2s ease !important;
+ display: flex !important;
+ flex-direction: column !important;
+ justify-content: center !important;
+ align-items: flex-start !important;
+
+ &:hover {
+ box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1) !important;
+ transform: scale(1.02) !important;
+ }
+
+ &.completed {
+ opacity: 0.6 !important;
+ background-color: hsl(var(--muted) / 0.5) !important;
+ cursor: default !important;
+
+ &:hover {
+ box-shadow: none !important;
+ transform: none !important;
+ opacity: 0.6 !important;
+ }
+ }
+}
+
+.cardContent {
+ padding: 1rem !important;
+ width: 100% !important;
+}
+
+.content {
+ display: flex !important;
+ align-items: center !important;
+ justify-content: space-between !important;
+ gap: 0.75rem !important;
+ width: 100% !important;
+}
+
+.mainContent {
+ flex: 1 !important;
+ min-width: 0 !important;
+}
+
+.title {
+ font-weight: 500 !important;
+ font-size: 0.875rem !important;
+ line-height: 1.25 !important;
+ margin-bottom: 0.25rem !important;
+
+ &.completed {
+ text-decoration: line-through !important;
+ color: hsl(var(--muted-foreground)) !important;
+ }
+}
+
+.description {
+ font-size: 0.75rem !important;
+ color: hsl(var(--muted-foreground)) !important;
+ display: -webkit-box !important;
+ -webkit-line-clamp: 2 !important;
+ -webkit-box-orient: vertical !important;
+ overflow: hidden !important;
+}
+
+.metaInfo {
+ display: flex !important;
+ align-items: center !important;
+ gap: 0.5rem !important;
+ margin-top: 0.5rem !important;
+}
+
+.metaItem {
+ font-size: 0.75rem !important;
+ color: hsl(var(--muted-foreground)) !important;
+}
+
+.actions {
+ display: flex !important;
+ flex-direction: column !important;
+ align-items: flex-end !important;
+ gap: 0.5rem !important;
+ flex-shrink: 0 !important;
+}
+
+.deleteButton {
+ background: none !important;
+ border: none !important;
+ cursor: pointer !important;
+ padding: 0.25rem !important;
+ border-radius: 0.25rem !important;
+ transition: all 0.2s ease !important;
+ display: flex !important;
+ align-items: center !important;
+ justify-content: center !important;
+
+ &:hover {
+ background-color: hsl(var(--destructive) / 0.1) !important;
+ color: hsl(var(--destructive)) !important;
+ }
+}
+
+.deleteIcon {
+ width: 1rem !important;
+ height: 1rem !important;
+ color: hsl(var(--destructive)) !important;
+ transition: color 0.2s ease !important;
+}
+
+.checkbox {
+ flex-shrink: 0 !important;
+ margin: 0 !important;
+ align-self: center !important;
+}
+
+.completionIndicator {
+ width: 1rem !important;
+ height: 1rem !important;
+ border-radius: 50% !important;
+ background-color: #22c55e !important;
+ flex-shrink: 0 !important;
+ margin-top: 0.25rem !important;
+}
diff --git a/client/src/styles/TaskForm.module.scss b/client/src/styles/TaskForm.module.scss
new file mode 100644
index 0000000..8927743
--- /dev/null
+++ b/client/src/styles/TaskForm.module.scss
@@ -0,0 +1,41 @@
+.form {
+ // Form container styles
+}
+
+.formContent {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+}
+
+.field {
+ // Individual field container
+}
+
+.fieldGrid {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 1rem;
+}
+
+.input {
+ margin-top: 0.5rem;
+}
+
+.textarea {
+ margin-top: 0.5rem;
+}
+
+.buttonGroup {
+ display: flex;
+ gap: 0.5rem;
+ padding-top: 1rem;
+}
+
+.submitButton {
+ flex: 1;
+}
+
+.cancelButton {
+ // Cancel button styles
+}
diff --git a/client/src/styles/Tasks.module.scss b/client/src/styles/Tasks.module.scss
new file mode 100644
index 0000000..71d9249
--- /dev/null
+++ b/client/src/styles/Tasks.module.scss
@@ -0,0 +1,56 @@
+.card {
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ justify-content: center;
+}
+
+.cardContent {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ justify-content: center;
+}
+
+.container {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+}
+
+.taskList {
+ display: flex;
+ flex-direction: column;
+ gap: 0.75rem;
+}
+
+.emptyState {
+ font-size: 0.875rem;
+ color: hsl(var(--muted-foreground));
+ text-align: center;
+ padding: 2rem 0;
+}
+
+.completedSection {
+ padding-top: 1rem;
+ border-top: 1px solid hsl(var(--border));
+}
+
+.completedTitle {
+ font-size: 0.875rem;
+ font-weight: 500;
+ color: hsl(var(--muted-foreground));
+ margin-bottom: 0.75rem;
+}
+
+.completedList {
+ display: flex;
+ flex-direction: column;
+ gap: 0.75rem;
+}
+
+.sheetContent {
+ padding: 1rem;
+}
diff --git a/client/src/styles/TodayProgress.module.scss b/client/src/styles/TodayProgress.module.scss
new file mode 100644
index 0000000..639af43
--- /dev/null
+++ b/client/src/styles/TodayProgress.module.scss
@@ -0,0 +1,54 @@
+.card {
+ margin-top: 1.5rem;
+}
+
+.cardContent {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+}
+
+.statRow {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+}
+
+.statLabel {
+ font-size: 0.875rem;
+ color: hsl(var(--muted-foreground));
+ word-break: break-words;
+}
+
+.statValue {
+ font-weight: 500;
+ flex-shrink: 0;
+ margin-left: 0.5rem;
+}
+
+.completionValue {
+ color: hsl(var(--chart-2));
+}
+
+.progressBar {
+ width: 100%;
+ background-color: hsl(var(--muted));
+ border-radius: 9999px;
+ height: 0.5rem;
+}
+
+.progressFill {
+ background-color: hsl(var(--chart-2));
+ height: 0.5rem;
+ border-radius: 9999px;
+ transition: all 0.3s ease;
+}
+
+.taskStats {
+ padding-top: 1rem;
+ border-top: 1px solid hsl(var(--border));
+}
+
+.taskStatsTitle {
+ margin-bottom: 0.75rem;
+}
diff --git a/package-lock.json b/package-lock.json
index 0ffccd8..377d522 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -96,6 +96,7 @@
"drizzle-kit": "^0.30.4",
"esbuild": "^0.25.0",
"postcss": "^8.4.47",
+ "sass": "^1.92.0",
"tailwindcss": "^3.4.17",
"tsx": "^4.19.1",
"typescript": "5.6.3",
@@ -1477,6 +1478,330 @@
"node": ">= 8"
}
},
+ "node_modules/@parcel/watcher": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz",
+ "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "detect-libc": "^1.0.3",
+ "is-glob": "^4.0.3",
+ "micromatch": "^4.0.5",
+ "node-addon-api": "^7.0.0"
+ },
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ },
+ "optionalDependencies": {
+ "@parcel/watcher-android-arm64": "2.5.1",
+ "@parcel/watcher-darwin-arm64": "2.5.1",
+ "@parcel/watcher-darwin-x64": "2.5.1",
+ "@parcel/watcher-freebsd-x64": "2.5.1",
+ "@parcel/watcher-linux-arm-glibc": "2.5.1",
+ "@parcel/watcher-linux-arm-musl": "2.5.1",
+ "@parcel/watcher-linux-arm64-glibc": "2.5.1",
+ "@parcel/watcher-linux-arm64-musl": "2.5.1",
+ "@parcel/watcher-linux-x64-glibc": "2.5.1",
+ "@parcel/watcher-linux-x64-musl": "2.5.1",
+ "@parcel/watcher-win32-arm64": "2.5.1",
+ "@parcel/watcher-win32-ia32": "2.5.1",
+ "@parcel/watcher-win32-x64": "2.5.1"
+ }
+ },
+ "node_modules/@parcel/watcher-android-arm64": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz",
+ "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-darwin-arm64": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz",
+ "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-darwin-x64": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz",
+ "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-freebsd-x64": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz",
+ "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-arm-glibc": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz",
+ "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-arm-musl": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz",
+ "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-arm64-glibc": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz",
+ "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-arm64-musl": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz",
+ "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-x64-glibc": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz",
+ "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-x64-musl": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz",
+ "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-win32-arm64": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz",
+ "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-win32-ia32": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz",
+ "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-win32-x64": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz",
+ "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher/node_modules/detect-libc": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
+ "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "bin": {
+ "detect-libc": "bin/detect-libc.js"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
"node_modules/@petamoriken/float16": {
"version": "3.9.2",
"resolved": "https://registry.npmjs.org/@petamoriken/float16/-/float16-3.9.2.tgz",
@@ -3423,6 +3748,66 @@
"node": ">=14.0.0"
}
},
+ "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/core": {
+ "version": "1.4.5",
+ "dev": true,
+ "inBundle": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/wasi-threads": "1.0.4",
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/runtime": {
+ "version": "1.4.5",
+ "dev": true,
+ "inBundle": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/wasi-threads": {
+ "version": "1.0.4",
+ "dev": true,
+ "inBundle": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": {
+ "version": "0.2.12",
+ "dev": true,
+ "inBundle": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/core": "^1.4.3",
+ "@emnapi/runtime": "^1.4.3",
+ "@tybys/wasm-util": "^0.10.0"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@tybys/wasm-util": {
+ "version": "0.10.0",
+ "dev": true,
+ "inBundle": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/tslib": {
+ "version": "2.8.0",
+ "dev": true,
+ "inBundle": true,
+ "license": "0BSD",
+ "optional": true
+ },
"node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
"version": "4.1.12",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.12.tgz",
@@ -5978,6 +6363,13 @@
"url": "https://opencollective.com/immer"
}
},
+ "node_modules/immutable": {
+ "version": "5.1.3",
+ "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.3.tgz",
+ "integrity": "sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
@@ -6715,6 +7107,14 @@
"react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc"
}
},
+ "node_modules/node-addon-api": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
+ "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true
+ },
"node_modules/node-gyp-build": {
"version": "4.8.4",
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz",
@@ -7831,6 +8231,57 @@
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"license": "MIT"
},
+ "node_modules/sass": {
+ "version": "1.92.0",
+ "resolved": "https://registry.npmjs.org/sass/-/sass-1.92.0.tgz",
+ "integrity": "sha512-KDNI0BxgIRDAfJgzNm5wuy+4yOCIZyrUbjSpiU/JItfih+KGXAVefKL53MTml054MmBA3DDKIBMSI/7XLxZJ3A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chokidar": "^4.0.0",
+ "immutable": "^5.0.2",
+ "source-map-js": ">=0.6.2 <2.0.0"
+ },
+ "bin": {
+ "sass": "sass.js"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "optionalDependencies": {
+ "@parcel/watcher": "^2.4.1"
+ }
+ },
+ "node_modules/sass/node_modules/chokidar": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
+ "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "readdirp": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 14.16.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/sass/node_modules/readdirp": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
+ "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 14.18.0"
+ },
+ "funding": {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
"node_modules/scheduler": {
"version": "0.26.0",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz",
diff --git a/package.json b/package.json
index 19c03b5..a58271d 100644
--- a/package.json
+++ b/package.json
@@ -99,6 +99,7 @@
"drizzle-kit": "^0.30.4",
"esbuild": "^0.25.0",
"postcss": "^8.4.47",
+ "sass": "^1.92.0",
"tailwindcss": "^3.4.17",
"tsx": "^4.19.1",
"typescript": "5.6.3",