Skip to content

Commit 8cb264b

Browse files
committed
two-column editor landing with date-fns for our edits
1 parent 11d997b commit 8cb264b

File tree

5 files changed

+146
-20
lines changed

5 files changed

+146
-20
lines changed

config/webpack.config.dev.js

+1
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ module.exports = {
142142
include: [
143143
/node_modules[\/\\]usehooks-ts/,
144144
/node_modules[\/\\]@babel[\/\\]runtime/,
145+
/node_modules[\/\\]date-fns/,
145146
],
146147
loader: require.resolve("babel-loader"),
147148
options: {

config/webpack.config.prod.js

+1
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ module.exports = {
171171
include: [
172172
/node_modules[\/\\]usehooks-ts/,
173173
/node_modules[\/\\]@babel[\/\\]runtime/,
174+
/node_modules[\/\\]date-fns/,
174175
],
175176
loader: require.resolve("babel-loader"),
176177
options: {

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
"citation-js": "^0.7.4",
4444
"country-emoji": "^1.5.6",
4545
"css-loader": "0.28.7",
46+
"date-fns": "^4.1.0",
4647
"directory-tree": "2.2.1",
4748
"dotenv": "4.0.0",
4849
"dotenv-expand": "4.2.0",

pnpm-lock.yaml

+7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/components/rawl/editor/EditorLandingPage.tsx

+136-20
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
1-
import React from "react";
1+
import { formatDistanceToNow } from "date-fns";
2+
import {
3+
collection,
4+
getDocs,
5+
getFirestore,
6+
query,
7+
where,
8+
} from "firebase/firestore/lite";
9+
import React, { useContext, useEffect, useState } from "react";
210
import { Link } from "react-router-dom";
311
import styled from "styled-components";
12+
import { AppContext } from "../../AppContext";
413
import { beautifySlug } from "../corpora/utils";
514

615
export const StyledButton = styled.button`
@@ -40,19 +49,37 @@ const StyledButtonLink = styled(Link)`
4049

4150
const LandingContainer = styled.div`
4251
display: flex;
43-
flex-direction: column;
44-
align-items: center;
52+
flex-direction: row;
4553
padding: 50px 20px;
46-
margin-top: 30px; /* Add space below the header */
47-
min-height: calc(100vh - 30px); /* Subtract header height */
54+
margin-top: 30px;
55+
min-height: calc(100vh - 30px);
4856
box-sizing: border-box;
4957
`;
5058

59+
// Two column layout
60+
const LeftColumn = styled.div`
61+
flex: 1;
62+
margin-right: 20px;
63+
max-width: 350px;
64+
`;
65+
66+
const RightColumn = styled.div`
67+
flex: 2;
68+
display: flex;
69+
flex-direction: column;
70+
align-items: center;
71+
`;
72+
73+
// Styling for the user's scores
74+
const UserScoresContainer = styled.div`
75+
width: 100%;
76+
margin-bottom: 30px;
77+
`;
78+
5179
// Styled components for the scores list
5280
const ScoresContainer = styled.div`
5381
width: 100%;
5482
max-width: 600px;
55-
margin-top: 30px;
5683
text-align: left;
5784
`;
5885

@@ -68,22 +95,47 @@ const ScoresList = styled.ul`
6895
`;
6996

7097
const ScoreItem = styled.li`
71-
margin: 8px 0;
98+
margin: 12px 0;
7299
`;
73100

74101
const ScoreLink = styled(Link)`
75102
color: white;
76103
text-decoration: none;
77104
font-size: 16px;
78-
padding: 5px 0;
79105
display: block;
80106
81107
&:hover {
82108
text-decoration: underline;
83109
}
84110
`;
85111

112+
const ScoreTimestamp = styled.span`
113+
color: #888;
114+
font-size: 12px;
115+
display: block;
116+
margin-top: 2px;
117+
`;
118+
119+
const VersionBadge = styled.span`
120+
display: inline-block;
121+
background-color: transparent;
122+
color: #888;
123+
font-size: 11px;
124+
margin-left: 8px;
125+
`;
126+
127+
interface UserScore {
128+
id: string;
129+
title: string;
130+
updatedAt: Date;
131+
versions: number;
132+
}
133+
86134
const EditorLandingPage: React.FC = () => {
135+
const [userScores, setUserScores] = useState<UserScore[]>([]);
136+
const appContext = useContext(AppContext);
137+
const user = appContext?.user;
138+
87139
// Hard-coded list of featured scores
88140
const featuredScores = [
89141
"schubert_d365_09",
@@ -94,20 +146,84 @@ const EditorLandingPage: React.FC = () => {
94146
"idea-n.10---gibran-alcocer",
95147
];
96148

149+
// Fetch user scores when component mounts and user is available
150+
useEffect(() => {
151+
const fetchUserScores = async () => {
152+
if (!user) {
153+
setUserScores([]);
154+
return;
155+
}
156+
157+
try {
158+
const db = getFirestore();
159+
const editsCollection = collection(db, "edits");
160+
const q = query(editsCollection, where("owner", "==", user.uid));
161+
const querySnapshot = await getDocs(q);
162+
163+
const scores: UserScore[] = [];
164+
querySnapshot.forEach((doc) => {
165+
const data = doc.data();
166+
scores.push({
167+
id: doc.id,
168+
title: data.title || "",
169+
updatedAt: data.updatedAt?.toDate() || new Date(),
170+
versions: data.versions?.length || 0,
171+
});
172+
});
173+
174+
// Sort by most recently updated
175+
scores.sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime());
176+
setUserScores(scores);
177+
} catch (error) {
178+
console.error("Error fetching user scores:", error);
179+
}
180+
};
181+
182+
fetchUserScores();
183+
}, [user]);
184+
97185
return (
98186
<LandingContainer>
99-
<StyledButtonLink to="/e/new">New Score</StyledButtonLink>
100-
101-
<ScoresContainer>
102-
<ScoresTitle>Featured Scores</ScoresTitle>
103-
<ScoresList>
104-
{featuredScores.map((name) => (
105-
<ScoreItem key={name}>
106-
<ScoreLink to={`/e/${name}`}>{beautifySlug(name)}</ScoreLink>
107-
</ScoreItem>
108-
))}
109-
</ScoresList>
110-
</ScoresContainer>
187+
<LeftColumn>
188+
{user && (
189+
<UserScoresContainer>
190+
<ScoresTitle>My Scores</ScoresTitle>
191+
<ScoresList>
192+
{userScores.length > 0 ? (
193+
userScores.map((score) => (
194+
<ScoreItem key={score.id}>
195+
<ScoreLink to={`/ef/${score.id}/${score.versions}`}>
196+
{score.title || score.id}
197+
<VersionBadge>v{score.versions}</VersionBadge>
198+
</ScoreLink>
199+
<ScoreTimestamp>
200+
{formatDistanceToNow(score.updatedAt, {
201+
addSuffix: true,
202+
})}
203+
</ScoreTimestamp>
204+
</ScoreItem>
205+
))
206+
) : (
207+
<ScoreItem>No saved scores yet</ScoreItem>
208+
)}
209+
</ScoresList>
210+
</UserScoresContainer>
211+
)}
212+
<StyledButtonLink to="/e/new">New Score</StyledButtonLink>
213+
</LeftColumn>
214+
215+
<RightColumn>
216+
<ScoresContainer>
217+
<ScoresTitle>Examples</ScoresTitle>
218+
<ScoresList>
219+
{featuredScores.map((name) => (
220+
<ScoreItem key={name}>
221+
<ScoreLink to={`/e/${name}`}>{beautifySlug(name)}</ScoreLink>
222+
</ScoreItem>
223+
))}
224+
</ScoresList>
225+
</ScoresContainer>
226+
</RightColumn>
111227
</LandingContainer>
112228
);
113229
};

0 commit comments

Comments
 (0)