diff --git a/Dockerfile b/Dockerfile index f727609..b3ad1cb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,6 +19,8 @@ RUN apt-get update && apt-get upgrade -y \ && apt-get install --no-install-recommends -y \ bash \ curl \ + nodejs \ + npm \ && curl -sSL 'https://install.python-poetry.org' | python - \ && poetry --version \ && apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \ @@ -33,6 +35,12 @@ RUN chown -R timetracker:timetracker /home/timetracker/app COPY entrypoint.sh / RUN chmod +x /entrypoint.sh +USER timetracker + +# Install Node.js dependencies and build Svelte app +RUN npm install +RUN npm run build + RUN --mount=type=cache,target="$POETRY_CACHE_DIR" \ echo "$PROD" \ && poetry version \ diff --git a/Makefile b/Makefile index 069514e..bfb691d 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,7 @@ initialize: npm css migrate sethookdir loadplatforms HTMLFILES := $(shell find games/templates -type f) PYTHON_VERSION = 3.12 +.PHONY: build frontend-dev frontend-build npm: npm install @@ -24,13 +25,26 @@ init: poetry install npm install +# Run Django, Tailwind, and Vite development servers concurrently dev: @npx concurrently \ - --names "Django,Tailwind" \ - --prefix-colors "blue,green" \ + --names "Django,Tailwind,Vite" \ + --prefix-colors "blue,green,yellow" \ "poetry run python -Wa manage.py runserver" \ - "npx tailwindcss -i ./common/input.css -o ./games/static/base.css --watch" + "npx tailwindcss -i ./common/input.css -o ./games/static/base.css --watch" \ + "npm run dev" +# Only start the Vite development server +frontend-dev: + npm run dev + +# Build frontend assets for production +build: frontend-build collectstatic + +# Only build frontend assets +frontend-build: + @echo "Building frontend assets with Vite..." + npm run build caddy: caddy run --watch diff --git a/common/input.css b/common/input.css index 9499c59..78ab8e1 100644 --- a/common/input.css +++ b/common/input.css @@ -53,11 +53,11 @@ } .responsive-table tr:nth-child(even) { - @apply bg-slate-800 + @apply bg-indigo-100 dark:bg-slate-800 } .responsive-table tbody tr:nth-child(odd) { - @apply bg-slate-900 + @apply bg-indigo-200 dark:bg-slate-900 } .responsive-table thead th { diff --git a/frontend/components/CrownIcon.svelte b/frontend/components/CrownIcon.svelte new file mode 100644 index 0000000..5ddb6ab --- /dev/null +++ b/frontend/components/CrownIcon.svelte @@ -0,0 +1,6 @@ + +{#if mastered} + 👑 +{/if} diff --git a/frontend/main.js b/frontend/main.js new file mode 100644 index 0000000..60282b1 --- /dev/null +++ b/frontend/main.js @@ -0,0 +1,13 @@ +import CrownIcon from './components/CrownIcon.svelte'; + +// Expose a function to mount the CrownIcon component globally +// This allows Django templates to easily initialize Svelte components. +window.mountCrownIcon = (selector, props) => { + const target = document.querySelector(selector); + if (target) { + new CrownIcon({ + target: target, + props: props, + }); + } +}; diff --git a/games/static/base.css b/games/static/base.css index bdb24db..1724da8 100644 --- a/games/static/base.css +++ b/games/static/base.css @@ -2268,6 +2268,11 @@ input:checked + .toggle-bg { color: rgb(107 114 128 / var(--tw-text-opacity, 1)); } +.text-gray-600 { + --tw-text-opacity: 1; + color: rgb(75 85 99 / var(--tw-text-opacity, 1)); +} + .text-gray-700 { --tw-text-opacity: 1; color: rgb(55 65 81 / var(--tw-text-opacity, 1)); @@ -2288,11 +2293,6 @@ input:checked + .toggle-bg { color: rgb(203 213 225 / var(--tw-text-opacity, 1)); } -.text-slate-400 { - --tw-text-opacity: 1; - color: rgb(148 163 184 / var(--tw-text-opacity, 1)); -} - .text-slate-500 { --tw-text-opacity: 1; color: rgb(100 116 139 / var(--tw-text-opacity, 1)); @@ -2491,11 +2491,21 @@ input:checked + .toggle-bg { } .responsive-table tr:nth-child(even) { + --tw-bg-opacity: 1; + background-color: rgb(229 237 255 / var(--tw-bg-opacity, 1)); +} + +.responsive-table tr:nth-child(even):is(.dark *) { --tw-bg-opacity: 1; background-color: rgb(30 41 59 / var(--tw-bg-opacity, 1)); } .responsive-table tbody tr:nth-child(odd) { + --tw-bg-opacity: 1; + background-color: rgb(205 219 254 / var(--tw-bg-opacity, 1)); +} + +.responsive-table tbody tr:nth-child(odd):is(.dark *) { --tw-bg-opacity: 1; background-color: rgb(15 23 42 / var(--tw-bg-opacity, 1)); } @@ -3081,6 +3091,11 @@ div [type="submit"] { color: rgb(75 85 99 / var(--tw-text-opacity, 1)); } +.dark\:text-slate-300:is(.dark *) { + --tw-text-opacity: 1; + color: rgb(203 213 225 / var(--tw-text-opacity, 1)); +} + .dark\:text-slate-400:is(.dark *) { --tw-text-opacity: 1; color: rgb(148 163 184 / var(--tw-text-opacity, 1)); diff --git a/games/templates/cotton/icon/arrowdown.html b/games/templates/cotton/icon/arrowdown.html new file mode 100644 index 0000000..26ede59 --- /dev/null +++ b/games/templates/cotton/icon/arrowdown.html @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/games/templates/cotton/icon/play.html b/games/templates/cotton/icon/play.html index 7f4bdc9..e51f307 100644 --- a/games/templates/cotton/icon/play.html +++ b/games/templates/cotton/icon/play.html @@ -2,7 +2,7 @@ x="0px" y="0px" viewBox="0 0 48 48" - class="text-black dark:text-white w-4 h-4"> + class="w-4 h-4"> diff --git a/games/templates/cotton/layouts/base.html b/games/templates/cotton/layouts/base.html index b438e6a..d39b35d 100644 --- a/games/templates/cotton/layouts/base.html +++ b/games/templates/cotton/layouts/base.html @@ -39,46 +39,59 @@ {% version %} ({% version_date %}) {{ scripts }} - diff --git a/games/templates/navbar.html b/games/templates/navbar.html index 552e3b0..128df2e 100644 --- a/games/templates/navbar.html +++ b/games/templates/navbar.html @@ -26,9 +26,19 @@