├── .github └── dependabot.yml ├── .gitignore ├── components ├── AllBooksContext.tsx ├── Book.tsx ├── BookPlaceholder.tsx ├── Header.tsx └── Highlight.tsx ├── lib └── fetchHighlights.ts ├── next-env.d.ts ├── package.json ├── pages ├── _app.tsx ├── _document.tsx ├── api │ └── highlights.ts ├── book │ └── [title].tsx └── index.tsx ├── styles.css ├── tsconfig.json ├── utils ├── ellipsify.ts └── linkify.ts └── yarn.lock /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: npm 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .vercel 3 | .next 4 | .env* -------------------------------------------------------------------------------- /components/AllBooksContext.tsx: -------------------------------------------------------------------------------- 1 | import { createContext } from "react" 2 | import { Highlight } from "../lib/fetchHighlights" 3 | 4 | const AllBooksContext = createContext(null) 5 | 6 | export default AllBooksContext 7 | -------------------------------------------------------------------------------- /components/Book.tsx: -------------------------------------------------------------------------------- 1 | import Link from "next/link" 2 | import linkify from "../utils/linkify" 3 | import Highlight from "./Highlight" 4 | export default function Book({ title, author, highlights }) { 5 | const slug = linkify(title) 6 | 7 | return ( 8 | <> 9 | 45 |
46 |
47 |
48 |

49 | 50 | {title} 51 | 52 |

53 |

54 | {author} 55 |
56 | {highlights.length} highlights 57 |

58 |
59 |
60 | 61 | 73 |
74 | 75 | ) 76 | } 77 | -------------------------------------------------------------------------------- /components/BookPlaceholder.tsx: -------------------------------------------------------------------------------- 1 | export default function BookPlaceholder() { 2 | return ( 3 | <> 4 | 64 |
65 |
66 |
67 |

68 | Lorem Ipsum Dolor Sit 69 |

70 |

71 | Sit Amet 72 |
73 | 2 highlights 74 |

75 |
76 |
77 | 78 | 108 |
109 | 110 | ) 111 | } 112 | -------------------------------------------------------------------------------- /components/Header.tsx: -------------------------------------------------------------------------------- 1 | import { useContext } from "react" 2 | import linkify from "../utils/linkify" 3 | import AllBooksContext from "./AllBooksContext" 4 | 5 | export default function Header() { 6 | const tableOfContents = useContext(AllBooksContext) 7 | return ( 8 |
9 |

Highlights

10 |
11 | 12 | A selection of Kindle highlights from the library of{" "} 13 | Daniel Eden. 14 | 15 |

16 | Highlights are manually synced from a Kindle to Airtable using a{" "} 17 | 18 | JavaScript program 19 | 20 | . The source code for this website is{" "} 21 | 22 | available to view 23 | 24 | . 25 |

26 |
27 | {tableOfContents?.length && ( 28 | <> 29 |

Table of Contents

30 | 37 | 38 | )} 39 |
40 | ) 41 | } 42 | -------------------------------------------------------------------------------- /components/Highlight.tsx: -------------------------------------------------------------------------------- 1 | import ellipsify from "../utils/ellipsify" 2 | 3 | export default function Highlight({ 4 | date, 5 | note, 6 | locStart, 7 | locEnd, 8 | pageNumber, 9 | }) { 10 | return ( 11 | <> 12 | 23 |
  • 24 |
    25 | 26 | {ellipsify(note)} 27 | {note} 28 | 29 |
    30 |

    31 | Loc {locStart}–{locEnd} 32 | {pageNumber && ( 33 | <> 34 | {" "} 35 | (Page {pageNumber}) 36 | 37 | )} 38 |

    39 |
  • 40 | 41 | ) 42 | } 43 | -------------------------------------------------------------------------------- /lib/fetchHighlights.ts: -------------------------------------------------------------------------------- 1 | import Airtable, { FieldSet, Table } from "airtable" 2 | 3 | export interface Highlight extends FieldSet { 4 | title: string 5 | author: string 6 | date: string 7 | pageNumber?: number 8 | locStart: number 9 | locEnd: number 10 | } 11 | 12 | export interface Book { 13 | title: string 14 | author: string 15 | highlights: [Highlight] 16 | } 17 | 18 | const { AIRTABLE_API_KEY, AIRTABLE_BASE_ID, AIRTABLE_TABLE_NAME } = process.env 19 | 20 | const base = new Airtable({ apiKey: AIRTABLE_API_KEY }).base(AIRTABLE_BASE_ID) 21 | const table = base(AIRTABLE_TABLE_NAME) as Table 22 | export default async function fetchHighlights(): Promise { 23 | const query = table.select({ 24 | maxRecords: 1000, 25 | }) 26 | const rows = await query.all() 27 | 28 | // Filter to unique values 29 | const rowsSet = new Set(rows.map((row) => row.fields)) 30 | 31 | return Array.from(rowsSet) 32 | } 33 | 34 | export function groupHighlights(highlights: Highlight[]) { 35 | const groupedHighlights = highlights 36 | .reduce((books, highlight) => { 37 | const titleIndex = books.findIndex( 38 | ({ title }) => title == highlight.title 39 | ) 40 | if (titleIndex === -1) { 41 | books.push({ 42 | title: highlight.title, 43 | author: highlight.author, 44 | highlights: [highlight], 45 | }) 46 | } else { 47 | books[titleIndex].highlights.push(highlight) 48 | } 49 | 50 | return books 51 | }, []) 52 | .map((title) => { 53 | const sortedHighlights = title.highlights.sort( 54 | (a, b) => a.locStart - b.locStart 55 | ) 56 | title.highlights = sortedHighlights 57 | 58 | return title 59 | }) 60 | 61 | return groupedHighlights 62 | } 63 | -------------------------------------------------------------------------------- /next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "kindle-highlights", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "scripts": { 7 | "dev": "next dev", 8 | "build": "next build", 9 | "start": "next start" 10 | }, 11 | "dependencies": { 12 | "airtable": "^0.11.6", 13 | "next": "^12.2.2", 14 | "react": "^18.2.0", 15 | "react-dom": "^18.2.0" 16 | }, 17 | "devDependencies": { 18 | "@types/airtable": "^0.10.1", 19 | "@types/node": "^18.11.18", 20 | "@types/react": "^18.0.15", 21 | "@types/react-dom": "^18.0.10", 22 | "typescript": "^4.7.4" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import { AppProps } from "next/app" 2 | import "../styles.css" 3 | 4 | function App({ Component, pageProps }: AppProps) { 5 | return 6 | } 7 | 8 | export default App 9 | -------------------------------------------------------------------------------- /pages/_document.tsx: -------------------------------------------------------------------------------- 1 | import Document, { Head, Html, Main, NextScript } from "next/document" 2 | 3 | class MyDocument extends Document { 4 | render() { 5 | return ( 6 | 7 | 8 | 12 | 16 | 17 | 18 |
    19 | 20 | 21 | 22 | ) 23 | } 24 | } 25 | 26 | export default MyDocument 27 | -------------------------------------------------------------------------------- /pages/api/highlights.ts: -------------------------------------------------------------------------------- 1 | import { NextApiRequest, NextApiResponse } from "next" 2 | import fetchHighlights from "../../lib/fetchHighlights" 3 | export default async (req: NextApiRequest, res: NextApiResponse) => { 4 | const highlights = await fetchHighlights() 5 | 6 | res.status(200).json(highlights) 7 | } 8 | -------------------------------------------------------------------------------- /pages/book/[title].tsx: -------------------------------------------------------------------------------- 1 | import { useRouter } from "next/dist/client/router" 2 | import Head from "next/head" 3 | import Link from "next/link" 4 | import Book from "../../components/Book" 5 | import BookPlaceholder from "../../components/BookPlaceholder" 6 | import fetchHighlights, { 7 | Book as TBook, 8 | groupHighlights, 9 | } from "../../lib/fetchHighlights" 10 | import linkify from "../../utils/linkify" 11 | 12 | export default function BookPage({ book }: { book: TBook }) { 13 | const router = useRouter() 14 | 15 | if (router.isFallback) { 16 | return ( 17 |
    18 |
    19 | 24 |
    25 | 26 |
    27 | ) 28 | } 29 | 30 | const { title, author, highlights } = book 31 | 32 | return ( 33 | <> 34 | 35 | Highlights for “{title}” | Daniel Eden, Designer 36 | 37 |
    38 |
    39 | 44 |
    45 | 51 |
    52 | 53 | ) 54 | } 55 | 56 | export async function getStaticProps(context) { 57 | const { 58 | params: { title }, 59 | } = context 60 | const highlights = await fetchHighlights() 61 | const grouped = groupHighlights(highlights) 62 | const book = grouped.find((book) => linkify(book.title) == linkify(title)) 63 | 64 | return { 65 | props: { 66 | book, 67 | unstable_revalidate: 1, 68 | }, 69 | } 70 | } 71 | 72 | export async function getStaticPaths() { 73 | const highlights = await fetchHighlights() 74 | const titles = groupHighlights(highlights).map((book) => linkify(book.title)) 75 | return { 76 | paths: titles.map((title) => { 77 | return { 78 | params: { title }, 79 | } 80 | }), 81 | fallback: true, 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /pages/index.tsx: -------------------------------------------------------------------------------- 1 | import Head from "next/head" 2 | import AllBooksContext from "../components/AllBooksContext" 3 | import Book from "../components/Book" 4 | import Header from "../components/Header" 5 | import fetchHighlights, { 6 | groupHighlights, 7 | Highlight as THighlight, 8 | } from "../lib/fetchHighlights" 9 | 10 | interface Book { 11 | title: string 12 | author: string 13 | highlights: [THighlight] 14 | } 15 | 16 | export default function HomePage({ highlights }: { highlights: [THighlight] }) { 17 | return ( 18 | 19 | 20 | Kindle Highlights | Daniel Eden, Designer 21 | 22 |
    23 |
    24 | {highlights.map(({ title, author, highlights }) => ( 25 | 31 | ))} 32 |
    33 |
    34 | ) 35 | } 36 | 37 | export async function getStaticProps() { 38 | const highlights = await fetchHighlights() 39 | const groupedHighlights = groupHighlights(highlights) 40 | 41 | return { 42 | props: { 43 | highlights: groupedHighlights, 44 | unstable_revalidate: 1, 45 | }, 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /styles.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | position: relative; 5 | box-sizing: border-box; 6 | } 7 | 8 | :root { 9 | --darkgray: #111; 10 | --lightgray: #eee; 11 | --wash-color: var(--lightgray); 12 | --text-color: var(--darkgray); 13 | --site-color: royalblue; 14 | --sp: 1.5rem; 15 | } 16 | 17 | @media (prefers-color-scheme: dark) { 18 | :root { 19 | --wash-color: var(--darkgray); 20 | --text-color: var(--lightgray); 21 | } 22 | } 23 | 24 | html { 25 | font: 100%/1.5 "IBM Plex Serif", serif; 26 | color: var(--text-color); 27 | background-color: var(--wash-color); 28 | padding: var(--sp); 29 | } 30 | 31 | main { 32 | max-width: 75rem; 33 | margin: 0 auto; 34 | } 35 | 36 | h1, 37 | h2 { 38 | line-height: 1.25; 39 | margin-bottom: 0.5rem; 40 | } 41 | 42 | a { 43 | color: inherit; 44 | } 45 | 46 | a:hover { 47 | color: var(--site-color); 48 | } 49 | 50 | header { 51 | margin-bottom: 3rem; 52 | } 53 | 54 | p, 55 | details, 56 | ul { 57 | margin-bottom: var(--sp); 58 | } 59 | 60 | ul { 61 | padding-left: var(--sp); 62 | } 63 | 64 | .sans { 65 | font-family: "IBM Plex Sans", sans-serif; 66 | } 67 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "skipLibCheck": true, 11 | "strict": false, 12 | "forceConsistentCasingInFileNames": true, 13 | "noEmit": true, 14 | "esModuleInterop": true, 15 | "module": "esnext", 16 | "moduleResolution": "node", 17 | "resolveJsonModule": true, 18 | "isolatedModules": true, 19 | "jsx": "preserve" 20 | }, 21 | "exclude": [ 22 | "node_modules" 23 | ], 24 | "include": [ 25 | "next-env.d.ts", 26 | "**/*.ts", 27 | "**/*.tsx" 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /utils/ellipsify.ts: -------------------------------------------------------------------------------- 1 | export default function ellipsify(s: string): string { 2 | return /^[a-z]/.test(s) ? "[\u2026] " : null 3 | } 4 | -------------------------------------------------------------------------------- /utils/linkify.ts: -------------------------------------------------------------------------------- 1 | export default function linkify(s: string): string { 2 | return encodeURI( 3 | s 4 | .replace(/ /g, "-") 5 | .replace(/[:&;—?!]/, "") 6 | .toLowerCase() 7 | ) 8 | } 9 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@next/env@12.2.2": 6 | version "12.2.2" 7 | resolved "https://registry.yarnpkg.com/@next/env/-/env-12.2.2.tgz#cc1a0a445bd254499e30f632968c03192455f4cc" 8 | integrity sha512-BqDwE4gDl1F608TpnNxZqrCn6g48MBjvmWFEmeX5wEXDXh3IkAOw6ASKUgjT8H4OUePYFqghDFUss5ZhnbOUjw== 9 | 10 | "@next/swc-android-arm-eabi@12.2.2": 11 | version "12.2.2" 12 | resolved "https://registry.yarnpkg.com/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.2.2.tgz#f6c4111e6371f73af6bf80c9accb3d96850a92cd" 13 | integrity sha512-VHjuCHeq9qCprUZbsRxxM/VqSW8MmsUtqB5nEpGEgUNnQi/BTm/2aK8tl7R4D0twGKRh6g1AAeFuWtXzk9Z/vQ== 14 | 15 | "@next/swc-android-arm64@12.2.2": 16 | version "12.2.2" 17 | resolved "https://registry.yarnpkg.com/@next/swc-android-arm64/-/swc-android-arm64-12.2.2.tgz#b69de59c51e631a7600439e7a8993d6e82f3369e" 18 | integrity sha512-v5EYzXUOSv0r9mO/2PX6mOcF53k8ndlu9yeFHVAWW1Dhw2jaJcvTRcCAwYYN8Q3tDg0nH3NbEltJDLKmcJOuVA== 19 | 20 | "@next/swc-darwin-arm64@12.2.2": 21 | version "12.2.2" 22 | resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.2.2.tgz#80157c91668eff95b72d052428c353eab0fc4c50" 23 | integrity sha512-JCoGySHKGt+YBk7xRTFGx1QjrnCcwYxIo3yGepcOq64MoiocTM3yllQWeOAJU2/k9MH0+B5E9WUSme4rOCBbpA== 24 | 25 | "@next/swc-darwin-x64@12.2.2": 26 | version "12.2.2" 27 | resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-12.2.2.tgz#12be2f58e676fccff3d48a62921b9927ed295133" 28 | integrity sha512-dztDtvfkhUqiqpXvrWVccfGhLe44yQ5tQ7B4tBfnsOR6vxzI9DNPHTlEOgRN9qDqTAcFyPxvg86mn4l8bB9Jcw== 29 | 30 | "@next/swc-freebsd-x64@12.2.2": 31 | version "12.2.2" 32 | resolved "https://registry.yarnpkg.com/@next/swc-freebsd-x64/-/swc-freebsd-x64-12.2.2.tgz#de1363431a49059f1efb8c0f86ce6a79c53b3a95" 33 | integrity sha512-JUnXB+2xfxqsAvhFLPJpU1NeyDsvJrKoOjpV7g3Dxbno2Riu4tDKn3kKF886yleAuD/1qNTUCpqubTvbbT2VoA== 34 | 35 | "@next/swc-linux-arm-gnueabihf@12.2.2": 36 | version "12.2.2" 37 | resolved "https://registry.yarnpkg.com/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.2.2.tgz#d5b8e0d1bb55bbd9db4d2fec018217471dc8b9e6" 38 | integrity sha512-XeYC/qqPLz58R4pjkb+x8sUUxuGLnx9QruC7/IGkK68yW4G17PHwKI/1njFYVfXTXUukpWjcfBuauWwxp9ke7Q== 39 | 40 | "@next/swc-linux-arm64-gnu@12.2.2": 41 | version "12.2.2" 42 | resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.2.2.tgz#3bc75984e1d5ec8f59eb53702cc382d8e1be2061" 43 | integrity sha512-d6jT8xgfKYFkzR7J0OHo2D+kFvY/6W8qEo6/hmdrTt6AKAqxs//rbbcdoyn3YQq1x6FVUUd39zzpezZntg9Naw== 44 | 45 | "@next/swc-linux-arm64-musl@12.2.2": 46 | version "12.2.2" 47 | resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.2.2.tgz#270db73e07a18d999f61e79a917943fa5bc1ef56" 48 | integrity sha512-rIZRFxI9N/502auJT1i7coas0HTHUM+HaXMyJiCpnY8Rimbo0495ir24tzzHo3nQqJwcflcPTwEh/DV17sdv9A== 49 | 50 | "@next/swc-linux-x64-gnu@12.2.2": 51 | version "12.2.2" 52 | resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.2.2.tgz#e6c72fa20478552e898c434f4d4c0c5e89d2ea78" 53 | integrity sha512-ir1vNadlUDj7eQk15AvfhG5BjVizuCHks9uZwBfUgT5jyeDCeRvaDCo1+Q6+0CLOAnYDR/nqSCvBgzG2UdFh9A== 54 | 55 | "@next/swc-linux-x64-musl@12.2.2": 56 | version "12.2.2" 57 | resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.2.2.tgz#b9ef9efe2c401839cdefa5e70402386aafdce15a" 58 | integrity sha512-bte5n2GzLN3O8JdSFYWZzMgEgDHZmRz5wiispiiDssj4ik3l8E7wq/czNi8RmIF+ioj2sYVokUNa/ekLzrESWw== 59 | 60 | "@next/swc-win32-arm64-msvc@12.2.2": 61 | version "12.2.2" 62 | resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.2.2.tgz#18fa7ec7248da3a7926a0601d9ececc53ac83157" 63 | integrity sha512-ZUGCmcDmdPVSAlwJ/aD+1F9lYW8vttseiv4n2+VCDv5JloxiX9aY32kYZaJJO7hmTLNrprvXkb4OvNuHdN22Jg== 64 | 65 | "@next/swc-win32-ia32-msvc@12.2.2": 66 | version "12.2.2" 67 | resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.2.2.tgz#54936e84f4a219441d051940354da7cd3eafbb4f" 68 | integrity sha512-v7ykeEDbr9eXiblGSZiEYYkWoig6sRhAbLKHUHQtk8vEWWVEqeXFcxmw6LRrKu5rCN1DY357UlYWToCGPQPCRA== 69 | 70 | "@next/swc-win32-x64-msvc@12.2.2": 71 | version "12.2.2" 72 | resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.2.2.tgz#7460be700a60d75816f01109400b51fe929d7e89" 73 | integrity sha512-2D2iinWUL6xx8D9LYVZ5qi7FP6uLAoWymt8m8aaG2Ld/Ka8/k723fJfiklfuAcwOxfufPJI+nRbT5VcgHGzHAQ== 74 | 75 | "@swc/helpers@0.4.2": 76 | version "0.4.2" 77 | resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.4.2.tgz#ed1f6997ffbc22396665d9ba74e2a5c0a2d782f8" 78 | integrity sha512-556Az0VX7WR6UdoTn4htt/l3zPQ7bsQWK+HqdG4swV7beUCxo/BqmvbOpUkTIm/9ih86LIf1qsUnywNL3obGHw== 79 | dependencies: 80 | tslib "^2.4.0" 81 | 82 | "@types/airtable@^0.10.1": 83 | version "0.10.1" 84 | resolved "https://registry.yarnpkg.com/@types/airtable/-/airtable-0.10.1.tgz#d7575251c890cb9a93e92c59344f7b7c4f7d9ae0" 85 | integrity sha512-ZwMU+ZztgmN1k12ist39+lDQAkeeaPLO5pgXdRodJecVTMo+zKHNn83dQcLY3eaD3BbUfEZ/6uJsqBTcM+UKuQ== 86 | dependencies: 87 | airtable "*" 88 | 89 | "@types/node@>=8.0.0 <15": 90 | version "14.14.41" 91 | resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.41.tgz#d0b939d94c1d7bd53d04824af45f1139b8c45615" 92 | integrity sha512-dueRKfaJL4RTtSa7bWeTK1M+VH+Gns73oCgzvYfHZywRCoPSd8EkXBL0mZ9unPTveBn+D9phZBaxuzpwjWkW0g== 93 | 94 | "@types/node@^18.11.18": 95 | version "18.11.18" 96 | resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.18.tgz#8dfb97f0da23c2293e554c5a50d61ef134d7697f" 97 | integrity sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA== 98 | 99 | "@types/prop-types@*": 100 | version "15.7.3" 101 | resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7" 102 | integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw== 103 | 104 | "@types/react-dom@^18.0.10": 105 | version "18.0.10" 106 | resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.0.10.tgz#3b66dec56aa0f16a6cc26da9e9ca96c35c0b4352" 107 | integrity sha512-E42GW/JA4Qv15wQdqJq8DL4JhNpB3prJgjgapN3qJT9K2zO5IIAQh4VXvCEDupoqAwnz0cY4RlXeC/ajX5SFHg== 108 | dependencies: 109 | "@types/react" "*" 110 | 111 | "@types/react@*", "@types/react@^18.0.15": 112 | version "18.0.15" 113 | resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.15.tgz#d355644c26832dc27f3e6cbf0c4f4603fc4ab7fe" 114 | integrity sha512-iz3BtLuIYH1uWdsv6wXYdhozhqj20oD4/Hk2DNXIn1kFsmp9x8d9QB6FnPhfkbhd2PgEONt9Q1x/ebkwjfFLow== 115 | dependencies: 116 | "@types/prop-types" "*" 117 | "@types/scheduler" "*" 118 | csstype "^3.0.2" 119 | 120 | "@types/scheduler@*": 121 | version "0.16.1" 122 | resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.1.tgz#18845205e86ff0038517aab7a18a62a6b9f71275" 123 | integrity sha512-EaCxbanVeyxDRTQBkdLb3Bvl/HK7PBK6UJjsSixB0iHKoWxE5uu2Q/DgtpOhPIojN0Zl1whvOd7PoHs2P0s5eA== 124 | 125 | abort-controller@^3.0.0: 126 | version "3.0.0" 127 | resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" 128 | integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== 129 | dependencies: 130 | event-target-shim "^5.0.0" 131 | 132 | abortcontroller-polyfill@^1.4.0: 133 | version "1.5.0" 134 | resolved "https://registry.yarnpkg.com/abortcontroller-polyfill/-/abortcontroller-polyfill-1.5.0.tgz#2c562f530869abbcf88d949a2b60d1d402e87a7c" 135 | integrity sha512-O6Xk757Jb4o0LMzMOMdWvxpHWrQzruYBaUruFaIOfAQRnWFxfdXYobw12jrVHGtoXk6WiiyYzc0QWN9aL62HQA== 136 | 137 | airtable@*, airtable@^0.11.6: 138 | version "0.11.6" 139 | resolved "https://registry.yarnpkg.com/airtable/-/airtable-0.11.6.tgz#3b90f9c671ee93c4ad647eb131d630dea9f1f84a" 140 | integrity sha512-Na67L2TO1DflIJ1yOGhQG5ilMfL2beHpsR+NW/jhaYOa4QcoxZOtDFs08cpSd1tBMsLpz5/rrz/VMX/pGL/now== 141 | dependencies: 142 | "@types/node" ">=8.0.0 <15" 143 | abort-controller "^3.0.0" 144 | abortcontroller-polyfill "^1.4.0" 145 | lodash "^4.17.21" 146 | node-fetch "^2.6.7" 147 | 148 | caniuse-lite@^1.0.30001332: 149 | version "1.0.30001364" 150 | resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001364.tgz#1e118f0e933ed2b79f8d461796b8ce45398014a0" 151 | integrity sha512-9O0xzV3wVyX0SlegIQ6knz+okhBB5pE0PC40MNdwcipjwpxoUEHL24uJ+gG42cgklPjfO5ZjZPme9FTSN3QT2Q== 152 | 153 | csstype@^3.0.2: 154 | version "3.0.5" 155 | resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.5.tgz#7fdec6a28a67ae18647c51668a9ff95bb2fa7bb8" 156 | integrity sha512-uVDi8LpBUKQj6sdxNaTetL6FpeCqTjOvAQuQUa/qAqq8oOd4ivkbhgnqayl0dnPal8Tb/yB1tF+gOvCBiicaiQ== 157 | 158 | event-target-shim@^5.0.0: 159 | version "5.0.1" 160 | resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" 161 | integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== 162 | 163 | "js-tokens@^3.0.0 || ^4.0.0": 164 | version "4.0.0" 165 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" 166 | integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== 167 | 168 | lodash@^4.17.21: 169 | version "4.17.21" 170 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" 171 | integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== 172 | 173 | loose-envify@^1.1.0: 174 | version "1.4.0" 175 | resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" 176 | integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== 177 | dependencies: 178 | js-tokens "^3.0.0 || ^4.0.0" 179 | 180 | nanoid@^3.1.30: 181 | version "3.3.4" 182 | resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab" 183 | integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw== 184 | 185 | next@^12.2.2: 186 | version "12.2.2" 187 | resolved "https://registry.yarnpkg.com/next/-/next-12.2.2.tgz#029bf5e4a18a891ca5d05b189b7cd983fd22c072" 188 | integrity sha512-zAYFY45aBry/PlKONqtlloRFqU/We3zWYdn2NoGvDZkoYUYQSJC8WMcalS5C19MxbCZLUVCX7D7a6gTGgl2yLg== 189 | dependencies: 190 | "@next/env" "12.2.2" 191 | "@swc/helpers" "0.4.2" 192 | caniuse-lite "^1.0.30001332" 193 | postcss "8.4.5" 194 | styled-jsx "5.0.2" 195 | use-sync-external-store "1.1.0" 196 | optionalDependencies: 197 | "@next/swc-android-arm-eabi" "12.2.2" 198 | "@next/swc-android-arm64" "12.2.2" 199 | "@next/swc-darwin-arm64" "12.2.2" 200 | "@next/swc-darwin-x64" "12.2.2" 201 | "@next/swc-freebsd-x64" "12.2.2" 202 | "@next/swc-linux-arm-gnueabihf" "12.2.2" 203 | "@next/swc-linux-arm64-gnu" "12.2.2" 204 | "@next/swc-linux-arm64-musl" "12.2.2" 205 | "@next/swc-linux-x64-gnu" "12.2.2" 206 | "@next/swc-linux-x64-musl" "12.2.2" 207 | "@next/swc-win32-arm64-msvc" "12.2.2" 208 | "@next/swc-win32-ia32-msvc" "12.2.2" 209 | "@next/swc-win32-x64-msvc" "12.2.2" 210 | 211 | node-fetch@^2.6.7: 212 | version "2.6.7" 213 | resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" 214 | integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== 215 | dependencies: 216 | whatwg-url "^5.0.0" 217 | 218 | picocolors@^1.0.0: 219 | version "1.0.0" 220 | resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" 221 | integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== 222 | 223 | postcss@8.4.5: 224 | version "8.4.5" 225 | resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.5.tgz#bae665764dfd4c6fcc24dc0fdf7e7aa00cc77f95" 226 | integrity sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg== 227 | dependencies: 228 | nanoid "^3.1.30" 229 | picocolors "^1.0.0" 230 | source-map-js "^1.0.1" 231 | 232 | react-dom@^18.2.0: 233 | version "18.2.0" 234 | resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d" 235 | integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g== 236 | dependencies: 237 | loose-envify "^1.1.0" 238 | scheduler "^0.23.0" 239 | 240 | react@^18.2.0: 241 | version "18.2.0" 242 | resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5" 243 | integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ== 244 | dependencies: 245 | loose-envify "^1.1.0" 246 | 247 | scheduler@^0.23.0: 248 | version "0.23.0" 249 | resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe" 250 | integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw== 251 | dependencies: 252 | loose-envify "^1.1.0" 253 | 254 | source-map-js@^1.0.1: 255 | version "1.0.2" 256 | resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" 257 | integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== 258 | 259 | styled-jsx@5.0.2: 260 | version "5.0.2" 261 | resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.0.2.tgz#ff230fd593b737e9e68b630a694d460425478729" 262 | integrity sha512-LqPQrbBh3egD57NBcHET4qcgshPks+yblyhPlH2GY8oaDgKs8SK4C3dBh3oSJjgzJ3G5t1SYEZGHkP+QEpX9EQ== 263 | 264 | tr46@~0.0.3: 265 | version "0.0.3" 266 | resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" 267 | integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== 268 | 269 | tslib@^2.4.0: 270 | version "2.4.0" 271 | resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" 272 | integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== 273 | 274 | typescript@^4.7.4: 275 | version "4.7.4" 276 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235" 277 | integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ== 278 | 279 | use-sync-external-store@1.1.0: 280 | version "1.1.0" 281 | resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.1.0.tgz#3343c3fe7f7e404db70f8c687adf5c1652d34e82" 282 | integrity sha512-SEnieB2FPKEVne66NpXPd1Np4R1lTNKfjuy3XdIoPQKYBAFdzbzSZlSn1KJZUiihQLQC5Znot4SBz1EOTBwQAQ== 283 | 284 | webidl-conversions@^3.0.0: 285 | version "3.0.1" 286 | resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" 287 | integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== 288 | 289 | whatwg-url@^5.0.0: 290 | version "5.0.0" 291 | resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" 292 | integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== 293 | dependencies: 294 | tr46 "~0.0.3" 295 | webidl-conversions "^3.0.0" 296 | --------------------------------------------------------------------------------