#Using markdown with a reusable component?

102 messages · Page 1 of 1 (latest)

tiny gyro
#

I am building a website which hosts multiple projects. Each project needs to have it's own Terms of Service, and it's own Privacy Policy. With that, most of it is just copy paste however I'd like to be able to find a method to use markdown to write it. I also want to be able to refer to it within my project page which is a markdown file.

What would be the best method to do this? For reference, I'm using a modified version of the Astrofy template.

queen shadow
#

Content collections are by far the easiest way, but you have that already

#

You'll be able to pull in the specific TOS you need for a given path

#

For example you can have a page pages/terms/[slug].astro.
That uses static paths from your terms content collection

#

That way it can generate X separate terms pages, using Markdown files

tiny gyro
#

I have been just duplicating from previous uses (ie. duplicating blog collection folder). Do I need this [..page].astro file too?

#

I also can't seemm to figure out what's wrong with my config.ts file 🤔

queen shadow
#

[...slug].astro is only needed if you have multi-deep paths

#

Because the slug can consist of multiple URL parts

tiny gyro
#

This is what my file structure looks like right now.

queen shadow
#

If you only have [slug].astro, it's just 1 level deep

#

For your projects, you don't actually need the page and the slug

#

They both do the same

tiny gyro
#

Oh really 🤔

queen shadow
#

Well, you can omit the slug one

#

The page only can handle that too

#

[slug].astro -> 1 level deep
[...slug].astro -> Multi level deep

tiny gyro
#

Forgive my noviceness, but what do you mean by level?

queen shadow
#

/projects/mypage

#

/projects/myfolder/mypage

tiny gyro
#

Ah!

queen shadow
#

The first one would be valid on both [slug] and [...slug]

#

But the second one is only valid using [...slug]

#

So if you have one with ... on it, you don't need the other one

tiny gyro
#

So do I even need the terms -> [slug].astro at all or any of that or can I just somehow rope it off with the projects -> [slug].astro?

queen shadow
#

I would have the terms folder

#

Because otherwise your terms pages would appear under the /projects path

tiny gyro
#

Well, since I need to create individual terms for each project - wouldn't that be ideal? 🤔

#

I build mobile applications, Apple requires individual Terms of Service and Privacy Policies. So I was going to attach them to each project, then link them from there.

queen shadow
#

It's more so SEO

tiny gyro
#

So ideally it'd be like... /projects/project-name/terms and /projects/project-name/privacy?

queen shadow
#

Well you can do that

#

But then I'd consider nesting the pages

tiny gyro
#

Okay, my first question would be how lol

I greatly apprecaite you working with me on this thus far.

queen shadow
#

It's difficulty to write a file tree

#
  • pages
    • projects
      • [project].astro <-- project page itself
      • [project]
        • terms.astro <-- project terms page
        • privacy.astro <-- project privacy page
#

I'd go for that

#

Folders may also be written using []

tiny gyro
#

[project].astro <-- project page itself
Forgive me to bring back up the [slug].astro file but is that not what this is? 🤔

queen shadow
#

The word you use in the brackets doesn't matter

tiny gyro
#

Ah that makes more sense.

queen shadow
#

It's what you have to define in static paths that has to match

#
export function getStaticPaths () {
 return [
    { params: { slug: 'path' }},
    { params: { project: 'my-project' }},
  ];
}
#

Any of this works, as long as a field in the params exists

tiny gyro
#

The [project] folder that contains my terms.astro and privacy.astro - are these dynamic? are these layouts? How do these get the markdown file.

queen shadow
#

So in your project page you have a getStaticPaths(), right?

#

That fetches the project content collection

tiny gyro
#
export async function getStaticPaths() {
  const itemEntries = await getCollection("projects");
  return itemEntries.map((entry) => ({
    params: { slug: entry.slug },
    props: { entry },
  }));
}
queen shadow
#

Exactly

#

You do the same for both the terms and privacy

#

Because we also need the project slug there

#

Then inside the render of the terms and privacy separately

#

You pull the terms and privacy that you need, based on the project you're getting in

#

And what I'd recommend is that you use reference()s in your content collections

#
import { z, defineCollection, reference } from "astro:content";

const blogSchema = z.object({
    title: z.string(),
    description: z.string(),
    author: z.string(),
    pubDate: z.coerce.date(),
    updatedDate: z.string().optional(),
    heroImage: z.string().optional(),
    badge: z.string().optional(),
    tags: z.array(z.string()).refine(items => new Set(items).size === items.length, {
        message: 'tags must be unique',
    }).optional(),
});

const projectSchema = z.object({
    title: z.string(),
    description: z.string(),
    custom_link: z.string().optional(),
    updatedDate: z.coerce.date(),
    badge: z.string().optional(),
    checkoutUrl: z.string().optional(),
    heroImage: z.string().optional(),
    terms: reference("terms"),
    privacy: reference("privacy")
});

const termsSchema = z.object({
    title: z.string(),
    updatedDate: z.coerce.date(),
});

const blogCollection = defineCollection({ schema: blogSchema });
const projectCollection = defineCollection({ schema: projectSchema });
const termsCollection = defineCollection({ schema: termsSchema });

export const collections = {
    blog: blogCollection,
    projects: projectCollection,
    terms: termsCollection
};
#

That way you have to provide which terms and which privacy are applicable for that project

tiny gyro
#

You do the same for both the terms and privacy
When you say this, I don't quite follow.

The terms.astroand privacy.astro are layout files right or components? I'm getting tripped up in terms of trying to understand how my rendering gets done to pull in my markdown file.

queen shadow
#

They are pages

queen shadow
#

Do you have that folder structure?

tiny gyro
#

Not yet. Doing it as we speak.

queen shadow
#

Terms and privacy need to be within a folder

#

That [project] folder I wrote

#

Else it just becomes one page

tiny gyro
#

Gotcha.

#

So now inside the terms.astro I can import my BaseLayout and then build out my rendered view?

queen shadow
#

Yes

tiny gyro
#

How does this terms.astro know which terms markdown to render inside of it? 🤔

#

I feel like I'm asking a lot of dumb questions - forgive me.

queen shadow
#

I mentioned that reference there

#

That's how you can you tell a content collection to refer elsewhere

#

So in your terms page

#

You have a project

#

(Because you get that from the getStaticPaths())

#

That thing has a reference to a terms

#

So then you can load in those terms, and render the page using it

#
---
export async function getStaticPaths() {
  const itemEntries = await getCollection("projects");
  return itemEntries.map((entry) => ({
    params: { slug: entry.slug },
    props: { entry },
  }));
}

const { entry } = Astro.props;
const terms = await getEntry(entry.data.terms);

const { Content } = await terms.render();
---

<BaseLayout>
  <Content />
</BaseLayout>
#

Something like this

tiny gyro
#

Hmm okay. 🤔

#

I broke everything hahahaha

tiny gyro
#

Is there a more appropriate way to link / route to the specific files? I'm getting an error that the href is not a valid url.

           <a href={terms}>Terms of Service</a>
           <a href={privacy}>Privacy Policy</a>
tiny gyro
#

How do I appropriately link that? I'm a bit confused with this. I tried using our fearless Support AI with no dice... This is the top of my .md file for project. Anyway I attempt I get a syntax / formatting error stating that it doesn't match the schema.

---
title: "foritude"
description: "Discover your guide to personal growth and mental wellness. Embrace transformative journaling and unlock the path to resilience and self-discovery. Begin your journey now and empower yourself with clarity, strength, and purpose."
updatedDate: "March 30, 2024"
badge: "Featured"
checkoutUrl: "https://apps.apple.com/app/id6478435046"
heroImage: "/site-placeholder/fortitude/fortitude_hero.png"
terms: "term1"
privacy: "privacy1"
---
queen shadow
#

If that's just named term1, then it should be fine

#

But you don't need the quotes

tiny gyro
#

So if the path is /projects/project/term1 I pass that without any quotations?

queen shadow
#

Do you actually have a content collection file in the terms folder?

#

Let's start with that

tiny gyro
#

Yes. I’ve got 1 in terms named terms1 that’s under [content] -> [terms] then the same namespace for privacy for now. Both have their frontmatter setup to match the schema which is appName and updatedDate.

Now that I think of it, the frontmatter is wrong because I’m using title not appName so I need to fix that first.

queen shadow
#

Ok if your file is named terms1

#

That's the ID of that file

#

So in your reference you have to use the ID, aka "terms1"

#

And not "term1"

tiny gyro
#

Double checked my schema, I'm using title and updatedDate. This is the current file structure currently. I replaced the frontmatter terms to be term1 and I'm still 404'ing. I apologize for my lack of understanding thus far.

queen shadow
#

Do you want to hop in a call

#

This back and forth at slow pace isn't really helping a lot

tiny gyro
#

I could do that in an hour or so - playing Daddy Daycare right this moment.

queen shadow
#

Just @ me when you are available

tiny gyro
#

👍

tiny gyro
#

@queen shadow available when you are.