Using ResourceArrays to show a list of projects
We are going to edit our portfolio ontology and give the homepage a list of projects to display.
Go back to our ontology and add a recommended property to the homepage
class called projects
.
Give it a nice description and set the datatype to ResourceArray
.
This is basically an array of subjects pointing to other resources.
Click on the configure button next to datatype and in the classtype field type project
, an option with the text Create: project
should appear, click it and the new class will be added to the ontology.
We are going to give project
3 required and 2 recommended properties.
For the required add: name and description then create a property called image
with datatype RESOURCE
and a classtype of file.
For the recommended properties create one called demo-url
with datatype STRING
and one called repo-url
with the same type. demo-url
will be used to point to a demo of the project (if there is one), and repo-url
will point to a git repository if there is one.
project
should now look something like this:
Now in your data folder create some projects and add them to your homepage resource like I did here:
NOTE: To edit a resource press
Cmd + e
orCtrl + e
, alternatively you can click the context menu on the right of the search bar and clickEdit
Since we changed the ontology we will have to generate our types again:
npx ad-generate ontologies
In your Astro code make a new Component in the src/components
folder called Project.astro
.
---
// src/components/Project.astro
import { marked } from 'marked';
import { getStore } from '../helpers/getStore';
import type { Project } from '../ontologies/myPortfolio';
import type { Server } from '@tomic/lib';
interface Props {
subject: string;
}
const store = getStore();
const { subject } = Astro.props;
const project = await store.getResource<Project>(subject);
const coverImg = await store.getResource<Server.File>(project.props.image);
const description = marked.parse(project.props.description);
---
<div>
<h3>
{project.title}
</h3>
<img src={coverImg.props.downloadUrl} alt='' />
<div set:html={description} />
<div>
{
project.props.demoUrl && (
<a
href={project.props.demoUrl}
target='_blank'
rel='noopener noreferrer'
>
Visit project
</a>
)
}
{
project.props.repoUrl && (
<a
href={project.props.repoUrl}
target='_blank'
rel='noopener noreferrer'
>
View on Github
</a>
)
}
</div>
</div>
<style>
img {
width: 100%;
aspect-ratio: 16 / 9;
object-fit: cover;
}
</style>
The component takes a subject as a prop that we use to fetch the project resource using the .getResource()
method.
We then fetch the image resource using the same method.
The description is markdown so we have to parse that first like we did on the homepage.
Finally the links. Because demoUrl and repoUrl are recommended properties and may therefore be undefined we use the short circuit &&
operator here. This makes sure we don't render an empty link.
Let's update the homepage to use this Project component:
---
// src/pages/index.astro
import { marked } from 'marked';
import Layout from '../layouts/Layout.astro';
import { getStore } from '../helpers/getStore';
import type { Homepage } from '../ontologies/myPortfolio';
import Project from '../components/Project.astro';
const store = getStore();
const homepage = await store.getResource<Homepage>(
import.meta.env.ATOMIC_HOMEPAGE_SUBJECT,
);
const bodyTextContent = marked.parse(homepage.props.bodyText);
---
<Layout resource={homepage}>
<p set:html={bodyTextContent} />
<h2>Projects</h2>
<div class='grid'>
{homepage.props.projects?.map(subject => <Project subject={subject} />)}
</div>
</Layout>
<style>
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 1rem;
}
</style>
Since a ResourceArray is just an array of subjects we can map through them and pass the subject to <Project />
.
Our homepage is now complete and looks like this: