reworked astro collections
This commit is contained in:
@@ -1,19 +1,26 @@
|
|||||||
FROM node:18-alpine
|
FROM node:lts AS base
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
# Set working directory
|
# By copying only the package.json and package-lock.json here, we ensure that the following `-deps` steps are independent of the source code.
|
||||||
WORKDIR /opt/app
|
# Therefore, the `-deps` steps will be skipped if only the source code changes.
|
||||||
|
COPY package.json package-lock.json ./
|
||||||
|
|
||||||
# Copy package files
|
FROM base AS prod-deps
|
||||||
COPY package*.json ./
|
RUN npm install --omit=dev
|
||||||
|
|
||||||
# Install dependencies
|
FROM base AS build-deps
|
||||||
RUN npm ci
|
RUN npm install
|
||||||
|
|
||||||
# Copy source code
|
FROM build-deps AS build
|
||||||
COPY . .
|
COPY . .
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
FROM base AS runtime
|
||||||
|
COPY --from=prod-deps /app/node_modules ./node_modules
|
||||||
|
COPY --from=build /app/dist ./dist
|
||||||
|
|
||||||
|
ENV HOST=0.0.0.0
|
||||||
|
ENV PORT=4321
|
||||||
|
|
||||||
# Expose port
|
|
||||||
EXPOSE 4321
|
EXPOSE 4321
|
||||||
|
CMD node ./dist/server/entry.mjs
|
||||||
# Start the development server
|
|
||||||
CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0"]
|
|
||||||
@@ -3,9 +3,16 @@ import { defineConfig } from 'astro/config';
|
|||||||
|
|
||||||
import tailwindcss from '@tailwindcss/vite';
|
import tailwindcss from '@tailwindcss/vite';
|
||||||
|
|
||||||
|
import node from '@astrojs/node';
|
||||||
|
|
||||||
// https://astro.build/config
|
// https://astro.build/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
output: 'server',
|
||||||
vite: {
|
vite: {
|
||||||
plugins: [tailwindcss()]
|
plugins: [tailwindcss()]
|
||||||
}
|
},
|
||||||
|
|
||||||
|
adapter: node({
|
||||||
|
mode: 'standalone'
|
||||||
|
})
|
||||||
});
|
});
|
||||||
27
client/docker-compose.yml
Normal file
27
client/docker-compose.yml
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
client:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
container_name: astro-client
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "4321:4321"
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
environment:
|
||||||
|
NODE_ENV: ${NODE_ENV}
|
||||||
|
STRAPI_URL: ${STRAPI_URL}
|
||||||
|
volumes:
|
||||||
|
- ./src:/opt/app/src
|
||||||
|
- ./public:/opt/app/public
|
||||||
|
- ./astro.config.mjs:/opt/app/astro.config.mjs
|
||||||
|
- ./tsconfig.json:/opt/app/tsconfig.json
|
||||||
|
networks:
|
||||||
|
- strapi-network
|
||||||
|
|
||||||
|
networks:
|
||||||
|
strapi-network:
|
||||||
|
external: true
|
||||||
188
client/package-lock.json
generated
188
client/package-lock.json
generated
@@ -8,6 +8,7 @@
|
|||||||
"name": "client",
|
"name": "client",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@astrojs/node": "^9.2.2",
|
||||||
"@tailwindcss/vite": "^4.1.10",
|
"@tailwindcss/vite": "^4.1.10",
|
||||||
"@types/qs": "^6.14.0",
|
"@types/qs": "^6.14.0",
|
||||||
"astro": "^5.7.12",
|
"astro": "^5.7.12",
|
||||||
@@ -70,6 +71,20 @@
|
|||||||
"vfile": "^6.0.3"
|
"vfile": "^6.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@astrojs/node": {
|
||||||
|
"version": "9.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@astrojs/node/-/node-9.2.2.tgz",
|
||||||
|
"integrity": "sha512-PtLPuuojmcl9O3CEvXqL/D+wB4x5DlbrGOvP0MeTAh/VfKFprYAzgw1+45xsnTO+QvPWb26l1cT+ZQvvohmvMw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@astrojs/internal-helpers": "0.6.1",
|
||||||
|
"send": "^1.2.0",
|
||||||
|
"server-destroy": "^1.0.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"astro": "^5.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@astrojs/prism": {
|
"node_modules/@astrojs/prism": {
|
||||||
"version": "3.2.0",
|
"version": "3.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@astrojs/prism/-/prism-3.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@astrojs/prism/-/prism-3.2.0.tgz",
|
||||||
@@ -1433,6 +1448,15 @@
|
|||||||
"integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==",
|
"integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/depd": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/dequal": {
|
"node_modules/dequal": {
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
|
||||||
@@ -1532,12 +1556,27 @@
|
|||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ee-first": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/emoji-regex": {
|
"node_modules/emoji-regex": {
|
||||||
"version": "10.4.0",
|
"version": "10.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz",
|
||||||
"integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==",
|
"integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/encodeurl": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/enhanced-resolve": {
|
"node_modules/enhanced-resolve": {
|
||||||
"version": "5.18.1",
|
"version": "5.18.1",
|
||||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz",
|
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz",
|
||||||
@@ -1639,6 +1678,12 @@
|
|||||||
"@esbuild/win32-x64": "0.25.4"
|
"@esbuild/win32-x64": "0.25.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/escape-html": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/escape-string-regexp": {
|
"node_modules/escape-string-regexp": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
|
||||||
@@ -1660,6 +1705,15 @@
|
|||||||
"@types/estree": "^1.0.0"
|
"@types/estree": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/etag": {
|
||||||
|
"version": "1.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
|
||||||
|
"integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/eventemitter3": {
|
"node_modules/eventemitter3": {
|
||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz",
|
||||||
@@ -1728,6 +1782,15 @@
|
|||||||
"unicode-trie": "^2.0.0"
|
"unicode-trie": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/fresh": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/function-bind": {
|
"node_modules/function-bind": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||||
@@ -2060,6 +2123,31 @@
|
|||||||
"integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==",
|
"integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==",
|
||||||
"license": "BSD-2-Clause"
|
"license": "BSD-2-Clause"
|
||||||
},
|
},
|
||||||
|
"node_modules/http-errors": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"depd": "2.0.0",
|
||||||
|
"inherits": "2.0.4",
|
||||||
|
"setprototypeof": "1.2.0",
|
||||||
|
"statuses": "2.0.1",
|
||||||
|
"toidentifier": "1.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/http-errors/node_modules/statuses": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/import-meta-resolve": {
|
"node_modules/import-meta-resolve": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz",
|
||||||
@@ -2070,6 +2158,12 @@
|
|||||||
"url": "https://github.com/sponsors/wooorm"
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/inherits": {
|
||||||
|
"version": "2.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||||
|
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
"node_modules/iron-webcrypto": {
|
"node_modules/iron-webcrypto": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/iron-webcrypto/-/iron-webcrypto-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/iron-webcrypto/-/iron-webcrypto-1.2.1.tgz",
|
||||||
@@ -3274,6 +3368,27 @@
|
|||||||
],
|
],
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/mime-db": {
|
||||||
|
"version": "1.54.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
|
||||||
|
"integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mime-types": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"mime-db": "^1.54.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/minipass": {
|
"node_modules/minipass": {
|
||||||
"version": "7.1.2",
|
"version": "7.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
|
||||||
@@ -3435,6 +3550,18 @@
|
|||||||
"integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==",
|
"integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/on-finished": {
|
||||||
|
"version": "2.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
|
||||||
|
"integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"ee-first": "1.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/oniguruma-parser": {
|
"node_modules/oniguruma-parser": {
|
||||||
"version": "0.12.1",
|
"version": "0.12.1",
|
||||||
"resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.12.1.tgz",
|
"resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.12.1.tgz",
|
||||||
@@ -3645,6 +3772,15 @@
|
|||||||
"integrity": "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==",
|
"integrity": "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/range-parser": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/readdirp": {
|
"node_modules/readdirp": {
|
||||||
"version": "4.1.2",
|
"version": "4.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
|
||||||
@@ -3942,6 +4078,40 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/send": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"debug": "^4.3.5",
|
||||||
|
"encodeurl": "^2.0.0",
|
||||||
|
"escape-html": "^1.0.3",
|
||||||
|
"etag": "^1.8.1",
|
||||||
|
"fresh": "^2.0.0",
|
||||||
|
"http-errors": "^2.0.0",
|
||||||
|
"mime-types": "^3.0.1",
|
||||||
|
"ms": "^2.1.3",
|
||||||
|
"on-finished": "^2.4.1",
|
||||||
|
"range-parser": "^1.2.1",
|
||||||
|
"statuses": "^2.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/server-destroy": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/server-destroy/-/server-destroy-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-rb+9B5YBIEzYcD6x2VKidaa+cqYBJQKnU4oe4E3ANwRRN56yk/ua1YCJT1n21NTS8w6CcOclAKNP3PhdCXKYtQ==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
|
"node_modules/setprototypeof": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
"node_modules/sharp": {
|
"node_modules/sharp": {
|
||||||
"version": "0.33.5",
|
"version": "0.33.5",
|
||||||
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz",
|
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz",
|
||||||
@@ -4117,6 +4287,15 @@
|
|||||||
"url": "https://github.com/sponsors/wooorm"
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/statuses": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/string-width": {
|
"node_modules/string-width": {
|
||||||
"version": "7.2.0",
|
"version": "7.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
|
||||||
@@ -4223,6 +4402,15 @@
|
|||||||
"url": "https://github.com/sponsors/SuperchupuDev"
|
"url": "https://github.com/sponsors/SuperchupuDev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/toidentifier": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/tr46": {
|
"node_modules/tr46": {
|
||||||
"version": "0.0.3",
|
"version": "0.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
"astro": "astro"
|
"astro": "astro"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@astrojs/node": "^9.2.2",
|
||||||
"@tailwindcss/vite": "^4.1.10",
|
"@tailwindcss/vite": "^4.1.10",
|
||||||
"@types/qs": "^6.14.0",
|
"@types/qs": "^6.14.0",
|
||||||
"astro": "^5.7.12",
|
"astro": "^5.7.12",
|
||||||
|
|||||||
@@ -1,87 +0,0 @@
|
|||||||
import { defineCollection, z } from "astro:content";
|
|
||||||
import qs from "qs";
|
|
||||||
|
|
||||||
// Define a custom content collection that loads data from Strapi
|
|
||||||
const strapiPoleElementsLoader = defineCollection({
|
|
||||||
// Async loader function that fetches data from Strapi API
|
|
||||||
loader: async () => {
|
|
||||||
// Get Strapi URL from environment variables or fallback to localhost
|
|
||||||
const BASE_URL = import.meta.env.STRAPI_URL || "http://localhost:1337";
|
|
||||||
const path = "/api/elements";
|
|
||||||
const url = new URL(path, BASE_URL);
|
|
||||||
|
|
||||||
// Build query parameters using qs to populate cover image data
|
|
||||||
url.search = qs.stringify({
|
|
||||||
populate: {
|
|
||||||
mainImage: {
|
|
||||||
fields: ["url", "alternativeText"],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Fetch articles from Strapi
|
|
||||||
const poleElementsData = await fetch(url.href);
|
|
||||||
|
|
||||||
if (!poleElementsData.ok) {
|
|
||||||
throw new Error(`Failed to fetch data from Strapi: ${poleElementsData.status} ${poleElementsData.statusText}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await poleElementsData.json();
|
|
||||||
const { data } = response;
|
|
||||||
|
|
||||||
// Check if data is null or undefined
|
|
||||||
if (!data) {
|
|
||||||
throw new Error("No data received from Strapi API - the response was null or undefined");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure data is an array
|
|
||||||
const dataArray = Array.isArray(data) ? data : [data];
|
|
||||||
|
|
||||||
// Transform the API response into the desired data structure
|
|
||||||
return dataArray
|
|
||||||
.filter(item => item !== null && item !== undefined) // Filter out null/undefined items
|
|
||||||
.map((item) => ({
|
|
||||||
id: item.id?.toString() || "",
|
|
||||||
name: item.name || "",
|
|
||||||
title: item.name || "",
|
|
||||||
description: item.description || "",
|
|
||||||
createdAt: item.createdAt || "",
|
|
||||||
updatedAt: item.updatedAt || "",
|
|
||||||
publishedAt: item.publishedAt || "",
|
|
||||||
mainImage: item.mainImage ? {
|
|
||||||
id: Number(item.mainImage.id) || 0,
|
|
||||||
documentId: item.mainImage.documentId || "",
|
|
||||||
url: item.mainImage.url || "",
|
|
||||||
alternativeText: item.mainImage.alternativeText || "",
|
|
||||||
} : {
|
|
||||||
id: 0,
|
|
||||||
documentId: "",
|
|
||||||
url: "",
|
|
||||||
alternativeText: "",
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error loading pole elements from Strapi:", error);
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// Define the schema for type validation using Zod
|
|
||||||
schema: z.object({
|
|
||||||
id: z.string(),
|
|
||||||
name: z.string(),
|
|
||||||
title: z.string(),
|
|
||||||
description: z.string(),
|
|
||||||
createdAt: z.string(),
|
|
||||||
updatedAt: z.string(),
|
|
||||||
publishedAt: z.string(),
|
|
||||||
mainImage: z.object({
|
|
||||||
id: z.number(),
|
|
||||||
documentId: z.string(),
|
|
||||||
url: z.string(),
|
|
||||||
alternativeText: z.string(),
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
export default strapiPoleElementsLoader;
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
// Import necessary components and utilities
|
// Import necessary components and utilities
|
||||||
import MarkdownComponent from "./MardownContent.astro";
|
import MarkdownComponent from "./MardownContent.astro";
|
||||||
import { getStrapiMedia } from "../utils/strapi";
|
import { getStrapiMedia } from "../lib/strapi";
|
||||||
import { getStrapiBaseUrl } from "../config/strapi";
|
import { getStrapiBaseUrl } from "../config/strapi";
|
||||||
import type { HTMLAttributes } from "astro/types";
|
import type { HTMLAttributes } from "astro/types";
|
||||||
|
|
||||||
@@ -18,19 +18,20 @@ const BASE_URL = getStrapiBaseUrl();
|
|||||||
<div {...otherProps}>
|
<div {...otherProps}>
|
||||||
{
|
{
|
||||||
elements.map((poleElement) => (
|
elements.map((poleElement) => (
|
||||||
|
console.log(poleElement),
|
||||||
<a href={`/elements/${poleElement.id}`} class="block">
|
<a href={`/elements/${poleElement.id}`} class="block">
|
||||||
<article class="flex items-center bg-white rounded-lg shadow-lg overflow-hidden hover:shadow-xl transition-shadow duration-200">
|
<article class="flex items-center bg-white rounded-lg shadow-lg overflow-hidden hover:shadow-xl transition-shadow duration-200">
|
||||||
<img
|
<img
|
||||||
src={getStrapiMedia(
|
src={getStrapiMedia(
|
||||||
poleElement.data.mainImage.url,
|
poleElement.mainImage.url,
|
||||||
BASE_URL,
|
BASE_URL,
|
||||||
)}
|
)}
|
||||||
alt={poleElement.data.mainImage.alternativeText}
|
alt={poleElement.mainImage.alternativeText}
|
||||||
class="w-24 h-24 object-cover flex-shrink-0"
|
class="w-24 h-24 object-cover flex-shrink-0"
|
||||||
/>
|
/>
|
||||||
<div class="p-4">
|
<div class="p-4">
|
||||||
<h2 class="text-xl font-bold">
|
<h2 class="text-xl font-bold">
|
||||||
{poleElement.data.name}
|
{poleElement.name}
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
import strapiPoleElementsLoader from "./collections/strapiPoleElementsLoader.mjs";
|
|
||||||
|
|
||||||
// Export the collection for use in Astro pages
|
|
||||||
export const collections = {
|
|
||||||
poleElements: strapiPoleElementsLoader,
|
|
||||||
};
|
|
||||||
3
client/src/env.d.ts
vendored
Normal file
3
client/src/env.d.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
interface ImportMetaEnv {
|
||||||
|
readonly STRAPI_URL: string;
|
||||||
|
}
|
||||||
15
client/src/interfaces/poleElement.ts
Normal file
15
client/src/interfaces/poleElement.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
export default interface PoleElement {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
publishedAt: string;
|
||||||
|
mainImage: {
|
||||||
|
id: number;
|
||||||
|
documentId: string;
|
||||||
|
url: string;
|
||||||
|
alternativeText: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
68
client/src/lib/strapi.ts
Normal file
68
client/src/lib/strapi.ts
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
interface Props {
|
||||||
|
endpoint: string;
|
||||||
|
query?: Record<string, string>;
|
||||||
|
wrappedByKey?: string;
|
||||||
|
wrappedByList?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches data from the Strapi API
|
||||||
|
* @param endpoint - The endpoint to fetch from
|
||||||
|
* @param query - The query parameters to add to the url
|
||||||
|
* @param wrappedByKey - The key to unwrap the response from
|
||||||
|
* @param wrappedByList - If the response is a list, unwrap it
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export default async function fetchApi<T>({
|
||||||
|
endpoint,
|
||||||
|
query,
|
||||||
|
wrappedByKey,
|
||||||
|
wrappedByList,
|
||||||
|
}: Props): Promise<T> {
|
||||||
|
if (endpoint.startsWith('/')) {
|
||||||
|
endpoint = endpoint.slice(1);
|
||||||
|
}
|
||||||
|
const strapiUrl = import.meta.env.STRAPI_URL || process.env.STRAPI_URL || "http://localhost:1337";
|
||||||
|
console.log(strapiUrl);
|
||||||
|
const url = new URL(`${strapiUrl}/api/${endpoint}`);
|
||||||
|
|
||||||
|
if (query) {
|
||||||
|
Object.entries(query).forEach(([key, value]) => {
|
||||||
|
url.searchParams.append(key, value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch(url.toString());
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
throw new Error(`HTTP error! status: ${res.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
let data = await res.json();
|
||||||
|
|
||||||
|
if (wrappedByKey) {
|
||||||
|
data = data[wrappedByKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wrappedByList) {
|
||||||
|
data = data[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return data as T;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching from Strapi API:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to handle media URLs from Strapi
|
||||||
|
export function getStrapiMedia(url: string | null, baseUrl: string) {
|
||||||
|
if (url == null) return null;
|
||||||
|
// Return as-is if it's a data URL (base64)
|
||||||
|
if (url.startsWith("data:")) return url;
|
||||||
|
// Return as-is if it's an absolute URL
|
||||||
|
if (url.startsWith("http") || url.startsWith("//")) return url;
|
||||||
|
// Prepend baseUrl for relative URLs
|
||||||
|
return `${baseUrl}${url}`;
|
||||||
|
}
|
||||||
@@ -1,14 +1,15 @@
|
|||||||
---
|
---
|
||||||
// Import necessary components and utilities
|
// Import necessary components and utilities
|
||||||
import Layout from "../layouts/Layout.astro";
|
import Layout from "../layouts/Layout.astro";
|
||||||
import { getCollection } from "astro:content";
|
|
||||||
import PoleElementsList from "../components/PoleElementsList.astro";
|
import PoleElementsList from "../components/PoleElementsList.astro";
|
||||||
import { getStrapiBaseUrl } from "../config/strapi";
|
|
||||||
|
|
||||||
// Fetch all posts from Strapi using Astro's content collection
|
import fetchApi from '../lib/strapi';
|
||||||
const strapiPoleElements = await getCollection("poleElements");
|
import type PoleElement from "../interfaces/poleElement";
|
||||||
// Get Strapi URL from global config
|
|
||||||
const BASE_URL = getStrapiBaseUrl();
|
const strapiPoleElements = await fetchApi<PoleElement[]>({
|
||||||
|
endpoint: 'elements?populate=*', // the content type to fetch
|
||||||
|
wrappedByKey: 'data', // the key to unwrap the response
|
||||||
|
});
|
||||||
---
|
---
|
||||||
|
|
||||||
<Layout title="Pole Elements" description="Pole Elements">
|
<Layout title="Pole Elements" description="Pole Elements">
|
||||||
|
|||||||
@@ -1,20 +1,30 @@
|
|||||||
---
|
---
|
||||||
import { getCollection } from 'astro:content';
|
|
||||||
import MardownContent from '../../components/MardownContent.astro';
|
import MardownContent from '../../components/MardownContent.astro';
|
||||||
import Layout from '../../layouts/Layout.astro';
|
import Layout from '../../layouts/Layout.astro';
|
||||||
|
|
||||||
// 1. Genera una nueva ruta para cada entrada de colección
|
import fetchApi from '../../lib/strapi';
|
||||||
export async function getStaticPaths() {
|
import type PoleElement from '../../interfaces/poleElement';
|
||||||
const poleElements = await getCollection('poleElements');
|
|
||||||
return poleElements.map(entry => ({
|
|
||||||
params: { id: entry.id }, props: { entry },
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
// 2. Para tu plantilla, puedes obtener la entrada directamente de la prop
|
|
||||||
const { entry } = Astro.props;
|
|
||||||
---
|
|
||||||
|
|
||||||
<Layout title={entry.data.title} description={entry.data.description}>
|
const { id } = Astro.params;
|
||||||
<h1>{entry.data.title}</h1>
|
|
||||||
<MardownContent content={entry.data.description} />
|
let poleElement: PoleElement;
|
||||||
|
|
||||||
|
try {
|
||||||
|
poleElement = await fetchApi<PoleElement>({
|
||||||
|
endpoint: 'elements',
|
||||||
|
wrappedByKey: 'data',
|
||||||
|
wrappedByList: true,
|
||||||
|
query: {
|
||||||
|
'populate': '*',
|
||||||
|
'filters[id][$eq]': id || '',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
return Astro.redirect('/404');
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
<Layout title={poleElement.name} description={poleElement.description}>
|
||||||
|
<h1>{poleElement.name}</h1>
|
||||||
|
{poleElement.description && <MardownContent content={poleElement.description} />}
|
||||||
</Layout>
|
</Layout>
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
// Helper function to handle media URLs from Strapi
|
|
||||||
export function getStrapiMedia(url: string | null, baseUrl: string) {
|
|
||||||
if (url == null) return null;
|
|
||||||
// Return as-is if it's a data URL (base64)
|
|
||||||
if (url.startsWith("data:")) return url;
|
|
||||||
// Return as-is if it's an absolute URL
|
|
||||||
if (url.startsWith("http") || url.startsWith("//")) return url;
|
|
||||||
// Prepend baseUrl for relative URLs
|
|
||||||
return `${baseUrl}${url}`;
|
|
||||||
}
|
|
||||||
@@ -27,4 +27,4 @@ PORT=1337
|
|||||||
|
|
||||||
# Client Configuration
|
# Client Configuration
|
||||||
CLIENT_NODE_ENV=development
|
CLIENT_NODE_ENV=development
|
||||||
STRAPI_URL=http://strapi:1337
|
STRAPI_URL=http://localhost:1337
|
||||||
@@ -10,7 +10,7 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "1337:1337"
|
- "1337:1337"
|
||||||
env_file:
|
env_file:
|
||||||
- docker-compose.env
|
- .env
|
||||||
environment:
|
environment:
|
||||||
DATABASE_CLIENT: ${DATABASE_CLIENT}
|
DATABASE_CLIENT: ${DATABASE_CLIENT}
|
||||||
DATABASE_HOST: ${DATABASE_HOST}
|
DATABASE_HOST: ${DATABASE_HOST}
|
||||||
@@ -29,31 +29,14 @@ services:
|
|||||||
- ./server/public/uploads:/opt/app/public/uploads
|
- ./server/public/uploads:/opt/app/public/uploads
|
||||||
- ./server/.tmp:/opt/app/.tmp
|
- ./server/.tmp:/opt/app/.tmp
|
||||||
depends_on:
|
depends_on:
|
||||||
- postgres
|
postgres:
|
||||||
networks:
|
condition: service_healthy
|
||||||
- strapi-network
|
healthcheck:
|
||||||
|
test: ["CMD", "nc", "-z", "localhost", "1337"]
|
||||||
client:
|
interval: 10s
|
||||||
build:
|
timeout: 5s
|
||||||
context: ./client
|
retries: 5
|
||||||
dockerfile: Dockerfile
|
start_period: 30s
|
||||||
container_name: astro-client
|
|
||||||
restart: unless-stopped
|
|
||||||
ports:
|
|
||||||
- "4321:4321"
|
|
||||||
env_file:
|
|
||||||
- docker-compose.env
|
|
||||||
environment:
|
|
||||||
NODE_ENV: ${CLIENT_NODE_ENV}
|
|
||||||
STRAPI_URL: ${STRAPI_URL}
|
|
||||||
volumes:
|
|
||||||
- ./client/src:/opt/app/src
|
|
||||||
- ./client/public:/opt/app/public
|
|
||||||
- ./client/astro.config.mjs:/opt/app/astro.config.mjs
|
|
||||||
- ./client/tsconfig.json:/opt/app/tsconfig.json
|
|
||||||
depends_on:
|
|
||||||
- strapi
|
|
||||||
- postgres
|
|
||||||
networks:
|
networks:
|
||||||
- strapi-network
|
- strapi-network
|
||||||
|
|
||||||
@@ -69,8 +52,12 @@ services:
|
|||||||
POSTGRES_PASSWORD: ${DATABASE_PASSWORD}
|
POSTGRES_PASSWORD: ${DATABASE_PASSWORD}
|
||||||
volumes:
|
volumes:
|
||||||
- postgres_data:/var/lib/postgresql/data
|
- postgres_data:/var/lib/postgresql/data
|
||||||
ports:
|
healthcheck:
|
||||||
- "5432:5432"
|
test: ["CMD-SHELL", "pg_isready -U ${DATABASE_USERNAME} -d ${DATABASE_NAME}"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
start_period: 10s
|
||||||
networks:
|
networks:
|
||||||
- strapi-network
|
- strapi-network
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user