diff --git a/.cache/pages.json b/.cache/pages.json index 5f4910f3c..57343e1db 100644 --- a/.cache/pages.json +++ b/.cache/pages.json @@ -22,29 +22,49 @@ "contact", "offline", { - "privacy": ["my-data"] + "privacy": [ + "my-data" + ] }, { - "services": ["consulting", "overview", "web-development"] + "services": [ + "consulting", + "overview", + "web-development" + ] }, { "tags": [ + "adTech", "apiDesign", + "articles", "aws", + "case-studies", + "cd", "ci", "cms", "code", + "contact", "crm", "databaseNormalization", "deployment", "devPortals", + "express", "graphql", + "home", + "Joomla!", + "laravel", + "marTech", "online-learning", + "rails", "react", "restful", + "scss", "services", + "site", "sqlOptimization", + "testimonials", "typescript" ] } -] +] \ No newline at end of file diff --git a/_TODO.md b/_TODO.md index 5b8ebc0ef..308a686ec 100644 --- a/_TODO.md +++ b/_TODO.md @@ -1,6 +1,8 @@ # TODO +continue + ## Refactor API Endpoints to Astro Actions ### Action / Domain / Responder Pattern @@ -143,24 +145,15 @@ cat.structure: Rules related to the document's overall structure, like the prope cat.tables: Rules for data tables, including headers and associations. cat.text-alternatives: Rules for ensuring that text alternatives are provided for non-text content, such as images. -## Privacy policy errors - -fatal: /home/kevin/Repos/Webstack: '/home/kevin/Repos/Webstack' is outside repository at '/home/kevin/Repos/Webstack Builders/Corporate Website/astro.webstackbuilders.com' - -[privacy-policy-version] Could not get privacy policy version from git: Command failed: git log -1 --format=%cd --date=format:%Y-%m-%d -- /home/kevin/Repos/Webstack Builders/Corporate Website/astro.webstackbuilders.com/src/pages/privacy/index.astro - -fatal: /home/kevin/Repos/Webstack: '/home/kevin/Repos/Webstack' is outside repository at '/home/kevin/Repos/Webstack Builders/Corporate Website/astro.webstackbuilders.com' +## Tags -⚠️ Privacy policy version fallback applied: 2025-12-08 +- Sitemap +- E2E all pages helper ## Build output errors 00:19:09 [WARN] [vite] [plugin:astro:assets:esm] context method emitFile() is not supported in serve mode. This plugin is likely not vite-compatible. -## Tags - -Can we add a markdown page to explain what each tag is, and use those pages instead of src/content/_tagList.ts to define the tags available? - ## Use Confetti on CTA forms `canvas-confetti` diff --git a/src/content.config.ts b/src/content.config.ts index c5184b03b..63a6099a0 100644 --- a/src/content.config.ts +++ b/src/content.config.ts @@ -10,7 +10,8 @@ */ import { defineCollection, reference, z, type SchemaContext } from 'astro:content' import { glob, file } from 'astro/loaders' -import { validTags } from '@content/_tagList' +import { existsSync, readdirSync } from 'node:fs' +import { fileURLToPath } from 'node:url' /** * Wraps a collection schema with a refinement that enforces breadcrumb title length limits */ import { withBreadcrumbTitleWarning } from '@lib/helpers/breadcrumbTitleLengthRefinement' @@ -21,6 +22,28 @@ import { withBreadcrumbTitleWarning } from '@lib/helpers/breadcrumbTitleLengthRe /** Only load markdown and MDX files that do not start with an underscore */ const pattern = '**\/[^_]*.{md,mdx}' +const tagContentDir = fileURLToPath(new URL('./content/tags', import.meta.url)) +const tagSlugs = readdirSync(tagContentDir, { withFileTypes: true }) + .filter(entry => entry.isDirectory() && !entry.name.startsWith('_')) + .filter(entry => { + const indexMd = new URL(`./content/tags/${entry.name}/index.md`, import.meta.url) + const indexMdx = new URL(`./content/tags/${entry.name}/index.mdx`, import.meta.url) + return fsExists(indexMd) || fsExists(indexMdx) + }) + .map(entry => entry.name) + .sort((a, b) => a.localeCompare(b, 'en')) + +if (tagSlugs.length === 0) { + throw new Error('No tags found. Add markdown files under src/content/tags.') +} + +type ZodEnumType = [string, ...string[]] +const validTags = tagSlugs as ZodEnumType + +function fsExists(url: URL) { + return existsSync(fileURLToPath(url)) +} + const createBaseCollectionSchema = ({ image }: SchemaContext) => z.object({ title: z.string(), @@ -121,6 +144,22 @@ const downloadsCollection = defineCollection({ * ================================================================================= */ +/** + * Tags + */ +const tagsCollection = defineCollection({ + loader: glob({ pattern: '**/index.{md,mdx}', base: './src/content/tags' }), + schema: ({ image }) => + z.object({ + slug: z.string(), + displayName: z.string(), + description: z.string(), + cover: image(), + coverAlt: z.string(), + featured: z.boolean().default(false), + }), +}) + /** * About */ @@ -223,5 +262,6 @@ export const collections = { contactData: contactDataCollection, downloads: downloadsCollection, services: servicesCollection, + tags: tagsCollection, testimonials: testimonialCollection, } diff --git a/src/content/_tagList.ts b/src/content/_tagList.ts deleted file mode 100644 index 5e5f4ef2d..000000000 --- a/src/content/_tagList.ts +++ /dev/null @@ -1,60 +0,0 @@ -/** - * List of tags to use for validation. These can't be an Astro Collection because - * they're used to validate that other Astro Collections have valid tags. - */ -type ZodEnumType = [string, ...string[]] - -const pageTags: ZodEnumType = [ - `articles`, - `case-studies`, - `contact`, - `home`, - `services`, - `site`, - `testimonials`, -] - -const blogTopicTags: ZodEnumType = [`cms`, `code`, `Joomla!`, `online-learning`] - -const serviceOfferingsTags: ZodEnumType = [ - `adTech`, - `apiDesign`, - `aws`, - `cd`, - `ci`, - `cms`, - `crm`, - `databaseNormalization`, - `deployment`, - `devPortals`, - `express`, - `graphql`, - `laravel`, - `marTech`, - `rails`, - `react`, - `restful`, - `scss`, - `sqlOptimization`, - `typescript`, -] - -export const validTags: ZodEnumType = [...blogTopicTags, ...pageTags, ...serviceOfferingsTags] - -/** List of normalizations for tag names that can be used in UI */ -export const exceptions = { - apiDesign: `API Design`, - aws: `AWS`, - cd: `CD`, - ci: `CI`, - cms: `CMS`, - crm: `CRM`, - graphql: `GraphQl`, - restful: `RESTful`, - scss: `SCSS`, - sqlOptimization: `SQL Optimization`, - typescript: `TypeScript`, -} - -// site, tagline, testimonials, articles, case-studies, services, featured, -// casestudies, sitemap, home diff --git a/src/content/tags/Joomla!/cover.png b/src/content/tags/Joomla!/cover.png new file mode 100644 index 000000000..b7084c0cf Binary files /dev/null and b/src/content/tags/Joomla!/cover.png differ diff --git a/src/content/tags/Joomla!/index.md b/src/content/tags/Joomla!/index.md new file mode 100644 index 000000000..d57abed1a --- /dev/null +++ b/src/content/tags/Joomla!/index.md @@ -0,0 +1,10 @@ +--- +slug: "Joomla!" +displayName: "Joomla!" +description: "Content tagged with Joomla!." +cover: "./cover.png" +coverAlt: "Joomla!" +featured: false +--- + +Joomla! content will be curated here. diff --git a/src/content/tags/Joomla!/joomla.svg b/src/content/tags/Joomla!/joomla.svg new file mode 100644 index 000000000..1e3fda10a --- /dev/null +++ b/src/content/tags/Joomla!/joomla.svg @@ -0,0 +1,6 @@ + + + + + Joomla! + diff --git a/src/content/tags/adTech/cover.png b/src/content/tags/adTech/cover.png new file mode 100644 index 000000000..b7084c0cf Binary files /dev/null and b/src/content/tags/adTech/cover.png differ diff --git a/src/content/tags/adTech/index.md b/src/content/tags/adTech/index.md new file mode 100644 index 000000000..cecd5e04a --- /dev/null +++ b/src/content/tags/adTech/index.md @@ -0,0 +1,10 @@ +--- +slug: "adTech" +displayName: "Ad Tech" +description: "Content tagged with Ad Tech." +cover: "./cover.png" +coverAlt: "Ad Tech" +featured: false +--- + +Ad Tech content will be curated here. diff --git a/src/content/tags/apiDesign/apidesign.svg b/src/content/tags/apiDesign/apidesign.svg new file mode 100644 index 000000000..2909dfeae --- /dev/null +++ b/src/content/tags/apiDesign/apidesign.svg @@ -0,0 +1,6 @@ + + + + + API Design + diff --git a/src/content/tags/apiDesign/cover.png b/src/content/tags/apiDesign/cover.png new file mode 100644 index 000000000..b7084c0cf Binary files /dev/null and b/src/content/tags/apiDesign/cover.png differ diff --git a/src/content/tags/apiDesign/index.md b/src/content/tags/apiDesign/index.md new file mode 100644 index 000000000..e1104c8c0 --- /dev/null +++ b/src/content/tags/apiDesign/index.md @@ -0,0 +1,10 @@ +--- +slug: "apiDesign" +displayName: "API Design" +description: "Content tagged with API Design." +cover: "./cover.png" +coverAlt: "API Design" +featured: false +--- + +API Design content will be curated here. diff --git a/src/content/tags/articles/articles.svg b/src/content/tags/articles/articles.svg new file mode 100644 index 000000000..2f1e9f996 --- /dev/null +++ b/src/content/tags/articles/articles.svg @@ -0,0 +1,6 @@ + + + + + articles + diff --git a/src/content/tags/articles/cover.png b/src/content/tags/articles/cover.png new file mode 100644 index 000000000..b7084c0cf Binary files /dev/null and b/src/content/tags/articles/cover.png differ diff --git a/src/content/tags/articles/index.md b/src/content/tags/articles/index.md new file mode 100644 index 000000000..e73272782 --- /dev/null +++ b/src/content/tags/articles/index.md @@ -0,0 +1,10 @@ +--- +slug: "articles" +displayName: "articles" +description: "Content tagged with articles." +cover: "./cover.png" +coverAlt: "articles" +featured: false +--- + +articles content will be curated here. diff --git a/src/content/tags/aws/aws.svg b/src/content/tags/aws/aws.svg new file mode 100644 index 000000000..5f622ab2d --- /dev/null +++ b/src/content/tags/aws/aws.svg @@ -0,0 +1,6 @@ + + + + + AWS + diff --git a/src/content/tags/aws/cover.png b/src/content/tags/aws/cover.png new file mode 100644 index 000000000..b7084c0cf Binary files /dev/null and b/src/content/tags/aws/cover.png differ diff --git a/src/content/tags/aws/index.md b/src/content/tags/aws/index.md new file mode 100644 index 000000000..e6a35225d --- /dev/null +++ b/src/content/tags/aws/index.md @@ -0,0 +1,10 @@ +--- +slug: "aws" +displayName: "AWS" +description: "Content tagged with AWS." +cover: "./cover.png" +coverAlt: "AWS" +featured: false +--- + +AWS content will be curated here. diff --git a/src/content/tags/case-studies/case-studies.svg b/src/content/tags/case-studies/case-studies.svg new file mode 100644 index 000000000..dfb8c860a --- /dev/null +++ b/src/content/tags/case-studies/case-studies.svg @@ -0,0 +1,6 @@ + + + + + Case Studies + diff --git a/src/content/tags/case-studies/cover.png b/src/content/tags/case-studies/cover.png new file mode 100644 index 000000000..b7084c0cf Binary files /dev/null and b/src/content/tags/case-studies/cover.png differ diff --git a/src/content/tags/case-studies/index.md b/src/content/tags/case-studies/index.md new file mode 100644 index 000000000..d71770316 --- /dev/null +++ b/src/content/tags/case-studies/index.md @@ -0,0 +1,10 @@ +--- +slug: "case-studies" +displayName: "Case Studies" +description: "Content tagged with Case Studies." +cover: "./cover.png" +coverAlt: "Case Studies" +featured: false +--- + +Case Studies content will be curated here. diff --git a/src/content/tags/cd/cd.svg b/src/content/tags/cd/cd.svg new file mode 100644 index 000000000..e5dd5e941 --- /dev/null +++ b/src/content/tags/cd/cd.svg @@ -0,0 +1,6 @@ + + + + + CD + diff --git a/src/content/tags/cd/cover.png b/src/content/tags/cd/cover.png new file mode 100644 index 000000000..b7084c0cf Binary files /dev/null and b/src/content/tags/cd/cover.png differ diff --git a/src/content/tags/cd/index.md b/src/content/tags/cd/index.md new file mode 100644 index 000000000..56668769f --- /dev/null +++ b/src/content/tags/cd/index.md @@ -0,0 +1,10 @@ +--- +slug: "cd" +displayName: "CD" +description: "Content tagged with CD." +cover: "./cover.png" +coverAlt: "CD" +featured: false +--- + +CD content will be curated here. diff --git a/src/content/tags/ci/ci.svg b/src/content/tags/ci/ci.svg new file mode 100644 index 000000000..8279bee07 --- /dev/null +++ b/src/content/tags/ci/ci.svg @@ -0,0 +1,6 @@ + + + + + CI + diff --git a/src/content/tags/ci/cover.png b/src/content/tags/ci/cover.png new file mode 100644 index 000000000..b7084c0cf Binary files /dev/null and b/src/content/tags/ci/cover.png differ diff --git a/src/content/tags/ci/index.md b/src/content/tags/ci/index.md new file mode 100644 index 000000000..6c6c00008 --- /dev/null +++ b/src/content/tags/ci/index.md @@ -0,0 +1,10 @@ +--- +slug: "ci" +displayName: "CI" +description: "Content tagged with CI." +cover: "./cover.png" +coverAlt: "CI" +featured: false +--- + +CI content will be curated here. diff --git a/src/content/tags/cms/cms.svg b/src/content/tags/cms/cms.svg new file mode 100644 index 000000000..3a97983c9 --- /dev/null +++ b/src/content/tags/cms/cms.svg @@ -0,0 +1,6 @@ + + + + + CMS + diff --git a/src/content/tags/cms/cover.png b/src/content/tags/cms/cover.png new file mode 100644 index 000000000..b7084c0cf Binary files /dev/null and b/src/content/tags/cms/cover.png differ diff --git a/src/content/tags/cms/index.md b/src/content/tags/cms/index.md new file mode 100644 index 000000000..b5b4a1d03 --- /dev/null +++ b/src/content/tags/cms/index.md @@ -0,0 +1,10 @@ +--- +slug: "cms" +displayName: "CMS" +description: "Content tagged with CMS." +cover: "./cover.png" +coverAlt: "CMS" +featured: false +--- + +CMS content will be curated here. diff --git a/src/content/tags/code/code.svg b/src/content/tags/code/code.svg new file mode 100644 index 000000000..5267b9f8d --- /dev/null +++ b/src/content/tags/code/code.svg @@ -0,0 +1,6 @@ + + + + + code + diff --git a/src/content/tags/code/cover.png b/src/content/tags/code/cover.png new file mode 100644 index 000000000..b7084c0cf Binary files /dev/null and b/src/content/tags/code/cover.png differ diff --git a/src/content/tags/code/index.md b/src/content/tags/code/index.md new file mode 100644 index 000000000..678207499 --- /dev/null +++ b/src/content/tags/code/index.md @@ -0,0 +1,10 @@ +--- +slug: "code" +displayName: "code" +description: "Content tagged with code." +cover: "./cover.png" +coverAlt: "code" +featured: false +--- + +code content will be curated here. diff --git a/src/content/tags/contact/contact.svg b/src/content/tags/contact/contact.svg new file mode 100644 index 000000000..3bb051c49 --- /dev/null +++ b/src/content/tags/contact/contact.svg @@ -0,0 +1,6 @@ + + + + + contact + diff --git a/src/content/tags/contact/cover.png b/src/content/tags/contact/cover.png new file mode 100644 index 000000000..b7084c0cf Binary files /dev/null and b/src/content/tags/contact/cover.png differ diff --git a/src/content/tags/contact/index.md b/src/content/tags/contact/index.md new file mode 100644 index 000000000..05b392013 --- /dev/null +++ b/src/content/tags/contact/index.md @@ -0,0 +1,10 @@ +--- +slug: "contact" +displayName: "contact" +description: "Content tagged with contact." +cover: "./cover.png" +coverAlt: "contact" +featured: false +--- + +contact content will be curated here. diff --git a/src/content/tags/crm/cover.png b/src/content/tags/crm/cover.png new file mode 100644 index 000000000..b7084c0cf Binary files /dev/null and b/src/content/tags/crm/cover.png differ diff --git a/src/content/tags/crm/crm.svg b/src/content/tags/crm/crm.svg new file mode 100644 index 000000000..3fd9b22fb --- /dev/null +++ b/src/content/tags/crm/crm.svg @@ -0,0 +1,6 @@ + + + + + CRM + diff --git a/src/content/tags/crm/index.md b/src/content/tags/crm/index.md new file mode 100644 index 000000000..ca1ad266e --- /dev/null +++ b/src/content/tags/crm/index.md @@ -0,0 +1,10 @@ +--- +slug: "crm" +displayName: "CRM" +description: "Content tagged with CRM." +cover: "./cover.png" +coverAlt: "CRM" +featured: false +--- + +CRM content will be curated here. diff --git a/src/content/tags/databaseNormalization/cover.png b/src/content/tags/databaseNormalization/cover.png new file mode 100644 index 000000000..b7084c0cf Binary files /dev/null and b/src/content/tags/databaseNormalization/cover.png differ diff --git a/src/content/tags/databaseNormalization/databasenormalization.svg b/src/content/tags/databaseNormalization/databasenormalization.svg new file mode 100644 index 000000000..f322059e8 --- /dev/null +++ b/src/content/tags/databaseNormalization/databasenormalization.svg @@ -0,0 +1,6 @@ + + + + + Database Normalization + diff --git a/src/content/tags/databaseNormalization/index.md b/src/content/tags/databaseNormalization/index.md new file mode 100644 index 000000000..9d1a6cc01 --- /dev/null +++ b/src/content/tags/databaseNormalization/index.md @@ -0,0 +1,10 @@ +--- +slug: "databaseNormalization" +displayName: "Database Normalization" +description: "Content tagged with Database Normalization." +cover: "./cover.png" +coverAlt: "Database Normalization" +featured: false +--- + +Database Normalization content will be curated here. diff --git a/src/content/tags/deployment/cover.png b/src/content/tags/deployment/cover.png new file mode 100644 index 000000000..b7084c0cf Binary files /dev/null and b/src/content/tags/deployment/cover.png differ diff --git a/src/content/tags/deployment/deployment.svg b/src/content/tags/deployment/deployment.svg new file mode 100644 index 000000000..cb846c61e --- /dev/null +++ b/src/content/tags/deployment/deployment.svg @@ -0,0 +1,6 @@ + + + + + deployment + diff --git a/src/content/tags/deployment/index.md b/src/content/tags/deployment/index.md new file mode 100644 index 000000000..b8678510a --- /dev/null +++ b/src/content/tags/deployment/index.md @@ -0,0 +1,10 @@ +--- +slug: "deployment" +displayName: "deployment" +description: "Content tagged with deployment." +cover: "./cover.png" +coverAlt: "deployment" +featured: false +--- + +deployment content will be curated here. diff --git a/src/content/tags/devPortals/cover.png b/src/content/tags/devPortals/cover.png new file mode 100644 index 000000000..b7084c0cf Binary files /dev/null and b/src/content/tags/devPortals/cover.png differ diff --git a/src/content/tags/devPortals/devportals.svg b/src/content/tags/devPortals/devportals.svg new file mode 100644 index 000000000..74cf2a076 --- /dev/null +++ b/src/content/tags/devPortals/devportals.svg @@ -0,0 +1,6 @@ + + + + + Dev Portals + diff --git a/src/content/tags/devPortals/index.md b/src/content/tags/devPortals/index.md new file mode 100644 index 000000000..9ebabbbf0 --- /dev/null +++ b/src/content/tags/devPortals/index.md @@ -0,0 +1,10 @@ +--- +slug: "devPortals" +displayName: "Dev Portals" +description: "Content tagged with Dev Portals." +cover: "./cover.png" +coverAlt: "Dev Portals" +featured: false +--- + +Dev Portals content will be curated here. diff --git a/src/content/tags/express/cover.png b/src/content/tags/express/cover.png new file mode 100644 index 000000000..b7084c0cf Binary files /dev/null and b/src/content/tags/express/cover.png differ diff --git a/src/content/tags/express/express.svg b/src/content/tags/express/express.svg new file mode 100644 index 000000000..c63f793ee --- /dev/null +++ b/src/content/tags/express/express.svg @@ -0,0 +1,6 @@ + + + + + express + diff --git a/src/content/tags/express/index.md b/src/content/tags/express/index.md new file mode 100644 index 000000000..64ce45c9c --- /dev/null +++ b/src/content/tags/express/index.md @@ -0,0 +1,10 @@ +--- +slug: "express" +displayName: "express" +description: "Content tagged with express." +cover: "./cover.png" +coverAlt: "express" +featured: false +--- + +express content will be curated here. diff --git a/src/content/tags/graphql/cover.png b/src/content/tags/graphql/cover.png new file mode 100644 index 000000000..b7084c0cf Binary files /dev/null and b/src/content/tags/graphql/cover.png differ diff --git a/src/content/tags/graphql/graphql.svg b/src/content/tags/graphql/graphql.svg new file mode 100644 index 000000000..8f02ad338 --- /dev/null +++ b/src/content/tags/graphql/graphql.svg @@ -0,0 +1,6 @@ + + + + + GraphQl + diff --git a/src/content/tags/graphql/index.md b/src/content/tags/graphql/index.md new file mode 100644 index 000000000..98fb4e9d6 --- /dev/null +++ b/src/content/tags/graphql/index.md @@ -0,0 +1,10 @@ +--- +slug: "graphql" +displayName: "GraphQl" +description: "Content tagged with GraphQl." +cover: "./cover.png" +coverAlt: "GraphQl" +featured: false +--- + +GraphQl content will be curated here. diff --git a/src/content/tags/home/cover.png b/src/content/tags/home/cover.png new file mode 100644 index 000000000..b7084c0cf Binary files /dev/null and b/src/content/tags/home/cover.png differ diff --git a/src/content/tags/home/home.svg b/src/content/tags/home/home.svg new file mode 100644 index 000000000..c4808cd6e --- /dev/null +++ b/src/content/tags/home/home.svg @@ -0,0 +1,6 @@ + + + + + home + diff --git a/src/content/tags/home/index.md b/src/content/tags/home/index.md new file mode 100644 index 000000000..056a5fa34 --- /dev/null +++ b/src/content/tags/home/index.md @@ -0,0 +1,10 @@ +--- +slug: "home" +displayName: "home" +description: "Content tagged with home." +cover: "./cover.png" +coverAlt: "home" +featured: false +--- + +home content will be curated here. diff --git a/src/content/tags/laravel/cover.png b/src/content/tags/laravel/cover.png new file mode 100644 index 000000000..b7084c0cf Binary files /dev/null and b/src/content/tags/laravel/cover.png differ diff --git a/src/content/tags/laravel/index.md b/src/content/tags/laravel/index.md new file mode 100644 index 000000000..2973ab8d0 --- /dev/null +++ b/src/content/tags/laravel/index.md @@ -0,0 +1,10 @@ +--- +slug: "laravel" +displayName: "laravel" +description: "Content tagged with laravel." +cover: "./cover.png" +coverAlt: "laravel" +featured: false +--- + +laravel content will be curated here. diff --git a/src/content/tags/laravel/laravel.svg b/src/content/tags/laravel/laravel.svg new file mode 100644 index 000000000..7104fa3fb --- /dev/null +++ b/src/content/tags/laravel/laravel.svg @@ -0,0 +1,6 @@ + + + + + laravel + diff --git a/src/content/tags/marTech/cover.png b/src/content/tags/marTech/cover.png new file mode 100644 index 000000000..b7084c0cf Binary files /dev/null and b/src/content/tags/marTech/cover.png differ diff --git a/src/content/tags/marTech/index.md b/src/content/tags/marTech/index.md new file mode 100644 index 000000000..4c43b430f --- /dev/null +++ b/src/content/tags/marTech/index.md @@ -0,0 +1,10 @@ +--- +slug: "marTech" +displayName: "Mar Tech" +description: "Content tagged with Mar Tech." +cover: "./cover.png" +coverAlt: "Mar Tech" +featured: false +--- + +Mar Tech content will be curated here. diff --git a/src/content/tags/marTech/martech.svg b/src/content/tags/marTech/martech.svg new file mode 100644 index 000000000..2ee955d92 --- /dev/null +++ b/src/content/tags/marTech/martech.svg @@ -0,0 +1,6 @@ + + + + + Mar Tech + diff --git a/src/content/tags/online-learning/cover.png b/src/content/tags/online-learning/cover.png new file mode 100644 index 000000000..b7084c0cf Binary files /dev/null and b/src/content/tags/online-learning/cover.png differ diff --git a/src/content/tags/online-learning/index.md b/src/content/tags/online-learning/index.md new file mode 100644 index 000000000..76e5381bb --- /dev/null +++ b/src/content/tags/online-learning/index.md @@ -0,0 +1,10 @@ +--- +slug: "online-learning" +displayName: "Online Learning" +description: "Content tagged with Online Learning." +cover: "./cover.png" +coverAlt: "Online Learning" +featured: false +--- + +Online Learning content will be curated here. diff --git a/src/content/tags/online-learning/online-learning.svg b/src/content/tags/online-learning/online-learning.svg new file mode 100644 index 000000000..3d8a756c0 --- /dev/null +++ b/src/content/tags/online-learning/online-learning.svg @@ -0,0 +1,6 @@ + + + + + Online Learning + diff --git a/src/content/tags/rails/cover.png b/src/content/tags/rails/cover.png new file mode 100644 index 000000000..b7084c0cf Binary files /dev/null and b/src/content/tags/rails/cover.png differ diff --git a/src/content/tags/rails/index.md b/src/content/tags/rails/index.md new file mode 100644 index 000000000..9ce23c428 --- /dev/null +++ b/src/content/tags/rails/index.md @@ -0,0 +1,10 @@ +--- +slug: "rails" +displayName: "rails" +description: "Content tagged with rails." +cover: "./cover.png" +coverAlt: "rails" +featured: false +--- + +rails content will be curated here. diff --git a/src/content/tags/rails/rails.svg b/src/content/tags/rails/rails.svg new file mode 100644 index 000000000..e09e66616 --- /dev/null +++ b/src/content/tags/rails/rails.svg @@ -0,0 +1,6 @@ + + + + + rails + diff --git a/src/content/tags/react/cover.png b/src/content/tags/react/cover.png new file mode 100644 index 000000000..b7084c0cf Binary files /dev/null and b/src/content/tags/react/cover.png differ diff --git a/src/content/tags/react/index.md b/src/content/tags/react/index.md new file mode 100644 index 000000000..787b05f03 --- /dev/null +++ b/src/content/tags/react/index.md @@ -0,0 +1,10 @@ +--- +slug: "react" +displayName: "react" +description: "Content tagged with react." +cover: "./cover.png" +coverAlt: "react" +featured: false +--- + +react content will be curated here. diff --git a/src/content/tags/react/react.svg b/src/content/tags/react/react.svg new file mode 100644 index 000000000..c070bff9a --- /dev/null +++ b/src/content/tags/react/react.svg @@ -0,0 +1,6 @@ + + + + + react + diff --git a/src/content/tags/restful/cover.png b/src/content/tags/restful/cover.png new file mode 100644 index 000000000..b7084c0cf Binary files /dev/null and b/src/content/tags/restful/cover.png differ diff --git a/src/content/tags/restful/index.md b/src/content/tags/restful/index.md new file mode 100644 index 000000000..7cbfa8669 --- /dev/null +++ b/src/content/tags/restful/index.md @@ -0,0 +1,10 @@ +--- +slug: "restful" +displayName: "RESTful" +description: "Content tagged with RESTful." +cover: "./cover.png" +coverAlt: "RESTful" +featured: false +--- + +RESTful content will be curated here. diff --git a/src/content/tags/restful/restful.svg b/src/content/tags/restful/restful.svg new file mode 100644 index 000000000..afa10aa88 --- /dev/null +++ b/src/content/tags/restful/restful.svg @@ -0,0 +1,6 @@ + + + + + RESTful + diff --git a/src/content/tags/scss/cover.png b/src/content/tags/scss/cover.png new file mode 100644 index 000000000..b7084c0cf Binary files /dev/null and b/src/content/tags/scss/cover.png differ diff --git a/src/content/tags/scss/index.md b/src/content/tags/scss/index.md new file mode 100644 index 000000000..53093e575 --- /dev/null +++ b/src/content/tags/scss/index.md @@ -0,0 +1,10 @@ +--- +slug: "scss" +displayName: "SCSS" +description: "Content tagged with SCSS." +cover: "./cover.png" +coverAlt: "SCSS" +featured: false +--- + +SCSS content will be curated here. diff --git a/src/content/tags/scss/scss.svg b/src/content/tags/scss/scss.svg new file mode 100644 index 000000000..9c757bddc --- /dev/null +++ b/src/content/tags/scss/scss.svg @@ -0,0 +1,6 @@ + + + + + SCSS + diff --git a/src/content/tags/services/cover.png b/src/content/tags/services/cover.png new file mode 100644 index 000000000..b7084c0cf Binary files /dev/null and b/src/content/tags/services/cover.png differ diff --git a/src/content/tags/services/index.md b/src/content/tags/services/index.md new file mode 100644 index 000000000..f5691238d --- /dev/null +++ b/src/content/tags/services/index.md @@ -0,0 +1,10 @@ +--- +slug: "services" +displayName: "services" +description: "Content tagged with services." +cover: "./cover.png" +coverAlt: "services" +featured: false +--- + +services content will be curated here. diff --git a/src/content/tags/services/services.svg b/src/content/tags/services/services.svg new file mode 100644 index 000000000..75a1bb7e5 --- /dev/null +++ b/src/content/tags/services/services.svg @@ -0,0 +1,6 @@ + + + + + services + diff --git a/src/content/tags/site/cover.png b/src/content/tags/site/cover.png new file mode 100644 index 000000000..b7084c0cf Binary files /dev/null and b/src/content/tags/site/cover.png differ diff --git a/src/content/tags/site/index.md b/src/content/tags/site/index.md new file mode 100644 index 000000000..112167375 --- /dev/null +++ b/src/content/tags/site/index.md @@ -0,0 +1,10 @@ +--- +slug: "site" +displayName: "site" +description: "Content tagged with site." +cover: "./cover.png" +coverAlt: "site" +featured: false +--- + +site content will be curated here. diff --git a/src/content/tags/site/site.svg b/src/content/tags/site/site.svg new file mode 100644 index 000000000..b1142d828 --- /dev/null +++ b/src/content/tags/site/site.svg @@ -0,0 +1,6 @@ + + + + + site + diff --git a/src/content/tags/sqlOptimization/cover.png b/src/content/tags/sqlOptimization/cover.png new file mode 100644 index 000000000..b7084c0cf Binary files /dev/null and b/src/content/tags/sqlOptimization/cover.png differ diff --git a/src/content/tags/sqlOptimization/index.md b/src/content/tags/sqlOptimization/index.md new file mode 100644 index 000000000..08cfb9405 --- /dev/null +++ b/src/content/tags/sqlOptimization/index.md @@ -0,0 +1,10 @@ +--- +slug: "sqlOptimization" +displayName: "SQL Optimization" +description: "Content tagged with SQL Optimization." +cover: "./cover.png" +coverAlt: "SQL Optimization" +featured: false +--- + +SQL Optimization content will be curated here. diff --git a/src/content/tags/sqlOptimization/sqloptimization.svg b/src/content/tags/sqlOptimization/sqloptimization.svg new file mode 100644 index 000000000..254e0d97a --- /dev/null +++ b/src/content/tags/sqlOptimization/sqloptimization.svg @@ -0,0 +1,6 @@ + + + + + SQL Optimization + diff --git a/src/content/tags/testimonials/cover.png b/src/content/tags/testimonials/cover.png new file mode 100644 index 000000000..b7084c0cf Binary files /dev/null and b/src/content/tags/testimonials/cover.png differ diff --git a/src/content/tags/testimonials/index.md b/src/content/tags/testimonials/index.md new file mode 100644 index 000000000..5203f28f7 --- /dev/null +++ b/src/content/tags/testimonials/index.md @@ -0,0 +1,10 @@ +--- +slug: "testimonials" +displayName: "testimonials" +description: "Content tagged with testimonials." +cover: "./cover.png" +coverAlt: "testimonials" +featured: false +--- + +testimonials content will be curated here. diff --git a/src/content/tags/testimonials/testimonials.svg b/src/content/tags/testimonials/testimonials.svg new file mode 100644 index 000000000..72273f47a --- /dev/null +++ b/src/content/tags/testimonials/testimonials.svg @@ -0,0 +1,6 @@ + + + + + testimonials + diff --git a/src/content/tags/typescript/cover.png b/src/content/tags/typescript/cover.png new file mode 100644 index 000000000..b7084c0cf Binary files /dev/null and b/src/content/tags/typescript/cover.png differ diff --git a/src/content/tags/typescript/index.md b/src/content/tags/typescript/index.md new file mode 100644 index 000000000..fbe2c356b --- /dev/null +++ b/src/content/tags/typescript/index.md @@ -0,0 +1,10 @@ +--- +slug: "typescript" +displayName: "TypeScript" +description: "Content tagged with TypeScript." +cover: "./cover.png" +coverAlt: "TypeScript" +featured: false +--- + +TypeScript content will be curated here. diff --git a/src/content/tags/typescript/typescript.svg b/src/content/tags/typescript/typescript.svg new file mode 100644 index 000000000..3cfc3ccfe --- /dev/null +++ b/src/content/tags/typescript/typescript.svg @@ -0,0 +1,6 @@ + + + + + TypeScript + diff --git a/src/layouts/BaseLayout.astro b/src/layouts/BaseLayout.astro index d249b1c3f..943a42933 100644 --- a/src/layouts/BaseLayout.astro +++ b/src/layouts/BaseLayout.astro @@ -19,6 +19,8 @@ import '@styles/icons.css' export interface Props { author?: string + /** Optional title override for the breadcrumbs UI */ + breadcrumbTitle?: string /** Enforce that child is passed to slot */ children: unknown /** Optional metadata for articles */ @@ -46,6 +48,7 @@ export interface Props { const { author, + breadcrumbTitle, contentType, description, modifiedDate, @@ -95,7 +98,7 @@ const {
- + {/* SLOT: default (unnamed) - Main page content */} diff --git a/src/lib/config/siteUrlServer.ts b/src/lib/config/siteUrlServer.ts index d1a79bf33..7bc016003 100644 --- a/src/lib/config/siteUrlServer.ts +++ b/src/lib/config/siteUrlServer.ts @@ -12,7 +12,6 @@ const resolvedDevServerPort = devServerPort && devServerPort.length > 0 ? devSer /** Called from astro.config.ts to determine "site" config key */ export const getSiteUrl = (): string => { if (isVercel() && domain) { - console.log(`✅ Using production environment with domain from package.json: ${domain}`) return `https://${domain}` } @@ -20,13 +19,5 @@ export const getSiteUrl = (): string => { throw new BuildError('❌ Domain is required in package.json for Vercel production environment.') } - if (devServerPort && devServerPort.length > 0) { - console.log(`Using development environment on port ${resolvedDevServerPort}.`) - } else { - console.log( - '✅ Using default value of "http://localhost:4321" for the site URL. DEV_SERVER_PORT is not set in the environment.' - ) - } - return `http://localhost:${resolvedDevServerPort}` } diff --git a/src/pages/api/_environment/siteUrlApi.ts b/src/pages/api/_environment/siteUrlApi.ts index 9761e6950..1c146d9ab 100644 --- a/src/pages/api/_environment/siteUrlApi.ts +++ b/src/pages/api/_environment/siteUrlApi.ts @@ -12,17 +12,8 @@ const { domain } = packageJson /** Called from astro.config.ts to determine "site" config key */ export const getSiteUrl = (): string => { if (isVercel() && domain) { - console.log(`Using production environment with domain from package.json: ${domain}`) return `https://${domain}` } - if (devServerPort && devServerPort.length > 0) { - console.log(`Using development environment on port ${resolvedDevServerPort}.`) - } else { - console.log( - 'Using default value of "http://localhost:4321" for the site URL. DEV_SERVER_PORT is not set in the environment.' - ) - } - return `http://localhost:${resolvedDevServerPort}` } diff --git a/src/pages/tags/[tag].astro b/src/pages/tags/[tag].astro index 6342844f9..c80a04496 100644 --- a/src/pages/tags/[tag].astro +++ b/src/pages/tags/[tag].astro @@ -1,9 +1,8 @@ --- -import { type CollectionEntry, getCollection } from 'astro:content' +import { type CollectionEntry, getCollection, render } from 'astro:content' import { Picture } from 'astro:assets' import { isDev, isProd } from '@lib/config/environmentServer' import BaseLayout from '@layouts/BaseLayout.astro' -import { exceptions } from '@content/_tagList' export interface Params { tag: string @@ -20,6 +19,8 @@ export interface Props { } export async function getStaticPaths() { + const allTags = await getCollection('tags') + // Get all content collections with tags const allArticles = await getCollection('articles', ({ data }) => { return isDev() || (isProd() && data.isDraft !== true) @@ -45,8 +46,12 @@ export async function getStaticPaths() { const uniqueTags = [...new Set(allContent.map(item => item.data.tags).flat())] - return uniqueTags.map(tag => { - const filteredContent = allContent.filter(item => item.data.tags.includes(tag)) + return allTags.map(tagEntry => { + const tag = tagEntry.data.slug + const filteredContent = uniqueTags.includes(tag) + ? allContent.filter(item => item.data.tags.includes(tag)) + : [] + return { params: { tag }, props: { content: filteredContent }, @@ -57,6 +62,18 @@ export async function getStaticPaths() { const { tag } = Astro.params const { content: allTagContent } = Astro.props +const [tagEntry] = await getCollection('tags', ({ data }) => data.slug === tag) +if (!tagEntry) { + throw new Error(`Unknown tag: ${tag}`) +} + +const allTags = await getCollection('tags') +const tagDisplayNameBySlug = Object.fromEntries( + allTags.map(t => [t.data.slug, t.data.displayName]) +) + +const { Content: TagContent } = await render(tagEntry) + // Pagination setup const ITEMS_PER_PAGE = 12 const currentPage = parseInt(Astro.url.searchParams.get('page') || '1') @@ -72,9 +89,8 @@ const sortedContent = allTagContent.sort( const paginatedContent = sortedContent.slice(startIndex, endIndex) -// Function to get display name for tags -const getTagDisplayName = (tag: string) => { - return exceptions[tag as keyof typeof exceptions] || tag +const getTagDisplayName = (tagSlug: string) => { + return tagDisplayNameBySlug[tagSlug] || tagSlug } const typeMetadata = { @@ -84,10 +100,11 @@ const typeMetadata = { download: { label: 'Download', badgeClass: 'bg-secondary', hrefBase: 'downloads' }, } as const -const displayName = getTagDisplayName(tag) -const path = `/tags/${tag}/` -const pageDescription= `List of content tagged with ${displayName}` +const displayName = tagEntry.data.displayName +const path = `/tags/${tag}` +const pageDescription = tagEntry.data.description const pageTitle = `${displayName} - Tag` +const breadcrumbTitle = displayName const section = 'Tags' --- @@ -95,21 +112,44 @@ const section = 'Tags' pageTitle={pageTitle} path={path} description={pageDescription} + breadcrumbTitle={breadcrumbTitle} section={section} >
-
-

- {displayName} -

-

- {totalItems} item{totalItems !== 1 ? 's' : ''} tagged with {displayName.toLowerCase()} -

- +
+
+
+
+ {tagEntry.data.coverAlt} +
+
+ +
+

+ {displayName} +

+

+ {totalItems} item{totalItems !== 1 ? 's' : ''} tagged with {displayName.toLowerCase()} +

+
+ +
+ + +
+
{ @@ -122,8 +162,8 @@ const section = 'Tags' return (
- - {item.data.cover && ( + {item.data.cover && ( +
- )} +
+ )} -
-
- - {typeMeta.label} - - -
+
+
+ + {typeMeta.label} + + +
-

+

+ {item.data.title} -

+ + - {item.data.description && ( -

- {item.data.description} -

+ {item.data.description && ( +

+ {item.data.description} +

+ )} + +
+ {/* Client or Author info */} + {'client' in item.data && item.data.client && ( + + Client: {item.data.client} + )} -
- {/* Client or Author info */} - {'client' in item.data && item.data.client && ( - - Client: {item.data.client} - - )} - - {/* Additional tags */} - {item.data.tags && item.data.tags.length > 1 && ( -
- {item.data.tags - .filter((t: string) => t !== tag) - .slice(0, 3) - .map((relatedTag: string) => ( - - {getTagDisplayName(relatedTag)} - - ))} -
- )} -
+ {/* Additional tags */} + {item.data.tags && item.data.tags.length > 1 && ( +
+ {item.data.tags + .filter((t: string) => t !== tag) + .slice(0, 3) + .map((relatedTag: string) => ( + + {getTagDisplayName(relatedTag)} + + ))} +
+ )}
- +
) })} @@ -278,7 +323,7 @@ const section = 'Tags'

No content found for this tag.

- + Browse other tags
diff --git a/src/pages/tags/index.astro b/src/pages/tags/index.astro index 245b4957c..3bc7d4448 100644 --- a/src/pages/tags/index.astro +++ b/src/pages/tags/index.astro @@ -3,7 +3,6 @@ import { getCollection } from 'astro:content' import { Picture } from 'astro:assets' import { isDev, isProd } from '@lib/config/environmentServer' import BaseLayout from '@layouts/BaseLayout.astro' -import { exceptions } from '@content/_tagList' // Get all content collections with tags const allArticles = await getCollection('articles', ({ data }) => { @@ -25,24 +24,20 @@ const allContent = [ ...allServices.map(item => ({ ...item, type: 'service' })), ].sort((a, b) => new Date(b.data.publishDate).getTime() - new Date(a.data.publishDate).getTime()) -// Extract all unique tags from all content -const allTags = Array.from(new Set(allContent.flatMap(item => item.data.tags || []))).filter( - tag => tag -) // Remove any undefined/null tags - -// Function to get display name for tags -const getTagDisplayName = (tag: string) => { - return exceptions[tag as keyof typeof exceptions] || tag -} +const allTags = await getCollection('tags') // Function to get content preview for a specific tag -const getContentPreviewForTag = (tag: string, limit: number = 4) => { +function getContentPreviewForTag(tag: string, limit: number = 4) { return allContent.filter(item => item.data.tags && item.data.tags.includes(tag)).slice(0, limit) } +const tagsWithContent = allTags.filter(tag => { + return getContentPreviewForTag(tag.data.slug, 1).length > 0 +}) + const pageDescription = 'Webstack Builders Services List' const pageTitle = 'All Tags' -const path = '/tags/' +const path = '/tags' const section = 'Tags' --- @@ -64,16 +59,19 @@ const section = 'Tags'
{ - allTags.sort().map(tag => { - const contentPreview = getContentPreviewForTag(tag, 4) - const displayName = getTagDisplayName(tag) + tagsWithContent + .sort((a, b) => a.data.displayName.localeCompare(b.data.displayName, 'en')) + .map(tag => { + const tagSlug = tag.data.slug + const contentPreview = getContentPreviewForTag(tagSlug, 4) + const displayName = tag.data.displayName return (

{displayName} @@ -84,7 +82,7 @@ const section = 'Tags' {contentPreview.length >= 4 && ( View all →