this repo has no description www.baileykane.co/
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Migrate to App router. V1

BK610 9b67f0ab 528d2c56

+302 -607
+5
app/about/page.tsx
··· 1 + import About from "@/components/pageContent/AboutPage"; 2 + 3 + export default function Page(): React.ReactElement { 4 + return <About />; 5 + }
+24
app/feed/page.tsx
··· 1 + import { agent } from "@/lib/bskyApi"; 2 + import Feed from "@/components/pageContent/FeedPage"; 3 + 4 + export const revalidate = 60; 5 + 6 + export default async function Page(): Promise<React.ReactElement> { 7 + const feed = await getFeed(); 8 + 9 + return <Feed feed={feed} />; 10 + } 11 + 12 + async function getFeed(): Promise<Array<Object>> { 13 + const did = await fetch( 14 + "https://bsky.social/xrpc/com.atproto.identity.resolveHandle?handle=baileykane.co" 15 + ) 16 + .then((res) => res.json()) 17 + .then((json) => json.did); 18 + 19 + const posts = await agent.getAuthorFeed({ 20 + actor: did, 21 + }); 22 + 23 + return JSON.parse(JSON.stringify(posts.data.feed)); 24 + }
+21
app/library-cards/page.tsx
··· 1 + import LibraryCards from "@/components/pageContent/LibraryCardsPage"; 2 + import { importCSVDataAsJson } from "@/lib/sheetsConnector"; 3 + import type LibraryCard from "@/types/LibraryCard"; 4 + 5 + export const revalidate = 60; 6 + 7 + export default async function Page(): Promise<React.ReactElement> { 8 + const libraryCards = await getLibraryCards(); 9 + 10 + return <LibraryCards libraryCardsList={libraryCards} />; 11 + } 12 + 13 + async function getLibraryCards(): Promise<{ 14 + data: Array<LibraryCard>; 15 + }> { 16 + const libraryCardsList = await importCSVDataAsJson( 17 + process.env.NEXT_PUBLIC_LIBRARY_CARDS_DATA_URL || "undefined" 18 + ); 19 + 20 + return libraryCardsList; 21 + }
+21
app/music/page.tsx
··· 1 + import Music from "@/components/pageContent/MusicPage"; 2 + import { importCSVDataAsJson } from "@/lib/sheetsConnector"; 3 + import type MusicItem from "@/types/MusicItem"; 4 + 5 + export const revalidate = 60; 6 + 7 + export default async function Page(): Promise<React.ReactElement> { 8 + const musicItems = await getMusicItems(); 9 + 10 + return <Music musicList={musicItems} />; 11 + } 12 + 13 + async function getMusicItems(): Promise<{ 14 + data: Array<MusicItem>; 15 + }> { 16 + const musicList = await importCSVDataAsJson( 17 + process.env.NEXT_PUBLIC_MUSIC_DATA_URL 18 + ); 19 + 20 + return musicList; 21 + }
+8 -3
app/page.tsx
··· 1 1 import Home from "@/components/pageContent/HomePage"; 2 2 import { importCSVDataAsJson } from "@/lib/sheetsConnector"; 3 + import type HomeSection from "@/types/home/HomeSection"; 4 + 5 + export const revalidate = 60; 3 6 4 - export default async function Page() { 7 + export default async function Page(): Promise<React.ReactElement> { 5 8 // Fetch data directly in a Server Component 6 9 const sectionsList = await getSections(); 7 10 // Forward fetched data to your Client Component 8 11 return <Home sectionsList={sectionsList} />; 9 12 } 10 13 11 - async function getSections() { 14 + async function getSections(): Promise<{ 15 + data: Array<HomeSection>; 16 + }> { 12 17 const sectionsList = await importCSVDataAsJson( 13 - process.env.NEXT_PUBLIC_HOME_DATA_URL ?? "fail" 18 + process.env.NEXT_PUBLIC_HOME_DATA_URL || "undefined" 14 19 ); 15 20 16 21 return sectionsList;
+37
app/projects/[slug]/page.tsx
··· 1 + import Project from "@/components/pageContent/projects/ProjectPage"; 2 + import { importCSVDataAsJson } from "@/lib/sheetsConnector"; 3 + import type ProjectType from "@/types/ProjectType"; 4 + import { Params } from "next/dist/server/request/params"; 5 + 6 + export const revalidate = 60; 7 + 8 + export default async function Page({ params }): Promise<React.ReactElement> { 9 + const project = await getProject(params); 10 + 11 + return <Project project={project} />; 12 + } 13 + 14 + async function getProject(params: Params): Promise<ProjectType> { 15 + const { slug } = await params; 16 + 17 + const projectsList = await importCSVDataAsJson( 18 + process.env.NEXT_PUBLIC_PROJECTS_DATA_URL 19 + ); 20 + 21 + // TODO: Pulling all data just to search for the one that matches the slug is inefficient. 22 + // Consider pulling these once, elsewhere, and passing the correct item to this component. 23 + // Followup: This might be irrelevant now that it's fetched server-side. 24 + const project = projectsList.data.find((project) => project.slug === slug); 25 + 26 + return project; 27 + } 28 + 29 + export async function generateStaticParams(): Promise<Array<any>> { 30 + const projectsList = await importCSVDataAsJson( 31 + process.env.NEXT_PUBLIC_PROJECTS_DATA_URL 32 + ); 33 + 34 + return projectsList.data.map((project) => ({ 35 + slug: project.slug, 36 + })); 37 + }
+21
app/projects/page.tsx
··· 1 + import Projects from "@/components/pageContent/projects/ProjectsPage"; 2 + import { importCSVDataAsJson } from "@/lib/sheetsConnector"; 3 + import type ProjectType from "@/types/ProjectType"; 4 + 5 + export const revalidate = 60; 6 + 7 + export default async function Page(): Promise<React.ReactElement> { 8 + const projects = await getProjects(); 9 + 10 + return <Projects projectsList={projects} />; 11 + } 12 + 13 + async function getProjects(): Promise<{ 14 + data: Array<ProjectType>; 15 + }> { 16 + const projectsList = await importCSVDataAsJson( 17 + process.env.NEXT_PUBLIC_PROJECTS_DATA_URL 18 + ); 19 + 20 + return projectsList; 21 + }
+37
app/recipes/[slug]/page.tsx
··· 1 + import Recipe from "@/components/pageContent/recipes/RecipePage"; 2 + import { importCSVDataAsJson } from "@/lib/sheetsConnector"; 3 + import type RecipeType from "@/types/RecipeType"; 4 + import { Params } from "next/dist/server/request/params"; 5 + 6 + export const revalidate = 60; 7 + 8 + export default async function Page({ params }): Promise<React.ReactElement> { 9 + const recipe = await getRecipe(params); 10 + 11 + return <Recipe recipe={recipe} />; 12 + } 13 + 14 + async function getRecipe(params: Params): Promise<RecipeType> { 15 + const { slug } = params; 16 + 17 + const recipesList = await importCSVDataAsJson( 18 + process.env.NEXT_PUBLIC_RECIPES_DATA_URL 19 + ); 20 + 21 + // TODO: Pulling all recipe data just to search for the one that matches the slug is inefficient. 22 + // Consider pulling these once, elsewhere, and passing the correct recipe to this component. 23 + // Followup: This might be irrelevant now that I'm using getStaticProps to fetch the data server-side. 24 + const recipe = recipesList.data.find((recipe) => recipe.slug === slug); 25 + 26 + return recipe; 27 + } 28 + 29 + export async function generateStaticParams(): Promise<Array<any>> { 30 + const recipesList = await importCSVDataAsJson( 31 + process.env.NEXT_PUBLIC_RECIPES_DATA_URL 32 + ); 33 + 34 + return recipesList.data.map((recipe) => ({ 35 + slug: recipe.slug, 36 + })); 37 + }
+21
app/recipes/page.tsx
··· 1 + import Recipes from "@/components/pageContent/recipes/RecipesPage"; 2 + import { importCSVDataAsJson } from "@/lib/sheetsConnector"; 3 + import type RecipeType from "@/types/RecipeType"; 4 + 5 + export const revalidate = 60; 6 + 7 + export default async function Page(): Promise<React.ReactElement> { 8 + const recipes = await getRecipes(); 9 + 10 + return <Recipes recipesList={recipes} />; 11 + } 12 + 13 + async function getRecipes(): Promise<{ 14 + data: Array<RecipeType>; 15 + }> { 16 + const projectsList = await importCSVDataAsJson( 17 + process.env.NEXT_PUBLIC_RECIPES_DATA_URL 18 + ); 19 + 20 + return projectsList; 21 + }
+2 -2
components/MusicItem.tsx
··· 1 1 import { micromark } from "micromark"; 2 - import type Music from "@/types/Music"; 3 - import type { MusicType } from "@/types/Music"; 2 + import type Music from "@/types/MusicItem"; 3 + import type { MusicType } from "@/types/MusicItem"; 4 4 5 5 interface MusicItemProps { 6 6 musicItem: Music;
+5 -4
components/NavBar.tsx
··· 1 + "use client"; 1 2 import Link from "next/link"; 2 - import { useRouter } from "next/compat/router"; 3 + import { usePathname } from "next/navigation"; 3 4 4 5 // Unused. Found that I can just use "." as shorthand for going up one URL level... 🤦 5 6 // function getUpURL() { ··· 58 59 } 59 60 60 61 export default function NavBar({ className }: NavBarProps): React.ReactElement { 61 - const router = useRouter(); 62 + const pathname = usePathname(); 62 63 63 - if (router) { 64 - var breadcrumbs = router.asPath.split("/"); 64 + if (pathname) { 65 + var breadcrumbs = pathname.split("/"); 65 66 breadcrumbs = breadcrumbs.slice(1, breadcrumbs.length - 1); 66 67 } 67 68
+2 -2
components/ProjectContent.tsx
··· 1 1 import { micromark } from "micromark"; 2 2 import Button from "./Button"; 3 - import type Project from "@/types/Project"; 3 + import type ProjectType from "@/types/ProjectType"; 4 4 5 5 export default function ProjectContent({ project }): React.ReactElement { 6 6 const { ··· 12 12 markdown, 13 13 link, 14 14 githubLink, 15 - } = project as Project; 15 + } = project as ProjectType; 16 16 17 17 const formattedDate = new Date(date).toLocaleDateString("en-US", { 18 18 month: "long",
+3 -3
components/ProjectSectionItem.tsx
··· 1 1 import Link from "next/link"; 2 - import type Project from "@/types/Project"; 2 + import type ProjectType from "@/types/ProjectType"; 3 3 4 4 interface ProjectSectionItemProps { 5 - project: Project; 5 + project: ProjectType; 6 6 } 7 7 8 8 export default function ProjectSectionItem({ 9 9 project, 10 10 }: ProjectSectionItemProps): React.ReactElement { 11 11 const { title, description, previewImage, date, emoji, slug } = 12 - project as Project; 12 + project as ProjectType; 13 13 14 14 const dateObj = new Date(date); 15 15
+3 -3
components/RecipeContent.tsx
··· 1 1 import { micromark } from "micromark"; 2 - import type Recipe from "@/types/Recipe"; 2 + import type RecipeType from "@/types/RecipeType"; 3 3 4 4 interface RecipeContentProps { 5 - recipe: Recipe; 5 + recipe: RecipeType; 6 6 } 7 7 8 8 export default function RecipeContent({ ··· 18 18 totalTime, 19 19 ingredients, 20 20 content, 21 - } = recipe as Recipe; 21 + } = recipe as RecipeType; 22 22 23 23 const dateObj = new Date(date); 24 24 return (
+33
components/pageContent/FeedPage.tsx
··· 1 + "use client"; 2 + 3 + import type { Key } from "react"; 4 + import BaseLayout from "@/components/BaseLayout"; 5 + import BlueskyPost from "@/components/BlueskyFeed/BlueskyPost"; 6 + 7 + interface FeedProps { 8 + feed: Array<Object>; 9 + } 10 + 11 + export default function Feed({ feed }: FeedProps): React.ReactElement { 12 + return ( 13 + <BaseLayout titleText={"Feed"}> 14 + <div className="max-w-2xl mx-auto"> 15 + <h1>My Bluesky Feed</h1> 16 + <p className="unerline text-stone-700 dark:text-stone-300 text-sm"> 17 + <a 18 + className="hover:opacity-70" 19 + href="https://bsky.app/profile/baileykane.co" 20 + target="_blank" 21 + > 22 + View my profile. 23 + </a> 24 + </p> 25 + <div className="col-span-2 sm:col-span-1"> 26 + {feed.map((post_data, k: Key) => ( 27 + <BlueskyPost post_data={post_data} key={k} /> 28 + ))} 29 + </div> 30 + </div> 31 + </BaseLayout> 32 + ); 33 + }
components/pageContent/GardenPage.tsx

This is a binary file and will not be displayed.

+1 -23
components/pageContent/HomePage.tsx
··· 4 4 import BaseLayout from "@/components/BaseLayout"; 5 5 import SectionList from "@/components/SectionList"; 6 6 import SocialLink from "@/components/SocialLink"; 7 - // import { importCSVDataAsJson } from "@/lib/sheetsConnector"; 8 7 import Link from "next/link"; 9 - // import type { GetStaticProps } from "next"; 10 8 import type { Key } from "react"; 9 + import type HomeSection from "@/types/home/HomeSection"; 11 10 12 11 interface HomeProps { 13 12 sectionsList: { 14 13 data: Array<HomeSection>; 15 14 }; 16 - } 17 - 18 - interface HomeSection { 19 - name: string; 20 - link: string; 21 - description: string; 22 - emoji: string; 23 15 } 24 16 25 17 export default function Home({ sectionsList }: HomeProps): React.ReactElement { ··· 130 122 </BaseLayout> 131 123 ); 132 124 } 133 - 134 - // // Reference: https://nextjs.org/docs/pages/building-your-application/data-fetching/get-static-props#using-getstaticprops-to-fetch-data-from-a-cms 135 - // export const getStaticProps = (async () => { 136 - // const sectionsList = await importCSVDataAsJson( 137 - // process.env.NEXT_PUBLIC_HOME_DATA_URL 138 - // ); 139 - 140 - // return { 141 - // props: { 142 - // sectionsList, 143 - // }, 144 - // revalidate: 60, 145 - // }; 146 - // }) satisfies GetStaticProps<HomeProps>;
+19
components/pageContent/projects/ProjectPage.tsx
··· 1 + import BaseLayout from "@/components/BaseLayout"; 2 + import ProjectContent from "@/components/ProjectContent"; 3 + import type ProjectType from "@/types/ProjectType"; 4 + 5 + interface ProjectPageProps { 6 + project: ProjectType; 7 + } 8 + 9 + export default function Project({ 10 + project, 11 + }: ProjectPageProps): React.ReactElement { 12 + return ( 13 + <BaseLayout titleText={`Projects | ${project.title}`}> 14 + <div className="max-w-3xl mx-auto"> 15 + <ProjectContent project={project} /> 16 + </div> 17 + </BaseLayout> 18 + ); 19 + }
+17
components/pageContent/recipes/RecipePage.tsx
··· 1 + import BaseLayout from "@/components/BaseLayout"; 2 + import RecipeContent from "@/components/RecipeContent"; 3 + import type RecipeType from "@/types/RecipeType"; 4 + 5 + interface RecipeProps { 6 + recipe: RecipeType; 7 + } 8 + 9 + export default function Recipe({ recipe }: RecipeProps): React.ReactElement { 10 + return ( 11 + <BaseLayout titleText={`Recipes | ${recipe.title}`}> 12 + <div className="max-w-3xl mx-auto"> 13 + <RecipeContent recipe={recipe} /> 14 + </div> 15 + </BaseLayout> 16 + ); 17 + }
-1
next-env.d.ts
··· 1 1 /// <reference types="next" /> 2 2 /// <reference types="next/image-types/global" /> 3 - /// <reference types="next/navigation-types/compat/navigation" /> 4 3 5 4 // NOTE: This file should not be edited 6 5 // see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
-46
pages/_app.tsx
··· 1 - import "@/styles/globals.css"; 2 - import { useEffect } from "react"; 3 - import { useRouter } from "next/compat/router"; 4 - import posthog from "posthog-js"; 5 - import { PostHogProvider } from "posthog-js/react"; 6 - 7 - // if (typeof window !== "undefined") { 8 - // // checks that we are client-side 9 - // posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY, { 10 - // api_host: 11 - // process.env.NEXT_PUBLIC_POSTHOG_HOST || "https://us.i.posthog.com", 12 - // person_profiles: "identified_only", // or 'always' to create profiles for anonymous users as well 13 - // loaded: (posthog) => { 14 - // if (process.env.NODE_ENV === "development") posthog.debug(); // debug mode in development 15 - // }, 16 - // }); 17 - // } 18 - 19 - export default function MyApp({ Component, pageProps }): React.ReactElement { 20 - useEffect(() => { 21 - posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY || "undefined", { 22 - api_host: 23 - process.env.NEXT_PUBLIC_POSTHOG_HOST || "https://us.i.posthog.com", 24 - // person_profiles: "identified_only", // or 'always' to create profiles for anonymous users as well 25 - loaded: (posthog) => { 26 - if (process.env.NODE_ENV === "development") posthog.debug(); // debug mode in development 27 - }, 28 - }); 29 - 30 - const router = useRouter(); 31 - 32 - const handleRouteChange = () => posthog?.capture("$pageview"); 33 - 34 - router.events.on("routeChangeComplete", handleRouteChange); 35 - 36 - return () => { 37 - router.events.off("routeChangeComplete", handleRouteChange); 38 - }; 39 - }, []); 40 - 41 - return ( 42 - <PostHogProvider client={posthog}> 43 - <Component {...pageProps} /> 44 - </PostHogProvider> 45 - ); 46 - }
-92
pages/_document.tsx
··· 1 - import Document, { Html, Head, Main, NextScript } from "next/document"; 2 - 3 - export default class MyDocument extends Document { 4 - render() { 5 - return ( 6 - <Html> 7 - <Head> 8 - <meta name="application-name" content="Baileykane.co" /> 9 - <meta name="apple-mobile-web-app-capable" content="yes" /> 10 - <meta 11 - name="apple-mobile-web-app-status-bar-style" 12 - content="default" 13 - /> 14 - <meta name="apple-mobile-web-app-title" content="Baileykane.co" /> 15 - <meta name="description" content="Baileykane.co" /> 16 - <meta name="format-detection" content="telephone=no" /> 17 - <meta name="mobile-web-app-capable" content="yes" /> 18 - <meta 19 - name="msapplication-config" 20 - content="/icons/browserconfig.xml" 21 - /> 22 - <meta name="msapplication-TileColor" content="#2B5797" /> 23 - <meta name="msapplication-tap-highlight" content="no" /> 24 - <meta name="theme-color" content="#ddd7fe" /> 25 - <meta charSet="UTF-8" /> 26 - 27 - {/* <link rel="apple-touch-icon" href="/img/touch-icon-iphone.png" /> 28 - <link 29 - rel="apple-touch-icon" 30 - sizes="180x180" 31 - href="/apple-touch-icon.png" 32 - /> */} 33 - {/* <link 34 - rel="icon" 35 - type="image/png" 36 - sizes="32x32" 37 - href="/favicon-32x32.png" 38 - /> 39 - <link 40 - rel="icon" 41 - type="image/png" 42 - sizes="16x16" 43 - href="/favicon-16x16.png" 44 - /> */} 45 - <link 46 - rel="icon" 47 - href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.90em%22 font-size=%2290%22>🅱️</text></svg>" 48 - ></link> 49 - 50 - <link 51 - rel="shortcut icon" 52 - href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.90em%22 font-size=%2290%22>🅱️</text></svg>" 53 - /> 54 - <link rel="manifest" href="/manifest.json" /> 55 - 56 - <meta name="twitter:card" content="summary" /> 57 - <meta name="twitter:url" content="https://baileykane.co" /> 58 - <meta name="twitter:title" content="Bailey Kane" /> 59 - <meta 60 - name="twitter:description" 61 - content="Bailey Kane | Helping small businesses get more done with technology" 62 - /> 63 - <meta 64 - name="twitter:image" 65 - content="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.90em%22 font-size=%2290%22>🅱️</text></svg>" 66 - /> 67 - <meta name="twitter:creator" content="@BK610" /> 68 - 69 - <meta property="og:type" content="website" /> 70 - <meta property="og:title" content="Bailey Kane" /> 71 - <meta 72 - property="og:description" 73 - content="Bailey Kane | Helping small businesses get more done with technology" 74 - /> 75 - <meta 76 - property="og:site_name" 77 - content="Bailey Kane's personal website" 78 - /> 79 - <meta property="og:url" content="https://baileykane.co" /> 80 - <meta 81 - property="og:image" 82 - content="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.90em%22 font-size=%2290%22>🅱️</text></svg>" 83 - /> 84 - </Head> 85 - <body className="antialiased"> 86 - <Main /> 87 - <NextScript /> 88 - </body> 89 - </Html> 90 - ); 91 - } 92 - }
pages/_offline.tsx app/_offline.tsx
-20
pages/about.tsx components/pageContent/AboutPage.tsx
··· 83 83 <a href="mailto:bailey.orion.kane@gmail.com">please reach out</a>. 84 84 I'd love to hear from you. 85 85 </p> 86 - {/* <p> 87 - In 2023 I joined{" "} 88 - <a href="https://utilityapi.com/" target="_blank"> 89 - UtilityAPI 90 - </a>{" "} 91 - to help energy services companies access energy usage data and 92 - combat the most important problem of our time, climate change. 93 - protecting our climate, educating everyone for a better future, 94 - and celebrating arts and music, some of the things that make 95 - life worth living. Reach out if you have a project in mind, want 96 - to connect over shared interests or history, or just want to say 97 - hi! 98 - </p> */} 99 86 </div> 100 - {/* <div className="col-span-2 sm:col-span-1 place-self-center sm:justify-self-auto"> 101 - <img 102 - className="rounded-lg border border-stone-800 dark:border-stone-200 object-cover h-72 w-72 sm:w-full" 103 - src={`/img/Headshot.jpg`} 104 - /> 105 - <p className="mt-1 text-center">Me, he/him.</p> 106 - </div> */} 107 87 </div> 108 88 </BaseLayout> 109 89 );
-32
pages/api/garden.ts
··· 1 - // pages/api/party.js - PartyKit API Route for Next.js Pages Router 2 - // import { NextApiRequest, NextApiResponse } from "next"; 3 - // import { Server } from "partykit/server"; 4 - 5 - // const flowers = []; 6 - 7 - // export default function handler(req: NextApiRequest, res: NextApiResponse) { 8 - // if (req.method === "GET") { 9 - // // Clean up old flowers (older than 24 hours) 10 - // const now = Date.now(); 11 - // while (flowers.length && now - flowers[0].createdAt > 86400000) { 12 - // flowers.shift(); 13 - // } 14 - // res.status(200).json({ flowers }); 15 - // } else if (req.method === "POST") { 16 - // const newFlower = { 17 - // id: Date.now(), 18 - // createdAt: Date.now(), 19 - // color: getRandomColor(), 20 - // }; 21 - // flowers.push(newFlower); 22 - // res.status(201).json(newFlower); 23 - // } else { 24 - // res.setHeader("Allow", ["GET", "POST"]); 25 - // res.status(405).end(`Method ${req.method} Not Allowed`); 26 - // } 27 - // } 28 - 29 - // function getRandomColor(): string { 30 - // const colors = ["#FF69B4", "#FFD700", "#8A2BE2", "#FF4500", "#00FF7F"]; 31 - // return colors[Math.floor(Math.random() * colors.length)]; 32 - // }
-52
pages/feed.tsx
··· 1 - import type { Key } from "react"; 2 - import BaseLayout from "@/components/BaseLayout"; 3 - import BlueskyPost from "@/components/BlueskyFeed/BlueskyPost"; 4 - import { agent } from "@/lib/bskyApi"; 5 - import type { GetStaticProps } from "next"; 6 - 7 - interface FeedProps { 8 - feed: Array<Object>; 9 - } 10 - 11 - export default function Feed({ feed }: FeedProps): React.ReactElement { 12 - return ( 13 - <BaseLayout titleText={"Feed"}> 14 - <div className="max-w-2xl mx-auto"> 15 - <h1>My Bluesky Feed</h1> 16 - <p className="underline text-stone-700 dark:text-stone-300 text-sm"> 17 - <a 18 - className="hover:opacity-70" 19 - href="https://bsky.app/profile/baileykane.co" 20 - target="_blank" 21 - > 22 - View my profile. 23 - </a> 24 - </p> 25 - <div className="col-span-2 sm:col-span-1"> 26 - {feed.map((post_data, k: Key) => ( 27 - <BlueskyPost post_data={post_data} key={k} /> 28 - ))} 29 - </div> 30 - </div> 31 - </BaseLayout> 32 - ); 33 - } 34 - 35 - export const getStaticProps = (async () => { 36 - const did = await fetch( 37 - "https://bsky.social/xrpc/com.atproto.identity.resolveHandle?handle=baileykane.co" 38 - ) 39 - .then((res) => res.json()) 40 - .then((json) => json.did); 41 - 42 - const posts = await agent.getAuthorFeed({ 43 - actor: did, 44 - }); 45 - 46 - const feed = posts.data.feed; 47 - 48 - return { 49 - props: { feed: JSON.parse(JSON.stringify(feed)) }, 50 - revalidate: 60, 51 - }; 52 - }) satisfies GetStaticProps<FeedProps>;
+1 -1
pages/garden.tsx app/garden/page.tsx
··· 1 1 import BaseLayout from "@/components/BaseLayout"; 2 2 3 - export default function Garden(): React.ReactElement { 3 + export default function Page(): React.ReactElement { 4 4 return ( 5 5 <BaseLayout> 6 6 <div>Coming soon!</div>
+2 -16
pages/library-cards.tsx components/pageContent/LibraryCardsPage.tsx
··· 1 + "use client"; 2 + 1 3 import { Key, useEffect, useState } from "react"; 2 - import { importCSVDataAsJson } from "@/lib/sheetsConnector"; 3 4 import BaseLayout from "@/components/BaseLayout"; 4 5 import SectionList from "@/components/SectionList"; 5 6 import LibraryCardItem from "@/components/LibraryCardItem"; 6 - import type { GetStaticProps } from "next"; 7 7 import type LibraryCard from "@/types/LibraryCard"; 8 8 9 9 interface LibraryCardsProps { ··· 89 89 </BaseLayout> 90 90 ); 91 91 } 92 - 93 - // Reference: https://nextjs.org/docs/pages/building-your-application/data-fetching/get-static-props#using-getstaticprops-to-fetch-data-from-a-cms 94 - export const getStaticProps = (async () => { 95 - const libraryCardsList = await importCSVDataAsJson( 96 - process.env.NEXT_PUBLIC_LIBRARY_CARDS_DATA_URL || "undefined" 97 - ); 98 - 99 - return { 100 - props: { 101 - libraryCardsList, 102 - }, 103 - revalidate: 60, 104 - }; 105 - }) satisfies GetStaticProps;
+1 -17
pages/music.tsx components/pageContent/MusicPage.tsx
··· 1 - import type { GetStaticProps } from "next"; 2 1 import BaseLayout from "@/components/BaseLayout"; 3 2 import Head from "next/head"; 4 3 import MusicItem from "@/components/MusicItem"; 5 - import { importCSVDataAsJson } from "@/lib/sheetsConnector"; 6 - import type Music from "@/types/Music"; 4 + import type Music from "@/types/MusicItem"; 7 5 import type { Key } from "react"; 8 6 9 7 interface MusicProps { ··· 34 32 </> 35 33 ); 36 34 } 37 - 38 - // Reference: https://nextjs.org/docs/pages/building-your-application/data-fetching/get-static-props#using-getstaticprops-to-fetch-data-from-a-cms 39 - export const getStaticProps = (async () => { 40 - const musicList = await importCSVDataAsJson( 41 - process.env.NEXT_PUBLIC_MUSIC_DATA_URL 42 - ); 43 - 44 - return { 45 - props: { 46 - musicList, 47 - }, 48 - revalidate: 60, 49 - }; 50 - }) satisfies GetStaticProps<MusicProps>;
-53
pages/projects/[slug].tsx
··· 1 - import BaseLayout from "@/components/BaseLayout"; 2 - import MissingContent from "@/components/MissingContent"; 3 - import ProjectContent from "@/components/ProjectContent"; 4 - import { importCSVDataAsJson } from "@/lib/sheetsConnector"; 5 - import type Project from "@/types/Project"; 6 - import type { GetStaticProps, GetStaticPaths } from "next"; 7 - 8 - interface ProjectProps { 9 - project: Project; 10 - } 11 - 12 - export default function Project({ project }: ProjectProps): React.ReactElement { 13 - if (!project) { 14 - return <MissingContent />; 15 - } 16 - 17 - return ( 18 - <BaseLayout titleText={`Projects | ${project.title}`}> 19 - <div className="max-w-3xl mx-auto"> 20 - <ProjectContent project={project} /> 21 - </div> 22 - </BaseLayout> 23 - ); 24 - } 25 - 26 - // Reference: https://nextjs.org/docs/pages/building-your-application/data-fetching/get-static-props#using-getstaticprops-to-fetch-data-from-a-cms 27 - export const getStaticProps = (async (context) => { 28 - const { slug } = context.params; 29 - 30 - const projectsList = await importCSVDataAsJson( 31 - process.env.NEXT_PUBLIC_PROJECTS_DATA_URL 32 - ); 33 - 34 - // TODO: Pulling all data just to search for the one that matches the slug is inefficient. 35 - // Consider pulling these once, elsewhere, and passing the correct item to this component. 36 - // Followup: This might be irrelevant now that I'm using getStaticProps to fetch the data server-side. 37 - const project = projectsList.data.find((project) => project.slug === slug); 38 - 39 - return { props: { project }, revalidate: 60 }; 40 - }) satisfies GetStaticProps<ProjectProps>; 41 - 42 - // Reference: https://nextjs.org/docs/pages/building-your-application/data-fetching/get-static-paths 43 - export const getStaticPaths = (async () => { 44 - const projectsList = await importCSVDataAsJson( 45 - process.env.NEXT_PUBLIC_PROJECTS_DATA_URL 46 - ); 47 - 48 - const paths = projectsList.data.map((project) => ({ 49 - params: { slug: project.slug }, 50 - })); 51 - 52 - return { paths, fallback: false }; 53 - }) satisfies GetStaticPaths;
+6 -20
pages/projects/index.tsx components/pageContent/projects/ProjectsPage.tsx
··· 1 + "use client"; 2 + 1 3 import ProjectSectionItem from "@/components/ProjectSectionItem"; 2 4 import BaseLayout from "@/components/BaseLayout"; 3 5 import SectionList from "@/components/SectionList"; 4 - import { importCSVDataAsJson } from "@/lib/sheetsConnector"; 5 - import type Project from "@/types/Project"; 6 - import type { GetStaticProps } from "next"; 6 + import type ProjectType from "@/types/ProjectType"; 7 7 import { Key } from "react"; 8 8 9 9 interface ProjectsProps { 10 10 projectsList: { 11 - data: Array<Project>; 11 + data: Array<ProjectType>; 12 12 }; 13 13 } 14 14 ··· 27 27 </div> 28 28 <SectionList className="item-list grid grid-cols-1 sm:grid-cols-2"> 29 29 {projectsList.data 30 - .sort((a: Project, b: Project) => { 30 + .sort((a: ProjectType, b: ProjectType) => { 31 31 // Sorting by date, newest --> oldest 32 32 return Date.parse(b.date) - Date.parse(a.date); 33 33 }) 34 - .map((project: Project, k: Key) => ( 34 + .map((project: ProjectType, k: Key) => ( 35 35 <ProjectSectionItem project={project} key={k} /> 36 36 ))} 37 37 </SectionList> ··· 40 40 </BaseLayout> 41 41 ); 42 42 } 43 - 44 - // Reference: https://nextjs.org/docs/pages/building-your-application/data-fetching/get-static-props#using-getstaticprops-to-fetch-data-from-a-cms 45 - export const getStaticProps = (async () => { 46 - const projectsList = await importCSVDataAsJson( 47 - process.env.NEXT_PUBLIC_PROJECTS_DATA_URL 48 - ); 49 - 50 - return { 51 - props: { 52 - projectsList, 53 - }, 54 - revalidate: 60, 55 - }; 56 - }) satisfies GetStaticProps<ProjectsProps>;
-53
pages/recipes/[slug].tsx
··· 1 - import MissingContent from "@/components/MissingContent"; 2 - import BaseLayout from "@/components/BaseLayout"; 3 - import RecipeContent from "@/components/RecipeContent"; 4 - import { importCSVDataAsJson } from "@/lib/sheetsConnector"; 5 - import type Recipe from "@/types/Recipe"; 6 - import type { GetStaticProps, GetStaticPaths } from "next"; 7 - 8 - interface RecipeProps { 9 - recipe: Recipe; 10 - } 11 - 12 - export default function Recipe({ recipe }: RecipeProps): React.ReactElement { 13 - if (!recipe) { 14 - return <MissingContent />; 15 - } 16 - 17 - return ( 18 - <BaseLayout titleText={`Recipes | ${recipe.title}`}> 19 - <div className="max-w-3xl mx-auto"> 20 - <RecipeContent recipe={recipe} /> 21 - </div> 22 - </BaseLayout> 23 - ); 24 - } 25 - 26 - // Reference: https://nextjs.org/docs/pages/building-your-application/data-fetching/get-static-props#using-getstaticprops-to-fetch-data-from-a-cms 27 - export const getStaticProps = (async (context) => { 28 - const { slug } = context.params; 29 - 30 - const recipesList = await importCSVDataAsJson( 31 - process.env.NEXT_PUBLIC_RECIPES_DATA_URL 32 - ); 33 - 34 - // TODO: Pulling all recipe data just to search for the one that matches the slug is inefficient. 35 - // Consider pulling these once, elsewhere, and passing the correct recipe to this component. 36 - // Followup: This might be irrelevant now that I'm using getStaticProps to fetch the data server-side. 37 - const recipe = recipesList.data.find((recipe) => recipe.slug === slug); 38 - 39 - return { props: { recipe }, revalidate: 60 }; 40 - }) satisfies GetStaticProps<RecipeProps>; 41 - 42 - // Reference: https://nextjs.org/docs/pages/building-your-application/data-fetching/get-static-paths 43 - export const getStaticPaths = (async () => { 44 - const recipesList = await importCSVDataAsJson( 45 - process.env.NEXT_PUBLIC_RECIPES_DATA_URL 46 - ); 47 - 48 - const paths = recipesList.data.map((recipe) => ({ 49 - params: { slug: recipe.slug }, 50 - })); 51 - 52 - return { paths, fallback: false }; 53 - }) satisfies GetStaticPaths;
+3 -17
pages/recipes/index.tsx components/pageContent/recipes/RecipesPage.tsx
··· 1 1 import RecipeSectionItem from "@/components/RecipeSectionItem"; 2 2 import BaseLayout from "@/components/BaseLayout"; 3 3 import SectionList from "@/components/SectionList"; 4 - import { importCSVDataAsJson } from "@/lib/sheetsConnector"; 5 - import type Recipe from "@/types/Recipe"; 4 + import type RecipeType from "@/types/RecipeType"; 6 5 import type { Key } from "react"; 7 - import type { GetStaticProps } from "next"; 8 6 9 7 interface RecipesProps { 10 8 recipesList: { 11 - data: Array<Recipe>; 9 + data: Array<RecipeType>; 12 10 }; 13 11 } 14 12 ··· 22 20 <h2>Recipes</h2> 23 21 <div className="text-lg">Behold, my lovely recipes.</div> 24 22 <SectionList className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3"> 25 - {recipesList.data.map((recipe: Recipe, k: Key) => ( 23 + {recipesList.data.map((recipe: RecipeType, k: Key) => ( 26 24 <RecipeSectionItem 27 25 link={"/recipes/" + recipe.slug} 28 26 name={recipe.title} ··· 37 35 </BaseLayout> 38 36 ); 39 37 } 40 - 41 - // Reference: https://nextjs.org/docs/pages/building-your-application/data-fetching/get-static-props#using-getstaticprops-to-fetch-data-from-a-cms 42 - export const getStaticProps = (async () => { 43 - const recipesList = await importCSVDataAsJson( 44 - process.env.NEXT_PUBLIC_RECIPES_DATA_URL 45 - ); 46 - 47 - return { 48 - props: { recipesList }, 49 - revalidate: 60, 50 - }; 51 - }) satisfies GetStaticProps<RecipesProps>;
-144
pages/temp.tsx
··· 1 - import HomeSectionItem from "@/components/HomeSectionItem"; 2 - import BaseLayout from "@/components/BaseLayout"; 3 - import SectionList from "@/components/SectionList"; 4 - import SocialLink from "@/components/SocialLink"; 5 - import { importCSVDataAsJson } from "@/lib/sheetsConnector"; 6 - import Link from "next/link"; 7 - import type { GetStaticProps } from "next"; 8 - import type { Key } from "react"; 9 - 10 - interface HomeProps { 11 - sectionsList: { 12 - data: Array<HomeSection>; 13 - }; 14 - } 15 - 16 - interface HomeSection { 17 - name: string; 18 - link: string; 19 - description: string; 20 - emoji: string; 21 - } 22 - 23 - export default function Home({ sectionsList }: HomeProps): React.ReactElement { 24 - return ( 25 - <BaseLayout navbarVisible={false}> 26 - <div className="max-w-5xl mx-auto w-full grid grid-cols-1 sm:grid-cols-2 gap-6"> 27 - <div> 28 - <h1 className="mb-2">Hello hello, this is Bailey speaking.</h1> 29 - <div className="prose prose-stone dark:prose-invert prose-a:no-underline leading-relaxed"> 30 - <p> 31 - I help small business owners{" "} 32 - <b>solve problems with technology,</b> so they can{" "} 33 - <b>reclaim their time</b> and{" "} 34 - <b>focus on the things that matter</b>. Contact me at{" "} 35 - <a 36 - className="" 37 - href="mailto:bailey.orion.kane@gmail.com" 38 - target="_blank" 39 - > 40 - <code className="underline">bailey.orion.kane@gmail.com</code> 41 - </a> 42 - . 43 - </p> 44 - <p>Some things I do:</p> 45 - <ul className="list-disc"> 46 - <li> 47 - <b>Build websites</b> for businesses, portfolios, or for fun 48 - </li> 49 - <li> 50 - <b>Create bespoke tools</b> and systems to work more efficiently 51 - </li> 52 - <li> 53 - <b>Connect systems</b> and tools together 54 - </li> 55 - </ul> 56 - <div className="mx-auto not-prose"> 57 - <Link href={"/projects"} className="rounded-lg"> 58 - <p 59 - className="w-full text-center px-4 py-2 font-semibold text-stone-900 dark:text-white 60 - bg-gradient-to-r from-purple-200 to-orange-100 dark:from-purple-500 dark:to-orange-300 61 - border border-stone-800 dark:border-stone-200 rounded-lg group transition hover:scale-105" 62 - > 63 - Example projects → 64 - </p> 65 - </Link> 66 - </div> 67 - <p> 68 - I enjoy working with <b>small business owners and individuals</b>. 69 - Even more fun if they work in{" "} 70 - <span className="underline decoration-green-700 dark:decoration-green-400 underline-offset-2"> 71 - climate 72 - </span> 73 - ,{" "} 74 - <span className="underline decoration-purple-700 dark:decoration-purple-400 underline-offset-2"> 75 - arts 76 - </span> 77 - ,{" "} 78 - <span className="underline decoration-orange-600 dark:decoration-orange-400 underline-offset-2"> 79 - music 80 - </span> 81 - , or{" "} 82 - <span className="underline decoration-blue-700 dark:decoration-blue-400 underline-offset-2"> 83 - education 84 - </span> 85 - . 86 - </p> 87 - <p> 88 - If this sounds like you and you might have a project to work on 89 - together, or you just want to say hi, please get in touch. 90 - </p> 91 - <p>Talk to you soon 👋</p> 92 - </div> 93 - <div className="pt-4 mt-4 border-t border-t-stone-400 dark:border-t-stone-500"> 94 - <div className="w-fit flex gap-2 items-center"> 95 - <SocialLink href="https://www.linkedin.com/in/baileykane/"> 96 - LinkedIn{" "} 97 - </SocialLink> 98 - <SocialLink 99 - href="https://bsky.app/profile/baileykane.co" 100 - icon="/img/bluesky_favicon.png" 101 - > 102 - Bluesky 103 - </SocialLink> 104 - </div> 105 - </div> 106 - </div> 107 - <div className="py-6 px-2 sm:px-4 rounded-lg bg-stone-100 dark:bg-stone-800 w-full flex flex-col relative z-10"> 108 - <h3 className="text-stone-600 dark:text-stone-300 mb-2 border-b border-b-stone-400 dark:border-b-stone-500"> 109 - All of my projects 110 - </h3> 111 - <div className="h-full w-full items-center"> 112 - <SectionList className="item-list flex flex-col"> 113 - {sectionsList.data.map((section: HomeSection, k: Key) => ( 114 - <HomeSectionItem 115 - link={ 116 - section.link ? section.link : section.name.toLowerCase() 117 - } 118 - name={section.name} 119 - description={section.description} 120 - emoji={section.emoji} 121 - key={k} 122 - /> 123 - ))} 124 - </SectionList> 125 - </div> 126 - </div> 127 - </div> 128 - </BaseLayout> 129 - ); 130 - } 131 - 132 - // Reference: https://nextjs.org/docs/pages/building-your-application/data-fetching/get-static-props#using-getstaticprops-to-fetch-data-from-a-cms 133 - export const getStaticProps = (async () => { 134 - const sectionsList = await importCSVDataAsJson( 135 - process.env.NEXT_PUBLIC_HOME_DATA_URL 136 - ); 137 - 138 - return { 139 - props: { 140 - sectionsList, 141 - }, 142 - revalidate: 60, 143 - }; 144 - }) satisfies GetStaticProps<HomeProps>;
+1 -1
types/Music.ts types/MusicItem.ts
··· 1 - export default interface Music { 1 + export default interface MusicItem { 2 2 title: string; 3 3 description: string; 4 4 type: MusicType;
+1 -1
types/Project.ts types/ProjectType.ts
··· 1 - export default interface Project { 1 + export default interface ProjectType { 2 2 title: string; 3 3 description?: string; 4 4 longDescription?: string;
+1 -1
types/Recipe.ts types/RecipeType.ts
··· 1 - export default interface Recipe { 1 + export default interface RecipeType { 2 2 title: string; 3 3 date: string; 4 4 thumbnail: string;
+6
types/home/HomeSection.ts
··· 1 + export default interface HomeSection { 2 + name: string; 3 + link: string; 4 + description: string; 5 + emoji: string; 6 + }