From 5dadb20607c0b1e8a4d548808843b97650826207 Mon Sep 17 00:00:00 2001 From: Arthur DANJOU Date: Fri, 5 Sep 2025 11:01:11 +0200 Subject: [PATCH] feat(infinite-canvas): add infinite canvas component with drag and zoom functionality - Implemented InfiniteCanvas.vue for rendering an infinite canvas with drag and zoom capabilities. - Created useInfiniteCanvas composable for managing canvas state and interactions. - Added useImagePreloader composable for preloading images and videos. - Introduced constants for physics, touch interactions, viewport settings, and zoom defaults. - Developed utility functions for touch handling and media type detection. - Defined TypeScript types for canvas items, grid items, and composables. - Registered components and composables in the Nuxt module. - Added screenshot generation functionality for content files. - Updated package.json to include capture-website dependency. --- app/components/chat/CommandPalette.vue | 7 +- app/error.vue | 10 +- app/pages/canva.vue | 258 +++++++- app/pages/projects/[slug].vue | 11 +- app/pages/writings/[slug].vue | 7 + bun.lock | 147 ++++- content.config.ts | 8 + locales/en.json | 3 + locales/es.json | 5 +- locales/fr.json | 3 + .../components/CanvasLoader.vue | 116 ++++ .../components/CanvasMinimap.vue | 116 ++++ .../components/InfiniteCanvas.vue | 142 +++++ .../composables/useImagePreloader.ts | 116 ++++ .../composables/useInfiniteCanvas.ts | 576 ++++++++++++++++++ modules/infinite-canvas/constants/index.ts | 55 ++ modules/infinite-canvas/index.ts | 110 ++++ modules/infinite-canvas/types/index.ts | 221 +++++++ modules/infinite-canvas/utils/index.ts | 73 +++ modules/screenshots.ts | 59 ++ package.json | 1 + 21 files changed, 2031 insertions(+), 13 deletions(-) create mode 100644 modules/infinite-canvas/components/CanvasLoader.vue create mode 100644 modules/infinite-canvas/components/CanvasMinimap.vue create mode 100644 modules/infinite-canvas/components/InfiniteCanvas.vue create mode 100644 modules/infinite-canvas/composables/useImagePreloader.ts create mode 100644 modules/infinite-canvas/composables/useInfiniteCanvas.ts create mode 100644 modules/infinite-canvas/constants/index.ts create mode 100644 modules/infinite-canvas/index.ts create mode 100644 modules/infinite-canvas/types/index.ts create mode 100644 modules/infinite-canvas/utils/index.ts create mode 100644 modules/screenshots.ts diff --git a/app/components/chat/CommandPalette.vue b/app/components/chat/CommandPalette.vue index 8419cc5..6b78859 100644 --- a/app/components/chat/CommandPalette.vue +++ b/app/components/chat/CommandPalette.vue @@ -45,10 +45,15 @@ defineShortcuts({ t: () => toggleDark({ clientX: window.innerWidth / 2, clientY: window.innerHeight }), }) +const isMobile = computed(() => { + if (!import.meta.client) + return false + return isMobileDevice(navigator.userAgent, window.innerWidth) +}) const activeElement = useActiveElement() watch(openMessageModal, async () => { await nextTick() - if (activeElement.value instanceof HTMLElement) { + if (activeElement.value instanceof HTMLElement && isMobile.value) { activeElement.value.blur() } }) diff --git a/app/error.vue b/app/error.vue index 5d4eca9..038036e 100644 --- a/app/error.vue +++ b/app/error.vue @@ -10,12 +10,12 @@ const { t } = useI18n()

{{ t('error.main') }} - - - {{ t('error.redirect') }} - -

+ + + {{ t('error.redirect') }} + + diff --git a/app/pages/canva.vue b/app/pages/canva.vue index 395ab7f..3ad81b7 100644 --- a/app/pages/canva.vue +++ b/app/pages/canva.vue @@ -1,7 +1,263 @@ diff --git a/app/pages/projects/[slug].vue b/app/pages/projects/[slug].vue index 340ba92..7e457f1 100644 --- a/app/pages/projects/[slug].vue +++ b/app/pages/projects/[slug].vue @@ -3,6 +3,13 @@ const route = useRoute() const { data: project } = await useAsyncData(`projects/${route.params.slug}`, () => queryCollection('projects').path(`/projects/${route.params.slug}`).first()) +if (!project.value) { + throw createError({ + statusCode: 404, + statusMessage: `Project "${route.params.slug}" not found`, + }) +} + useSeoMeta({ title: project.value?.title, description: project.value?.description, @@ -11,7 +18,7 @@ useSeoMeta({