Skip to content

Commit f2269f8

Browse files
committed
Mark sectors
1 parent 3fa2a43 commit f2269f8

File tree

6 files changed

+160
-33
lines changed

6 files changed

+160
-33
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { useEffect } from "react"
2+
3+
export function useOnClickOutside(
4+
ref: React.RefObject<HTMLElement | null>,
5+
handler: (event: MouseEvent) => void,
6+
) {
7+
useEffect(() => {
8+
const listener = (event: MouseEvent) => {
9+
if (ref.current && event.composedPath().includes(ref.current)) {
10+
return
11+
}
12+
handler(event)
13+
}
14+
15+
document.addEventListener("click", listener)
16+
return () => document.removeEventListener("click", listener)
17+
// eslint-disable-next-line react-hooks/exhaustive-deps
18+
}, [])
19+
}

src/components/footer/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,9 @@ export function Footer({ extraLinks }: { extraLinks: FooterLink[] }) {
6161
)}
6262
</h3>
6363
)}
64-
{section.links.map(link => (
64+
{section.links.map((link, i) => (
6565
<Anchor
66-
key={link.route}
66+
key={i}
6767
href={link.route}
6868
className="gql-focus-visible block p-4 underline-offset-4 hover:underline focus-visible:!-outline-offset-4 md:px-6 2xl:px-10"
6969
>

src/components/index-page/data-colocation/component-tree.tsx

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,45 +15,48 @@ export function ComponentTree({
1515
return (
1616
<div
1717
className={clsx(
18-
"mx-auto flex max-w-[500px] justify-between [--gap-x:20px] md:gap-x-10 md:[--gap-x:32px] 3xl:gap-x-20",
18+
"sector-opacity mx-auto flex max-w-[500px] justify-between [--gap-x:20px] md:gap-x-10 md:[--gap-x:32px] 3xl:gap-x-20",
1919
className,
2020
)}
2121
{...rest}
2222
>
2323
<div className="flex flex-col">
24-
<div className="flex h-12 items-center">
24+
<div className="flex h-12 items-center" data-sector="1">
2525
<ComponentLabel className="border-neu-300 bg-neu-0 dark:border-neu-200">
2626
{names[0]}
2727
</ComponentLabel>
2828
</div>
2929

3030
<div className="h-4" />
3131

32-
<div className="flex h-12 items-center">
32+
<div className="flex h-12 items-center" data-sector="2">
3333
<ComponentLabel className="border-neu-600 bg-neu-400 dark:border-neu-200 dark:bg-neu-50">
3434
{names[1]}
3535
</ComponentLabel>
3636
</div>
3737

3838
<div className="h-4" />
3939

40-
<div className="flex h-12 items-center">
40+
<div className="flex h-12 items-center" data-sector="3">
4141
<ComponentLabel className="border-sec-base bg-sec-lighter dark:border-sec-dark dark:bg-sec-darker/50">
4242
{names[2]}
4343
</ComponentLabel>
4444
</div>
4545

4646
<div className="h-4" />
4747

48-
<div className="flex h-12 items-center">
48+
<div className="flex h-12 items-center" data-sector="4">
4949
<ComponentLabel className="border-pri-base bg-pri-lighter/40 dark:border-pri-dark dark:bg-pri-darker/50">
5050
{names[3]}
5151
</ComponentLabel>
5252
</div>
5353
</div>
5454

5555
<div className="flex flex-col items-center">
56-
<div className="flex size-12 items-center justify-center bg-neu-100 dark:bg-neu-50">
56+
<div
57+
className="flex size-12 items-center justify-center bg-neu-100 dark:bg-neu-50"
58+
data-sector="1"
59+
>
5760
<ModemIcon className="size-6 text-neu-600" />
5861
</div>
5962

@@ -63,6 +66,7 @@ export function ComponentTree({
6366
bgColor="bg-neu-600 dark:bg-neu-200"
6467
middleColor="bg-sec-base"
6568
innerColor="bg-pri-base"
69+
data-sector="2"
6670
/>
6771

6872
<Fork
@@ -78,9 +82,10 @@ export function ComponentTree({
7882
bgColor="bg-neu-100 dark:bg-neu-50"
7983
middleColor="bg-sec-base"
8084
innerColor="bg-pri-base"
85+
data-sector="3"
8186
/>
8287
<Fork className="text-neu-300 dark:text-neu-100" />
83-
<div className="flex gap-[--gap-x]">
88+
<div className="flex gap-[--gap-x]" data-sector="4">
8489
<LeafBox />
8590
<LeafBox />
8691
</div>
@@ -90,9 +95,10 @@ export function ComponentTree({
9095
bgColor="bg-neu-100 dark:bg-neu-50"
9196
middleColor="bg-sec-base"
9297
innerColor="bg-pri-base"
98+
data-sector="3"
9399
/>
94100
<Fork className="text-neu-300 dark:text-neu-100" />
95-
<div className="flex gap-[--gap-x]">
101+
<div className="flex gap-[--gap-x]" data-sector="4">
96102
<LeafBox />
97103
<LeafBox />
98104
</div>
@@ -103,45 +109,55 @@ export function ComponentTree({
103109
)
104110
}
105111

106-
interface NestedBoxProps {
112+
interface NestedBoxProps extends React.HTMLAttributes<HTMLDivElement> {
107113
bgColor: string
108114
middleColor?: string
109115
innerColor: string
110116
}
111117

112-
function NestedBox({ bgColor, middleColor, innerColor }: NestedBoxProps) {
118+
function NestedBox({
119+
bgColor,
120+
middleColor,
121+
innerColor,
122+
...rest
123+
}: NestedBoxProps) {
113124
const padding = INNER_BOX_SIZE / 2
114125

115126
return (
116-
<div className={bgColor} style={{ padding }}>
127+
<div className={bgColor} style={{ padding }} {...rest}>
117128
<div className={middleColor || bgColor} style={{ padding }}>
118129
<div className={innerColor} style={{ padding }} />
119130
</div>
120131
</div>
121132
)
122133
}
123134

124-
interface ComponentLabelProps {
135+
interface ComponentLabelProps extends React.HTMLAttributes<HTMLDivElement> {
125136
children: React.ReactNode
126137
className: string
127138
}
128139

129-
function ComponentLabel({ children, className }: ComponentLabelProps) {
140+
function ComponentLabel({ children, className, ...rest }: ComponentLabelProps) {
130141
return (
131142
<div
132143
className={clsx(
133144
"rounded border px-1 py-0.5 font-mono text-[10px] text-neu-800 dark:font-medium",
134145
className,
135146
)}
147+
{...rest}
136148
>
137149
{children}
138150
</div>
139151
)
140152
}
141153

142-
function LeafBox() {
154+
function LeafBox(props: React.HTMLAttributes<HTMLDivElement>) {
143155
return (
144-
<NestedBox bgColor="bg-neu-100 dark:bg-neu-50" innerColor="bg-pri-base" />
156+
<NestedBox
157+
bgColor="bg-neu-100 dark:bg-neu-50"
158+
innerColor="bg-pri-base"
159+
{...props}
160+
/>
145161
)
146162
}
147163

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
.sector-opacity {
2+
& [data-sector] {
3+
transition: opacity 0.2s ease-out;
4+
}
5+
6+
[data-active-sector] & [data-sector] {
7+
opacity: 0.4;
8+
}
9+
10+
[data-active-sector="1"] & [data-sector="1"],
11+
[data-active-sector="2"] & [data-sector="2"],
12+
[data-active-sector="3"] & [data-sector="3"],
13+
[data-active-sector="4"] & [data-sector="4"] {
14+
opacity: 1;
15+
}
16+
}
17+
18+
.sector-ring {
19+
[data-active-sector="1"] & [data-sector="1"],
20+
[data-active-sector="2"] & [data-sector="2"],
21+
[data-active-sector="3"] & [data-sector="3"],
22+
[data-active-sector="4"] & [data-sector="4"] {
23+
@apply ring-2 ring-neu-500 ring-offset-2;
24+
}
25+
}

src/components/index-page/data-colocation/friend-list.tsx

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import { useState } from "react"
2-
31
import { friendAvatars } from "./friend-avatars"
42

53
interface FriendList {
@@ -8,11 +6,14 @@ interface FriendList {
86

97
export function FriendList({ friends }: FriendList) {
108
return (
11-
<section className="overflow-hidden rounded-lg border border-neu-200 dark:border-neu-100">
9+
<section
10+
className="overflow-hidden rounded-lg border border-neu-200 dark:border-neu-100"
11+
data-sector="2"
12+
>
1213
<h4 className="typography-body-lg border-b border-neu-200 bg-neu-50 px-3 py-2 dark:border-neu-100 dark:bg-neu-50/50">
1314
Friends
1415
</h4>
15-
<ul className="flex flex-col gap-6 p-6 max-sm:[&>*:not(:first-child)]:hidden">
16+
<ul className="flex flex-col gap-6 p-3 lg:p-6 max-sm:[&>*:not(:first-child)]:hidden">
1617
{friends.map(friend => (
1718
<FriendListItem key={friend.name} {...friend} />
1819
))}
@@ -39,7 +40,10 @@ export function FriendListItem({
3940
friendAvatars[profilePic.replace(".webp", "") as keyof typeof friendAvatars]
4041

4142
return (
42-
<li className="flex items-start gap-2">
43+
<li
44+
className="-m-1 flex items-start gap-2 rounded-[5px] p-1"
45+
data-sector="3"
46+
>
4347
<img
4448
src={avatar.src}
4549
alt=""
@@ -73,7 +77,10 @@ const friendInfoKeys: (keyof FriendInfo)[] = ["username", "email", "location"]
7377

7478
export function FriendInfo(props: FriendInfo) {
7579
return (
76-
<dl className="flex flex-col gap-0.5 rounded-[4px] border border-neu-100 bg-neu-50 px-1.5 py-1 dark:border-neu-50 dark:bg-neu-50/50">
80+
<dl
81+
className="flex flex-col gap-0.5 rounded-[4px] border border-neu-100 bg-neu-50 px-1.5 py-1 dark:border-neu-50 dark:bg-neu-50/50"
82+
data-sector="4"
83+
>
7784
{friendInfoKeys.map(key => (
7885
<div
7986
key={key}
@@ -89,16 +96,16 @@ export function FriendInfo(props: FriendInfo) {
8996

9097
function SubscribeIconButton() {
9198
return (
92-
<div className="size-8 bg-neu-50">
99+
<div className="pointer-events-none size-8 bg-neu-50">
93100
<svg width="32" height="33" viewBox="0 0 32 33" fill="currentColor">
94101
<path
95-
fill-rule="evenodd"
96-
clip-rule="evenodd"
102+
fillRule="evenodd"
103+
clipRule="evenodd"
97104
d="M25.2198 14.5H23.7486V15.8333H25.2198V14.5ZM20.8052 15.8332H19.334V17.1665H20.8052V15.8332ZM22.2771 17.1668H20.8058V18.5001H22.2771V17.1668ZM22.2768 15.8332H23.748V17.1665H22.2768V15.8332Z"
98105
/>
99106
<path
100-
fill-rule="evenodd"
101-
clip-rule="evenodd"
107+
fillRule="evenodd"
108+
clipRule="evenodd"
102109
d="M15.9991 9.8335H11.9992V11.1668H10.6661V15.1668H11.9994V11.1668H15.9991V9.8335ZM15.9991 15.1668H11.9992V16.5002H15.9991V15.1668ZM15.9993 11.1668H17.3326V15.1668H15.9993V11.1668ZM8.66602 19.1667H9.99931V17.8335H17.999V19.1668H9.99931V21.8335H17.9992V19.1667H19.3325V23.1667H19.3323V23.1668H8.66602V23.1667V21.8335V19.1667Z"
103110
/>
104111
</svg>

src/components/index-page/data-colocation/index.tsx

Lines changed: 65 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
import { clsx } from "clsx"
22
import { Code } from "nextra/components"
3-
import { ComponentPropsWithoutRef } from "react"
3+
import { ComponentPropsWithoutRef, useRef } from "react"
44

55
import { Pre } from "@/components/pre"
66
import { SectionLabel } from "@/app/conf/_design-system/section-label"
77
import InfoIcon from "@/app/conf/_design-system/pixelarticons/info.svg?svgr"
88

99
import { ComponentTree } from "./component-tree"
1010
import { FriendList } from "./friend-list"
11+
1112
import json from "./data-colocation.json"
1213
import Query from "./data-colocation.mdx"
14+
import "./data-colocation.css"
15+
import { useOnClickOutside } from "@/app/conf/_design-system/utils/useOnClickOutside"
1316

1417
const components = {
1518
pre: (props: ComponentPropsWithoutRef<typeof Pre>) => (
@@ -27,8 +30,63 @@ const components = {
2730
}
2831

2932
export function DataColocation() {
33+
const markSector = (event: React.MouseEvent<HTMLElement>) => {
34+
const target =
35+
event.target && event.target instanceof HTMLElement ? event.target : null
36+
37+
const sectorElement = target?.closest("[data-sector]") as HTMLElement | null
38+
const sector = sectorElement?.dataset.sector
39+
40+
if (!sector) return
41+
42+
const currentTarget = event.currentTarget
43+
44+
if (currentTarget.dataset.activeSector !== sector) {
45+
currentTarget.dataset.activeSector = sector
46+
}
47+
}
48+
49+
const unmarkSector = (event: React.MouseEvent<HTMLElement>) => {
50+
console.log("unmarkSector", window.matchMedia("(hover: none)").matches)
51+
if (window.matchMedia("(hover: none)").matches) return
52+
53+
const target =
54+
event.relatedTarget && event.relatedTarget instanceof HTMLElement
55+
? event.relatedTarget
56+
: null
57+
58+
const currentTarget = event.currentTarget
59+
60+
const sectorElement = target?.closest("[data-sector]") as HTMLElement | null
61+
const targetSector = sectorElement?.dataset.sector
62+
const currentActiveSector = currentTarget.dataset.activeSector
63+
64+
if (!targetSector) {
65+
delete currentTarget.dataset.activeSector
66+
return
67+
}
68+
69+
if (!currentActiveSector) return
70+
71+
currentTarget.dataset.activeSector = targetSector
72+
}
73+
74+
const ref = useRef<HTMLDivElement>(null)
75+
useOnClickOutside(ref, event => {
76+
console.log("clicked outside")
77+
if (event.currentTarget && event.currentTarget instanceof HTMLElement) {
78+
delete event.currentTarget.dataset.activeSector
79+
}
80+
})
81+
3082
return (
31-
<section className="gql-container gql-section flex flex-wrap justify-between gap-4 sm:max-xl:gap-y-8 xl:p-24">
83+
<section
84+
ref={ref}
85+
className="gql-container gql-section flex flex-wrap justify-between gap-4 sm:max-xl:gap-y-8 xl:p-24"
86+
onMouseOver={markSector}
87+
onMouseOut={unmarkSector}
88+
onPointerDown={markSector}
89+
>
3290
<div className="shrink">
3391
<header>
3492
<SectionLabel>Data Colocation</SectionLabel>
@@ -51,7 +109,9 @@ export function DataColocation() {
51109
<article className="flex flex-wrap divide-neu-100 dark:divide-neu-50 dark:shadow-[0_.5px_20px_0_hsl(0_0_0/.25)] max-xl:w-full max-lg:gap-4 lg:shadow-[0_.5px_20px_0_hsl(var(--color-neu-400))] lg:dark:bg-neu-50/10 xl:divide-x xl:rounded-lg">
52110
<div className="flex grow flex-col gap-y-4 lg:flex-col-reverse lg:p-4">
53111
<FigureInfo />
54-
<FriendList friends={json.friends} />
112+
<div className="sector-ring">
113+
<FriendList friends={json.friends} />
114+
</div>
55115
</div>
56116
<div className="flex grow *:w-full *:rounded-lg *:border *:border-neu-100 *:bg-neu-50/50 lg:p-4">
57117
<Query components={components} />
@@ -63,8 +123,8 @@ export function DataColocation() {
63123

64124
function FigureInfo() {
65125
return (
66-
<div className="flex w-full grow gap-2 xl:max-w-[240px]">
67-
<InfoIcon className="size-5 shrink-0 translate-y-[0.5px]" />
126+
<div className="flex w-full grow gap-2 hover-none:items-center xl:max-w-[240px]">
127+
<InfoIcon className="size-4 shrink-0 hover-hover:size-5 hover-hover:translate-y-[0.5px]" />
68128
<p className="typography-body-sm text-neu-800">
69129
<span className="hover-hover:hidden">Click on</span>
70130
<span className="hover-none:hidden">Hover over</span> the components to

0 commit comments

Comments
 (0)