Skip to content
This repository has been archived by the owner on Oct 30, 2024. It is now read-only.

Refresh of Tech Notes page #682

Merged
merged 28 commits into from
Jan 16, 2024
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
829402d
Refresh of Tech Notes page to make it easier to discover existing, up…
andrewmcgivery Dec 22, 2023
5640c60
Moving "Reporting issues" and "Adding new tech notes" up the page per…
andrewmcgivery Jan 2, 2024
a3ffba1
Styling changes, recent recently added and recently updated to 3 note…
andrewmcgivery Jan 2, 2024
36f767a
Move "Reporting issues" and "Adding new tech notes" to the top
andrewmcgivery Jan 2, 2024
58a0684
Remove "select a tag" note as it feels redundant
andrewmcgivery Jan 2, 2024
4abaf72
variants 3 and 4 with moving recents under search box but before "all…
andrewmcgivery Jan 2, 2024
134b918
Reduce headers size on variant 2
andrewmcgivery Jan 2, 2024
13ac821
Updating header sizes on variant 3 and variant 4
andrewmcgivery Jan 2, 2024
10503a3
Adding summary and publish date to some notes
andrewmcgivery Jan 3, 2024
ba58ee1
Adding more summaries and publish dates
andrewmcgivery Jan 3, 2024
44cce8f
Iterating to reduce scope, add "Sort by" options
andrewmcgivery Jan 8, 2024
c7ef61f
Cleanup
andrewmcgivery Jan 8, 2024
f46e187
Changed to table layout with sortable headers
andrewmcgivery Jan 8, 2024
412944d
Fix table on mobile
andrewmcgivery Jan 8, 2024
61189de
Update "summary" to "description" in tech notes
andrewmcgivery Jan 8, 2024
3e83042
Updating a batch of notes with description and published
andrewmcgivery Jan 9, 2024
2285fb8
Batch of notes adding metadata
andrewmcgivery Jan 10, 2024
daa080f
Another batch of tech notes meta data
andrewmcgivery Jan 10, 2024
69bc354
last batch of meta data
andrewmcgivery Jan 10, 2024
0b3966d
Removed unused files, fixed tags page to be able to do column sorting
andrewmcgivery Jan 10, 2024
a8b239e
Merge remote-tracking branch 'origin/main' into feature/technotespage…
andrewmcgivery Jan 10, 2024
b816bd3
Merge branch 'main' into feature/technotespagerefresh
Meschreiber Jan 11, 2024
5a034b2
Update landing page description
Meschreiber Jan 12, 2024
fb60209
Style cards
Meschreiber Jan 12, 2024
8998a65
Update subtitles/descriptions
Meschreiber Jan 12, 2024
38560ef
Edit descriptions and add subtitles
Meschreiber Jan 13, 2024
d43a00a
Edits
Meschreiber Jan 13, 2024
7bed666
Merge remote-tracking branch 'origin/main' into feature/technotespage…
andrewmcgivery Jan 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
189 changes: 173 additions & 16 deletions src/components/TechNotes/AllNotes.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,75 @@
import React, {useMemo, useState} from 'react';
import {Heading} from '@chakra-ui/react';
import {NotesList} from './NotesList';
import {TagList} from './TagList';
import {graphql, useStaticQuery} from 'gatsby';
import React, { useMemo, useState } from "react";
import { NotesList } from "./NotesList";
import { TagList } from "./TagList";
import { graphql, useStaticQuery } from "gatsby";
import { Heading } from "@chakra-ui/react";

export const SORT_OPTIONS = {
UPDATED_ASC: "UPDATED_ASC",
UPDATED_DESC: "UPDATED_DESC",
PUBLISHED_ASC: "PUBLISHED_ASC",
PUBLISHED_DESC: "PUBLISHED_DESC",
ALPHABETICAL_ASC: "ALPHABETICAL_ASC",
ALPHABETICAL_DESC: "ALPHABETICAL_DESC",
};

export function AllNotes() {
const data = useStaticQuery(
graphql`
query AllTechNotesAlphabetical {
notes: allFile(
query AllTechNotes {
notesUpdatedAsc: allFile(
filter: {childMdx: {slug: {regex: "/^TN\\d{4}/"}}}
sort: {fields: fields___gitLogLatestDate, order: ASC}
limit: 2000
) {
nodes {
fields {
gitLogLatestDate
}
childMdx {
id
fields {
slug
}
frontmatter {
title
description
published
tags
}
rawBody
timeToRead
}
}
}

notesUpdatedDesc: allFile(
filter: {childMdx: {slug: {regex: "/^TN\\d{4}/"}}}
sort: {fields: fields___gitLogLatestDate, order: DESC}
limit: 2000
) {
nodes {
fields {
gitLogLatestDate
}
childMdx {
id
fields {
slug
}
frontmatter {
title
description
published
tags
}
rawBody
timeToRead
}
}
}

notesAlphabeticalAsc: allFile(
filter: {childMdx: {slug: {regex: "/^TN\\d{4}/"}}}
sort: {fields: childMdx___frontmatter___title, order: ASC}
limit: 2000
Expand All @@ -24,8 +85,90 @@ export function AllNotes() {
}
frontmatter {
title
description
published
tags
}
rawBody
timeToRead
}
}
}

notesAlphabeticalDesc: allFile(
filter: {childMdx: {slug: {regex: "/^TN\\d{4}/"}}}
sort: {fields: childMdx___frontmatter___title, order: DESC}
limit: 2000
) {
nodes {
fields {
gitLogLatestDate
}
childMdx {
id
fields {
slug
}
frontmatter {
title
description
published
tags
}
rawBody
timeToRead
}
}
}

notesPublishedAsc: allFile(
filter: {childMdx: {slug: {regex: "/^TN\\d{4}/"}}}
sort: {fields: childMdx___frontmatter___published, order: ASC}
limit: 2000
) {
nodes {
fields {
gitLogLatestDate
}
childMdx {
id
fields {
slug
}
frontmatter {
title
description
published
tags
}
rawBody
timeToRead
}
}
}

notesPublishedDesc: allFile(
filter: {childMdx: {slug: {regex: "/^TN\\d{4}/"}}}
sort: {fields: childMdx___frontmatter___published, order: DESC}
limit: 2000
) {
nodes {
fields {
gitLogLatestDate
}
childMdx {
id
fields {
slug
}
frontmatter {
title
description
published
tags
}
rawBody
timeToRead
}
}
}
Expand All @@ -34,24 +177,38 @@ export function AllNotes() {
);

const [currentTag, setCurrentTag] = useState();
const [sort, setSort] = useState(SORT_OPTIONS.UPDATED_DESC);

const rawNotes = useMemo(() => {
switch (sort) {
case SORT_OPTIONS.UPDATED_ASC:
return data.notesUpdatedAsc;
case SORT_OPTIONS.UPDATED_DESC:
return data.notesUpdatedDesc;
case SORT_OPTIONS.PUBLISHED_ASC:
return data.notesPublishedAsc;
case SORT_OPTIONS.PUBLISHED_DESC:
return data.notesPublishedDesc;
case SORT_OPTIONS.ALPHABETICAL_ASC:
return data.notesAlphabeticalAsc;
case SORT_OPTIONS.ALPHABETICAL_DESC:
return data.notesAlphabeticalDesc;
}
}, [sort]);

const notes = useMemo(() => {
if (!currentTag) {
return data.notes.nodes;
return rawNotes.nodes;
} else {
return data.notes.nodes.filter(note =>
note.childMdx.frontmatter.tags.includes(currentTag)
);
return rawNotes.nodes.filter((note) => note.childMdx.frontmatter.tags.includes(currentTag));
}
}, [currentTag, data.notes.nodes]);
}, [currentTag, rawNotes]);

return (
<>
<Heading>
{currentTag ? `Notes tagged “${currentTag}”` : 'All notes'}
</Heading>
<Heading mb={2}>{currentTag ? `Notes tagged “${currentTag}”` : "All notes"}</Heading>
<TagList selected={currentTag} onClick={setCurrentTag} />
<NotesList notes={notes} />
<NotesList notes={notes} setCurrentTag={setCurrentTag} sort={sort} setSort={setSort} />
</>
);
}
157 changes: 122 additions & 35 deletions src/components/TechNotes/NotesList.js
Original file line number Diff line number Diff line change
@@ -1,47 +1,134 @@
import PropTypes from 'prop-types';
import React from 'react';
import RelativeLink from '../RelativeLink';
import moment from 'moment';
import {Table, Tbody, Td, Th, Thead, Tr} from '@chakra-ui/react';
import PropTypes from "prop-types";
import React from "react";
import { PrimaryLink } from "../RelativeLink";
import moment from "moment";
import { Stack, Flex, Text, Tag, HStack, Box, Table, Thead, Tbody, Th, Tr, Td, Link } from "@chakra-ui/react";
import { Link as GatsbyLink } from "gatsby";
import { SORT_OPTIONS } from "./AllNotes";
import { FaArrowDown, FaArrowUp } from "react-icons/fa";

const getBrowserCompatibleDate = note => {
const getBrowserCompatibleDate = (note) => {
// The date string here look like "2022-11-01 16:39:41 -0400"
// This is not valid in Safari, so we are just splitting and selecting the date part
// since the time and timezone offset are not needed
const gitLogDate = note.fields?.gitLogLatestDate ?? '';
const simpleDate = gitLogDate.split(' ')[0] ?? Date.now();
return moment(simpleDate).format('YYYY-MM-DD');
const gitLogDate = note.fields?.gitLogLatestDate ?? "";
const simpleDate = gitLogDate.split(" ")[0] ?? Date.now();
return moment(simpleDate).format("YYYY-MM-DD");
};

export function NotesList({notes}) {
export function NotesList({ notes, setCurrentTag, sort, setSort }) {
return (
<Table variant="unstyled">
<Thead>
<Tr>
<Th>Title</Th>
<Th>Last updated</Th>
</Tr>
</Thead>
<Tbody>
{notes.map(note => (
<Tr key={note.childMdx.id}>
<Td>
<RelativeLink href={note.childMdx.fields.slug}>
{note.childMdx.frontmatter.title}
</RelativeLink>
</Td>
<Td>
<span style={{whiteSpace: 'nowrap'}}>
{getBrowserCompatibleDate(note)}
</span>
</Td>
</Tr>
))}
</Tbody>
</Table>
<Box width={"100%"} overflowX={"auto"}>
<Table className="notesList">
<Thead>
<Th>
{sort === SORT_OPTIONS.ALPHABETICAL_ASC && (
<PrimaryLink as={Link} onClick={() => setSort(SORT_OPTIONS.ALPHABETICAL_DESC)}>
<Flex alignItems={"center"} gap={1}>
Note <FaArrowUp />
</Flex>
</PrimaryLink>
)}
{sort === SORT_OPTIONS.ALPHABETICAL_DESC && (
<PrimaryLink as={Link} onClick={() => setSort(SORT_OPTIONS.ALPHABETICAL_ASC)}>
<Flex alignItems={"center"} gap={1}>
Note <FaArrowDown />
</Flex>
</PrimaryLink>
)}
{sort !== SORT_OPTIONS.ALPHABETICAL_ASC && sort !== SORT_OPTIONS.ALPHABETICAL_DESC && (
<PrimaryLink as={Link} onClick={() => setSort(SORT_OPTIONS.ALPHABETICAL_ASC)}>
Note
</PrimaryLink>
)}
</Th>
<Th>
{sort === SORT_OPTIONS.PUBLISHED_ASC && (
<PrimaryLink as={Link} onClick={() => setSort(SORT_OPTIONS.PUBLISHED_DESC)}>
<Flex alignItems={"center"} gap={1}>
Published <FaArrowUp />
</Flex>
</PrimaryLink>
)}
{sort === SORT_OPTIONS.PUBLISHED_DESC && (
<PrimaryLink as={Link} onClick={() => setSort(SORT_OPTIONS.PUBLISHED_ASC)}>
<Flex alignItems={"center"} gap={1}>
Published <FaArrowDown />
</Flex>
</PrimaryLink>
)}
{sort !== SORT_OPTIONS.PUBLISHED_ASC && sort !== SORT_OPTIONS.PUBLISHED_DESC && (
<PrimaryLink as={Link} onClick={() => setSort(SORT_OPTIONS.PUBLISHED_ASC)}>
Published
</PrimaryLink>
)}
</Th>
<Th>
{sort === SORT_OPTIONS.UPDATED_ASC && (
<PrimaryLink as={Link} onClick={() => setSort(SORT_OPTIONS.UPDATED_DESC)}>
<Flex alignItems={"center"} gap={1}>
Updated <FaArrowUp />
</Flex>
</PrimaryLink>
)}
{sort === SORT_OPTIONS.UPDATED_DESC && (
<PrimaryLink as={Link} onClick={() => setSort(SORT_OPTIONS.UPDATED_ASC)}>
<Flex alignItems={"center"} gap={1}>
Updated <FaArrowDown />
</Flex>
</PrimaryLink>
)}
{sort !== SORT_OPTIONS.UPDATED_ASC && sort !== SORT_OPTIONS.UPDATED_DESC && (
<PrimaryLink as={Link} onClick={() => setSort(SORT_OPTIONS.UPDATED_ASC)}>
Updated
</PrimaryLink>
)}
</Th>
</Thead>
<Tbody>
{notes.map((note) => (
<>
<Tr>
<Td>
<PrimaryLink as={GatsbyLink} to={note.childMdx.fields.slug}>
{note.childMdx.frontmatter.title}
</PrimaryLink>
<Flex fontSize="sm" gap={4} mt={4}>
<HStack>
{note.childMdx.frontmatter.tags?.map((tag, index) => (
<Tag
key={index}
size="sm"
cursor={setCurrentTag ? "pointer" : "inherit"}
whiteSpace={"nowrap"}
onClick={() => setCurrentTag && setCurrentTag(tag)}
>
{tag}
</Tag>
))}
</HStack>
</Flex>

<Text mb="4" fontSize="md" noOfLines={3}>
{note.childMdx.frontmatter.description}
</Text>
<Box color={'primary'} fontSize="xs" textTransform="uppercase">{note.childMdx.timeToRead} min read</Box>
</Td>
<Td fontSize={"sm"} whiteSpace={"nowrap"}>
{moment(note.childMdx.frontmatter.published).format("YYYY-MM-DD")}
</Td>
<Td fontSize={"sm"} whiteSpace={"nowrap"}>
{getBrowserCompatibleDate(note)}
</Td>
</Tr>
</>
))}
</Tbody>
</Table>
</Box>
);
}

NotesList.propTypes = {
notes: PropTypes.array.isRequired
notes: PropTypes.array.isRequired,
};
Loading