Skip to content
Merged
Show file tree
Hide file tree
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
39 changes: 26 additions & 13 deletions apps/web/src/components/LandingPage/features.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,20 +66,24 @@ const FeaturesPage = () => {
return (
<section
id="features"
className="py-20 lg:py-28 bg-[#fafafa] relative overflow-hidden border-b-[1.5px] border-black"
className="py-20 lg:py-28 relative overflow-hidden border-b-[1.5px]"
style={{
backgroundColor: 'var(--surface)',
borderColor: 'var(--landing-divider)',
}}
>
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="mb-16">
<div className="flex items-center gap-3 mb-3">
<span className="tech-stamp">FEATURES</span>
<div className="h-[1px] flex-1 bg-black" />
<div className="h-[1px] flex-1" style={{ backgroundColor: 'var(--landing-divider)' }} />
</div>
<h2 className="heading-brutal text-4xl tracking-tight">
<h2 className="heading-brutal text-4xl tracking-tight" style={{ color: 'var(--text-primary)' }}>
POWER-UP YOUR
<br />
COLLEGE EXPERIENCE
</h2>
<p className="body-brutal mt-3 max-w-lg" style={{ color: "#6b7280" }}>
<p className="body-brutal mt-3 max-w-lg" style={{ color: 'var(--text-secondary)' }}>
Level up your academic journey with features designed for the modern
IIIT student
</p>
Expand All @@ -91,6 +95,11 @@ const FeaturesPage = () => {
to={routeTo}
key={feature.key}
className="feature-grid-item group"
style={{
borderColor: 'var(--landing-divider)',
backgroundColor: 'var(--card)',
color: 'var(--card-foreground)',
}}
>
<div
className={`h-full flex flex-col ${feature.accentBarClass}`}
Expand All @@ -110,16 +119,17 @@ const FeaturesPage = () => {
hyphens: "auto",
overflowWrap: "break-word",
wordBreak: "break-word",
color: 'var(--text-primary)',
}}
>
{feature.title}
</h3>
<p className="body-brutal text-sm flex-1">
<p className="body-brutal text-sm flex-1" style={{ color: 'var(--text-secondary)' }}>
{feature.description}
</p>
<div
className="mt-4 pt-3 flex items-center gap-1"
style={{ borderTop: "1px solid #e5e7eb" }}
style={{ borderTop: `1px solid var(--landing-divider)` }}
>
<span
className="mono-label"
Expand All @@ -143,8 +153,8 @@ const FeaturesPage = () => {
width: "36px",
height: "36px",
boxShadow: "none",
borderLeft: "1px solid #000000",
borderBottom: "1px solid #000000",
borderLeft: `1px solid var(--landing-divider)`,
borderBottom: `1px solid var(--landing-divider)`,
borderTop: "none",
borderRight: "none",
zIndex: 2,
Expand All @@ -164,8 +174,8 @@ const FeaturesPage = () => {
<div
style={{
display: "flex",
borderTop: "1px solid #000000",
borderBottom: "1px solid #000000",
borderTop: `1px solid var(--landing-divider)`,
borderBottom: `1px solid var(--landing-divider)`,
}}
>
{stats.map((stat, idx) => (
Expand All @@ -176,17 +186,20 @@ const FeaturesPage = () => {
flex: "1 1 0%",
padding: "1.5rem",
borderRight:
idx < stats.length - 1 ? "1px solid #000000" : "none",
idx < stats.length - 1 ? `1px solid var(--landing-divider)` : "none",
borderLeft: idx > 0 ? "none" : "none",
boxSizing: "border-box",
backgroundColor: 'var(--card)',
color: 'var(--card-foreground)',
transition: 'all 0.3s ease',
}}
>
<stat.icon
className="w-4 h-4 mx-auto mb-2"
strokeWidth={1.5}
style={{ color: "#6b7280" }}
style={{ color: 'var(--text-secondary)' }}
/>
<div className="heading-brutal text-2xl sm:text-3xl tracking-tighter mb-1">
<div className="heading-brutal text-2xl sm:text-3xl tracking-tighter mb-1" style={{ color: 'var(--text-primary)' }}>
{stat.value}
</div>
<span className="mono-label">{stat.label}</span>
Expand Down
36 changes: 22 additions & 14 deletions apps/web/src/components/LandingPage/hero.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ const Hero = () => {
const browseRoute = isAuthenticated ? "/threads" : "/login";

return (
<section className="relative min-h-screen flex items-center justify-center overflow-hidden border-b-[1.5px] border-black">
<div className="absolute inset-0 bg-white z-0" />
<section className="relative min-h-screen flex items-center justify-center overflow-hidden border-b-[1.5px] border-current" style={{ borderColor: 'var(--landing-divider)', backgroundColor: 'var(--background)' }}>
<div className="absolute inset-0 z-0" style={{ backgroundColor: 'var(--background)' }} />
<div
className="absolute inset-0 z-[1] opacity-[0.04]"
style={{
backgroundImage: "radial-gradient(#000000 1px, transparent 1px)",
backgroundImage: "radial-gradient(var(--landing-grid-color, #d1d1d1) 1px, transparent 1px)",
backgroundSize: "16px 16px",
}}
/>
Expand All @@ -54,12 +54,12 @@ const Hero = () => {

<h1
className="heading-brutal text-5xl sm:text-7xl lg:text-8xl tracking-tighter mb-6 fade-in-up"
style={{ lineHeight: 0.9 }}
style={{ lineHeight: 0.9, color: 'var(--text-primary)' }}
>
IIIT
<span
className="inline-block bg-black text-white px-3 py-1 transform rotate-1"
style={{ marginLeft: "4px" }}
className="inline-block text-white px-3 py-1 transform rotate-1"
style={{ marginLeft: "4px", backgroundColor: 'var(--primary)', color: 'var(--primary-foreground)' }}
>
BUZZ
</span>
Expand All @@ -75,14 +75,14 @@ const Hero = () => {
</div>

<div className="fade-in-up-delay-2 flex justify-center mb-10">
<div className="max-w-xl w-full border-[1.5px] border-black">
<div className="border-b-[1.5px] border-black bg-[#fafafa] px-4 py-2 flex items-center justify-between">
<div className="max-w-xl w-full border-[1.5px]" style={{ borderColor: 'var(--landing-divider)' }}>
<div className="border-b-[1.5px] px-4 py-2 flex items-center justify-between" style={{ borderColor: 'var(--landing-divider)', backgroundColor: 'var(--surface)' }}>
<span className="mono-label">ABOUT</span>
<span className="mono-label" style={{ color: "#000000" }}>
<span className="mono-label" style={{ color: 'var(--text-secondary)' }}>
INSTITUTE FORUM
</span>
</div>
<div className="p-6 bg-white">
<div className="p-6" style={{ backgroundColor: 'var(--card)' }}>
<p className="body-brutal text-base sm:text-lg mb-3">
<strong>
The ultimate community forum for IIIT students.
Expand Down Expand Up @@ -122,7 +122,7 @@ const Hero = () => {

<div className="fade-in-up-delay-4">
<div className="flex justify-center mb-6">
<span className="mono-label" style={{ color: "#9ca3af" }}>
<span className="mono-label" style={{ color: 'var(--muted-foreground)' }}>
&#x2500;&#x2500; CATEGORIES &#x2500;&#x2500;
</span>
</div>
Expand All @@ -131,22 +131,30 @@ const Hero = () => {
<Link
key={link.label}
to={isAuthenticated ? "/home" : "/login"}
className="landing-card p-4 flex flex-col items-center gap-2 cursor-pointer hover:bg-[#fafafa]"
className="landing-card p-4 flex flex-col items-center gap-2 cursor-pointer"
style={{
backgroundColor: 'var(--card)',
borderColor: 'var(--landing-card-border)',
color: 'var(--card-foreground)',
}}
>
<span className="mono-label" style={{ fontSize: "0.55rem" }}>
[ :: {link.stamp} ]
</span>
<div
className="feature-icon"
style={{ background: `${link.accent}15` }}
style={{
background: 'color-mix(in srgb, ' + link.accent + ', transparent 92%)',
borderColor: 'var(--landing-icon-border)',
}}
>
<link.icon
className="w-5 h-5"
strokeWidth={1.5}
style={{ color: link.accent }}
/>
</div>
<span className="mono-label" style={{ color: "#000000" }}>
<span className="mono-label" style={{ color: 'var(--text-secondary)' }}>
{link.label}
</span>
</Link>
Expand Down
35 changes: 25 additions & 10 deletions apps/web/src/components/forum/PostItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ThumbsUp, ThumbsDown, Flag, MessageSquare, Trash2 } from "lucide-react"
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { MarkdownContent } from "@/components/ui/markdown";
import { DeleteConfirmationModal } from "@/components/ui/delete-confirmation-modal";
import { api } from "@/lib/api";
import type { PostDetail } from "@/types/forum";
import { formatTimeAgo } from "@/lib/utils/date";
Expand Down Expand Up @@ -33,6 +34,7 @@ export const PostItem = ({
const [voting, setVoting] = useState(false);
const [reporting, setReporting] = useState(false);
const [hasReported, setHasReported] = useState(false);
const [isDeleting, setIsDeleting] = useState(false);
const profileUsername = !post.isAnonymous ? post.authorName : null;

useEffect(() => {
Expand Down Expand Up @@ -184,17 +186,30 @@ export const PostItem = ({
Quote
</Button>
{canDelete && onDelete && (
<Button
size="sm"
variant="neutral"
className="bg-card px-1.5 py-0.5 font-bold text-[10px] text-red-600"
onClick={() => {
void onDelete();
<DeleteConfirmationModal
trigger={
<Button
size="sm"
variant="neutral"
className="bg-card px-1.5 py-0.5 font-bold text-[10px] text-red-600"
>
<Trash2 className="h-3 w-3 mr-1" />
Delete
</Button>
}
title="Delete Post?"
description="Are you sure you want to delete this post? This action cannot be undone."
onConfirm={async () => {
setIsDeleting(true);
try {
await onDelete();
} finally {
setIsDeleting(false);
}
}}
>
<Trash2 className="h-3 w-3 mr-1" />
Delete
</Button>
isLoading={isDeleting}
confirmText="Delete Post"
/>
)}
<Button
size="sm"
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/components/forum/RecentThreadRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const RecentThreadRow = ({ thread }: { thread: RecentThread }) => {

return (
<Link to={`/thread/${thread.id}`} className="block">
<div className="p-3 border-b border-gray-200 last:border-b-0 hover:bg-gray-50 transition-colors">
<div className="p-3 border-b border-border last:border-b-0 hover:bg-muted/40 transition-colors">
<div className="flex flex-col gap-2 sm:flex-row sm:items-start sm:justify-between sm:gap-4">
<div className="flex-1 min-w-0">
<h3 className="mb-1 font-bold text-sm leading-tight truncate">
Expand Down
24 changes: 12 additions & 12 deletions apps/web/src/components/forum/TopicThreadRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ const ThreadRow = ({ thread, topicName, topicColor }: ThreadRowProps) => {

return (
<Link to={`/thread/${thread.id}`} className="block">
<div className="py-2 px-3 flex items-center gap-3 border-b border-border last:border-b-0 hover:bg-muted/40 transition-colors">
<div className="col-author w-10 flex-shrink-0">
<div className="py-2 px-3 flex items-center gap-2 sm:gap-3 border-b border-border last:border-b-0 hover:bg-muted/40 transition-colors">
<div className="col-author w-8 sm:w-10 flex-shrink-0">
<div
className={`h-8 w-8 flex items-center justify-center bg-foreground text-background text-[10px] font-bold border border-border overflow-hidden ${profileUsername ? "cursor-pointer hover:opacity-85" : ""}`}
onClick={goToProfile}
Expand All @@ -126,25 +126,25 @@ const ThreadRow = ({ thread, topicName, topicColor }: ThreadRowProps) => {
)}
</div>
</div>
<div className="col-title flex-[60] min-w-0">
<div className="flex items-center gap-1 mb-0.5">
<div className="col-title flex-1 min-w-0">
<div className="flex items-center gap-1 mb-0.5 flex-wrap">
{thread.isPinned && (
<span className="tech-stamp text-[9px] bg-foreground text-background border-foreground">
<span className="tech-stamp text-[8px] sm:text-[9px] bg-foreground text-background border-foreground">
PIN
</span>
)}
<span
className="mono-label border border-current px-1 text-[9px]"
className="mono-label border border-current px-1 text-[8px] sm:text-[9px]"
style={{ color, borderColor: color }}
>
{topicName || thread.topicName}
</span>
</div>
<h3 className="font-bold text-sm truncate text-foreground">
<h3 className="font-bold text-xs sm:text-sm truncate text-foreground">
{thread.title || thread.threadTitle}
</h3>
<span
className={`mono-meta ${profileUsername ? "cursor-pointer hover:underline" : ""}`}
className={`mono-meta text-[9px] ${profileUsername ? "cursor-pointer hover:underline" : ""}`}
onClick={goToProfile}
onKeyDown={(event) => {
if (event.key === "Enter" || event.key === " ") {
Expand All @@ -157,12 +157,12 @@ const ThreadRow = ({ thread, topicName, topicColor }: ThreadRowProps) => {
{username || "Unknown"}
</span>
</div>
<div className="col-replies w-16 text-center flex-shrink-0 flex flex-col justify-center">
<div className="col-replies hidden sm:flex w-12 sm:w-16 text-center flex-shrink-0 flex flex-col justify-center">
<div className="font-bold text-sm text-foreground">{thread.replies ?? 0}</div>
<div className="mono-label">Replies</div>
<div className="mono-label text-[8px]">Replies</div>
</div>
<div className="col-last w-20 text-right flex-shrink-0 flex flex-col justify-center">
<span className="mono-meta text-right">
<div className="col-last hidden sm:flex w-16 sm:w-20 text-right flex-shrink-0 flex flex-col justify-center">
<span className="mono-meta text-right text-[8px] sm:text-xs">
[ {formatTimeAgo(thread.lastActive || "").toUpperCase()} ]
</span>
</div>
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/components/profile/StatCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const colorMap = {
};

export const StatCard = ({ label, value, color }: StatCardProps) => (
<div className={`border-3 border-border ${colorMap[color]} p-3 sm:p-4 text-center shadow-[3px_3px_0px_0px_var(--shadow-color)]`}>
<div className={`border-3 border-border ${colorMap[color]} p-3 sm:p-4 text-center shadow-[3px_3px_0px_0px_var(--shadow-color)] transition-all hover:translate-x-[2px] hover:translate-y-[2px] hover:shadow-[1px_1px_0px_0px_var(--shadow-color)]`}>
<div className="font-bold text-2xl sm:text-3xl">{value}</div>
<div className="mt-1 font-bold text-[10px] sm:text-xs uppercase">{label}</div>
</div>
Expand Down
61 changes: 61 additions & 0 deletions apps/web/src/components/ui/delete-confirmation-modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
import { ReactNode } from "react";

interface DeleteConfirmationModalProps {
trigger: ReactNode;
title: string;
description: string;
onConfirm: () => void | Promise<void>;
isLoading?: boolean;
confirmText?: string;
cancelText?: string;
}

export function DeleteConfirmationModal({
trigger,
title,
description,
onConfirm,
isLoading = false,
confirmText = "Delete",
cancelText = "Cancel",
}: DeleteConfirmationModalProps) {
return (
<AlertDialog>
<AlertDialogTrigger asChild>{trigger}</AlertDialogTrigger>

<AlertDialogContent className="border-4 border-primary bg-card shadow-[8px_8px_0px_0px_var(--shadow-color)]">
<AlertDialogHeader>
<AlertDialogTitle className="pixel-font text-2xl text-destructive">
{title}
</AlertDialogTitle>
<AlertDialogDescription className="font-bold text-muted-foreground">
{description}
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter className="gap-3">
<AlertDialogCancel className="border-3 border-border font-bold bg-card shadow-[4px_4px_0px_0px_var(--shadow-color)] hover:translate-x-[2px] hover:translate-y-[2px] hover:shadow-[2px_2px_0px_0px_var(--shadow-color)]">
{cancelText}
</AlertDialogCancel>
<AlertDialogAction
onClick={onConfirm}
disabled={isLoading}
className="bg-destructive text-destructive-foreground border-3 border-primary font-bold shadow-[4px_4px_0px_0px_var(--shadow-color)] hover:translate-x-[2px] hover:translate-y-[2px] hover:shadow-[2px_2px_0px_0px_var(--shadow-color)] disabled:opacity-50 disabled:cursor-not-allowed"
>
{isLoading ? "Deleting..." : confirmText}
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
);
}
Loading
Loading