-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Going to revamp my portfolio a bit. So it meets next14 standards, and best practices.
- Loading branch information
1 parent
b3fdf89
commit ef2524c
Showing
11 changed files
with
1,736 additions
and
1,515 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -36,3 +36,5 @@ yarn-error.log* | |
next-env.d.ts | ||
|
||
.vercel | ||
.dccache | ||
.vscode |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import { createClient } from "@liveblocks/client"; | ||
import { createRoomContext } from "@liveblocks/react"; | ||
|
||
const client = createClient({ | ||
authEndpoint: "/api/liveblocks-auth", | ||
}); | ||
|
||
// Presence represents the properties that will exist on every User in the Room | ||
// and that will automatically be kept in sync. Accessible through the | ||
// `user.presence` property. Must be JSON-serializable. | ||
type Presence = { | ||
cursor: { x: number; y: number } | null; | ||
}; | ||
|
||
// Optionally, Storage represents the shared document that persists in the | ||
// Room, even after all Users leave. Fields under Storage typically are | ||
// LiveList, LiveMap, LiveObject instances, for which updates are | ||
// automatically persisted and synced to all connected clients. | ||
type Storage = { | ||
// animals: LiveList<string>, | ||
// ... | ||
}; | ||
|
||
// Optionally, UserMeta represents static/readonly metadata on each User, as | ||
// provided by your own custom auth backend (if used). Useful for data that | ||
// will not change during a session, like a User's name or avatar. | ||
type UserMeta = { | ||
info: { | ||
name: string; | ||
color: [string, string]; | ||
avatar: string; | ||
}; | ||
}; | ||
|
||
// Optionally, the type of custom events broadcasted and listened for in this | ||
// room. Must be JSON-serializable. | ||
// type RoomEvent = {}; | ||
|
||
export const { | ||
RoomProvider, | ||
useMyPresence, | ||
useUpdateMyPresence, | ||
useOthersMapped, | ||
} = createRoomContext<Presence, Storage, UserMeta /* RoomEvent */>(client); |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
.cursor { | ||
position: absolute; | ||
top: 0; | ||
left: 0; | ||
pointer-events: none; | ||
user-select: none; | ||
} | ||
|
||
.nameWrapper, | ||
.avatarWrapper { | ||
position: relative; | ||
} | ||
|
||
.cursorSvg { | ||
position: absolute; | ||
top: 0; | ||
left: 0; | ||
} | ||
|
||
.namePill { | ||
position: absolute; | ||
overflow: hidden; | ||
top: 1rem; | ||
left: 1rem; | ||
padding-top: 0.375rem; | ||
padding-bottom: 0.375rem; | ||
padding-left: 0.75rem; | ||
padding-right: 0.75rem; | ||
font-size: 0.875rem; | ||
line-height: 1.25rem; | ||
font-weight: 500; | ||
white-space: nowrap; | ||
border-radius: 0.5rem; | ||
} | ||
|
||
.namePillName { | ||
z-index: 10; | ||
position: relative; | ||
} | ||
|
||
.avatar { | ||
display: block; | ||
position: absolute; | ||
top: 16px; | ||
left: 16px; | ||
overflow: hidden; | ||
border-radius: 9999px; | ||
outline-width: 2px; | ||
outline-style: solid; | ||
outline-offset: 2px; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
import React, { useMemo } from "react"; | ||
import Image from "next/image"; | ||
import { motion } from "framer-motion"; | ||
import { getContrastingColor } from "@/utils/getContrastingColor"; | ||
import styles from "./Cursor.module.css"; | ||
|
||
type AllProps = { | ||
variant?: "basic" | "name" | "avatar"; | ||
x: number; | ||
y: number; | ||
color: [string, string]; | ||
}; | ||
|
||
type BasicCursorProps = AllProps & { | ||
variant?: "basic"; | ||
name?: never; | ||
avatar?: never; | ||
size?: never; | ||
}; | ||
|
||
type NameCursorProps = AllProps & { | ||
variant: "name"; | ||
name: string; | ||
avatar?: never; | ||
size?: never; | ||
}; | ||
|
||
type AvatarCursorProps = AllProps & { | ||
variant: "avatar"; | ||
avatar: string; | ||
name?: never; | ||
size?: number; | ||
}; | ||
|
||
type CursorProps = BasicCursorProps | NameCursorProps | AvatarCursorProps; | ||
|
||
export default function Cursor({ | ||
variant = "basic", | ||
x, | ||
y, | ||
color = ["", ""], | ||
name = "", | ||
avatar = "", | ||
size = 36, | ||
}: CursorProps) { | ||
return ( | ||
<motion.div | ||
className={styles.cursor} | ||
initial={{ x, y }} | ||
animate={{ x, y }} | ||
transition={{ | ||
type: "spring", | ||
bounce: 0.6, | ||
damping: 30, | ||
mass: 0.8, | ||
stiffness: 350, | ||
restSpeed: 0.01, | ||
}} | ||
> | ||
{variant === "basic" ? <BasicCursor color={color} /> : null} | ||
{variant === "name" ? <NameCursor color={color} name={name} /> : null} | ||
{variant === "avatar" ? ( | ||
<AvatarCursor color={color} avatar={avatar} size={size} /> | ||
) : null} | ||
</motion.div> | ||
); | ||
} | ||
|
||
function BasicCursor({ color }: Pick<BasicCursorProps, "color">) { | ||
return ( | ||
<svg width="32" height="44" viewBox="0 0 24 36" fill="none"> | ||
<defs> | ||
<linearGradient id="gradient" x1="0%" y1="0%" x2="500%" y2="0%"> | ||
<stop offset="0%" stopColor={color[0]} /> | ||
<stop offset="100%" stopColor={color[1]} /> | ||
</linearGradient> | ||
</defs> | ||
<path | ||
fill="url(#gradient)" | ||
d="M0.928548 2.18278C0.619075 1.37094 1.42087 0.577818 2.2293 0.896107L14.3863 5.68247C15.2271 6.0135 15.2325 7.20148 14.3947 7.54008L9.85984 9.373C9.61167 9.47331 9.41408 9.66891 9.31127 9.91604L7.43907 14.4165C7.09186 15.2511 5.90335 15.2333 5.58136 14.3886L0.928548 2.18278Z" | ||
/> | ||
</svg> | ||
); | ||
} | ||
|
||
function NameCursor({ color, name }: Pick<NameCursorProps, "color" | "name">) { | ||
const textColor = useMemo( | ||
() => (color ? getContrastingColor(color[1]) : undefined), | ||
[color] | ||
); | ||
return ( | ||
<div className={styles.nameWrapper}> | ||
<svg | ||
className={styles.cursorSvg} | ||
width="32" | ||
height="44" | ||
viewBox="0 0 24 36" | ||
fill="none" | ||
> | ||
<defs> | ||
<linearGradient id="gradient" x1="0%" y1="0%" x2="500%" y2="0%"> | ||
<stop offset="0%" stopColor={color[0]} /> | ||
<stop offset="100%" stopColor={color[1]} /> | ||
</linearGradient> | ||
</defs> | ||
<path | ||
fill="url(#gradient)" | ||
d="M0.928548 2.18278C0.619075 1.37094 1.42087 0.577818 2.2293 0.896107L14.3863 5.68247C15.2271 6.0135 15.2325 7.20148 14.3947 7.54008L9.85984 9.373C9.61167 9.47331 9.41408 9.66891 9.31127 9.91604L7.43907 14.4165C7.09186 15.2511 5.90335 15.2333 5.58136 14.3886L0.928548 2.18278Z" | ||
/> | ||
</svg> | ||
<div | ||
className={styles.namePill} | ||
style={{ | ||
backgroundImage: `linear-gradient(to bottom right, ${color[0]}, ${color[1]})`, | ||
color: textColor, | ||
}} | ||
> | ||
<div className={styles.namePillName}>{name}</div> | ||
</div> | ||
</div> | ||
); | ||
} | ||
|
||
function AvatarCursor({ | ||
color, | ||
avatar, | ||
size, | ||
}: Pick<AvatarCursorProps, "color" | "avatar" | "size">) { | ||
return ( | ||
<div className={styles.avatarWrapper}> | ||
<svg | ||
className={styles.cursorSvg} | ||
width="32" | ||
height="44" | ||
viewBox="0 0 24 36" | ||
fill="none" | ||
> | ||
<defs> | ||
<linearGradient id="gradient" x1="0%" y1="0%" x2="500%" y2="0%"> | ||
<stop offset="0%" stopColor={color[0]} /> | ||
<stop offset="100%" stopColor={color[1]} /> | ||
</linearGradient> | ||
</defs> | ||
<path | ||
fill="url(#gradient)" | ||
d="M0.928548 2.18278C0.619075 1.37094 1.42087 0.577818 2.2293 0.896107L14.3863 5.68247C15.2271 6.0135 15.2325 7.20148 14.3947 7.54008L9.85984 9.373C9.61167 9.47331 9.41408 9.66891 9.31127 9.91604L7.43907 14.4165C7.09186 15.2511 5.90335 15.2333 5.58136 14.3886L0.928548 2.18278Z" | ||
/> | ||
</svg> | ||
<div | ||
className={styles.avatar} | ||
style={{ | ||
outlineColor: color[0], | ||
width: size + "px", | ||
height: size + "px", | ||
}} | ||
> | ||
<Image src={avatar} height={size} width={size} alt="" /> | ||
</div> | ||
</div> | ||
); | ||
} |
Oops, something went wrong.
ef2524c
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
portfolio – ./
www.mikeodnis.com
portfolio-git-master-womb0comb0.vercel.app
portfolio-womb0comb0.vercel.app
mikeodnis.com