Skip to content
Open
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
2 changes: 1 addition & 1 deletion src/app/dashboard/page.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import TodayFocusHero from "@/components/TodayFocusHero";
import TodayFocusHero from "@/components/TodayFocusHero";
import DashboardHeader from "@/components/DashboardHeader";
import ExportButton from "@/components/ExportButton";
import Link from "next/link";
Expand Down
17 changes: 9 additions & 8 deletions src/components/ConfirmModal.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"use client";

import { useEffect, useRef } from "react";
import { Button } from "@/components/ui/button";

interface ConfirmModalProps {
isOpen: boolean;
Expand Down Expand Up @@ -70,20 +71,20 @@ export default function ConfirmModal({
</div>

<div className="mt-8 flex flex-col-reverse gap-3 sm:flex-row sm:justify-end">
<button
type="button"
<Button
variant="outline"
onClick={onCancel}
className="w-full sm:w-auto rounded-xl border border-[var(--border)] bg-[var(--control)] px-5 py-2.5 text-sm font-semibold text-[var(--card-foreground)] transition-all hover:bg-[var(--card-muted)] active:scale-95"
className="w-full sm:w-auto"
>
{cancelLabel}
</button>
<button
type="button"
</Button>
<Button
variant="default"
onClick={onConfirm}
className="w-full sm:w-auto rounded-xl bg-[var(--accent)] px-5 py-2.5 text-sm font-semibold text-[var(--accent-foreground)] transition-all hover:opacity-90 active:scale-95 shadow-lg shadow-[var(--accent)]/20"
className="w-full sm:w-auto shadow-lg shadow-[var(--accent)]/20"
>
{confirmLabel}
</button>
</Button>
</div>
</div>
</div>
Expand Down
14 changes: 8 additions & 6 deletions src/components/DashboardHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import UserAvatar from "@/components/UserAvatar";
import KeyboardShortcuts from "@/components/KeyboardShortcuts";
import { Moon, Sun } from "lucide-react";
import { toast } from "sonner";
import { Button, buttonVariants } from "@/components/ui/button";

type DashboardSyncContextValue = {
lastSynced: Date | null;
Expand Down Expand Up @@ -268,7 +269,7 @@ export default function DashboardHeader() {
href={`/u/${session.githubLogin}`}
target="_blank"
rel="noopener noreferrer"
className="primary-button inline-flex items-center justify-center rounded-xl px-4 py-2 text-sm font-semibold"
className={buttonVariants({ variant: "default" })}
title="View your public profile"
>
Share Profile
Expand Down Expand Up @@ -300,9 +301,10 @@ export default function DashboardHeader() {
</div>

{/* Mobile hamburger button */}
<button
type="button"
className="inline-flex items-center justify-center self-start rounded-xl border border-[var(--border)] bg-[var(--card-muted)]/70 p-2 text-[var(--card-foreground)] shadow-sm transition-all duration-200 hover:border-[var(--accent)] hover:text-[var(--accent)] sm:hidden"
<Button
variant="outline"
size="icon"
className="self-start sm:hidden"
onClick={() => setMenuOpen((v) => !v)}
aria-label="Toggle menu"
aria-expanded={menuOpen}
Expand Down Expand Up @@ -339,7 +341,7 @@ export default function DashboardHeader() {
<path d="M4 18h16" />
</svg>
)}
</button>
</Button>
</div>

{/* Mobile dropdown */}
Expand Down Expand Up @@ -372,7 +374,7 @@ export default function DashboardHeader() {
href={`/u/${session.githubLogin}`}
target="_blank"
rel="noopener noreferrer"
className="primary-button inline-flex w-full items-center justify-center rounded-xl px-4 py-2 text-sm font-semibold"
className={buttonVariants({ variant: "default", className: "w-full" })}
title="View your public profile"
onClick={() => setMenuOpen(false)}
>
Expand Down
38 changes: 21 additions & 17 deletions src/components/GoalTracker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useSession } from "next-auth/react";
import { submitGoalWithRefresh } from "@/lib/goal-tracker";
import ConfirmModal from "@/components/ConfirmModal"; // 🎯 Imported the native project confirmation layout
import { buildPublicGoalShareUrl } from "@/lib/goals/share";
import { Button } from "@/components/ui/button";

type Recurrence = "none" | "weekly" | "monthly";

Expand Down Expand Up @@ -411,12 +412,13 @@ export default function GoalTracker() {
{/* ── Header ── */}
<div className="flex items-center justify-between mb-4">
<h2 className="text-lg font-semibold text-[var(--card-foreground)]">Goals</h2>
<button
<Button
variant="outline"
size="sm"
onClick={handleSync}
disabled={syncing}
title="Refresh commit-based goals from GitHub"
aria-label="Refresh commit goals"
className="flex items-center gap-1.5 rounded-lg border border-[var(--border)] bg-[var(--background)] px-2.5 py-1 text-xs text-[var(--muted-foreground)] transition hover:text-[var(--card-foreground)] hover:border-[var(--accent)] disabled:opacity-50 disabled:cursor-not-allowed"
>
<svg
xmlns="http://www.w3.org/2000/svg"
Expand All @@ -432,7 +434,7 @@ export default function GoalTracker() {
/>
</svg>
{syncing ? "Syncing…" : "Refresh"}
</button>
</Button>
</div>

{/* Sync Error */}
Expand Down Expand Up @@ -552,7 +554,9 @@ export default function GoalTracker() {

{/* Manual +1 only for non-auto-synced goals */}
{!isAutoSynced && (
<button
<Button
variant="default"
size="sm"
onClick={async () => {
const newCurrent = goal.current + 1;
if (newCurrent > goal.target) return;
Expand All @@ -571,25 +575,25 @@ export default function GoalTracker() {
}}
disabled={goal.current >= goal.target}
aria-label={`Increment "${goal.title}" progress by 1`}
className="rounded bg-blue-600 px-2 py-1 text-xs text-white hover:bg-blue-700 disabled:opacity-50"
>
+1
</button>
</Button>
)}

{/* 🎯 Clean interception: Clicking trash icon sets confirmingId instead of trigger-deleting */}
<button
type="button"
<Button
variant="ghost"
size="icon"
className="text-[var(--muted-foreground)] hover:text-[var(--destructive)] hover:bg-[var(--destructive)]/10"
onClick={() => setConfirmingId(goal.id)}
disabled={isDeleting}
className="text-[var(--muted-foreground)] hover:text-[var(--destructive)] transition-colors disabled:opacity-50"
aria-label={`Delete goal: ${goal.title}`}
title="Delete goal"
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" className="w-4 h-4" aria-hidden="true">
<path fillRule="evenodd" d="M8.75 1A2.75 2.75 0 006 3.75v.443c-.795.077-1.584.176-2.365.298a.75.75 0 10.23 1.482l.149-.022.841 10.518A2.75 2.75 0 007.596 19h4.807a2.75 2.75 0 002.742-2.53l.841-10.52.149.023a.75.75 0 00.23-1.482A41.03 41.03 0 0014 4.193V3.75A2.75 2.75 0 0011.25 1h-2.5zM10 4c.84 0 1.673.025 2.5.075V3.75c0-.69-.56-1.25-1.25-1.25h-2.5c-.69 0-1.25.56-1.25 1.25v.325C8.327 4.025 9.16 4 10 4zM8.58 7.72a.75.75 0 00-1.5.06l.3 7.5a.75.75 0 101.5-.06l-.3-7.5zm4.34.06a.75.75 0 10-1.5-.06l-.3 7.5a.75.75 0 101.5.06l.3-7.5z" clipRule="evenodd" />
</svg>
</button>
</Button>
Comment on lines +584 to +596
</div>
</div>

Expand Down Expand Up @@ -630,13 +634,14 @@ export default function GoalTracker() {
</div>

{goal.is_public && (
<button
type="button"
<Button
variant="secondary"
size="sm"
className="mt-3"
onClick={() => copyGoalShareLink(goal.id)}
className="secondary-button mt-3 rounded-lg px-3 py-1.5 text-sm"
>
{copiedGoalId === goal.id ? "Copied!" : "Copy share link"}
</button>
</Button>
)}
</div>
</li>
Expand Down Expand Up @@ -768,10 +773,9 @@ export default function GoalTracker() {
</p>
)}

<button
<Button
type="submit"
disabled={creating || !title.trim()}
className="inline-flex items-center gap-2 rounded-lg bg-[var(--accent)] px-4 py-2 text-sm font-medium text-[var(--accent-foreground)] transition hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-60"
>
{creating ? (
<>
Expand All @@ -781,7 +785,7 @@ export default function GoalTracker() {
) : (
"Create goal"
)}
</button>
</Button>
{createError && (
<p className="text-sm text-[var(--destructive)]">{createError}</p>
)}
Expand Down
22 changes: 10 additions & 12 deletions src/components/SignOutButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import { useState } from "react"
import { signOut } from "next-auth/react"
import { Button } from "@/components/ui/button"

export default function SignOutButton() {
const [signingOut, setSigningOut] = useState(false)
Expand All @@ -21,37 +22,34 @@ export default function SignOutButton() {
if (confirming) {
return (
<div className="flex items-center gap-2">
<button
type="button"
<Button
variant="destructive"
onClick={handleSignOut}
aria-label="Confirm sign out"
disabled={signingOut}
className="inline-flex h-10 items-center rounded-full bg-red-600 px-4 text-sm font-semibold text-white hover:bg-red-700 disabled:opacity-70"
>
{signingOut ? "Signing out..." : "Confirm"}
</button>
</Button>

<button
type="button"
<Button
variant="outline"
onClick={() => setConfirming(false)}
disabled={signingOut}
className="inline-flex h-10 items-center rounded-full border px-4 text-sm font-semibold hover:bg-gray-100"
aria-label="Cancel sign out"
>
Cancel
</button>
</Button>
</div>
)
}

return (
<button
type="button"
<Button
variant="destructive"
disabled={signingOut}
suppressHydrationWarning
onClick={() => setConfirming(true)}
aria-label="Sign out"
className="inline-flex h-10 items-center gap-2 rounded-full border border-[var(--destructive)]/50 bg-[var(--destructive)]/80 px-4 text-sm font-semibold text-[var(--foreground)] transition-colors hover:bg-[var(--destructive)] disabled:cursor-not-allowed disabled:opacity-70"
>
{signingOut && (
<svg
Expand Down Expand Up @@ -81,6 +79,6 @@ export default function SignOutButton() {
)}

Sign out
</button>
</Button>
)
}
10 changes: 5 additions & 5 deletions src/components/repo-analytics/RepoCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
formatRelativeDate,
formatDate,
} from "@/lib/repoAnalyticsUtils";
import { Button, buttonVariants } from "@/components/ui/button";

interface RepoCardProps {
repo: ExplorerRepoCardData;
Expand Down Expand Up @@ -140,18 +141,17 @@ export default function RepoCard({
href={repo.htmlUrl}
target="_blank"
rel="noopener noreferrer"
className="flex items-center justify-center rounded-2xl border border-[var(--border)] bg-[var(--card)] px-4 py-3 text-sm font-medium text-[var(--card-foreground)] transition hover:bg-[color:color-mix(in_srgb,var(--card)_80%,var(--accent)_20%)]"
className={buttonVariants({ variant: "outline" })}
>
Repo
</a>

<button
type="button"
<Button
variant="outline"
onClick={() => onViewAnalytics(repo)}
className="flex items-center justify-center rounded-2xl border border-[var(--border)] bg-[var(--card)] px-4 py-3 text-sm font-medium text-[var(--card-foreground)] transition hover:bg-[color:color-mix(in_srgb,var(--card)_80%,var(--accent)_20%)]"
>
View
</button>
</Button>
</div>
</div>
</article>
Expand Down
18 changes: 9 additions & 9 deletions src/components/ui/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,26 @@ import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";

const buttonVariants = cva(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-[var(--ring)] disabled:pointer-events-none disabled:opacity-50",
"inline-flex items-center justify-center whitespace-nowrap rounded-xl text-sm font-semibold transition duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--background)] focus-visible:ring-[var(--accent)] disabled:pointer-events-none disabled:opacity-50 gap-2 active:scale-[0.98]",
{
variants: {
variant: {
default:
"bg-[var(--accent)] text-[var(--accent-foreground)] shadow hover:opacity-90",
destructive:
"bg-[var(--destructive)] text-white shadow-sm hover:opacity-90",
"border border-[var(--destructive)]/50 bg-[var(--destructive)]/80 text-white shadow hover:bg-[var(--destructive)]",
outline:
"border border-[var(--border)] bg-[var(--background)] shadow-sm hover:bg-[var(--card-muted)] hover:text-[var(--foreground)]",
"border border-[var(--border)] bg-[var(--background)] shadow-sm hover:border-[var(--accent)] hover:text-[var(--accent)] hover:bg-[var(--card-muted)]/50",
secondary:
"bg-[var(--card-muted)] text-[var(--foreground)] shadow-sm hover:opacity-80",
ghost: "hover:bg-[var(--card-muted)] hover:text-[var(--foreground)]",
"bg-[var(--card-muted)] text-[var(--foreground)] border border-[var(--border)] shadow-sm hover:opacity-80",
ghost: "hover:text-[var(--destructive)] transition-colors",
link: "text-[var(--accent)] underline-offset-4 hover:underline",
},
size: {
default: "h-9 px-4 py-2",
sm: "h-8 rounded-md px-3 text-xs",
lg: "h-10 rounded-md px-8",
icon: "h-9 w-9",
default: "h-10 px-4 py-2",
sm: "h-9 rounded-lg px-3",
lg: "h-11 rounded-xl px-8",
icon: "h-10 w-10",
},
},
defaultVariants: {
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading