use semibold

This commit is contained in:
miloschwartz
2026-04-25 15:42:19 -07:00
parent 8e16ff07a9
commit 6f6c24b6df
27 changed files with 95 additions and 87 deletions

View File

@@ -114,12 +114,7 @@ const listResourcesSchema = z.object({
description: description:
"Filter resources based on health status of their targets. `healthy` means all targets are healthy. `degraded` means at least one target is unhealthy, but not all are unhealthy. `offline` means all targets are unhealthy. `unknown` means all targets have unknown health status. `no_targets` means the resource has no targets." "Filter resources based on health status of their targets. `healthy` means all targets are healthy. `degraded` means at least one target is unhealthy, but not all are unhealthy. `offline` means all targets are unhealthy. `unknown` means all targets have unknown health status. `no_targets` means the resource has no targets."
}), }),
siteId: z.coerce siteId: z.coerce.number<string>().int().positive().optional().openapi({
.number<string>()
.int()
.positive()
.optional()
.openapi({
type: "integer", type: "integer",
description: description:
"When set, only resources that have at least one target on this site are returned" "When set, only resources that have at least one target on this site are returned"
@@ -270,6 +265,8 @@ export async function listResources(
); );
} }
await new Promise((resolve) => setTimeout(resolve, 3 * 1000));
const orgId = const orgId =
parsedParams.data.orgId || parsedParams.data.orgId ||
req.userOrg?.orgId || req.userOrg?.orgId ||

View File

@@ -112,10 +112,7 @@ export async function listSiteResources(
const siteResourcesList = await db const siteResourcesList = await db
.select() .select()
.from(siteNetworks) .from(siteNetworks)
.innerJoin( .innerJoin(networks, eq(siteNetworks.networkId, networks.networkId))
networks,
eq(siteNetworks.networkId, networks.networkId)
)
.innerJoin( .innerJoin(
siteResources, siteResources,
eq(siteResources.networkId, networks.networkId) eq(siteResources.networkId, networks.networkId)
@@ -136,7 +133,6 @@ export async function listSiteResources(
.limit(limit) .limit(limit)
.offset(offset); .offset(offset);
return response(res, { return response(res, {
data: { siteResources: siteResourcesList }, data: { siteResources: siteResourcesList },
success: true, success: true,

View File

@@ -836,7 +836,14 @@ export default function BillingPage() {
</SettingsSectionHeader> </SettingsSectionHeader>
<SettingsSectionBody> <SettingsSectionBody>
{/* Plan Cards Grid */} {/* Plan Cards Grid */}
<div className={cn("grid grid-cols-1 gap-4", visiblePlanOptions.length === 5 ? "md:grid-cols-5" : "md:grid-cols-4")}> <div
className={cn(
"grid grid-cols-1 gap-4",
visiblePlanOptions.length === 5
? "md:grid-cols-5"
: "md:grid-cols-4"
)}
>
{visiblePlanOptions.map((plan) => { {visiblePlanOptions.map((plan) => {
const isCurrentPlan = plan.id === currentPlanId; const isCurrentPlan = plan.id === currentPlanId;
const planAction = getPlanAction(plan); const planAction = getPlanAction(plan);
@@ -967,7 +974,7 @@ export default function BillingPage() {
{t("billingCurrentUsage") || "Current Usage"} {t("billingCurrentUsage") || "Current Usage"}
</div> </div>
<div className="flex items-baseline gap-2"> <div className="flex items-baseline gap-2">
<span className="text-3xl font-bold"> <span className="text-3xl font-semibold">
{getUserCount()} {getUserCount()}
</span> </span>
<span className="text-lg"> <span className="text-lg">
@@ -1298,7 +1305,7 @@ export default function BillingPage() {
"Current Keys"} "Current Keys"}
</div> </div>
<div className="flex items-baseline gap-2"> <div className="flex items-baseline gap-2">
<span className="text-3xl font-bold"> <span className="text-3xl font-semibold">
{getLicenseKeyCount()} {getLicenseKeyCount()}
</span> </span>
<span className="text-lg"> <span className="text-lg">

View File

@@ -5,7 +5,7 @@ export default async function NotFound() {
return ( return (
<div className="w-full max-w-md mx-auto p-3 md:mt-32 text-center"> <div className="w-full max-w-md mx-auto p-3 md:mt-32 text-center">
<h1 className="text-6xl font-bold mb-4">404</h1> <h1 className="text-6xl font-semibold mb-4">404</h1>
<h2 className="text-2xl font-semibold text-neutral-500 mb-4"> <h2 className="text-2xl font-semibold text-neutral-500 mb-4">
{t("pageNotFound")} {t("pageNotFound")}
</h2> </h2>

View File

@@ -92,7 +92,7 @@ export default function InitialSetupPage() {
/> />
</div> </div>
<div className="text-center space-y-1"> <div className="text-center space-y-1">
<h1 className="text-2xl font-bold mt-1"> <h1 className="text-2xl font-semibold mt-1">
{t("initialSetupTitle")} {t("initialSetupTitle")}
</h1> </h1>
<CardDescription> <CardDescription>

View File

@@ -23,8 +23,10 @@ export default function DeviceAuthSuccessPage() {
useEffect(() => { useEffect(() => {
// Detect if we're on iOS or Android // Detect if we're on iOS or Android
const userAgent = navigator.userAgent || navigator.vendor || (window as any).opera; const userAgent =
const isIOS = /iPad|iPhone|iPod/.test(userAgent) && !(window as any).MSStream; navigator.userAgent || navigator.vendor || (window as any).opera;
const isIOS =
/iPad|iPhone|iPod/.test(userAgent) && !(window as any).MSStream;
const isAndroid = /android/i.test(userAgent); const isAndroid = /android/i.test(userAgent);
if (isAndroid) { if (isAndroid) {
@@ -32,7 +34,8 @@ export default function DeviceAuthSuccessPage() {
// This explicitly tells Chrome to send an intent to the app, which will bring // This explicitly tells Chrome to send an intent to the app, which will bring
// SignInCodeActivity back to the foreground (it has launchMode="singleTop") // SignInCodeActivity back to the foreground (it has launchMode="singleTop")
setTimeout(() => { setTimeout(() => {
window.location.href = "intent://auth-success#Intent;scheme=pangolin;package=net.pangolin.Pangolin;end"; window.location.href =
"intent://auth-success#Intent;scheme=pangolin;package=net.pangolin.Pangolin;end";
}, 500); }, 500);
} else if (isIOS) { } else if (isIOS) {
// Wait 500ms then attempt to open the app // Wait 500ms then attempt to open the app
@@ -41,7 +44,8 @@ export default function DeviceAuthSuccessPage() {
window.location.href = "pangolin://"; window.location.href = "pangolin://";
setTimeout(() => { setTimeout(() => {
window.location.href = "https://apps.apple.com/app/pangolin/net.pangolin.Pangolin.PangoliniOS"; window.location.href =
"https://apps.apple.com/app/pangolin/net.pangolin.Pangolin.PangoliniOS";
}, 2000); }, 2000);
}, 500); }, 500);
} }
@@ -64,7 +68,7 @@ export default function DeviceAuthSuccessPage() {
<div className="flex flex-col items-center space-y-4"> <div className="flex flex-col items-center space-y-4">
<CheckCircle2 className="h-12 w-12 text-green-500" /> <CheckCircle2 className="h-12 w-12 text-green-500" />
<div className="space-y-2"> <div className="space-y-2">
<h3 className="text-xl font-bold text-center"> <h3 className="text-xl font-semibold text-center">
{t("deviceConnected")} {t("deviceConnected")}
</h3> </h3>
<p className="text-center text-sm text-muted-foreground"> <p className="text-center text-sm text-muted-foreground">

View File

@@ -135,7 +135,7 @@ export default async function Page(props: {
<div className="border rounded-md p-3 mb-4 bg-card"> <div className="border rounded-md p-3 mb-4 bg-card">
<div className="flex flex-col items-center"> <div className="flex flex-col items-center">
<Mail className="w-12 h-12 mb-4 text-primary" /> <Mail className="w-12 h-12 mb-4 text-primary" />
<h2 className="text-2xl font-bold mb-2 text-center"> <h2 className="text-2xl font-semibold mb-2 text-center">
{t("inviteAlready")} {t("inviteAlready")}
</h2> </h2>
<p className="text-center"> <p className="text-center">

View File

@@ -65,7 +65,7 @@ export default async function Page(props: {
<div className="border rounded-md p-3 mb-4 bg-card"> <div className="border rounded-md p-3 mb-4 bg-card">
<div className="flex flex-col items-center"> <div className="flex flex-col items-center">
<Mail className="w-12 h-12 mb-4 text-primary" /> <Mail className="w-12 h-12 mb-4 text-primary" />
<h2 className="text-2xl font-bold mb-2 text-center"> <h2 className="text-2xl font-semibold mb-2 text-center">
{t("inviteAlready")} {t("inviteAlready")}
</h2> </h2>
<p className="text-center"> <p className="text-center">

View File

@@ -5,7 +5,7 @@ export default async function NotFound() {
return ( return (
<div className="w-full max-w-md mx-auto p-3 md:mt-32 text-center"> <div className="w-full max-w-md mx-auto p-3 md:mt-32 text-center">
<h1 className="text-6xl font-bold mb-4">404</h1> <h1 className="text-6xl font-semibold mb-4">404</h1>
<h2 className="text-2xl font-semibold text-neutral-500 mb-4"> <h2 className="text-2xl font-semibold text-neutral-500 mb-4">
{t("pageNotFound")} {t("pageNotFound")}
</h2> </h2>

View File

@@ -143,7 +143,7 @@ export default function AccessToken({ token, resourceId }: AccessTokenProps) {
) : ( ) : (
<Card className="w-full max-w-md"> <Card className="w-full max-w-md">
<CardHeader> <CardHeader>
<CardTitle className="text-center text-2xl font-bold"> <CardTitle className="text-center text-2xl font-semibold">
{renderTitle()} {renderTitle()}
</CardTitle> </CardTitle>
</CardHeader> </CardHeader>

View File

@@ -58,12 +58,12 @@ export default function AccessTokenSection({
<TabsContent value="token" className="space-y-4"> <TabsContent value="token" className="space-y-4">
<div className="space-y-1"> <div className="space-y-1">
<div className="font-bold">{t("tokenId")}</div> <div className="font-semibold">{t("tokenId")}</div>
<CopyToClipboard text={tokenId} isLink={false} /> <CopyToClipboard text={tokenId} isLink={false} />
</div> </div>
<div className="space-y-1"> <div className="space-y-1">
<div className="font-bold">{t("token")}</div> <div className="font-semibold">{t("token")}</div>
<CopyToClipboard text={token} isLink={false} /> <CopyToClipboard text={token} isLink={false} />
</div> </div>
</TabsContent> </TabsContent>

View File

@@ -92,7 +92,7 @@ export default function ConfirmDeleteDialog({
<CredenzaBody> <CredenzaBody>
<div className="mb-4 break-all overflow-hidden"> <div className="mb-4 break-all overflow-hidden">
{dialog} {dialog}
<div className="mt-2 mb-6 font-bold text-destructive"> <div className="mt-2 mb-6 font-semibold text-destructive">
{warningText || t("cannotbeUndone")} {warningText || t("cannotbeUndone")}
</div> </div>
@@ -142,7 +142,9 @@ export default function ConfirmDeleteDialog({
form="confirm-delete-form" form="confirm-delete-form"
loading={loading} loading={loading}
disabled={loading || !isConfirmed} disabled={loading || !isConfirmed}
className={!isConfirmed && !loading ? "opacity-50" : ""} className={
!isConfirmed && !loading ? "opacity-50" : ""
}
> >
{buttonText} {buttonText}
</Button> </Button>

View File

@@ -107,7 +107,7 @@ export function DNSRecordsDataTable<TData, TValue>({
<CardHeader className="flex flex-col space-y-4 sm:flex-row sm:items-center sm:justify-between sm:space-y-0 pb-4"> <CardHeader className="flex flex-col space-y-4 sm:flex-row sm:items-center sm:justify-between sm:space-y-0 pb-4">
<div className="flex flex-row space-y-3 w-full sm:mr-2 gap-2 justify-between"> <div className="flex flex-row space-y-3 w-full sm:mr-2 gap-2 justify-between">
<div className="relative w-full sm:max-w-sm flex flex-row gap-4 items-center"> <div className="relative w-full sm:max-w-sm flex flex-row gap-4 items-center">
<h1 className="font-bold">{t("dnsRecord")}</h1> <h1 className="font-semibold">{t("dnsRecord")}</h1>
<Badge variant="secondary">{t("required")}</Badge> <Badge variant="secondary">{t("required")}</Badge>
</div> </div>
<Link <Link

View File

@@ -252,7 +252,7 @@ export default function DeleteAccountConfirmDialog({
</> </>
)} )}
</div> </div>
<p className="text-sm font-bold text-destructive"> <p className="text-sm font-semibold text-destructive">
{t("cannotbeUndone")} {t("cannotbeUndone")}
</p> </p>
</> </>

View File

@@ -204,7 +204,7 @@ export default function InviteStatusCard({
<div className="flex items-center justify-center min-h-screen"> <div className="flex items-center justify-center min-h-screen">
<Card className="w-full max-w-md"> <Card className="w-full max-w-md">
<CardHeader> <CardHeader>
<CardTitle className="text-center text-2xl font-bold"> <CardTitle className="text-center text-2xl font-semibold">
{loading ? t("checkingInvite") : t("inviteNotAccepted")} {loading ? t("checkingInvite") : t("inviteNotAccepted")}
</CardTitle> </CardTitle>
</CardHeader> </CardHeader>

View File

@@ -720,7 +720,7 @@ export default function MemberResourcesPortal({
<TooltipProvider> <TooltipProvider>
<Tooltip> <Tooltip>
<TooltipTrigger className="min-w-0 max-w-full"> <TooltipTrigger className="min-w-0 max-w-full">
<CardTitle className="text-lg font-bold text-foreground truncate group-hover:text-primary transition-colors"> <CardTitle className="text-lg font-semibold text-foreground truncate group-hover:text-primary transition-colors">
{ {
resource.name resource.name
} }
@@ -822,7 +822,7 @@ export default function MemberResourcesPortal({
<TooltipProvider> <TooltipProvider>
<Tooltip> <Tooltip>
<TooltipTrigger className="min-w-0 max-w-full"> <TooltipTrigger className="min-w-0 max-w-full">
<CardTitle className="text-lg font-bold text-foreground truncate group-hover:text-primary transition-colors"> <CardTitle className="text-lg font-semibold text-foreground truncate group-hover:text-primary transition-colors">
{ {
siteResource.name siteResource.name
} }

View File

@@ -32,9 +32,7 @@ export function OptionSelect<TValue extends string>({
}: OptionSelectProps<TValue>) { }: OptionSelectProps<TValue>) {
return ( return (
<div className={className}> <div className={className}>
{label && ( {label && <p className="font-semibold mb-3">{label}</p>}
<p className="font-bold mb-3">{label}</p>
)}
<div <div
className={cn( className={cn(
"grid gap-2", "grid gap-2",
@@ -51,7 +49,11 @@ export function OptionSelect<TValue extends string>({
<Button <Button
key={option.value} key={option.value}
type="button" type="button"
variant={isSelected ? "squareOutlinePrimary" : "squareOutline"} variant={
isSelected
? "squareOutlinePrimary"
: "squareOutline"
}
className={cn( className={cn(
"flex-1 min-w-30 shadow-none", "flex-1 min-w-30 shadow-none",
isSelected && "bg-primary/10" isSelected && "bg-primary/10"

View File

@@ -86,7 +86,7 @@ export function OrgSelector({
<div className="flex items-center justify-between w-full min-w-0"> <div className="flex items-center justify-between w-full min-w-0">
<div className="flex items-center min-w-0 flex-1"> <div className="flex items-center min-w-0 flex-1">
<div className="flex flex-col items-start min-w-0 flex-1 gap-1"> <div className="flex flex-col items-start min-w-0 flex-1 gap-1">
<span className="font-bold"> <span className="font-semibold">
{t("org")} {t("org")}
</span> </span>
<span className="text-sm text-muted-foreground truncate w-full text-left"> <span className="text-sm text-muted-foreground truncate w-full text-left">

View File

@@ -70,7 +70,7 @@ export default function OrganizationLandingCard(
return ( return (
<Card> <Card>
<CardHeader> <CardHeader>
<CardTitle className="flex items-center text-3xl font-bold"> <CardTitle className="flex items-center text-3xl font-semibold">
{orgData.overview.orgName} {orgData.overview.orgName}
</CardTitle> </CardTitle>
</CardHeader> </CardHeader>
@@ -82,7 +82,7 @@ export default function OrganizationLandingCard(
className="flex flex-col items-center p-4 bg-secondary rounded-lg" className="flex flex-col items-center p-4 bg-secondary rounded-lg"
> >
{stat.icon} {stat.icon}
<span className="mt-2 text-2xl font-bold"> <span className="mt-2 text-2xl font-semibold">
{stat.value} {stat.value}
</span> </span>
<span className="text-sm text-muted-foreground"> <span className="text-sm text-muted-foreground">

View File

@@ -17,7 +17,7 @@ export default function ResourceAccessDenied() {
return ( return (
<Card className="w-full max-w-md"> <Card className="w-full max-w-md">
<CardHeader> <CardHeader>
<CardTitle className="text-center text-2xl font-bold"> <CardTitle className="text-center text-2xl font-semibold">
{t("accessDenied")} {t("accessDenied")}
</CardTitle> </CardTitle>
</CardHeader> </CardHeader>

View File

@@ -15,7 +15,7 @@ export default async function ResourceNotFound() {
return ( return (
<Card className="w-full max-w-md"> <Card className="w-full max-w-md">
<CardHeader> <CardHeader>
<CardTitle className="text-center text-2xl font-bold"> <CardTitle className="text-center text-2xl font-semibold">
{t("resourceNotFound")} {t("resourceNotFound")}
</CardTitle> </CardTitle>
</CardHeader> </CardHeader>

View File

@@ -38,7 +38,7 @@ export function SettingsSectionTitle({
children: React.ReactNode; children: React.ReactNode;
}) { }) {
return ( return (
<h2 className="text-1xl font-bold tracking-tight flex items-center gap-2"> <h2 className="text-1xl font-semibold tracking-tight flex items-center gap-2">
{children} {children}
</h2> </h2>
); );

View File

@@ -16,7 +16,7 @@ export default function SettingsSectionTitle({
<h2 <h2
className={`text-${ className={`text-${
size ? size : "2xl" size ? size : "2xl"
} font-bold tracking-tight`} } font-semibold tracking-tight`}
> >
{title} {title}
</h2> </h2>

View File

@@ -199,7 +199,7 @@ function OverviewColumn({
<div className="border-b px-5 py-5"> <div className="border-b px-5 py-5">
<div className="flex items-start justify-between gap-4"> <div className="flex items-start justify-between gap-4">
<div className="text-lg space-y-0.5 pb-6"> <div className="text-lg space-y-0.5 pb-6">
<h2 className="text-1xl font-bold tracking-tight flex items-center gap-2"> <h2 className="text-1xl font-semibold tracking-tight flex items-center gap-2">
{title} {title}
</h2> </h2>
<p className="text-muted-foreground text-sm"> <p className="text-muted-foreground text-sm">

View File

@@ -77,8 +77,12 @@ sudo install -d -m 0755 /etc/newt
sudo tee /etc/newt/newt.env > /dev/null << 'EOF' sudo tee /etc/newt/newt.env > /dev/null << 'EOF'
NEWT_ID=${id} NEWT_ID=${id}
NEWT_SECRET=${secret} NEWT_SECRET=${secret}
PANGOLIN_ENDPOINT=${endpoint}${!acceptClients ? ` PANGOLIN_ENDPOINT=${endpoint}${
DISABLE_CLIENTS=true` : ""} !acceptClients
? `
DISABLE_CLIENTS=true`
: ""
}
EOF EOF
sudo chmod 600 /etc/newt/newt.env` sudo chmod 600 /etc/newt/newt.env`
}, },
@@ -232,9 +236,7 @@ WantedBy=default.target`
<OptionSelect<string> <OptionSelect<string>
label={ label={
platform === "windows" platform === "windows" ? t("architecture") : t("method")
? t("architecture")
: t("method")
} }
options={getArchitectures(platform).map((arch) => ({ options={getArchitectures(platform).map((arch) => ({
value: arch, value: arch,
@@ -247,7 +249,9 @@ WantedBy=default.target`
/> />
<div className="pt-4"> <div className="pt-4">
<p className="font-bold mb-3">{t("siteConfiguration")}</p> <p className="font-semibold mb-3">
{t("siteConfiguration")}
</p>
<div className="flex items-center space-x-2 mb-2"> <div className="flex items-center space-x-2 mb-2">
<CheckboxWithLabel <CheckboxWithLabel
id="acceptClients" id="acceptClients"
@@ -269,7 +273,7 @@ WantedBy=default.target`
</div> </div>
<div className="pt-4"> <div className="pt-4">
<p className="font-bold mb-3">{t("commands")}</p> <p className="font-semibold mb-3">{t("commands")}</p>
{platform === "kubernetes" && ( {platform === "kubernetes" && (
<p className="text-sm text-muted-foreground mb-3"> <p className="text-sm text-muted-foreground mb-3">
For more and up to date Kubernetes installation For more and up to date Kubernetes installation

View File

@@ -122,9 +122,7 @@ curl -o olm.exe -L "https://github.com/fosrl/olm/releases/download/${version}/ol
<OptionSelect<string> <OptionSelect<string>
label={ label={
platform === "docker" platform === "docker" ? t("method") : t("architecture")
? t("method")
: t("architecture")
} }
options={getArchitectures(platform).map((arch) => ({ options={getArchitectures(platform).map((arch) => ({
value: arch, value: arch,
@@ -137,13 +135,11 @@ curl -o olm.exe -L "https://github.com/fosrl/olm/releases/download/${version}/ol
/> />
<div className="pt-4"> <div className="pt-4">
<p className="font-bold mb-3">{t("commands")}</p> <p className="font-semibold mb-3">{t("commands")}</p>
<div className="mt-2 space-y-3"> <div className="mt-2 space-y-3">
{commands.map((item, index) => { {commands.map((item, index) => {
const commandText = const commandText =
typeof item === "string" typeof item === "string" ? item : item.command;
? item
: item.command;
const title = const title =
typeof item === "string" typeof item === "string"
? undefined ? undefined

View File

@@ -57,7 +57,7 @@ export const tagVariants = cva(
}, },
textStyle: { textStyle: {
normal: "font-normal", normal: "font-normal",
bold: "font-bold", bold: "font-semibold",
italic: "italic", italic: "italic",
underline: "underline", underline: "underline",
lineThrough: "line-through" lineThrough: "line-through"