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
49 changes: 49 additions & 0 deletions frontend/src/lib/components/ui/badge/badge.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<script lang="ts" module>
import { type VariantProps, tv } from 'tailwind-variants';

export const badgeVariants = tv({
base: 'focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive inline-flex w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-full border px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-[3px] [&>svg]:pointer-events-none [&>svg]:size-3',
variants: {
variant: {
default: 'bg-primary text-primary-foreground [a&]:hover:bg-primary/90 border-transparent',
secondary:
'bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90 border-transparent',
destructive:
'bg-destructive [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/70 border-transparent text-white',
outline: 'text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground'
}
},
defaultVariants: {
variant: 'default'
}
});

export type BadgeVariant = VariantProps<typeof badgeVariants>['variant'];
</script>

<script lang="ts">
import type { HTMLAnchorAttributes } from 'svelte/elements';
import { cn, type WithElementRef } from '$lib/utils.js';

let {
ref = $bindable(null),
href,
class: className,
variant = 'default',
children,
...restProps
}: WithElementRef<HTMLAnchorAttributes> & {
variant?: BadgeVariant;
} = $props();
</script>

<svelte:element
this={href ? 'a' : 'span'}
bind:this={ref}
data-slot="badge"
{href}
class={cn(badgeVariants({ variant }), className)}
{...restProps}
>
{@render children?.()}
</svelte:element>
2 changes: 2 additions & 0 deletions frontend/src/lib/components/ui/badge/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as Badge } from './badge.svelte';
export { badgeVariants, type BadgeVariant } from './badge.svelte';
3 changes: 2 additions & 1 deletion frontend/src/lib/config/config.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export const cfg = {
apiBaseUrl: import.meta.env.VITE_API_BASE_URL || 'http://localhost:3003/api/users'
apiBaseUrl: import.meta.env.VITE_API_BASE_URL || 'http://localhost:3003/api/users',
apiHealthCheckUrl: import.meta.env.VITE_API_HEALTH_CHECK_URL || 'http://localhost:3003/api/ping'
};
9 changes: 9 additions & 0 deletions frontend/src/lib/service/authApiService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,15 @@ import { cfg } from '$lib/config/config.js';

type MethodType = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';

export const healthCheck = async (): Promise<boolean> => {
try {
const response = await fetch(cfg.apiHealthCheckUrl, { method: 'GET' });
return response.ok;
} catch {
return false;
}
};

const apiFetcher = async <TRequest, TResponse>(
path: string,
method: MethodType,
Expand Down
13 changes: 10 additions & 3 deletions frontend/src/routes/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
<script lang="ts">
import { browser } from '$app/environment';
import HealthCheck from './HealthCheck.svelte';
import NavLinks from './NavLinks.svelte';
</script>

<div class="flex flex-1 flex-col items-center justify-center gap-10">
<div class="flex max-w-4xl flex-col items-center justify-center gap-18 p-4">
<h1 class="animate-enter text-center text-2xl font-semibold lg:text-3xl xl:text-4xl">
Welcome to the Authentication Demo
</h1>
<div class="flex flex-col items-center justify-center gap-2">
<h1 class="animate-enter text-center text-2xl font-semibold lg:text-3xl xl:text-4xl">
Welcome to the Authentication Demo
</h1>
<p class="mt-6 text-center text-sm text-muted-foreground">
This is a demo environment. Data is reset periodically.
</p>
<HealthCheck />
</div>

{#if browser}
<NavLinks />
Expand Down
19 changes: 19 additions & 0 deletions frontend/src/routes/HealthCheck.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<script lang="ts">
import { Badge } from '$lib/components/ui/badge';
import { healthCheck } from '$lib/service/authApiService';
import { onMount } from 'svelte';

let backendHealthCheck = false;

onMount(async () => {
backendHealthCheck = await healthCheck();
});
</script>

<div class="text-sm text-muted-foreground">
{#if backendHealthCheck}
<Badge variant="secondary" class="font-semibold text-green-600">Backend is ready</Badge>
{:else}
<Badge variant="secondary" class="font-semibold text-red-600">Backend is waking up...</Badge>
{/if}
</div>