Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Social sharing and social buttons rework #36

Merged
merged 2 commits into from
Jul 10, 2023
Merged
Changes from all commits
Commits
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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -10,6 +10,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

- Back to top button
- SocialIcon component
- Share post component

### Changed

- Changed social icons to use [simple-icons](https://simpleicons.org)

## [0.5.0] - 2023-07-06

7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -172,11 +172,14 @@ Note: DO NOT overdo it. You can easily make images look bad with lossy compressi
- [x] contributing docs
- [x] Docs refresh
- [x] Back to top button
- [ ] Social sharing buttons
- [x] Social icons component
- [x] Social sharing buttons
- [ ] Tags, categories
- [ ] newsletter integration (form, api route, keys, welcome page, previous issues)
- [ ] Other analytics providers (fathom, simplelytics, plausible, etc)
- [ ] Tags, categories
- [ ] Post series page
- [ ] prev/next post links
- [ ] related posts
- [ ] Layouts/templates system
- [ ] hero title and subtitle text HTML support(?)
- [ ] Design improvements (whitespace, layout, etc.)
30 changes: 19 additions & 11 deletions app/(site)/posts/[slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import { Metadata } from "next";
import Link from "next/link";
import { notFound } from "next/navigation";
import { PostSeries, PostWithSeries, SeriesItem } from "@/types";
import { allPosts, Post } from "contentlayer/generated";
import { PostSeries, SeriesItem } from "@/types";
import { allPosts } from "contentlayer/generated";
import { format, parseISO } from "date-fns";
import { Home } from "lucide-react";

import siteMetadata, { defaultAuthor } from "@/lib/metadata";
import { cn } from "@/lib/utils";
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion";
import { Card, CardContent, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
import { Separator } from "@/components/ui/separator";
import { Mdx } from "@/components/mdx-components";
import { PostSeriesBox } from "@/components/post-series-box";
import { SocialShare } from "@/components/social-share";
import { TableOfContents } from "@/components/table-of-contents";

interface PostProps {
@@ -156,15 +158,21 @@ export default async function PostPage({ params }: PostProps) {
)}
<Mdx code={post.body.code} />
<hr className="my-4" />
{post.tags && (
<ul className="m-0 list-none space-x-2 p-0 text-sm text-muted-foreground">
{post.tags.map((tag: any) => (
<li className="inline-block p-0" key={tag.trim()}>
{tag}
</li>
))}
</ul>
)}
<div className="flex flex-row items-center justify-between">
{post.tags && (
<ul className="m-0 list-none space-x-2 p-0 text-sm text-muted-foreground">
{post.tags.map((tag: any) => (
<li className="inline-block p-0" key={tag.trim()}>
{tag}
</li>
))}
</ul>
)}
<SocialShare
text={`${post.title} via ${defaultAuthor.handle}`}
url={`${siteMetadata.metadataBase}${post._raw.flattenedPath}`}
/>
</div>
</article>
<aside className="hidden lg:block">
<Card className={cn("sticky top-28 mb-4")}>
37 changes: 6 additions & 31 deletions app/(social)/social/page.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
"use client";

import Image from "next/image";
import Link from "next/link";
import { Github, Instagram, Linkedin, Mail, Twitter, Youtube } from "lucide-react";
import { Mail } from "lucide-react";

import { defaultAuthor } from "@/lib/metadata";
import { projects } from "@/lib/projects-data";
import { Button } from "@/components/ui/button";
import { CopyButton } from "@/components/copy-button";
import CTA from "@/components/cta";
import { Signature } from "@/components/signature";
import { SocialButton } from "@/components/social-button";
import { SpotlightCard } from "@/components/spotlight-card";

export default async function SocialPage() {
@@ -32,33 +29,11 @@ export default async function SocialPage() {
</div>
<h2 className="mb-2 mt-6 font-heading text-2xl font-bold">My socials</h2>
<div className="mb-4 flex w-full max-w-2xl flex-col space-y-4">
<Button variant="default" asChild>
<Link href={defaultAuthor.social.twitter} target="_blank">
<Twitter /> My Twitter profile
</Link>
</Button>
<Button variant="default" asChild>
<Link href={defaultAuthor.social.youtube} target="_blank">
<Youtube /> My Youtube channel
</Link>
</Button>
<Button variant="default" asChild>
<Link href={defaultAuthor.social.github} target="_blank">
<Github /> My Github profile
</Link>
</Button>
<Button variant="default" asChild>
<Link href={defaultAuthor.social.instagram} target="_blank">
<Instagram /> My Instagram profile
</Link>
</Button>
<Button variant="default" asChild>
<Link href={defaultAuthor.social.linkedin} target="_blank">
<Linkedin /> My LinkedIn profile
</Link>
</Button>
{defaultAuthor.socialProfiles.map((platform) => (
<SocialButton key={platform.name} variant="outline" platform={platform} />
))}
<CopyButton variant="default" copyText={defaultAuthor.email}>
<Mail /> Email address
<Mail className="mr-2" /> Email address
</CopyButton>
</div>
<Signature />
8 changes: 6 additions & 2 deletions components/command-dialog.tsx
Original file line number Diff line number Diff line change
@@ -100,15 +100,19 @@ export function CommandDialogComponent({ ...props }: DialogProps) {
<CommandGroup heading="Social">
<CommandItem
onSelect={() => {
runCommand(() => navigate(defaultAuthor.social.twitter));
runCommand(() =>
navigate(defaultAuthor.socialProfiles.find((platform) => platform.name === "twitter")?.link as string)
);
}}
>
<Twitter className="mr-2 h-4 w-4" />
<span>Twitter</span>
</CommandItem>
<CommandItem
onSelect={() => {
runCommand(() => navigate(defaultAuthor.social.github));
runCommand(() =>
navigate(defaultAuthor.socialProfiles.find((platform) => platform.name === "github")?.link as string)
);
}}
>
<Github className="mr-2 h-4 w-4" />
2 changes: 2 additions & 0 deletions components/copy-button.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"use client";

import { useCallback, useEffect, useState } from "react";

import { Button, ButtonProps } from "@/components/ui/button";
48 changes: 12 additions & 36 deletions components/footer.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
"use client";

import React from "react";
import Link from "next/link";
import { Github, Instagram, Linkedin, Mail, Twitter, Youtube } from "lucide-react";
import { Mail } from "lucide-react";

import siteMetadata, { defaultAuthor } from "@/lib/metadata";
import { Button } from "@/components/ui/button";
import { CopyButton } from "@/components/copy-button";
import { Signature } from "@/components/signature";
import { SocialButton } from "@/components/social-button";

const Footer = () => {
return (
@@ -16,36 +13,15 @@ const Footer = () => {
<div className="container flex flex-col items-center justify-between space-y-5 text-center lg:flex-row lg:space-y-0 lg:text-left">
<div className="flex flex-col items-center gap-4 px-8 md:flex-row md:gap-2 md:px-0 lg:order-2">
<div className="flex flex-row space-x-2 text-sm text-muted-foreground">
<Button asChild variant="ghost" size="icon" className="hover:text-foreground">
<Link href={defaultAuthor.social.twitter} target="_blank">
<Twitter />
<span className="sr-only">Go to my Twitter profile</span>
</Link>
</Button>
<Button asChild variant="ghost" size="icon" className="hover:text-foreground">
<Link href={defaultAuthor.social.youtube} target="_blank">
<Youtube />
<span className="sr-only">Go to my Youtube channel</span>
</Link>
</Button>
<Button asChild variant="ghost" size="icon" className="hover:text-foreground">
<Link href={defaultAuthor.social.github} target="_blank">
<Github />
<span className="sr-only">Go to my Github profile</span>
</Link>
</Button>
<Button asChild variant="ghost" size="icon" className="hover:text-foreground">
<Link href={defaultAuthor.social.instagram} target="_blank">
<Instagram />
<span className="sr-only">Go to my Instagram profile</span>
</Link>
</Button>
<Button asChild variant="ghost" size="icon" className="hover:text-foreground">
<Link href={defaultAuthor.social.linkedin} target="_blank">
<Linkedin />
<span className="sr-only">Go to my LinkedIn profile</span>
</Link>
</Button>
{defaultAuthor.socialProfiles.map((platform) => (
<SocialButton
key={platform.name}
variant="ghost"
size="icon"
className="hover:text-foreground"
platform={platform}
/>
))}
<CopyButton size="icon" variant="ghost" className="hover:text-foreground" copyText={defaultAuthor.email}>
<Mail />
<span className="sr-only">Email address</span>
@@ -56,7 +32,7 @@ const Footer = () => {
<p className="text-sm text-muted-foreground md:text-left">
&copy; {new Date().getFullYear()} Built by {defaultAuthor.name}. &nbsp;
<a
href={defaultAuthor.social.twitter}
href={defaultAuthor.socialProfiles.find((platform) => platform.name === "twitter")?.link}
target="_blank"
rel="noreferrer"
className="font-medium underline underline-offset-4"
38 changes: 38 additions & 0 deletions components/social-button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import Link from "next/link";
import { SocialProfile } from "@/types";
import type { SimpleIcon } from "simple-icons";
import * as Icons from "simple-icons";

import { cn } from "@/lib/utils";
import { Button, ButtonProps } from "@/components/ui/button";

interface SocialButtonProps extends ButtonProps {
platform: SocialProfile;
}

export function SocialButton({ platform, ...props }: SocialButtonProps) {
const platformCamel = platform.name.toLocaleLowerCase().charAt(0).toUpperCase() + platform.name.slice(1);

const platformIconIdentifier = `si${platformCamel}`;

const renderIcon = () => {
const icon: SimpleIcon = Icons[platformIconIdentifier as keyof typeof Icons];
if (!icon) {
return null;
}
return (
<svg role="img" viewBox="0 0 24 24" className="h-5 w-5" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path d={icon.path}></path>
</svg>
);
};

return (
<Button asChild {...props}>
<Link href={platform.link} rel={platform.name === "mastodon" ? "me" : "noreferrer noopener"} target="_blank">
{renderIcon()}
<span className={cn(props.size === "icon" ? "sr-only" : "ml-2")}>Go to my {platformCamel} profile</span>
</Link>
</Button>
);
}
115 changes: 115 additions & 0 deletions components/social-share.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import Link from "next/link";
import { SocialProfile } from "@/types";
import { Mail } from "lucide-react";
import { siFacebook, siLinkedin, siTwitter, siYcombinator } from "simple-icons";

import { Button, ButtonProps } from "@/components/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";

interface SocialShareProps {
url: string;
text?: string;
}
export const SocialShare = ({ url, text }: SocialShareProps) => {
const encodedUrl = encodeURIComponent(url);
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline">Share</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuLabel>Share Post</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuItem asChild>
<Link
href={`https://twitter.com/intent/tweet?url=${encodedUrl}&text=${text}`}
rel="noreferrer noopener"
target="_blank"
>
<svg
role="img"
viewBox="0 0 24 24"
className="mr-2 h-3 w-3"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
>
<path d={siTwitter.path}></path>
</svg>
Twitter
</Link>
</DropdownMenuItem>
<DropdownMenuItem asChild>
<Link
href={`https://www.facebook.com/sharer/sharer.php?u=${encodedUrl}`}
rel="noreferrer noopener"
target="_blank"
>
<svg
role="img"
viewBox="0 0 24 24"
className="mr-2 h-3 w-3"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
>
<path d={siFacebook.path}></path>
</svg>
Facebook
</Link>
</DropdownMenuItem>
<DropdownMenuItem asChild>
<Link
href={`https://www.linkedin.com/sharing/share-offsite/?url=${encodedUrl}`}
rel="noreferrer noopener"
target="_blank"
>
<svg
role="img"
viewBox="0 0 24 24"
className="mr-2 h-3 w-3"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
>
<path d={siLinkedin.path}></path>
</svg>
LinkedIn
</Link>
</DropdownMenuItem>
<DropdownMenuItem asChild>
<Link
href={`https://news.ycombinator.com/submitlink?u=${encodedUrl}`}
rel="noreferrer noopener"
target="_blank"
>
<svg
role="img"
viewBox="0 0 24 24"
className="mr-2 h-3 w-3"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
>
<path d={siYcombinator.path}></path>
</svg>
Hacker News
</Link>
</DropdownMenuItem>
<DropdownMenuItem asChild>
<Link
href={`mailto:info@example.com?&subject=&cc=&bcc=&body=${encodedUrl}%20${text}`}
rel="noreferrer noopener"
target="_blank"
>
<Mail className="mr-2 h-3 w-3" />
Email
</Link>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
);
};
200 changes: 200 additions & 0 deletions components/ui/dropdown-menu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
"use client"

import * as React from "react"
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
import { Check, ChevronRight, Circle } from "lucide-react"

import { cn } from "@/lib/utils"

const DropdownMenu = DropdownMenuPrimitive.Root

const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger

const DropdownMenuGroup = DropdownMenuPrimitive.Group

const DropdownMenuPortal = DropdownMenuPrimitive.Portal

const DropdownMenuSub = DropdownMenuPrimitive.Sub

const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup

const DropdownMenuSubTrigger = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
inset?: boolean
}
>(({ className, inset, children, ...props }, ref) => (
<DropdownMenuPrimitive.SubTrigger
ref={ref}
className={cn(
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent",
inset && "pl-8",
className
)}
{...props}
>
{children}
<ChevronRight className="ml-auto h-4 w-4" />
</DropdownMenuPrimitive.SubTrigger>
))
DropdownMenuSubTrigger.displayName =
DropdownMenuPrimitive.SubTrigger.displayName

const DropdownMenuSubContent = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>
>(({ className, ...props }, ref) => (
<DropdownMenuPrimitive.SubContent
ref={ref}
className={cn(
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className
)}
{...props}
/>
))
DropdownMenuSubContent.displayName =
DropdownMenuPrimitive.SubContent.displayName

const DropdownMenuContent = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
>(({ className, sideOffset = 4, ...props }, ref) => (
<DropdownMenuPrimitive.Portal>
<DropdownMenuPrimitive.Content
ref={ref}
sideOffset={sideOffset}
className={cn(
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className
)}
{...props}
/>
</DropdownMenuPrimitive.Portal>
))
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName

const DropdownMenuItem = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
inset?: boolean
}
>(({ className, inset, ...props }, ref) => (
<DropdownMenuPrimitive.Item
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
inset && "pl-8",
className
)}
{...props}
/>
))
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName

const DropdownMenuCheckboxItem = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>
>(({ className, children, checked, ...props }, ref) => (
<DropdownMenuPrimitive.CheckboxItem
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className
)}
checked={checked}
{...props}
>
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<DropdownMenuPrimitive.ItemIndicator>
<Check className="h-4 w-4" />
</DropdownMenuPrimitive.ItemIndicator>
</span>
{children}
</DropdownMenuPrimitive.CheckboxItem>
))
DropdownMenuCheckboxItem.displayName =
DropdownMenuPrimitive.CheckboxItem.displayName

const DropdownMenuRadioItem = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>
>(({ className, children, ...props }, ref) => (
<DropdownMenuPrimitive.RadioItem
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className
)}
{...props}
>
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<DropdownMenuPrimitive.ItemIndicator>
<Circle className="h-2 w-2 fill-current" />
</DropdownMenuPrimitive.ItemIndicator>
</span>
{children}
</DropdownMenuPrimitive.RadioItem>
))
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName

const DropdownMenuLabel = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Label>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
inset?: boolean
}
>(({ className, inset, ...props }, ref) => (
<DropdownMenuPrimitive.Label
ref={ref}
className={cn(
"px-2 py-1.5 text-sm font-semibold",
inset && "pl-8",
className
)}
{...props}
/>
))
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName

const DropdownMenuSeparator = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
>(({ className, ...props }, ref) => (
<DropdownMenuPrimitive.Separator
ref={ref}
className={cn("-mx-1 my-1 h-px bg-muted", className)}
{...props}
/>
))
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName

const DropdownMenuShortcut = ({
className,
...props
}: React.HTMLAttributes<HTMLSpanElement>) => {
return (
<span
className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
{...props}
/>
)
}
DropdownMenuShortcut.displayName = "DropdownMenuShortcut"

export {
DropdownMenu,
DropdownMenuTrigger,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuCheckboxItem,
DropdownMenuRadioItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuShortcut,
DropdownMenuGroup,
DropdownMenuPortal,
DropdownMenuSub,
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuRadioGroup,
}
11 changes: 3 additions & 8 deletions lib/metadata.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
import { AuthorType, SiteMetaData } from "@/types";

import { socialProfiles } from "./social-data";

export const BASE_URL = process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3000";

export const defaultAuthor: AuthorType = {
name: "Amy Shields",
handle: "@amyshieldsfake",
social: {
github: "https://github.com/thedevdavid",
instagram: "https://instagram.com/thedevdavid",
linkedin: "https://linkedin.com/in/thedevdavid",
tiktok: "https://tiktok.com/@thedevdavid",
twitter: "https://twitter.com/thedevdavid",
youtube: "https://youtube.com/@thedevdavid",
},
socialProfiles,
email: "definitelyfake@nevermind.com",
website: "https://nextjs.org",
jobTitle: "Frontend Engineer & UI Designer",
2 changes: 1 addition & 1 deletion lib/navigation-links.ts
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@ const content: ContentNavItem[] = [
},
{
title: "Videos",
href: defaultAuthor.social.youtube,
href: defaultAuthor.socialProfiles.find((platform) => platform.name === "youtube")?.link as string,
description: "My YouTube channel where I talk about web development.",
},
{
37 changes: 33 additions & 4 deletions lib/social-data.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,36 @@
export const socialLinks = [
import { SocialProfile } from "@/types";

export const socialProfiles: SocialProfile[] = [
{
title: "Download my free learning path for software devs",
description: `I made this in collaboration with @dragonsandcodes`,
href: "https://dragons-and-codes.notion.site/100-days-of-becoming-a-full-stack-developer-challenge-dragonsandcodeschallenge-0dfc9f2e19784a498e0bbd05fa199f9c?ref=thedevdavid",
name: "github",
link: "https://github.com/thedevdavid",
},
{
name: "instagram",
link: "https://instagram.com/thedevdavid",
},
{
name: "linkedin",
link: "https://linkedin.com/in/thedevdavid",
},
{
name: "mastodon",
link: "https://mastodon.social/@thedevdavid",
},
{
name: "threads",
link: "https://threads.net/@thedevdavid",
},
{
name: "tiktok",
link: "https://tiktok.com/@thedevdavid",
},
{
name: "twitter",
link: "https://twitter.com/thedevdavid",
},
{
name: "youtube",
link: "https://youtube.com/@thedevdavid",
},
];
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -21,6 +21,7 @@
"@radix-ui/react-alert-dialog": "1.0.4",
"@radix-ui/react-aspect-ratio": "1.0.3",
"@radix-ui/react-dialog": "1.0.4",
"@radix-ui/react-dropdown-menu": "^2.0.5",
"@radix-ui/react-label": "2.0.2",
"@radix-ui/react-navigation-menu": "1.1.3",
"@radix-ui/react-scroll-area": "1.0.4",
@@ -48,6 +49,7 @@
"remark-gfm": "3.0.1",
"rss": "1.2.2",
"seti-icons": "0.0.4",
"simple-icons": "9.5.0",
"tailwind-merge": "1.13.2",
"zod": "3.21.4"
},
105 changes: 105 additions & 0 deletions pnpm-lock.yaml
14 changes: 6 additions & 8 deletions types/index.tsx
Original file line number Diff line number Diff line change
@@ -49,17 +49,15 @@ export type PostSeries = Series & { posts: SeriesItem[] };

export type PostWithSeries = Omit<Post, "series"> & { series: PostSeries };

export type SocialProfile = {
name: string;
link: string;
};

export type AuthorType = {
name: string;
handle: string;
social: {
github: string;
instagram: string;
linkedin: string;
tiktok: string;
twitter: string;
youtube: string;
};
socialProfiles: SocialProfile[];
email: string;
website: string;
jobTitle: string;