diff --git a/docker-compose.yml b/docker-compose.yml index a9af318..532127b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -60,8 +60,10 @@ services: - ./portfolio/src:/src environment: - VIRTUAL_HOST=${DOMAIN},www.${DOMAIN} - - VIRTUAL_PATH=/ - #- VIRTUAL_DEST=/ + #- VIRTUAL_PATH=/ + # For subdirectory baseURL needs to be set in app.js for static files and routes + - VIRTUAL_PATH=/legacy + - VIRTUAL_DEST=/legacy - VIRTUAL_PORT=3000 - LETSENCRYPT_HOST=${DOMAIN},www.${DOMAIN},gitea.${DOMAIN} #this last one is for legacy support - LETSENCRYPT_EMAIL=${EMAIL} @@ -76,6 +78,39 @@ services: #labels: # com.github.nginx-proxy.nginx-proxy.keepalive: "64" + portfolio-nuxt: + # NOTE: This is the rewrite of the frontend + # NOTE: The build process for nuxt seems to require that sharp be reinstalled in the .output folder + container_name: portfolio-nuxt + build: ./portfolio-nuxt + # To rebuild the site and the server run this + #command: bash -c "npm run build && node .output/server/index.mjs" + # To just start the server run this + command: bash -c "node .output/server/index.mjs" + volumes: + #- portfolio-nuxt:/src/node_modules + - ./portfolio-nuxt:/src + environment: + - VIRTUAL_HOST=${DOMAIN},www.${DOMAIN} + - VIRTUAL_PATH=/ + #- VIRTUAL_DEST=/dev + # For subdirectory baseURL needs to be set in nuxt config + #- VIRTUAL_PATH=/dev + #- VIRTUAL_DEST=/dev + - VIRTUAL_PORT=4000 + #- LETSENCRYPT_HOST=${DOMAIN},www.${DOMAIN},gitea.${DOMAIN} #this last one is for legacy support + #- LETSENCRYPT_EMAIL=${EMAIL} + ports: + - "4000:4000" + restart: always + #depends_on: + #mongo: + #condition: service_healthy + #restheart: + #nginx-proxy: + #labels: + # com.github.nginx-proxy.nginx-proxy.keepalive: "64" + mongo: container_name: mongo # using mongo4 or mongo5 as opposed to mongo:6 for server status in mongo-express and because of bugs @@ -349,3 +384,4 @@ volumes: #nextcloud: acme: portfolio: + portfolio-nuxt: diff --git a/package.json b/package.json new file mode 100644 index 0000000..65a4b2f --- /dev/null +++ b/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "sharp": "^0.32.1" + } +} diff --git a/portfolio-nuxt/Dockerfile b/portfolio-nuxt/Dockerfile new file mode 100644 index 0000000..0b52ded --- /dev/null +++ b/portfolio-nuxt/Dockerfile @@ -0,0 +1,18 @@ +FROM node:18-alpine + +WORKDIR /src + +COPY package*.json ./ + +COPY . . + +RUN apk add bash +RUN npm ci --platform=linuxmusl --arch=x64 --ignore-scripts=false --foreground-scripts --verbose +# RUN npm run build + +ENV NITRO_HOST=0.0.0.0 +ENV NITRO_PORT=4000 + +EXPOSE 4000 + +# ENTRYPOINT ["npm", "run", "build", "node", ".output/server/index.mjs"] \ No newline at end of file diff --git a/portfolio-nuxt/components/Collapsible/CollapseTransition.vue b/portfolio-nuxt/components/Collapsible/CollapseTransition.vue new file mode 100644 index 0000000..f8f0515 --- /dev/null +++ b/portfolio-nuxt/components/Collapsible/CollapseTransition.vue @@ -0,0 +1,313 @@ + + + diff --git a/portfolio-nuxt/components/Collapsible/Collapsible.stories.ts b/portfolio-nuxt/components/Collapsible/Collapsible.stories.ts new file mode 100644 index 0000000..22a43cc --- /dev/null +++ b/portfolio-nuxt/components/Collapsible/Collapsible.stories.ts @@ -0,0 +1,25 @@ +import type { Story } from '@storybook/vue3' +import Collapsible from './Collapsible.vue' + +export default { + title: 'Components/Collapsible', + component: Collapsible, + args: { + modelValue: false, + title: 'Item', + content: 'lorem ipsum dolor sit amet', + }, +} + +const Template: Story = (args, { argTypes }) => ({ + components: { Collapsible }, + setup() { + return { args, argTypes } + }, + template: ` + + `, +}) + +export const Default = Template.bind({}) +Default.args = {} diff --git a/portfolio-nuxt/components/Collapsible/Collapsible.vue b/portfolio-nuxt/components/Collapsible/Collapsible.vue new file mode 100644 index 0000000..b17e7ea --- /dev/null +++ b/portfolio-nuxt/components/Collapsible/Collapsible.vue @@ -0,0 +1,88 @@ + + + diff --git a/portfolio-nuxt/components/Collapsible/CollapsibleGroup.stories.ts b/portfolio-nuxt/components/Collapsible/CollapsibleGroup.stories.ts new file mode 100644 index 0000000..9d564e7 --- /dev/null +++ b/portfolio-nuxt/components/Collapsible/CollapsibleGroup.stories.ts @@ -0,0 +1,38 @@ +import type { Story } from '@storybook/vue3' +import CollapsibleGroup from './CollapsibleGroup.vue' + +const genItems = (length = 5): any[] => + Array.from({ length }, (_, v) => ({ + title: `Item ${v + 1}`, + content: `lorem ipsum ${v + 1}`, + })) + +const items = genItems(5) + +export default { + title: 'Components/CollapsibleGroup', + component: CollapsibleGroup, + args: { + modelValue: false, + accordion: false, + items, + }, +} + +const Template: Story = (args, { argTypes }) => ({ + components: { CollapsibleGroup }, + setup() { + return { args, argTypes } + }, + template: ` + + `, +}) + +export const Default = Template.bind({}) +Default.args = {} + +export const Accordion = Template.bind({}) +Accordion.args = { + accordion: true, +} diff --git a/portfolio-nuxt/components/Collapsible/CollapsibleGroup.vue b/portfolio-nuxt/components/Collapsible/CollapsibleGroup.vue new file mode 100644 index 0000000..0e71617 --- /dev/null +++ b/portfolio-nuxt/components/Collapsible/CollapsibleGroup.vue @@ -0,0 +1,55 @@ + + + diff --git a/portfolio-nuxt/nuxt.config.ts b/portfolio-nuxt/nuxt.config.ts index e485183..062588e 100644 --- a/portfolio-nuxt/nuxt.config.ts +++ b/portfolio-nuxt/nuxt.config.ts @@ -2,12 +2,13 @@ // https://nuxt.com/docs/api/configuration/nuxt-config export default defineNuxtConfig({ - modules: ['@nuxtjs/tailwindcss', '@nuxt/image', 'nuxt-icon', '@pinia/nuxt', 'nuxt-headlessui', 'nuxt-swiper'], + modules: ['@nuxtjs/tailwindcss', '@nuxt/image', 'nuxt-icon', '@pinia/nuxt', 'nuxt-headlessui', 'nuxt-swiper', 'nuxt-api-party'], extends: ['nuxt-umami'], image: { domains: ['unboundedpress.org'] }, app: { + //baseURL: "/dev/", pageTransition: { name: 'page', mode: 'out-in' } }, appConfig: { @@ -17,18 +18,21 @@ export default defineNuxtConfig({ version: 2 }, }, - nitro: { - prerender: { - crawlLinks: true + apiParty: { + endpoints: { + jsonPlaceholder: { + url: process.env.JSON_PLACEHOLDER_API_BASE_URL!, + // Global headers sent with each request + headers: { + Authorization: `Bearer ${process.env.JSON_PLACEHOLDER_API_TOKEN!}` + } + } } }, - routeRules: { - "https://unboundedpress.org/api/*": { - swr: 60 * 60, - // or - cache: { - maxAge: 60 * 60 - } - }, + nitro: { + prerender: { crawlLinks: true} + }, + experimental: { + payloadExtraction: true } }) diff --git a/portfolio-nuxt/package-lock.json b/portfolio-nuxt/package-lock.json index 1f50e58..ffc81a1 100644 --- a/portfolio-nuxt/package-lock.json +++ b/portfolio-nuxt/package-lock.json @@ -8,6 +8,8 @@ "hasInstallScript": true, "dependencies": { "@pinia/nuxt": "^0.4.11", + "nuxt-swiper": "^1.1.0", + "nuxt-umami": "^2.4.2", "pinia": "^2.1.3" }, "devDependencies": { @@ -15,6 +17,7 @@ "@nuxtjs/tailwindcss": "^6.7.0", "@types/node": "^18", "nuxt": "^3.5.2", + "nuxt-api-party": "^0.11.4", "nuxt-headlessui": "^1.1.4", "nuxt-icon": "^0.4.1" } @@ -1631,6 +1634,11 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.17", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.17.tgz", + "integrity": "sha512-4p9vcSmxAayx72yn70joFoL44c9MO/0+iVEBIQXe3v2h2SiAsEIo/G5v6ObFWvNKRFjbrVadNf9LqEEZeQPzdA==" + }, "node_modules/@unhead/dom": { "version": "1.1.27", "resolved": "https://registry.npmjs.org/@unhead/dom/-/dom-1.1.27.tgz", @@ -1946,6 +1954,39 @@ "integrity": "sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ==", "license": "MIT" }, + "node_modules/@vueuse/core": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-10.1.2.tgz", + "integrity": "sha512-roNn8WuerI56A5uiTyF/TEYX0Y+VKlhZAF94unUfdhbDUI+NfwQMn4FUnUscIRUhv3344qvAghopU4bzLPNFlA==", + "dependencies": { + "@types/web-bluetooth": "^0.0.17", + "@vueuse/metadata": "10.1.2", + "@vueuse/shared": "10.1.2", + "vue-demi": ">=0.14.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/metadata": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-10.1.2.tgz", + "integrity": "sha512-3mc5BqN9aU2SqBeBuWE7ne4OtXHoHKggNgxZR2K+zIW4YLsy6xoZ4/9vErQs6tvoKDX6QAqm3lvsrv0mczAwIQ==", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-10.1.2.tgz", + "integrity": "sha512-1uoUTPBlgyscK9v6ScGeVYDDzlPSFXBlxuK7SfrDGyUTBiznb3mNceqhwvZHjtDRELZEN79V5uWPTF1VDV8svA==", + "dependencies": { + "vue-demi": ">=0.14.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", @@ -6564,6 +6605,20 @@ } } }, + "node_modules/nuxt-api-party": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/nuxt-api-party/-/nuxt-api-party-0.11.4.tgz", + "integrity": "sha512-JySJtJYJGPBUkRrChJM6a+LeER/e35SNTypXb6FYi1oevg3Wa+zWSHgpQVHwi954Dee25QW5ax/KxagXVZu6eQ==", + "dev": true, + "dependencies": { + "@nuxt/kit": "^3.5.2", + "defu": "^6.1.2", + "ofetch": "^1.0.1", + "ohash": "^1.1.2", + "scule": "^1.0.0", + "ufo": "^1.1.2" + } + }, "node_modules/nuxt-headlessui": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/nuxt-headlessui/-/nuxt-headlessui-1.1.4.tgz", @@ -6586,6 +6641,23 @@ "@nuxt/kit": "^3.5.0" } }, + "node_modules/nuxt-swiper": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/nuxt-swiper/-/nuxt-swiper-1.1.0.tgz", + "integrity": "sha512-DJFxKLIKvJw8BQ4VL/64Eu/znOL9UlQA07R4vA4fJCUxbk/vUvgrWEX1fRS7z7+vb2tEY8HIAxSLdoRSneFogA==", + "dependencies": { + "@nuxt/kit": "^3.3.3", + "swiper": "^9.2.0" + } + }, + "node_modules/nuxt-umami": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/nuxt-umami/-/nuxt-umami-2.4.3.tgz", + "integrity": "sha512-qeNgyBsoxZ7ej6otz2XGSRzemk236IW4L7rQRVO8Qht2YgUou9hIOw7RWuoiVU68fBJlWIQz5bDX3RRTx7rxSQ==", + "dependencies": { + "@vueuse/core": "^10.1.2" + } + }, "node_modules/nuxt/node_modules/estree-walker": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", @@ -8684,6 +8756,11 @@ "source-map": "^0.6.0" } }, + "node_modules/ssr-window": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/ssr-window/-/ssr-window-4.0.2.tgz", + "integrity": "sha512-ISv/Ch+ig7SOtw7G2+qkwfVASzazUnvlDTwypdLoPoySv+6MqlOV10VwPSE6EWkGjhW50lUmghPmpYZXMu/+AQ==" + }, "node_modules/standard-as-callback": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", @@ -8928,6 +9005,27 @@ "node": ">= 10" } }, + "node_modules/swiper": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/swiper/-/swiper-9.4.1.tgz", + "integrity": "sha512-1nT2T8EzUpZ0FagEqaN/YAhRj33F2x/lN6cyB0/xoYJDMf8KwTFT3hMOeoB8Tg4o3+P/CKqskP+WX0Df046fqA==", + "funding": [ + { + "type": "patreon", + "url": "https://www.patreon.com/swiperjs" + }, + { + "type": "open_collective", + "url": "http://opencollective.com/swiper" + } + ], + "dependencies": { + "ssr-window": "^4.0.2" + }, + "engines": { + "node": ">= 4.7.0" + } + }, "node_modules/tailwind-config-viewer": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/tailwind-config-viewer/-/tailwind-config-viewer-1.7.2.tgz", @@ -11321,6 +11419,11 @@ "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", "dev": true }, + "@types/web-bluetooth": { + "version": "0.0.17", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.17.tgz", + "integrity": "sha512-4p9vcSmxAayx72yn70joFoL44c9MO/0+iVEBIQXe3v2h2SiAsEIo/G5v6ObFWvNKRFjbrVadNf9LqEEZeQPzdA==" + }, "@unhead/dom": { "version": "1.1.27", "resolved": "https://registry.npmjs.org/@unhead/dom/-/dom-1.1.27.tgz", @@ -11561,6 +11664,30 @@ "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.4.tgz", "integrity": "sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ==" }, + "@vueuse/core": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-10.1.2.tgz", + "integrity": "sha512-roNn8WuerI56A5uiTyF/TEYX0Y+VKlhZAF94unUfdhbDUI+NfwQMn4FUnUscIRUhv3344qvAghopU4bzLPNFlA==", + "requires": { + "@types/web-bluetooth": "^0.0.17", + "@vueuse/metadata": "10.1.2", + "@vueuse/shared": "10.1.2", + "vue-demi": ">=0.14.0" + } + }, + "@vueuse/metadata": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-10.1.2.tgz", + "integrity": "sha512-3mc5BqN9aU2SqBeBuWE7ne4OtXHoHKggNgxZR2K+zIW4YLsy6xoZ4/9vErQs6tvoKDX6QAqm3lvsrv0mczAwIQ==" + }, + "@vueuse/shared": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-10.1.2.tgz", + "integrity": "sha512-1uoUTPBlgyscK9v6ScGeVYDDzlPSFXBlxuK7SfrDGyUTBiznb3mNceqhwvZHjtDRELZEN79V5uWPTF1VDV8svA==", + "requires": { + "vue-demi": ">=0.14.0" + } + }, "@webassemblyjs/ast": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", @@ -14795,6 +14922,20 @@ } } }, + "nuxt-api-party": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/nuxt-api-party/-/nuxt-api-party-0.11.4.tgz", + "integrity": "sha512-JySJtJYJGPBUkRrChJM6a+LeER/e35SNTypXb6FYi1oevg3Wa+zWSHgpQVHwi954Dee25QW5ax/KxagXVZu6eQ==", + "dev": true, + "requires": { + "@nuxt/kit": "^3.5.2", + "defu": "^6.1.2", + "ofetch": "^1.0.1", + "ohash": "^1.1.2", + "scule": "^1.0.0", + "ufo": "^1.1.2" + } + }, "nuxt-headlessui": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/nuxt-headlessui/-/nuxt-headlessui-1.1.4.tgz", @@ -14816,6 +14957,23 @@ "@nuxt/kit": "^3.5.0" } }, + "nuxt-swiper": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/nuxt-swiper/-/nuxt-swiper-1.1.0.tgz", + "integrity": "sha512-DJFxKLIKvJw8BQ4VL/64Eu/znOL9UlQA07R4vA4fJCUxbk/vUvgrWEX1fRS7z7+vb2tEY8HIAxSLdoRSneFogA==", + "requires": { + "@nuxt/kit": "^3.3.3", + "swiper": "^9.2.0" + } + }, + "nuxt-umami": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/nuxt-umami/-/nuxt-umami-2.4.3.tgz", + "integrity": "sha512-qeNgyBsoxZ7ej6otz2XGSRzemk236IW4L7rQRVO8Qht2YgUou9hIOw7RWuoiVU68fBJlWIQz5bDX3RRTx7rxSQ==", + "requires": { + "@vueuse/core": "^10.1.2" + } + }, "nypm": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.2.0.tgz", @@ -16139,6 +16297,11 @@ "source-map": "^0.6.0" } }, + "ssr-window": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/ssr-window/-/ssr-window-4.0.2.tgz", + "integrity": "sha512-ISv/Ch+ig7SOtw7G2+qkwfVASzazUnvlDTwypdLoPoySv+6MqlOV10VwPSE6EWkGjhW50lUmghPmpYZXMu/+AQ==" + }, "standard-as-callback": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", @@ -16302,6 +16465,14 @@ } } }, + "swiper": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/swiper/-/swiper-9.4.1.tgz", + "integrity": "sha512-1nT2T8EzUpZ0FagEqaN/YAhRj33F2x/lN6cyB0/xoYJDMf8KwTFT3hMOeoB8Tg4o3+P/CKqskP+WX0Df046fqA==", + "requires": { + "ssr-window": "^4.0.2" + } + }, "tailwind-config-viewer": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/tailwind-config-viewer/-/tailwind-config-viewer-1.7.2.tgz", diff --git a/portfolio-nuxt/package.json b/portfolio-nuxt/package.json index d6656be..b5d304f 100644 --- a/portfolio-nuxt/package.json +++ b/portfolio-nuxt/package.json @@ -13,6 +13,7 @@ "@nuxtjs/tailwindcss": "^6.7.0", "@types/node": "^18", "nuxt": "^3.5.2", + "nuxt-api-party": "^0.11.4", "nuxt-headlessui": "^1.1.4", "nuxt-icon": "^0.4.1" }, @@ -20,6 +21,7 @@ "@pinia/nuxt": "^0.4.11", "nuxt-swiper": "^1.1.0", "nuxt-umami": "^2.4.2", - "pinia": "^2.1.3" + "pinia": "^2.1.3", + "sharp": "^0.32.1" } } diff --git a/portfolio-nuxt/pages/[files]/[filename].vue b/portfolio-nuxt/pages/[files]/[filename].vue index 7d41056..7fb94b4 100644 --- a/portfolio-nuxt/pages/[files]/[filename].vue +++ b/portfolio-nuxt/pages/[files]/[filename].vue @@ -12,7 +12,6 @@ const { data: metadata } = await useFetch('https://unboundedpress.org/api/' + ro //lazy: true, //server: false, transform: (metadata) => { - console.log(metadata) return metadata[0] } }) diff --git a/portfolio-nuxt/pages/events.vue b/portfolio-nuxt/pages/events.vue index a3879bb..b2b16e6 100644 --- a/portfolio-nuxt/pages/events.vue +++ b/portfolio-nuxt/pages/events.vue @@ -4,16 +4,32 @@

performances

-
-
-
- {{ item.formatted_date }}: {{item.venue.city}}, {{item.venue.state}} -
- {{ item.venue.name }} + + + +
@@ -23,8 +39,8 @@
{{ item.formatted_date }}: {{item.location}} -
- {{ item.title }} +
+ {{ talk.title }}
@@ -50,6 +66,14 @@ for (const event of events) { let date = new Date(event.date) event.formatted_date = ("0" + (date.getMonth() + 1)).slice(-2) + "." + ("0" + date.getDate()).slice(-2) + "." + date.getFullYear() + if(typeof event.title === 'string' || event.title instanceof String) {event.talks = [{'title': event.title}] + } else { + let talks = [] + for(const talk of event.title){ + talks.push({"title": talk}) + } + event.talks = talks + } } return events.sort((a,b) => b.date - a.date) } diff --git a/portfolio-nuxt/pages/index.vue b/portfolio-nuxt/pages/index.vue index 51cc7bf..7337585 100644 --- a/portfolio-nuxt/pages/index.vue +++ b/portfolio-nuxt/pages/index.vue @@ -70,6 +70,7 @@