Skip to content

Commit fbcc135

Browse files
committed
Add Camera Roll collection and update related components
1 parent 678318e commit fbcc135

File tree

10 files changed

+98
-35
lines changed

10 files changed

+98
-35
lines changed

src/components/layout/elements/footer.astro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ import { ExternalLinkIcon } from "@/components/icons";
7676
<div class="col-span-6 sm:col-span-3">
7777
<ul class="text-muted">
7878
{
79-
getPublishedEntries(site.tree.social).map(
79+
getPublishedEntries(site.tree.sharing).map(
8080
([_, { title, url, blank }]) => {
8181
return (
8282
<li class="list-none">

src/components/templates/entry/default.astro

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import { getEntryNavigation } from "@/lib/entry-navigation";
3636
3737
const { collection, id } = Astro.props as Entry;
3838
39-
const entry = (await getEntry(collection, id)) as Entry | undefined;
39+
const entry = await getEntry(collection, id);
4040
4141
if (!entry) {
4242
throw new Error(`Entry not found: ${collection}/${id}`);
@@ -72,13 +72,20 @@ const layoutProps = {
7272
breadcrumbs,
7373
};
7474
75-
// Only show share buttons for blog, wiki, and projects
76-
const showShare = ["blog", "wiki", "projects"].includes(collection);
75+
// Only show share buttons for blog, wiki, projects, and cameraroll
76+
const showShare = ["blog", "wiki", "projects", "cameraroll"].includes(
77+
collection,
78+
);
7779
const shareUrl = `${site.url}${Astro.url.pathname}`;
7880
7981
// Get navigation for prev/next entries
82+
const filteredCollections = ["blog", "wiki", "projects", "cameraroll"];
8083
const allEntries = await getAllCollections();
81-
const navigation = getEntryNavigation(entry, allEntries);
84+
const navigation = getEntryNavigation(
85+
entry,
86+
allEntries,
87+
filteredCollections.includes(collection) ? collection : undefined,
88+
);
8289
---
8390

8491
<LayoutDefault {...layoutProps} type="article">

src/components/templates/entry/series.astro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import { getEntryNavigation } from "@/lib/entry-navigation";
3131
3232
const { collection, id } = Astro.props as Entry;
3333
34-
const entry = (await getEntry(collection, id)) as Entry | undefined;
34+
const entry = (await getEntry(collection, id));
3535
3636
if (!entry) {
3737
throw new Error(`Entry not found: ${collection}/${id}`);

src/constants.ts

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,14 @@ const contentCollections: Record<CollectionName, Meta> = {
118118
url: "/blogroll",
119119
published: true,
120120
},
121+
cameraroll: {
122+
title: "Camera Roll",
123+
description:
124+
"Una colección de fotografías tomadas con mis cámaras, tanto digital como analógicas.",
125+
entriesPerPage: 15,
126+
url: "/cameraroll",
127+
published: false,
128+
},
121129
uses: {
122130
title: "Uses",
123131
description:
@@ -141,7 +149,16 @@ const pages = {
141149
...contentCollections,
142150
};
143151

144-
const social: TreeNode = {
152+
const sharing: TreeNode = {
153+
feed: {
154+
title: "Feed",
155+
description:
156+
"Suscríbete al RSS feed para recibir nuevos artículos en tu lector favorito.",
157+
entriesPerPage: 0,
158+
url: "/rss.xml",
159+
blank: true,
160+
published: true,
161+
},
145162
github: {
146163
title: "GitHub",
147164
url: `https://github.com/${metasite.github}`,
@@ -156,22 +173,6 @@ const social: TreeNode = {
156173
},
157174
};
158175

159-
const explore: TreeNode = {
160-
tags,
161-
wiki,
162-
archive,
163-
series,
164-
feed: {
165-
title: "Feed",
166-
description:
167-
"Suscríbete al RSS feed para recibir nuevos artículos en tu lector favorito.",
168-
entriesPerPage: 0,
169-
url: "/rss.xml",
170-
blank: true,
171-
published: true,
172-
},
173-
};
174-
175176
const tree: Tree = {
176177
personal: {
177178
home,
@@ -183,12 +184,18 @@ const tree: Tree = {
183184
content: {
184185
blog: contentCollections.blog,
185186
projects: contentCollections.projects,
187+
cameraroll: contentCollections.cameraroll,
186188
blogroll: contentCollections.blogroll,
187-
bookmarks,
188189
reading,
189190
},
190-
explore,
191-
social,
191+
explore: {
192+
bookmarks,
193+
wiki,
194+
series,
195+
archive,
196+
tags,
197+
},
198+
sharing,
192199
};
193200

194201
export const site = {

src/content.config.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,26 @@ const wiki = defineCollection({
128128
schema: wikiSchema,
129129
});
130130

131+
/**
132+
* Camera Roll Collection
133+
*/
134+
135+
const camerarollSchema = commonSchema.merge(
136+
z.object({
137+
takenAt: z.coerce.date().optional(),
138+
mediumType: z.enum(["film", "digital", "both"]),
139+
camera: z.enum(["Canon 350D", "Canon 6D", "Canon 50E", "Canon 33"]),
140+
film: z.string().optional(),
141+
locations: z.array(z.string()).optional(),
142+
thumbnails: z.array(z.string()).optional(),
143+
}),
144+
);
145+
146+
const cameraroll = defineCollection({
147+
loader: glob({ pattern: "**/*.md", base: `${path}/cameraroll` }),
148+
schema: camerarollSchema,
149+
});
150+
131151
export const collections = {
132152
blog,
133153
now,
@@ -136,6 +156,7 @@ export const collections = {
136156
blogroll,
137157
uses,
138158
wiki,
159+
cameraroll,
139160
};
140161

141162
export const collectionNames = Object.keys(collections);
@@ -148,5 +169,6 @@ export type Entry = z.infer<
148169
| typeof blogRollSchema
149170
| typeof usesSchema
150171
| typeof wikiSchema
172+
| typeof camerarollSchema
151173
>;
152174
export type Meta = z.infer<typeof metaSchema>;
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
title: Verano en los Pirineos
3+
description: Una serie de fotografías tomadas durante el verano en los Pirineos, capturando la belleza natural y la tranquilidad de la región.
4+
tags: [photography, travel, nature, pirineos, summer]
5+
mediumType: digital
6+
camera: Canon 6D
7+
published: false
8+
date: 2024-05-01
9+
mod: 2025-10-25
10+
11+
---
12+
13+
<div class="columns-1 sm:columns-2 gap-2 space-y-2">
14+
<img src="https://asg-cms.s3.eu-west-3.amazonaws.com/01-series/72-noviembre-2023-kodak-portra-400/1x/01.webp" class="w-full object-cover aspect-2/3"/>
15+
<img src="https://asg-cms.s3.eu-west-3.amazonaws.com/01-series/72-noviembre-2023-kodak-portra-400/1x/02.webp" class="w-full object-cover aspect-2/3"/>
16+
<img src="https://asg-cms.s3.eu-west-3.amazonaws.com/01-series/72-noviembre-2023-kodak-portra-400/1x/03.webp" class="w-full object-cover aspect-2/3"/>
17+
<img src="https://asg-cms.s3.eu-west-3.amazonaws.com/01-series/72-noviembre-2023-kodak-portra-400/1x/04.webp" class="w-full object-cover aspect-2/3"/>
18+
</div>

src/lib/collections.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,17 @@ import { site } from "@/constants";
2828
*
2929
* @property {string} id - Unique entry identifier.
3030
* @property {InferEntrySchema<CollectionName>} data - Frontmatter data inferred from the collection schema.
31-
* @property {string} body - Raw content body (markdown) as string.
31+
* @property {string} [body] - Optional raw content body (markdown) as string.
3232
* @property {string} [filePath] - Optional file path for the source file.
33-
* @property {RenderedContent} rendered - The rendered content produced by Astro.
33+
* @property {RenderedContent} [rendered] - Optional rendered content produced by Astro.
3434
* @property {CollectionName} collection - The collection name this entry belongs to.
3535
*/
3636
export type Entry = {
3737
id: string;
3838
data: InferEntrySchema<CollectionName>;
39-
body: string;
39+
body?: string;
4040
filePath?: string;
41-
rendered: RenderedContent;
41+
rendered?: RenderedContent;
4242
collection: CollectionName;
4343
};
4444

@@ -67,6 +67,7 @@ export const getAllPromiseCollections = async () => {
6767
*/
6868
export const getAllCollections = async () => {
6969
const collections = await getAllPromiseCollections();
70+
7071
return collections
7172
.filter(({ data: { published } }) => published)
7273
.map((entry) => {
@@ -113,7 +114,6 @@ export const getAllCollectionsByCategory = async (): Promise<
113114
.forEach((key) => {
114115
sortedContentByCategory[key] = contentByCategory[key];
115116
});
116-
117117
return sortedContentByCategory as Record<CollectionName, Entries>;
118118
};
119119

src/lib/entry-navigation.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
* - 🔄 Works seamlessly with all entry types
1313
*/
1414

15+
import type { CollectionName } from "@/content.config";
1516
import type { Entry, Entries } from "@/lib/collections";
1617

1718
/**
@@ -44,6 +45,7 @@ export type EntryNavigation = {
4445
export function getEntryNavigation(
4546
currentEntry: Entry,
4647
allEntries: Entries,
48+
filterCollection?: CollectionName,
4749
): EntryNavigation {
4850
// Filter entries with dates and exclude single-page entries (index: true)
4951
const orderedEntries = allEntries
@@ -54,8 +56,11 @@ export function getEntryNavigation(
5456
return dateB - dateA; // Newest first
5557
});
5658

59+
const filteredEntries = filterCollection
60+
? orderedEntries.filter((e) => e.collection === filterCollection)
61+
: orderedEntries;
5762
// Find current entry index
58-
const currentIndex = orderedEntries.findIndex(
63+
const currentIndex = filteredEntries.findIndex(
5964
(e) => e.id === currentEntry.id && e.collection === currentEntry.collection,
6065
);
6166

@@ -65,10 +70,10 @@ export function getEntryNavigation(
6570
}
6671

6772
// Get prev (older entry)
68-
const prevEntry = orderedEntries[currentIndex + 1] || null;
73+
const prevEntry = filteredEntries[currentIndex + 1] || null;
6974

7075
// Get next (newer entry)
71-
const nextEntry = orderedEntries[currentIndex - 1] || null;
76+
const nextEntry = filteredEntries[currentIndex - 1] || null;
7277

7378
return {
7479
prev: prevEntry

src/lib/utils.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ export const capitalize = (s: string) => s && s[0].toUpperCase() + s.slice(1);
5151
* @param {string} html The HTML content to analyze.
5252
* @returns {number} Estimated reading time in minutes (rounded).
5353
*/
54-
export const getReadingTime = (html: string): number => {
54+
export const getReadingTime = (html?: string): number => {
55+
if (!html) return 0;
5556
const text = html.replace(/<[^>]+>/g, "");
5657
const wordCount = text.trim().split(/\s+/).length;
5758
const speedReadingWordsPerMinute = 200;

src/pages/[collection]/index.astro

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ export { getCollectionStaticPaths as getStaticPaths };
1414
1515
const { collection } = Astro.params as { collection: CollectionName };
1616
const entries = (await getAllCollectionsByCategory())[collection];
17+
console.log(
18+
`Fetched ${entries.length} entries for collection: ${collection}`
19+
);
1720
const simpleCollection = getIsSimpleCollection(entries);
1821
if (!entries) return Astro.redirect("/");
1922
---

0 commit comments

Comments
 (0)