Skip to content

Commit 2995d16

Browse files
committed
feat: refactor article channel retrieval and improve type inference in multiple components
1 parent 200b2d2 commit 2995d16

File tree

11 files changed

+51
-27
lines changed

11 files changed

+51
-27
lines changed

.github/workflows/lint.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: Lint
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches:
7+
- main
8+
9+
jobs:
10+
lint:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- name: Checkout repository
14+
uses: actions/checkout@v4
15+
16+
- name: Setup Node.js
17+
uses: actions/setup-node@v4
18+
with:
19+
node-version: '20'
20+
cache: 'npm'
21+
22+
- name: Install dependencies
23+
run: npm ci
24+
25+
- name: Run ESLint
26+
run: npm run lint
27+
env:
28+
NEXT_TELEMETRY_DISABLED: '1'

src/app/atlas/AtlasClient.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export default function AtlasClient({ articles }: { articles: Article[] }) {
1919
const loadMoreRef = useRef<HTMLDivElement>(null)
2020

2121
const getArticleChannel = (article: Article): string | null => {
22-
const fm: any = article.frontmatter
22+
const fm = article.frontmatter
2323
const explicitChannel = fm.channel
2424
if (explicitChannel && typeof explicitChannel === 'string') return explicitChannel
2525
const tags = article.frontmatter.tags || []
@@ -211,4 +211,3 @@ export default function AtlasClient({ articles }: { articles: Article[] }) {
211211
</div>
212212
)
213213
}
214-

src/app/explore/ExploreClient.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import { useMemo, useState, useEffect } from 'react'
44
import Link from 'next/link'
5-
import { cn } from '@/lib/utils'
65
import {
76
Table,
87
TableBody,
@@ -29,7 +28,7 @@ export default function ExploreClient({ articles }: { articles: Article[] }) {
2928

3029
// Helper function to determine article's primary channel
3130
const getArticleChannel = (article: Article): string | null => {
32-
const fm: any = article.frontmatter
31+
const fm = article.frontmatter
3332
const explicitChannel = fm.channel
3433
if (explicitChannel && typeof explicitChannel === 'string') return explicitChannel
3534

@@ -204,4 +203,3 @@ export default function ExploreClient({ articles }: { articles: Article[] }) {
204203
</div>
205204
)
206205
}
207-

src/app/page.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { AppSidebar } from '@/components/app-sidebar'
22
import { BackgroundBeams } from '@/components/ui/background-beams'
3-
import { Button } from '@/components/ui/button'
43
import { Footer } from '@/components/ui/footer'
54
import { cn } from '@/lib/utils'
65
import Link from 'next/link'

src/components/app-sidebar.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import React from "react"
44
import { cn } from "@/lib/utils"
55
import { Sidebar, SidebarBody } from "@/components/ui/sidebar"
6-
import Image from "next/image"
76
import Link from "next/link"
87
import {
98
Home,
@@ -66,4 +65,4 @@ export function AppSidebar() {
6665
</SidebarBody>
6766
</Sidebar>
6867
)
69-
}
68+
}

src/components/channel-badge.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { cn } from "@/lib/utils";
22
import {
3-
Circle,
43
Atom,
54
Brain,
65
Calculator,

src/components/channels-sidebar.tsx

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
"use client";
22

33
import { cn } from "@/lib/utils";
4-
import { useState } from "react";
54
import { Checkbox } from "@/components/ui/checkbox";
65
import type { Article } from "@/lib/markdown";
76
import {
8-
Circle,
97
Atom,
10-
Brain,
118
Calculator,
129
Dna,
1310
Scale,
@@ -48,12 +45,11 @@ export function ChannelsSidebar({
4845
articles = [],
4946
className
5047
}: ChannelsSidebarProps) {
51-
const [hoveredChannel, setHoveredChannel] = useState<string | null>(null);
5248

5349
// Helper function to determine article's primary channel (same logic as Atlas page)
5450
const getArticleChannel = (article: Article): string | null => {
5551
// First check if explicit channel is defined in frontmatter
56-
const explicitChannel = (article.frontmatter as any).channel;
52+
const explicitChannel = article.frontmatter.channel;
5753
if (explicitChannel && typeof explicitChannel === 'string') {
5854
return explicitChannel;
5955
}
@@ -165,13 +161,10 @@ export function ChannelsSidebar({
165161
<nav className="p-2 space-y-1">
166162
{channels.map((channel) => {
167163
const isSelected = selectedChannels.includes(channel.id);
168-
const isHovered = hoveredChannel === channel.id;
169164

170165
return (
171166
<label
172167
key={channel.id}
173-
onMouseEnter={() => setHoveredChannel(channel.id)}
174-
onMouseLeave={() => setHoveredChannel(null)}
175168
className={cn(
176169
"w-full flex items-center gap-3 px-3 py-2 rounded-md cursor-pointer",
177170
"transition-all duration-200 group relative",

src/components/recent-updates.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ export function RecentUpdates({ className }: RecentUpdatesProps) {
8686
const persona = personaMap[mainAuthor];
8787

8888
// Determine correct route based on channel/content type
89-
const getArticleRoute = (slug: string, channel: string) => {
89+
const getArticleRoute = (slug: string) => {
9090
// For now, assume dialogue if multiple authors, monologue if single
9191
const isDialogue = update.author.includes('&');
9292
return isDialogue ? `/atlas/dialogue/${slug}` : `/atlas/monologue/${slug}`;
@@ -95,7 +95,7 @@ export function RecentUpdates({ className }: RecentUpdatesProps) {
9595
return (
9696
<div key={index}>
9797
<div
98-
onClick={() => router.push(getArticleRoute(update.slug, update.channel))}
98+
onClick={() => router.push(getArticleRoute(update.slug))}
9999
className={cn(
100100
"group p-3 rounded-md transition-all duration-200",
101101
"hover:bg-white dark:hover:bg-neutral-700",
@@ -161,4 +161,4 @@ export function RecentUpdates({ className }: RecentUpdatesProps) {
161161
<div className="h-8" />
162162
</div>
163163
);
164-
}
164+
}

src/components/ui/infinite-moving-cards.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ export const InfiniteMovingCards = ({
8181
>
8282
<blockquote>
8383
<span className="relative z-20 text-sm leading-[1.6] text-neutral-800 dark:text-gray-100 font-normal">
84-
"{item.quote}"
84+
&ldquo;{item.quote}&rdquo;
8585
</span>
8686
<div className="relative z-20 mt-6 flex flex-row items-center">
8787
<span className="flex flex-col gap-1">

src/components/ui/pixelated-canvas.tsx

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
"use client";
22
import React from "react";
33

4+
type CleanupImage = HTMLImageElement & { _cleanup?: () => void };
5+
46
type PixelatedCanvasProps = {
57
src: string;
68
width?: number;
@@ -114,7 +116,7 @@ export const PixelatedCanvas: React.FC<PixelatedCanvasProps> = ({
114116
const canvas = canvasRef.current;
115117
if (!canvas) return;
116118

117-
const img = new Image();
119+
const img: CleanupImage = new Image();
118120
img.crossOrigin = "anonymous";
119121
img.src = src;
120122

@@ -242,7 +244,10 @@ export const PixelatedCanvas: React.FC<PixelatedCanvasProps> = ({
242244
return [parseInt(m[1], 10), parseInt(m[2], 10), parseInt(m[3], 10)];
243245
return null;
244246
};
245-
tintRGB = parse(tintColor) as any;
247+
const parsedTint = parse(tintColor);
248+
if (parsedTint) {
249+
tintRGB = parsedTint;
250+
}
246251
}
247252

248253
for (let y = 0; y < offscreen.height; y += cellSize) {
@@ -498,7 +503,7 @@ export const PixelatedCanvas: React.FC<PixelatedCanvasProps> = ({
498503
canvasEl.removeEventListener("pointerleave", onPointerLeave);
499504
if (rafRef.current) cancelAnimationFrame(rafRef.current);
500505
};
501-
(img as any)._cleanup = cleanup;
506+
img._cleanup = cleanup;
502507
};
503508

504509
img.onerror = () => {
@@ -515,13 +520,13 @@ export const PixelatedCanvas: React.FC<PixelatedCanvasProps> = ({
515520
return () => {
516521
isCancelled = true;
517522
window.removeEventListener("resize", onResize);
518-
if ((img as any)._cleanup) (img as any)._cleanup();
523+
if (img._cleanup) img._cleanup();
519524
};
520525
}
521526

522527
return () => {
523528
isCancelled = true;
524-
if ((img as any)._cleanup) (img as any)._cleanup();
529+
if (img._cleanup) img._cleanup();
525530
};
526531
}, [
527532
src,

0 commit comments

Comments
 (0)