-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDndAuthorsPage.jsx
More file actions
137 lines (127 loc) · 4.61 KB
/
DndAuthorsPage.jsx
File metadata and controls
137 lines (127 loc) · 4.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
import React, { useState, useEffect, useContext } from 'react';
import { motion } from 'framer-motion';
import Seo from '../../components/Seo';
import piml from 'piml';
import { DndContext } from '../../context/DndContext';
import DndAuthorCard from '../../components/dnd/DndAuthorCard';
import DndLayout from '../../components/dnd/DndLayout';
import DndSearchInput from '../../components/dnd/DndSearchInput';
import { useAchievements } from '../../context/AchievementContext';
import { UsersIcon } from '@phosphor-icons/react';
function DndAuthorsPage() {
const { setBreadcrumbs, language } = useContext(DndContext);
const [authors, setAuthors] = useState([]);
const [books, setBooks] = useState([]);
const [searchQuery, setSearchQuery] = useState('');
const { unlockAchievement } = useAchievements();
useEffect(() => {
unlockAchievement('author_aficionado');
setBreadcrumbs([{ label: 'S&F', path: '/stories' }, { label: 'Authors' }]);
const fetchData = async () => {
try {
const [authRes, booksRes] = await Promise.all([
fetch(`${process.env.PUBLIC_URL}/stories/authors.piml`),
fetch(
`${process.env.PUBLIC_URL}/stories/books_${language || 'en'}.piml`,
),
]);
if (authRes.ok && booksRes.ok) {
const [authText, booksText] = await Promise.all([
authRes.text(),
booksRes.text(),
]);
setAuthors(piml.parse(authText).authors);
setBooks(piml.parse(booksText).books);
}
} catch (error) {
console.error('Failed to fetch data:', error);
}
};
fetchData();
}, [setBreadcrumbs, unlockAchievement, language]);
const getBooksByAuthor = (authorName, authorAlias) => {
const authorBooks = [];
books.forEach((book) => {
book.episodes.forEach((episode) => {
if (
(episode.author === authorName || episode.author === authorAlias) &&
!authorBooks.some((b) => b.bookTitle === book.bookTitle)
) {
authorBooks.push({
bookId: book.bookId,
bookTitle: book.bookTitle,
});
}
});
});
return authorBooks;
};
const filteredAuthors = authors.filter((author) => {
const term = searchQuery.toLowerCase();
return (
author.name.toLowerCase().includes(term) ||
author.alias.toLowerCase().includes(term)
);
});
return (
<DndLayout>
<Seo
title="Authors | From Serfs and Frauds"
description="Meet the authors behind the Dungeons & Dragons stories, From Serfs and Frauds."
keywords={[
'Fezcodex',
'd&d',
'dnd',
'from serfs and frauds',
'authors',
]}
/>
<div className="max-w-7xl mx-auto px-6 py-12">
<header className="text-center mb-12 relative">
<div className="flex justify-center mb-6">
<UsersIcon
size={48}
className="text-dnd-gold-light drop-shadow-[0_0_8px_rgba(249,224,118,0.4)]"
weight="duotone"
/>
</div>
<h1 className="text-4xl md:text-8xl font-playfairDisplay italic font-black dnd-gold-gradient-text uppercase tracking-tighter mb-4 leading-none">
The Scribes
</h1>
<p className="text-lg md:text-xl font-arvo text-gray-400 max-w-2xl mx-auto uppercase tracking-widest opacity-60 mb-12">
Meeting the voices behind the recorded history of the realms.
</p>
<DndSearchInput
value={searchQuery}
onChange={setSearchQuery}
placeholder="Search scribes by name or alias..."
/>
</header>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-12">
{filteredAuthors.map((author, index) => (
<motion.div
key={index}
initial={{ opacity: 0, scale: 0.9 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ delay: index * 0.1 }}
>
<DndAuthorCard
authorName={author.name}
authorWebsite={author.website}
authorImage={author.image}
authorAlias={author.alias}
booksWritten={getBooksByAuthor(author.name, author.alias)}
/>
</motion.div>
))}
{filteredAuthors.length === 0 && (
<div className="col-span-full text-center py-12 text-white/60 font-arvo italic">
No scribes found matching your query.
</div>
)}
</div>
</div>
</DndLayout>
);
}
export default DndAuthorsPage;