diff --git a/README.md b/README.md index 242da88c..9a1a4356 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,7 @@ The routes are the same as a standard Ghost Blog so you can migrate to Astro eas | `/tag[slug]` | Tag page with related posts | | `/tags` | All the tags | | `/archives/[...page]` | All the posts, paginated | +| `/rss.xml` | All the posts, in a FEED | # Manual Function Mode (DIY MODE) diff --git a/index.ts b/index.ts index 3b0ac2dc..5dc35d90 100644 --- a/index.ts +++ b/index.ts @@ -11,8 +11,19 @@ const mode = 'all'; const prefixes = 'CONTENT_API'; const env = loadEnv(mode, process.cwd(), prefixes); -// SET LOCAL PACKAGE NAME +// INTERNAL CONSTANTS const pkg = '@matthiesenxyz/astro-ghostcms'; +const CHECK_ENV = "Checking for Environment Variables..."; +const KEY_MISSING = "CONTENT_API_KEY Missing from .env"; +const URL_MISSING = "CONTENT_API_URL Missing from .env"; +const IT = "Injecting Theme: " +const IR = "Injecting Routes..."; +const IRD = "Route Injection Disabled - Skipping..."; +const IIR = "Injecting Integration Route: " +const II = "Injecting Integration: "; +const AIbU = "Already Imported by User: "; +const CF = "Checking for "; +const CONFSETUPDONE = "GhostCMS Injection Complete. Integration is now ready." /** Astro-GhostCMS Integration * @ For more information and to see the docs check @@ -28,19 +39,7 @@ export default function GhostCMS(options: UserConfig): AstroIntegration { updateConfig, logger, }) => { - // Check For ENV Variables - logger.info("Checking for Environment Variables...") - - // CHECK FOR API KEY - if(env.CONTENT_API_KEY === undefined){ - logger.error("CONTENT_API_KEY Missing from .env") - } - // CHECK FOR API URL - if(env.CONTENT_API_URL === undefined){ - logger.error("CONTENT_API_URL Missing from .env") - } - - // CHECK USER CONFIG + // CHECK USER CONFIG AND MAKE AVAILBLE TO INTEGRATIONS logger.info("Checking Config...") const o = UserConfigSchema.safeParse(options || {}) as SafeParseSuccess; if (!o.success) { @@ -48,98 +47,121 @@ export default function GhostCMS(options: UserConfig): AstroIntegration { logger.error(`Config Error - ${ validationError }`); throw validationError; } - const entry = o.data.theme; const uconf = o.data; + const injection = uconf.disableRouteInjection; + const entry = uconf.theme; + const logs = uconf.disableConsoleOutput; - // THEME SELECTOR - if (entry === pkg) { - logger.info("Injecting Theme: astro-ghostcms-basetheme"); - } else { - logger.info(`Injecting Theme: ${entry}`); + // Check For ENV Variables + if(!logs) {logger.info(CHECK_ENV)} + + // CHECK FOR API KEY + if(env.CONTENT_API_KEY === undefined){ + logger.error(KEY_MISSING); + throw KEY_MISSING; + } + // CHECK FOR API URL + if(env.CONTENT_API_URL === undefined){ + logger.error(URL_MISSING); + throw URL_MISSING; } - // INJECT ROUTES - logger.info("Injecting Routes..."); - injectRoute({ - pattern: '/', - entrypoint: `${entry}/index.astro` - }); + if(!injection){ + // THEME SELECTOR + if (entry === pkg) { + if(!logs) {logger.info(IT + pkg)} + } else { + if(!logs) {logger.info(IT + entry)} + } - injectRoute({ - pattern: '/[slug]', - entrypoint: `${entry}/[slug].astro` - }); + // INJECT ROUTES + if(!logs) {logger.info(IR)} - injectRoute({ - pattern: '/tags', - entrypoint: `${entry}/tags.astro` - }); + injectRoute({ + pattern: '/', + entrypoint: `${entry}/index.astro` + }); + + injectRoute({ + pattern: '/404', + entrypoint: `${entry}/404.astro` + }); - injectRoute({ - pattern: '/authors', - entrypoint: `${entry}/authors.astro` - }); + injectRoute({ + pattern: '/[slug]', + entrypoint: `${entry}/[slug].astro` + }); - injectRoute({ - pattern: '/tag/[slug]', - entrypoint: `${entry}/tag/[slug].astro` - }); + injectRoute({ + pattern: '/tags', + entrypoint: `${entry}/tags.astro` + }); - injectRoute({ - pattern: '/author/[slug]', - entrypoint: `${entry}/author/[slug].astro` - }); + injectRoute({ + pattern: '/authors', + entrypoint: `${entry}/authors.astro` + }); - injectRoute({ - pattern: '/archives/[...page]', - entrypoint: `${entry}/archives/[...page].astro` - }); + injectRoute({ + pattern: '/tag/[slug]', + entrypoint: `${entry}/tag/[slug].astro` + }); + + injectRoute({ + pattern: '/author/[slug]', + entrypoint: `${entry}/author/[slug].astro` + }); + + injectRoute({ + pattern: '/archives/[...page]', + entrypoint: `${entry}/archives/[...page].astro` + }); + } else { + if(!logs) {logger.info(IRD)} + } // IMPORT INTEGRATIONS & INTEGRATION ROUTES const int = [...config.integrations]; // IMPORT INTEGRATION: @ASTROJS/RSS - logger.info("Injecting Integration Route: @astrojs/rss"); + if(!logs) {logger.info(IIR + "@astrojs/rss")} injectRoute({ pattern: '/rss.xml', entrypoint: `${pkg}/rss.xml.js` }); // IMPORT INTEGRATION: @ASTROJS/SITEMAP - logger.info("Checking for @astrojs/sitemap"); + if(!logs) {logger.info(CF + "@astrojs/sitemap")} if (!int.find(({ name }) => name === '@astrojs/sitemap')) { - logger.info("Injecting Integration: @astrojs/sitemap"); + if(!logs) {logger.info(II + "@astrojs/sitemap")} int.push(ghostSitemap(uconf)); } else { - logger.info("Already Imported by User: @astrojs/sitemap"); - } + if(!logs) {logger.info(AIbU + "@astrojs/sitemap")} + }; // IMPORT INTEGRATION: ASTRO-ROBOTS-TXT - logger.info("Checking for astro-robots-txt"); + if(!logs) {logger.info(CF + "astro-robots-txt")} if (!int.find(({ name }) => name === 'astro-robots-txt')) { - logger.info("Injecting Integration: astro-robots-txt"); + if(!logs) {logger.info(II + "astro-robots-txt")} int.push(ghostRobots(uconf)); } else { - logger.info("Already Imported by User: astro-robots-txt"); - } - try { updateConfig({ - integrations: [ - ghostSitemap(uconf), - ghostRobots(uconf) - ], - vite: { - plugins: [ - viteGhostCMS(uconf,config) - ] - } }) } catch (e) { - logger.error(e as string) - throw e - } + if(!logs) {logger.info(AIbU + "astro-robots-txt")} + }; + try {updateConfig({ + integrations: [ + ghostSitemap(uconf), + ghostRobots(uconf), + ], + vite:{plugins:[viteGhostCMS(uconf,config)]}, + }) } catch (e) { + logger.error(e as string); + throw e; + }; }, 'astro:config:done': async ({ logger }) => { - logger.info('GhostCMS Injection Complete. Integration is now ready.'); + logger.info(CONFSETUPDONE); } } } diff --git a/package.json b/package.json index 00797c2c..108813e1 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@matthiesenxyz/astro-ghostcms", "description": "Astro GhostCMS integration to allow easier importing of GhostCMS Content", - "version": "2.1.5", + "version": "2.1.6", "author": "MatthiesenXYZ (https://matthiesen.xyz)", "type": "module", "license": "MIT", @@ -18,6 +18,7 @@ ".": "./index.ts", "./api": "./src/api/index.ts", "./index.astro": "./src/routes/index.astro", + "./404.astro": "./src/routes/404.astro", "./[slug].astro": "./src/routes/[slug].astro", "./tags.astro": "./src/routes/tags.astro", "./authors.astro": "./src/routes/authors.astro", diff --git a/src/routes/404.astro b/src/routes/404.astro new file mode 100644 index 00000000..9925585a --- /dev/null +++ b/src/routes/404.astro @@ -0,0 +1,24 @@ +--- +import '../styles/404.css' +--- + + + + 404 Error + + + +
+
+

404

+

No worries traveller, this way.

+ +
+ + + + + \ No newline at end of file diff --git a/src/routes/404.js b/src/routes/404.js new file mode 100644 index 00000000..1e639148 --- /dev/null +++ b/src/routes/404.js @@ -0,0 +1,57 @@ +const particles = { + fpsLimit: 120, + particles: { + number: { + value: 3, + density: { + enable: true, + area: 100, + }, + }, + color: { + value: "#008781", + }, + shape: { + type: "circle", + }, + opacity: { + value: 1, + random: { + enable: true, + minimumValue: 0.1, + }, + animation: { + enable: true, + speed: 1, + minimumValue: 0, + sync: false, + }, + }, + size: { + value: 50, + random: { + enable: true, + minimumValue: 15, + }, + }, + move: { + enable: true, + speed: 17, + direction: "down", + random: false, + straight: true, + outModes: { + default: "out", + }, + }, + }, + interactivity: { + detectsOn: "canvas", + events: { + resize: false, + }, + }, + detectRetina: true, + }; + + tsParticles.load("tsparticles", particles); \ No newline at end of file diff --git a/src/styles/404.css b/src/styles/404.css new file mode 100644 index 00000000..e9a35099 --- /dev/null +++ b/src/styles/404.css @@ -0,0 +1,124 @@ +@import url("https://fonts.googleapis.com/css2?family=Silkscreen&display=swap"); +.particle-error, +.wrapper, +#tsparticles { + width: 100%; + height: 100%; + margin: 0px; + margin-top: -70px; +} + +#tsparticles { + position: fixed !important; + opacity: 0.23; +} + +.wrapper { + background: #002c37 !important; +} + +.wrapper a { + text-decoration: none; +} + +.denied__wrapper { + width: 100%; + display: block; + margin: 0 auto; + position: relative; + margin-top: 8vh; +} + +.wrapper h1 { + text-align: center; + color: #007ab8; + font-family: "Silkscreen", sans-serif; + font-size: 200px; + margin-bottom: 0px; +} + +.wrapper h3 { + text-align: center; + color: #f00a20; + font-size: 19px; + line-height: 23px; + max-width: 530px; + margin: 0px auto 30px auto; + font-family: "Silkscreen", sans-serif; +} + +.denied__link { + background: none; + color: #4d8800; + padding: 12px 0px 10px 0px; + border: 1px solid #4d8800; + outline: none; + border-radius: 7px; + width: 250px; + font-size: 15px; + text-align: center; + margin: 0 auto; + vertical-align: middle; + display: block; + margin-bottom: 40px; + margin-top: 25px; + font-family: "Dosis", sans-serif; + font-weight: 400; +} + +.denied__link:hover { + color: #ffbb39; + border-color: #ffbb39; + cursor: pointer; + opacity: 1; +} + +.wrapper .stars { + animation: sparkle 1.6s infinite ease-in-out alternate; +} + +@keyframes sparkle { + 0% { + opacity: 1; + } + 100% { + opacity: 0.3; + } +} + +@keyframes spin { + 0% { + transform: rotateZ(0deg); + } + 100% { + transform: rotateZ(360deg); + } +} + +@media (max-width: 600px) { + .wrapper h1 { + font-size: 75px; + } + .wrapper h3 { + font-size: 16px; + width: 200px; + margin: 0 auto; + line-height: 23px; + } + .wrapper h3 span { + width: 60px; + } +} + +.hover { + animation: hover 2s infinite ease-in-out alternate; +} + +@keyframes hover { + 0% { + transform: translateY(3px); + } + 100% { + transform: translateY(-3px); + } +} \ No newline at end of file diff --git a/src/utils/UserConfigSchema.ts b/src/utils/UserConfigSchema.ts index d62200e2..8e161285 100644 --- a/src/utils/UserConfigSchema.ts +++ b/src/utils/UserConfigSchema.ts @@ -2,6 +2,11 @@ import { z } from 'astro/zod'; import * as S from './schemas'; export const UserConfigSchema = z.object({ + /** OPTIONAL - Disable Route Injector + * This option allows the user to disable the route injection system and utilize just the integraions other functions. Such as API, sitemap and robotstxt integrations. */ + disableRouteInjection: z.boolean().default(false), + /** OPTIONAL - Allows the user to disable "info" console output */ + disableConsoleOutput: z.boolean().default(false), /** OPTIONAL - Theme Selector * This option allows the user to replace the included theme with an external npm module */ theme: z.string().default('@matthiesenxyz/astro-ghostcms'), diff --git a/src/utils/virtual-imports.ts b/src/utils/virtual-imports.ts index ef3679bd..180750a2 100644 --- a/src/utils/virtual-imports.ts +++ b/src/utils/virtual-imports.ts @@ -20,7 +20,7 @@ export function viteGhostCMS( JSON.stringify(id.startsWith('.') ? resolve(fileURLToPath(root), id) : id); const modules = { - 'virtual:@matthiesenxyz/astro-ghostcms/user-config': `export default ${ JSON.stringify(opts) }` + 'virtual:@matthiesenxyz/astro-ghostcms/config': `export default ${ JSON.stringify(opts) }` } satisfies Record /** Mapping names prefixed with `\0` to their original form. */ diff --git a/src/utils/virtual.d.ts b/src/utils/virtual.d.ts index 4e6aa013..4e42dc63 100644 --- a/src/utils/virtual.d.ts +++ b/src/utils/virtual.d.ts @@ -1,4 +1,4 @@ -declare module 'virtual:@matthiesenxyz/astro-ghostcms/user-config' { +declare module 'virtual:@matthiesenxyz/astro-ghostcms/config' { const Config: import('./UserConfigSchema').UserConfig; export default Config; } \ No newline at end of file