diff --git a/backend/Dockerfile b/backend/Dockerfile index 75ee03a..a983ab7 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -1,6 +1,6 @@ -FROM python:3.12-alpine +FROM python:3.12-slim -RUN apk add git +RUN apt update && apt install --no-install-recommends -y git gifsicle libgl1 WORKDIR /code RUN git clone https://gitea.typename.fr/mikael.capelle/advent-of-code . RUN pip install -e . diff --git a/backend/src/holt59/aoc/app.py b/backend/src/holt59/aoc/app.py index 77f22ac..30145f7 100644 --- a/backend/src/holt59/aoc/app.py +++ b/backend/src/holt59/aoc/app.py @@ -67,13 +67,21 @@ async def file(name: str): @app.post("/submit-sse") -async def submit_sse(year: int = Form(), day: int = Form(), input: str = Form()): +async def submit_sse( + year: int = Form(), day: int = Form(), input: str = Form(), verbose: bool = Form() +): data = input.rstrip().replace("\r\n", "\n") - process = await asyncio.create_subprocess_exec( + args = [ "holt59-aoc", "--stdin", "--api", + ] + if verbose: + args.append("--verbose") + + process = await asyncio.create_subprocess_exec( + *args, "--output", AOC_FILES_PATH, "--year", @@ -97,6 +105,10 @@ async def submit_sse(year: int = Form(), day: int = Form(), input: str = Form()) output = await fp.readline() if output == b"": break + + if stream == "stderr" and output.startswith(b"OpenCV: FFMPEG"): + continue + await message_queue.put( { "type": "stream", diff --git a/front/package.json b/front/package.json index cb0d809..2e9f167 100644 --- a/front/package.json +++ b/front/package.json @@ -21,8 +21,10 @@ "luxon": "^3.5.0", "pinia": "^2.2.6", "sse.js": "^2.5.0", + "svg-pan-zoom": "^3.6.2", "vue": "^3.5.13", - "vue-router": "4" + "vue-router": "4", + "vue3-toastify": "^0.2.8" }, "devDependencies": { "@tsconfig/node22": "^22.0.0", diff --git a/front/src/api/index.ts b/front/src/api/index.ts index b2053f9..b6b6f70 100644 --- a/front/src/api/index.ts +++ b/front/src/api/index.ts @@ -18,11 +18,12 @@ export const loadData = async (year: number, day: number, mode: "holt59" | "test }).then(r => r.json()).then(r => r["content"]).catch(() => ""); }; -export const submit = async (year: number, day: number, input: string, startCallback: (time: DateTime, commit: string) => void, streamCallback: (message: StreamMessage) => void) => { +export const submit = async (year: number, day: number, input: string, verbose: boolean, startCallback: (time: DateTime, commit: string) => void, streamCallback: (message: StreamMessage) => void) => { const data = new FormData(); data.append("year", year.toString()); data.append("day", day.toString()); data.append("input", input.toString()); + data.append("verbose", verbose.toString()); return new Promise((resolve) => { const eventSource = new SSE(urlFor("submit-sse"), { diff --git a/front/src/assets/base.css b/front/src/assets/base.css deleted file mode 100644 index 8691d1c..0000000 --- a/front/src/assets/base.css +++ /dev/null @@ -1,78 +0,0 @@ -/* color palette from */ -:root { - --vt-c-white: #ffffff; - --vt-c-white-soft: #f8f8f8; - --vt-c-white-mute: #f2f2f2; - - --vt-c-black: #181818; - --vt-c-black-soft: #222222; - --vt-c-black-mute: #282828; - - --vt-c-indigo: #2c3e50; - - --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); - --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); - --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); - --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); - - --vt-c-text-light-1: var(--vt-c-indigo); - --vt-c-text-light-2: rgba(60, 60, 60, 0.66); - --vt-c-text-dark-1: var(--vt-c-white); - --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); -} - -/* semantic color variables for this project */ -:root { - --color-background: var(--vt-c-white); - --color-background-soft: var(--vt-c-white-soft); - --color-background-mute: var(--vt-c-white-mute); - - --color-border: var(--vt-c-divider-light-2); - --color-border-hover: var(--vt-c-divider-light-1); - - --color-heading: var(--vt-c-text-light-1); - --color-text: var(--vt-c-text-light-1); - - --section-gap: 160px; -} - -@media (prefers-color-scheme: dark) { - :root { - --color-background: var(--vt-c-black); - --color-background-soft: var(--vt-c-black-soft); - --color-background-mute: var(--vt-c-black-mute); - - --color-border: var(--vt-c-divider-dark-2); - --color-border-hover: var(--vt-c-divider-dark-1); - - --color-heading: var(--vt-c-text-dark-1); - --color-text: var(--vt-c-text-dark-2); - } -} - -body { - min-height: 100vh; - color: var(--color-text); - background: var(--color-background); - transition: - color 0.5s, - background-color 0.5s; - line-height: 1.6; - font-family: - Inter, - -apple-system, - BlinkMacSystemFont, - 'Segoe UI', - Roboto, - Oxygen, - Ubuntu, - Cantarell, - 'Fira Sans', - 'Droid Sans', - 'Helvetica Neue', - sans-serif; - font-size: 15px; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} diff --git a/front/src/assets/main.scss b/front/src/assets/main.scss index 05f9182..b4b3555 100644 --- a/front/src/assets/main.scss +++ b/front/src/assets/main.scss @@ -3,6 +3,11 @@ @import '../../node_modules/bootstrap/scss/functions'; @import '../../node_modules/bootstrap/scss/variables'; @import '../../node_modules/bootstrap/scss/mixins'; +@import "../../node_modules/vue3-toastify/dist/index.css"; + +:root { + --toastify-color-progress-dark: var(--bs-primary); +} #content-div { min-height: 50px; @@ -13,3 +18,9 @@ #content-div>.progress { margin-bottom: .3rem; } + +@media (min-width: 1200px) { + .modal-xxl { + --bs-modal-width: 1320px; + } +} diff --git a/front/src/components/MainPage.vue b/front/src/components/MainPage.vue index c30d482..e732361 100644 --- a/front/src/components/MainPage.vue +++ b/front/src/components/MainPage.vue @@ -15,7 +15,7 @@ const inAocPeriod = (date: DateTime) => { } const currentInput = ref(""); -const showLogs = ref(false); +const currentVerbose = ref(false); const today = DateTime.now(); const maxYear = today.month == 12 ? today.year : today.year - 1; @@ -55,6 +55,8 @@ onMounted(() => { currentLoadMode.value = mode as "tests" | "holt59"; } + currentVerbose.value = query.verbose == 'true' + currentDay.value = initialDay.value; currentYear.value = initialYear.value; }); @@ -92,12 +94,15 @@ watch([currentDay, currentYear], () => { loadDataClicked(); } - router.push({ name: router.currentRoute.value.name, query: { "year": currentYear.value, "day": currentDay.value, "data": currentLoadMode.value } }); + router.push({ name: router.currentRoute.value.name, query: { "year": currentYear.value, "day": currentDay.value, "data": currentLoadMode.value, "verbose": currentVerbose.value.toString() } }); }); watch([currentLoadMode], () => { loadDataClicked(); - router.push({ name: router.currentRoute.value.name, query: { "year": currentYear.value, "day": currentDay.value, "data": currentLoadMode.value } }); + router.push({ name: router.currentRoute.value.name, query: { "year": currentYear.value, "day": currentDay.value, "data": currentLoadMode.value, "verbose": currentVerbose.value.toString() } }); }); +watch([currentVerbose], () => { + router.push({ name: router.currentRoute.value.name, query: { "year": currentYear.value, "day": currentDay.value, "data": currentLoadMode.value, "verbose": currentVerbose.value.toString() } }); +}) // handle submit @@ -106,18 +111,45 @@ const submitRunning = ref(false); const submitClicked = async () => { submitRunning.value = true; - await resultComponent.value!.submit(currentYear.value, currentDay.value, currentInput.value, () => { }); + await resultComponent.value!.submit(currentYear.value, currentDay.value, currentInput.value, currentVerbose.value); submitRunning.value = false; }; + +const reset = () => { + + const today = DateTime.now(); + const maxYear = today.month == 12 ? today.year : today.year - 1; + + const day = today.day as number; + if (day && day >= 1 && day <= 25) { + initialDay.value = day; + } + else { + initialDay.value = inAocPeriod(today) ? today.day as number : 1; + } + + const year = maxYear; + if (year && year >= 2015 && year <= maxYear) { + initialYear.value = year; + } + else { + initialYear.value = maxYear; + } + + currentDay.value = initialDay.value; + currentYear.value = initialYear.value; + + resultComponent.value!.clear(); +} diff --git a/front/yarn.lock b/front/yarn.lock index be7f106..c0e5386 100644 --- a/front/yarn.lock +++ b/front/yarn.lock @@ -2256,6 +2256,11 @@ supports-color@^7.1.0: dependencies: has-flag "^4.0.0" +svg-pan-zoom@^3.6.2: + version "3.6.2" + resolved "https://registry.yarnpkg.com/svg-pan-zoom/-/svg-pan-zoom-3.6.2.tgz#be136506211b242627a234a9656f8128fcbbabed" + integrity sha512-JwnvRWfVKw/Xzfe6jriFyfey/lWJLq4bUh2jwoR5ChWQuQoOH8FEh1l/bEp46iHHKHEJWIyFJETbazraxNWECg== + svg-tags@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764" @@ -2450,6 +2455,11 @@ vue-tsc@^2.1.10: "@vue/language-core" "2.1.10" semver "^7.5.4" +vue3-toastify@^0.2.8: + version "0.2.8" + resolved "https://registry.yarnpkg.com/vue3-toastify/-/vue3-toastify-0.2.8.tgz#0bb447b39f390ca9a1cb43c3c15ef3eede552b23" + integrity sha512-8jDOqsJaBZEbGpCbhWDETJc11D1lZefvgFPq/IPdM+U7+qyXoVPDvK6uq/FIgyV7qV0NcNzvGBMEzjsLQqGROw== + vue@^3.5.13: version "3.5.13" resolved "https://registry.yarnpkg.com/vue/-/vue-3.5.13.tgz#9f760a1a982b09c0c04a867903fc339c9f29ec0a"