enh: add discord and github buttons

This commit is contained in:
Ben Allfree
2026-04-17 05:07:57 -07:00
parent c68ce832b2
commit 54eeaa8978
7 changed files with 71 additions and 34 deletions
+3
View File
@@ -37,3 +37,6 @@
[submodule "vendor/meshtastic-web"]
path = vendor/meshtastic-web
url = git@github.com:meshtastic/web.git
[submodule "vendor/lobbs-meshtastic-firmware"]
path = vendor/lobbs-meshtastic-firmware
url = git@github.com:benallfree/lobbs-meshtstic-firmware.git
+16 -5
View File
@@ -13,14 +13,25 @@ interface DiscordButtonProps {
variant?: "default" | "outline" | "ghost" | "link" | "destructive"
size?: "default" | "sm" | "lg" | "icon"
className?: string
/** Icon only; link gets `aria-label` for accessibility */
iconOnly?: boolean
}
export function DiscordButton({ variant = "outline", size, className }: DiscordButtonProps) {
export function DiscordButton({ variant = "outline", size, className, iconOnly }: DiscordButtonProps) {
return (
<a href="https://discord.gg/8KgJpvjfaJ" target="_blank" rel="noopener noreferrer">
<Button variant={variant} size={size} className={cn("flex items-center gap-2", className)}>
<DiscordIcon className="w-4 h-4" />
Discord
<a
href="https://discord.gg/8KgJpvjfaJ"
target="_blank"
rel="noopener noreferrer"
aria-label={iconOnly ? "MeshForge on Discord" : undefined}
>
<Button
variant={variant}
size={iconOnly ? "icon" : size}
className={cn(iconOnly ? "shrink-0" : "flex items-center gap-2", className)}
>
<DiscordIcon className={iconOnly ? "h-[18px] w-[18px]" : "w-4 h-4"} />
{!iconOnly ? "Discord" : null}
</Button>
</a>
)
+2 -20
View File
@@ -1,14 +1,12 @@
import favicon from "@/assets/favicon-96x96.png"
import { DiscordButton } from "@/components/DiscordButton"
import { RedditButton } from "@/components/RedditButton"
import { Button } from "@/components/ui/button"
import { api } from "@/convex/_generated/api"
import { useAuthActions } from "@convex-dev/auth/react"
import { Authenticated, Unauthenticated, useQuery } from "convex/react"
import { Authenticated, useQuery } from "convex/react"
import { Link } from "react-router-dom"
export default function Navbar() {
const { signOut, signIn } = useAuthActions()
const { signOut } = useAuthActions()
const isAdmin = useQuery(api.admin.isAdmin)
return (
@@ -33,22 +31,6 @@ export default function Navbar() {
</div>
</div>
<div className="flex items-center gap-4">
<DiscordButton
variant="default"
className="bg-gradient-to-r from-indigo-500 to-purple-600 hover:from-indigo-600 hover:to-purple-700 text-white border-0 shadow-lg shadow-purple-500/50"
/>
<RedditButton
variant="default"
className="bg-gradient-to-r from-orange-500 to-red-600 hover:from-orange-600 hover:to-red-700 text-white border-0 shadow-lg shadow-orange-500/50"
/>
<Unauthenticated>
<Button
onClick={() => signIn("github", { redirectTo: window.location.href })}
className="bg-cyan-600 hover:bg-cyan-700"
>
Sign In
</Button>
</Unauthenticated>
<Authenticated>
<Button variant="outline" onClick={() => signOut()}>
Sign Out
+22 -9
View File
@@ -1,10 +1,12 @@
import { Button } from "@/components/ui/button"
import { cn } from "@/lib/utils"
import { useId } from "react"
function RedditIcon(props: React.SVGProps<SVGSVGElement>) {
function RedditIcon(props: React.SVGProps<SVGSVGElement> & { maskId: string }) {
const { maskId, ...rest } = props
return (
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" {...props}>
<mask id="SVGfUZuVbjp">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" {...rest}>
<mask id={maskId}>
<g fill="#fff">
<path
fillOpacity="0"
@@ -72,7 +74,7 @@ function RedditIcon(props: React.SVGProps<SVGSVGElement>) {
<animate fill="freeze" attributeName="stroke-dashoffset" begin="2s" dur="0.2s" values="10;0" />
</path>
</mask>
<rect width="24" height="24" fill="currentColor" mask="url(#SVGfUZuVbjp)" />
<rect width="24" height="24" fill="currentColor" mask={`url(#${maskId})`} />
</svg>
)
}
@@ -81,14 +83,25 @@ interface RedditButtonProps {
variant?: "default" | "outline" | "ghost" | "link" | "destructive"
size?: "default" | "sm" | "lg" | "icon"
className?: string
iconOnly?: boolean
}
export function RedditButton({ variant = "outline", size, className }: RedditButtonProps) {
export function RedditButton({ variant = "outline", size, className, iconOnly }: RedditButtonProps) {
const maskId = useId().replace(/:/g, "")
return (
<a href="https://www.reddit.com/r/MeshForge/" target="_blank" rel="noopener noreferrer">
<Button variant={variant} size={size} className={cn("flex items-center gap-2", className)}>
<RedditIcon className="w-4 h-4" />
Reddit
<a
href="https://www.reddit.com/r/MeshForge/"
target="_blank"
rel="noopener noreferrer"
aria-label={iconOnly ? "r/MeshForge on Reddit" : undefined}
>
<Button
variant={variant}
size={iconOnly ? "icon" : size}
className={cn(iconOnly ? "shrink-0" : "flex items-center gap-2", className)}
>
<RedditIcon maskId={maskId} className={iconOnly ? "h-[18px] w-[18px]" : "w-4 h-4"} />
{!iconOnly ? "Reddit" : null}
</Button>
</a>
)
+25
View File
@@ -0,0 +1,25 @@
import { DiscordButton } from "@/components/DiscordButton"
import { RedditButton } from "@/components/RedditButton"
import { cn } from "@/lib/utils"
export function SocialCornerBadges({ className }: { className?: string }) {
return (
<div
className={cn(
"fixed right-3 top-3 z-50 flex items-center gap-2 sm:right-4 sm:top-4",
className
)}
>
<DiscordButton
iconOnly
variant="ghost"
className="h-9 w-9 rounded-full border-0 bg-transparent text-slate-500 shadow-none hover:bg-transparent hover:text-slate-200"
/>
<RedditButton
iconOnly
variant="ghost"
className="h-9 w-9 rounded-full border-0 bg-transparent text-slate-500 shadow-none hover:bg-transparent hover:text-slate-200"
/>
</div>
)
}
+2
View File
@@ -1,5 +1,6 @@
import Footer from "@/components/Footer"
import Navbar from "@/components/Navbar"
import { SocialCornerBadges } from "@/components/SocialCornerBadges"
import { Navigate, Route, Routes, useLocation } from "react-router-dom"
import AdminPage from "./pages/AdminPage"
import HomePage from "./pages/HomePage"
@@ -14,6 +15,7 @@ function Layout({ children }: { children: React.ReactNode }) {
const hideNav = loc.pathname === "/"
return (
<div className="min-h-screen flex flex-col">
<SocialCornerBadges />
{!hideNav && <Navbar />}
<main className="flex-1">{children}</main>
<Footer />