mirror of https://github.com/TZGyn/shortener
Compare commits
2 Commits
56764e4aa6
...
9a044801db
| Author | SHA1 | Date |
|---|---|---|
|
|
9a044801db | 1 year ago |
|
|
8d74c44b1f | 1 year ago |
@ -0,0 +1 @@
|
||||
ALTER TABLE "shortener" DROP CONSTRAINT "shortener_code_unique";
|
||||
@ -0,0 +1,457 @@
|
||||
{
|
||||
"id": "c91acbf2-ca0a-4726-b2b2-70fd1f8bd9ff",
|
||||
"prevId": "49d0736b-4fb4-4ab7-bc0e-b3401b2dcc1d",
|
||||
"version": "7",
|
||||
"dialect": "postgresql",
|
||||
"tables": {
|
||||
"public.email_verification_token": {
|
||||
"name": "email_verification_token",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"email": {
|
||||
"name": "email",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"expires_at": {
|
||||
"name": "expires_at",
|
||||
"type": "timestamp with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
},
|
||||
"public.project": {
|
||||
"name": "project",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"uuid": {
|
||||
"name": "uuid",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"qr_background": {
|
||||
"name": "qr_background",
|
||||
"type": "varchar(7)",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'#ffffff'"
|
||||
},
|
||||
"qr_foreground": {
|
||||
"name": "qr_foreground",
|
||||
"type": "varchar(7)",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'#000000'"
|
||||
},
|
||||
"domain_status": {
|
||||
"name": "domain_status",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'verified'"
|
||||
},
|
||||
"enable_custom_domain": {
|
||||
"name": "enable_custom_domain",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": false
|
||||
},
|
||||
"custom_ip": {
|
||||
"name": "custom_ip",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"custom_domain_id": {
|
||||
"name": "custom_domain_id",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"custom_domain": {
|
||||
"name": "custom_domain",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"qr_corner_square_style": {
|
||||
"name": "qr_corner_square_style",
|
||||
"type": "varchar",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'square'"
|
||||
},
|
||||
"qr_dot_style": {
|
||||
"name": "qr_dot_style",
|
||||
"type": "varchar",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'square'"
|
||||
},
|
||||
"qr_image_base64": {
|
||||
"name": "qr_image_base64",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
},
|
||||
"public.session": {
|
||||
"name": "session",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"expires_at": {
|
||||
"name": "expires_at",
|
||||
"type": "timestamp with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
},
|
||||
"public.shortener": {
|
||||
"name": "shortener",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"link": {
|
||||
"name": "link",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"ios": {
|
||||
"name": "ios",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": false
|
||||
},
|
||||
"ios_link": {
|
||||
"name": "ios_link",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"android": {
|
||||
"name": "android",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": false
|
||||
},
|
||||
"android_link": {
|
||||
"name": "android_link",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"code": {
|
||||
"name": "code",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"active": {
|
||||
"name": "active",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": true
|
||||
},
|
||||
"project_id": {
|
||||
"name": "project_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
},
|
||||
"public.user": {
|
||||
"name": "user",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"uuid": {
|
||||
"name": "uuid",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"email_verified": {
|
||||
"name": "email_verified",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": false
|
||||
},
|
||||
"email": {
|
||||
"name": "email",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"google_id": {
|
||||
"name": "google_id",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"username": {
|
||||
"name": "username",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"password": {
|
||||
"name": "password",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"plan": {
|
||||
"name": "plan",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'free'"
|
||||
},
|
||||
"stripe_customer_id": {
|
||||
"name": "stripe_customer_id",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"qr_background": {
|
||||
"name": "qr_background",
|
||||
"type": "varchar(7)",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'#fff'"
|
||||
},
|
||||
"qr_foreground": {
|
||||
"name": "qr_foreground",
|
||||
"type": "varchar(7)",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'#000'"
|
||||
},
|
||||
"qr_corner_square_style": {
|
||||
"name": "qr_corner_square_style",
|
||||
"type": "varchar",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'square'"
|
||||
},
|
||||
"qr_dot_style": {
|
||||
"name": "qr_dot_style",
|
||||
"type": "varchar",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'square'"
|
||||
},
|
||||
"qr_image_base64": {
|
||||
"name": "qr_image_base64",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {
|
||||
"user_email_unique": {
|
||||
"name": "user_email_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"email"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"public.visitor": {
|
||||
"name": "visitor",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"shortener_id": {
|
||||
"name": "shortener_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"country_code": {
|
||||
"name": "country_code",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"country": {
|
||||
"name": "country",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"city": {
|
||||
"name": "city",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"device_type": {
|
||||
"name": "device_type",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "''"
|
||||
},
|
||||
"device_vendor": {
|
||||
"name": "device_vendor",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "''"
|
||||
},
|
||||
"os": {
|
||||
"name": "os",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "''"
|
||||
},
|
||||
"browser": {
|
||||
"name": "browser",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "''"
|
||||
},
|
||||
"referer": {
|
||||
"name": "referer",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "''"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
}
|
||||
},
|
||||
"enums": {},
|
||||
"schemas": {},
|
||||
"sequences": {},
|
||||
"_meta": {
|
||||
"columns": {},
|
||||
"schemas": {},
|
||||
"tables": {}
|
||||
}
|
||||
}
|
||||
@ -1,47 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { Button } from '$lib/components/ui/button'
|
||||
import * as AlertDialog from '$lib/components/ui/alert-dialog'
|
||||
import { Loader2 } from 'lucide-svelte'
|
||||
import { invalidateAll } from '$app/navigation'
|
||||
import { toast } from 'svelte-sonner'
|
||||
|
||||
export let deleteDialogOpen = false
|
||||
export let deleteShortenerCode = ''
|
||||
let isDeleteLoading = false
|
||||
|
||||
const deleteShortener = async () => {
|
||||
isDeleteLoading = true
|
||||
await fetch(`/api/shortener/${deleteShortenerCode}`, {
|
||||
method: 'delete',
|
||||
})
|
||||
isDeleteLoading = false
|
||||
toast.success('Shortener deleted successfully')
|
||||
deleteDialogOpen = false
|
||||
await invalidateAll()
|
||||
}
|
||||
</script>
|
||||
|
||||
<AlertDialog.Root bind:open={deleteDialogOpen}>
|
||||
<AlertDialog.Content>
|
||||
<AlertDialog.Header>
|
||||
<AlertDialog.Title>Are you absolutely sure?</AlertDialog.Title>
|
||||
<AlertDialog.Description>
|
||||
You are about to delete a shortener.
|
||||
</AlertDialog.Description>
|
||||
</AlertDialog.Header>
|
||||
<AlertDialog.Footer>
|
||||
<AlertDialog.Cancel disabled={isDeleteLoading}
|
||||
>Cancel</AlertDialog.Cancel>
|
||||
<Button
|
||||
variant="destructive"
|
||||
on:click={deleteShortener}
|
||||
class="flex gap-2"
|
||||
disabled={isDeleteLoading}>
|
||||
{#if isDeleteLoading}
|
||||
<Loader2 class="animate-spin" />
|
||||
{/if}
|
||||
Delete
|
||||
</Button>
|
||||
</AlertDialog.Footer>
|
||||
</AlertDialog.Content>
|
||||
</AlertDialog.Root>
|
||||
@ -1,225 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { Button, buttonVariants } from '$lib/components/ui/button'
|
||||
import * as Card from '$lib/components/ui/card'
|
||||
import * as Dialog from '$lib/components/ui/dialog'
|
||||
import * as DropdownMenu from '$lib/components/ui/dropdown-menu'
|
||||
import * as Tooltip from '$lib/components/ui/tooltip'
|
||||
import * as Avatar from '$lib/components/ui/avatar'
|
||||
import { Badge } from '$lib/components/ui/badge'
|
||||
import { ScrollArea } from '$lib/components/ui/scroll-area'
|
||||
import type { Shortener, Project } from '$lib/db/types'
|
||||
import {
|
||||
BarChart,
|
||||
EditIcon,
|
||||
ExternalLink,
|
||||
Loader2Icon,
|
||||
MoreVertical,
|
||||
QrCode,
|
||||
TrashIcon,
|
||||
} from 'lucide-svelte'
|
||||
import DeleteShortenerDialog from './DeleteShortenerDialog.svelte'
|
||||
import EditProjectLinkPage from '../links/[linkid]/edit/+page.svelte'
|
||||
import { goto, preloadData, pushState } from '$app/navigation'
|
||||
import { cn } from '$lib/utils'
|
||||
import type { page } from '$app/stores'
|
||||
|
||||
export let shortener: Shortener & {
|
||||
visitorCount: number
|
||||
}
|
||||
export let shortener_url: string
|
||||
export let selected_project: Project
|
||||
|
||||
let deleteDialogOpen = false
|
||||
let deleteShortenerCode = ''
|
||||
const openDeleteDialog = (code: string) => {
|
||||
deleteShortenerCode = code
|
||||
deleteDialogOpen = true
|
||||
}
|
||||
|
||||
let editProjectLinkOpen = false
|
||||
let editData: typeof $page.state.editProjectLink
|
||||
|
||||
const showEditModal = async (projectUuid: string, code: string) => {
|
||||
const href = `/dashboard/projects/${projectUuid}/links/${code}/edit`
|
||||
const result = await preloadData(href)
|
||||
|
||||
if (result.type === 'loaded' && result.status === 200) {
|
||||
editData = result.data as typeof $page.state.editProjectLink
|
||||
editProjectLinkOpen = true
|
||||
} else {
|
||||
// something bad happened! try navigating
|
||||
goto(href)
|
||||
}
|
||||
}
|
||||
|
||||
let isLoadingQrModal = false
|
||||
const showQRModal = async (e: MouseEvent) => {
|
||||
isLoadingQrModal = true
|
||||
const { href } = e.currentTarget as HTMLAnchorElement
|
||||
|
||||
if (innerWidth < 640) goto(href)
|
||||
|
||||
const result = await preloadData(href)
|
||||
|
||||
if (result.type === 'loaded' && result.status === 200) {
|
||||
pushState(href, { projectLinkQR: result.data })
|
||||
} else {
|
||||
goto(href)
|
||||
}
|
||||
isLoadingQrModal = false
|
||||
}
|
||||
|
||||
const shortenerUrl = selected_project.enable_custom_domain
|
||||
? selected_project.custom_domain || shortener_url
|
||||
: shortener_url
|
||||
</script>
|
||||
|
||||
<Card.Root>
|
||||
<Card.Header>
|
||||
<Card.Title class="flex items-center justify-between gap-4">
|
||||
<Avatar.Root class="overflow-visible">
|
||||
<Avatar.Image
|
||||
src={'https://www.google.com/s2/favicons?sz=128&domain_url=' +
|
||||
shortener.link}
|
||||
alt="favicon" />
|
||||
<Avatar.Fallback class="bg-opacity-0">
|
||||
<img src="/favicon.png" alt="favicon" />
|
||||
</Avatar.Fallback>
|
||||
</Avatar.Root>
|
||||
<div class="flex flex-grow flex-col items-start gap-2">
|
||||
<Tooltip.Root>
|
||||
<Tooltip.Trigger>
|
||||
<div
|
||||
class="max-w-[250px] overflow-x-clip overflow-ellipsis whitespace-nowrap">
|
||||
{shortener.link}
|
||||
</div>
|
||||
</Tooltip.Trigger>
|
||||
<Tooltip.Content>
|
||||
<p>{shortener.link}</p>
|
||||
</Tooltip.Content>
|
||||
</Tooltip.Root>
|
||||
|
||||
<div
|
||||
class="text-muted-foreground flex items-center gap-2 text-sm">
|
||||
<a
|
||||
href={'https://' + shortenerUrl + '/' + shortener.code}
|
||||
target="_blank"
|
||||
class="hover:underline">
|
||||
{shortenerUrl + '/' + shortener.code}
|
||||
</a>
|
||||
<ExternalLink size={16} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger>
|
||||
<MoreVertical />
|
||||
</DropdownMenu.Trigger>
|
||||
<DropdownMenu.Content>
|
||||
<DropdownMenu.Group>
|
||||
<a
|
||||
href={`/dashboard/projects/${selected_project.uuid}/links/${shortener.code}/edit`}
|
||||
on:click|preventDefault={() =>
|
||||
showEditModal(
|
||||
selected_project.uuid || '',
|
||||
shortener.code,
|
||||
)}>
|
||||
<DropdownMenu.Item class="flex items-center gap-2">
|
||||
<EditIcon size={16} />Edit
|
||||
</DropdownMenu.Item>
|
||||
</a>
|
||||
<DropdownMenu.Item
|
||||
on:click={() => openDeleteDialog(shortener.id)}
|
||||
class="text-destructive data-[highlighted]:bg-destructive flex items-center gap-2">
|
||||
<TrashIcon size={16} />
|
||||
Delete
|
||||
</DropdownMenu.Item>
|
||||
</DropdownMenu.Group>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Root>
|
||||
</Card.Title>
|
||||
</Card.Header>
|
||||
<Card.Content>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex gap-2">
|
||||
<Button
|
||||
href={`/dashboard/links/${shortener.code}`}
|
||||
class="bg-secondary flex h-8 items-center justify-center gap-1 rounded text-sm">
|
||||
<BarChart size={20} />
|
||||
<div>
|
||||
{shortener.visitorCount} visits
|
||||
</div>
|
||||
</Button>
|
||||
<a
|
||||
class={cn(
|
||||
buttonVariants({ variant: 'default' }),
|
||||
'bg-secondary flex h-8 items-center justify-center gap-1 rounded text-sm',
|
||||
)}
|
||||
href={`/dashboard/projects/${selected_project.uuid}/links/${shortener.code}/qr`}
|
||||
on:click|preventDefault={showQRModal}>
|
||||
{#if isLoadingQrModal}
|
||||
<Loader2Icon size={20} class="animate-spin" />
|
||||
{:else}
|
||||
<QrCode size={20} />
|
||||
{/if}
|
||||
</a>
|
||||
{#if shortener.ios}
|
||||
<Tooltip.Root>
|
||||
<Tooltip.Trigger>
|
||||
<Badge variant="outline" class="flex gap-2">iOS</Badge>
|
||||
</Tooltip.Trigger>
|
||||
<Tooltip.Content>
|
||||
<p>{shortener.ios_link}</p>
|
||||
</Tooltip.Content>
|
||||
</Tooltip.Root>
|
||||
{/if}
|
||||
{#if shortener.android}
|
||||
<Tooltip.Root>
|
||||
<Tooltip.Trigger>
|
||||
<Badge variant="outline" class="flex gap-2">
|
||||
Android
|
||||
</Badge>
|
||||
</Tooltip.Trigger>
|
||||
<Tooltip.Content>
|
||||
<p>{shortener.android_link}</p>
|
||||
</Tooltip.Content>
|
||||
</Tooltip.Root>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="flex gap-4">
|
||||
{#if shortener.projectName}
|
||||
<Badge variant="secondary">{shortener.projectName}</Badge>
|
||||
{/if}
|
||||
<Badge variant="outline" class="flex gap-2">
|
||||
{#if shortener.active}
|
||||
<span
|
||||
class="relative inline-flex h-2 w-2 rounded-full bg-green-400">
|
||||
</span>
|
||||
Active
|
||||
{:else}
|
||||
<span
|
||||
class="relative inline-flex h-2 w-2 rounded-full bg-gray-600">
|
||||
</span>
|
||||
Inactive
|
||||
{/if}
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
|
||||
<DeleteShortenerDialog bind:deleteDialogOpen {deleteShortenerCode} />
|
||||
|
||||
<Dialog.Root bind:open={editProjectLinkOpen}>
|
||||
<Dialog.Content>
|
||||
<Dialog.Header>
|
||||
<Dialog.Title>Edit Shortener</Dialog.Title>
|
||||
<Dialog.Description>
|
||||
Edit Shortener Here. Click Save To Save.
|
||||
</Dialog.Description>
|
||||
</Dialog.Header>
|
||||
<ScrollArea class="max-h-[calc(100vh-200px)]">
|
||||
<EditProjectLinkPage data={editData} shallowRouting />
|
||||
</ScrollArea>
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
Loading…
Reference in New Issue