give dark mode some love 🖤
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { StickyBelowHeader } from '@/app/(app)/[organizationSlug]/[projectId]/layout-sticky-below-header';
|
||||
import { FullPageEmptyState } from '@/components/full-page-empty-state';
|
||||
import { useOverviewOptions } from '@/components/overview/useOverviewOptions';
|
||||
import { LazyChart } from '@/components/report/chart/LazyChart';
|
||||
import { Button } from '@/components/ui/button';
|
||||
@@ -14,7 +15,13 @@ import {
|
||||
import { useAppParams } from '@/hooks/useAppParams';
|
||||
import { api, handleError } from '@/trpc/client';
|
||||
import { cn } from '@/utils/cn';
|
||||
import { ChevronRight, MoreHorizontal, PlusIcon, Trash } from 'lucide-react';
|
||||
import {
|
||||
ChevronRight,
|
||||
LayoutPanelTopIcon,
|
||||
MoreHorizontal,
|
||||
PlusIcon,
|
||||
Trash,
|
||||
} from 'lucide-react';
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { toast } from 'sonner';
|
||||
@@ -138,6 +145,26 @@ export function ListReports({ reports }: ListReportsProps) {
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
{reports.length === 0 && (
|
||||
<FullPageEmptyState title="No reports" icon={LayoutPanelTopIcon}>
|
||||
<p>You can visualize your data with a report</p>
|
||||
<Button
|
||||
onClick={() =>
|
||||
router.push(
|
||||
`/${params.organizationSlug}/${
|
||||
params.projectId
|
||||
}/reports?${new URLSearchParams({
|
||||
dashboardId: params.dashboardId,
|
||||
}).toString()}`
|
||||
)
|
||||
}
|
||||
className="mt-14"
|
||||
icon={PlusIcon}
|
||||
>
|
||||
Create report
|
||||
</Button>
|
||||
</FullPageEmptyState>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -96,7 +96,7 @@ export function ListDashboards({ dashboards }: ListDashboardsProps) {
|
||||
</div>
|
||||
<div
|
||||
className={cn(
|
||||
'mt-2 grid gap-4',
|
||||
'mt-4 grid gap-4',
|
||||
'grid-cols-2 @xs:grid-cols-3 @lg:grid-cols-4'
|
||||
)}
|
||||
>
|
||||
@@ -114,19 +114,19 @@ export function ListDashboards({ dashboards }: ListDashboardsProps) {
|
||||
|
||||
return (
|
||||
<div
|
||||
className="flex flex-col items-center justify-center rounded-xl bg-slate-50 p-4"
|
||||
className="bg-def-200 flex flex-col rounded-xl p-4"
|
||||
key={report.id}
|
||||
>
|
||||
<Icon size={24} className="text-blue-600" />
|
||||
<div className="mt-2 w-full overflow-hidden text-ellipsis whitespace-nowrap text-center text-xs">
|
||||
<Icon size={24} className="text-highlight" />
|
||||
<div className="mt-2 w-full overflow-hidden text-ellipsis whitespace-nowrap text-xs">
|
||||
{report.name}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
{item.reports.length > 6 && (
|
||||
<div className="flex flex-col items-center justify-center rounded-xl bg-slate-50 p-4">
|
||||
<PlusIcon size={24} className="text-blue-600" />
|
||||
<div className="bg-def-200 flex flex-col rounded-xl p-4">
|
||||
<PlusIcon size={24} className="text-highlight" />
|
||||
<div className="mt-2 min-w-0 overflow-hidden text-ellipsis whitespace-nowrap text-xs">
|
||||
{item.reports.length - 5} more
|
||||
</div>
|
||||
|
||||
@@ -28,7 +28,7 @@ export function EventConversionsList({ data }: EventListProps) {
|
||||
{showDateHeader(item.createdAt, list[index - 1]?.createdAt) && (
|
||||
<div className="flex flex-row justify-between gap-2 [&:not(:first-child)]:mt-12">
|
||||
<div className="flex gap-2">
|
||||
<div className="flex h-8 items-center gap-2 rounded border border-slate-300 bg-slate-100 px-3 text-sm font-medium leading-none">
|
||||
<div className="bg-def-200 border-def-200 flex h-8 items-center gap-2 rounded border px-3 text-sm font-medium leading-none">
|
||||
{item.createdAt.toLocaleDateString()}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -106,7 +106,7 @@ export function EventEdit({ event, open, setOpen }: Props) {
|
||||
setIcon(name);
|
||||
}}
|
||||
className={cn(
|
||||
'inline-flex h-8 w-8 flex-shrink-0 cursor-pointer items-center justify-center rounded-md bg-slate-100 transition-all',
|
||||
'bg-def-200 inline-flex h-8 w-8 flex-shrink-0 cursor-pointer items-center justify-center rounded-md transition-all',
|
||||
name === selectedIcon
|
||||
? 'scale-110 ring-1 ring-black'
|
||||
: '[&_svg]:opacity-50'
|
||||
|
||||
@@ -63,7 +63,7 @@ function EventList({ data, count }: EventListProps) {
|
||||
<div className="flex flex-row justify-between gap-2 [&:not(:first-child)]:mt-12">
|
||||
{index === 0 ? <EventListener /> : <div />}
|
||||
<div className="flex gap-2">
|
||||
<div className="flex h-8 items-center gap-2 rounded border border-slate-300 bg-slate-100 px-3 text-sm font-medium leading-none">
|
||||
<div className="bg-def-200 border-def-200 flex h-8 items-center gap-2 rounded border px-3 text-sm font-medium leading-none">
|
||||
{item.createdAt.toLocaleDateString()}
|
||||
</div>
|
||||
{index === 0 && (
|
||||
|
||||
@@ -38,7 +38,7 @@ export default function EventListener() {
|
||||
setCounter(0);
|
||||
router.refresh();
|
||||
}}
|
||||
className="flex h-8 items-center gap-2 rounded border border-border bg-background px-3 text-sm font-medium leading-none"
|
||||
className="flex h-8 items-center gap-2 rounded border border-border bg-card px-3 text-sm font-medium leading-none"
|
||||
>
|
||||
<div className="relative">
|
||||
<div
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
# setup caprover
|
||||
|
||||
## Firewall
|
||||
|
||||
ufw allow 22,80,443,3000,996,7946,4789,2377/tcp; ufw allow 22,7946,4789,2377/udp;
|
||||
|
||||
## Install docker
|
||||
|
||||
```
|
||||
# Add Docker's official GPG key:
|
||||
sudo apt-get update
|
||||
sudo apt-get install ca-certificates curl
|
||||
sudo install -m 0755 -d /etc/apt/keyrings
|
||||
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
|
||||
sudo chmod a+r /etc/apt/keyrings/docker.asc
|
||||
|
||||
# Add the repository to Apt sources:
|
||||
echo \
|
||||
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
|
||||
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
|
||||
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
||||
sudo apt-get update
|
||||
|
||||
# Install Docker
|
||||
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
||||
|
||||
# Verify
|
||||
sudo docker run hello-world
|
||||
```
|
||||
|
||||
## Install caprover
|
||||
|
||||
`docker run -p 80:80 -p 443:443 -p 3000:3000 -e ACCEPTED_TERMS=true -v /var/run/docker.sock:/var/run/docker.sock -v /captain:/captain caprover/caprover`
|
||||
|
||||
## Point domain to server
|
||||
|
||||
`*.apps.example.com -> server ip`
|
||||
|
||||
## Setup caprover
|
||||
|
||||
caprover serversetup
|
||||
@@ -42,8 +42,8 @@ function LinkWithIcon({
|
||||
return (
|
||||
<Link
|
||||
className={cn(
|
||||
'text-text flex items-center gap-2 rounded-md px-3 py-2 text-sm font-medium transition-all transition-colors hover:bg-slate-100',
|
||||
active && 'bg-slate-100',
|
||||
'text-text hover:bg-def-200 flex items-center gap-2 rounded-md px-3 py-2 text-sm font-medium transition-all transition-colors',
|
||||
active && 'bg-def-200',
|
||||
className
|
||||
)}
|
||||
href={href}
|
||||
|
||||
@@ -46,7 +46,7 @@ export function LayoutSidebar({
|
||||
/>
|
||||
<div
|
||||
className={cn(
|
||||
'fixed left-0 top-0 z-50 flex h-screen w-72 flex-col border-r border-border bg-background transition-transform',
|
||||
'fixed left-0 top-0 z-50 flex h-screen w-72 flex-col border-r border-border bg-card transition-transform',
|
||||
'-translate-x-72 lg:-translate-x-0', // responsive
|
||||
active && 'translate-x-0' // force active on mobile
|
||||
)}
|
||||
@@ -65,8 +65,8 @@ export function LayoutSidebar({
|
||||
<div className="block h-32 shrink-0"></div>
|
||||
</div>
|
||||
<div className="fixed bottom-0 left-0 right-0">
|
||||
<div className="h-8 w-full bg-gradient-to-t from-background to-background/0"></div>
|
||||
<div className="flex flex-col gap-2 bg-background p-4 pt-0">
|
||||
<div className="h-8 w-full bg-gradient-to-t from-card to-card/0"></div>
|
||||
<div className="flex flex-col gap-2 bg-card p-4 pt-0">
|
||||
<Link
|
||||
className={cn('flex gap-2', buttonVariants())}
|
||||
href={`/${organizationSlug}/${projectId}/reports`}
|
||||
|
||||
@@ -12,7 +12,7 @@ export function StickyBelowHeader({
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'top-0 z-20 border-b border-border bg-background md:sticky [[id=dashboard]_&]:top-16 [[id=dashboard]_&]:rounded-none',
|
||||
'top-0 z-20 border-b border-border bg-card md:sticky [[id=dashboard]_&]:top-16 [[id=dashboard]_&]:rounded-none',
|
||||
className
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -15,7 +15,7 @@ async function PageLayout({ title, organizationSlug }: PageLayoutProps) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="sticky top-0 z-20 flex h-16 flex-shrink-0 items-center justify-between border-b border-border bg-background px-4 pl-12 lg:pl-4">
|
||||
<div className="sticky top-0 z-20 flex h-16 flex-shrink-0 items-center justify-between border-b border-border bg-card px-4 pl-12 lg:pl-4">
|
||||
<div className="text-xl font-medium">{title}</div>
|
||||
<div className="flex gap-2">
|
||||
<div>
|
||||
@@ -30,7 +30,7 @@ async function PageLayout({ title, organizationSlug }: PageLayoutProps) {
|
||||
|
||||
const Loading = ({ title }: PageLayoutProps) => (
|
||||
<>
|
||||
<div className="sticky top-0 z-20 flex h-16 flex-shrink-0 items-center justify-between border-b border-border bg-background px-4 pl-12 lg:pl-4">
|
||||
<div className="sticky top-0 z-20 flex h-16 flex-shrink-0 items-center justify-between border-b border-border bg-card px-4 pl-12 lg:pl-4">
|
||||
<div className="text-xl font-medium">{title}</div>
|
||||
</div>
|
||||
</>
|
||||
|
||||
@@ -18,7 +18,7 @@ const MostEvents = ({ data }: Props) => {
|
||||
{data.slice(0, 5).map((item) => (
|
||||
<div key={item.name} className="relative px-3 py-2">
|
||||
<div
|
||||
className="absolute bottom-0 left-0 top-0 rounded bg-slate-100"
|
||||
className="bg-def-200 absolute bottom-0 left-0 top-0 rounded"
|
||||
style={{
|
||||
width: `${(item.count / max) * 100}%`,
|
||||
}}
|
||||
|
||||
@@ -18,7 +18,7 @@ const PopularRoutes = ({ data }: Props) => {
|
||||
{data.slice(0, 5).map((item) => (
|
||||
<div key={item.path} className="relative px-3 py-2">
|
||||
<div
|
||||
className="absolute bottom-0 left-0 top-0 rounded bg-slate-100"
|
||||
className="bg-def-200 absolute bottom-0 left-0 top-0 rounded"
|
||||
style={{
|
||||
width: `${(item.count / max) * 100}%`,
|
||||
}}
|
||||
|
||||
@@ -70,7 +70,7 @@ const ProfileActivity = ({ data }: Props) => {
|
||||
key={date.toISOString()}
|
||||
className={cn(
|
||||
'aspect-square w-full rounded',
|
||||
hit ? 'bg-blue-600' : 'bg-slate-100'
|
||||
hit ? 'bg-highlight' : 'bg-def-200'
|
||||
)}
|
||||
></div>
|
||||
);
|
||||
@@ -94,7 +94,7 @@ const ProfileActivity = ({ data }: Props) => {
|
||||
key={date.toISOString()}
|
||||
className={cn(
|
||||
'aspect-square w-full rounded',
|
||||
hit ? 'bg-blue-600' : 'bg-slate-100'
|
||||
hit ? 'bg-highlight' : 'bg-def-200'
|
||||
)}
|
||||
></div>
|
||||
);
|
||||
|
||||
@@ -37,7 +37,7 @@ export default async function ProfileLastSeenServer({ projectId }: Props) {
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<div
|
||||
className={cn('aspect-square w-full shrink-0 rounded bg-blue-600')}
|
||||
className={cn('bg-highlight aspect-square w-full shrink-0 rounded')}
|
||||
style={{
|
||||
opacity: calculateRatio(item.count),
|
||||
}}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { useFullscreen } from '@/components/fullscreen-toggle';
|
||||
import { Tooltiper } from '@/components/ui/tooltip';
|
||||
import { cn } from '@/utils/cn';
|
||||
import { bind } from 'bind-event-listener';
|
||||
import { useTheme } from 'next-themes';
|
||||
import {
|
||||
ComposableMap,
|
||||
Geographies,
|
||||
@@ -91,6 +92,9 @@ const Map = ({ markers }: Props) => {
|
||||
return size * multiplier;
|
||||
};
|
||||
|
||||
const theme = useTheme();
|
||||
console.log(theme.theme);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
@@ -119,8 +123,8 @@ const Map = ({ markers }: Props) => {
|
||||
<Geography
|
||||
key={geo.rsmKey}
|
||||
geography={geo}
|
||||
fill="#EAEAEC"
|
||||
stroke="black"
|
||||
fill={theme.theme === 'dark' ? '#0f0f0f' : '#F0F4F9'}
|
||||
stroke={theme.theme === 'dark' ? '#262626' : '#DDE3E9'}
|
||||
pointerEvents={'none'}
|
||||
/>
|
||||
))
|
||||
@@ -149,13 +153,17 @@ const Map = ({ markers }: Props) => {
|
||||
<Marker coordinates={coordinates}>
|
||||
<circle
|
||||
r={size}
|
||||
fill="#2463EB"
|
||||
fill={theme.theme === 'dark' ? '#3d79ff' : '#2266ec'}
|
||||
className="animate-ping opacity-20"
|
||||
/>
|
||||
</Marker>
|
||||
<Tooltiper asChild content={`${marker.count} visitors`}>
|
||||
<Marker coordinates={coordinates}>
|
||||
<circle r={size} fill="#2463EB" fillOpacity={0.5} />
|
||||
<circle
|
||||
r={size}
|
||||
fill={theme.theme === 'dark' ? '#3d79ff' : '#2266ec'}
|
||||
fillOpacity={0.5}
|
||||
/>
|
||||
</Marker>
|
||||
</Tooltiper>
|
||||
</Fragment>
|
||||
|
||||
@@ -29,7 +29,7 @@ export default function Page({
|
||||
<RealtimeMap projectId={projectId} />
|
||||
</Suspense>
|
||||
<div className="relative z-10 grid min-h-[calc(100vh-theme(spacing.16))] items-start gap-4 overflow-hidden p-8 md:grid-cols-3">
|
||||
<div className="card bg-background/80 p-4">
|
||||
<div className="card bg-card/80 p-4">
|
||||
<RealtimeLiveHistogram projectId={projectId} />
|
||||
</div>
|
||||
<div className="col-span-2">
|
||||
|
||||
@@ -85,7 +85,7 @@ export function RealtimeLiveHistogram({
|
||||
{staticArray.map((percent, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="flex-1 animate-pulse rounded-md bg-slate-200 dark:bg-slate-800"
|
||||
className="bg-def-200 flex-1 animate-pulse rounded-md"
|
||||
style={{ height: `${percent}%` }}
|
||||
/>
|
||||
))}
|
||||
@@ -106,7 +106,7 @@ export function RealtimeLiveHistogram({
|
||||
<div
|
||||
className={cn(
|
||||
'flex-1 rounded-md transition-all ease-in-out hover:scale-110',
|
||||
minute.count === 0 ? 'bg-slate-200' : 'bg-blue-600'
|
||||
minute.count === 0 ? 'bg-def-200' : 'bg-highlight'
|
||||
)}
|
||||
style={{
|
||||
height:
|
||||
|
||||
@@ -23,7 +23,7 @@ function Tooltip(props: any) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<div className="flex min-w-[180px] flex-col gap-2 rounded-xl border bg-background p-3 text-sm shadow-xl">
|
||||
<div className="flex min-w-[180px] flex-col gap-2 rounded-xl border bg-card p-3 text-sm shadow-xl">
|
||||
<div>
|
||||
<div className="text-xs text-muted-foreground">
|
||||
Days since last seen
|
||||
|
||||
@@ -29,7 +29,7 @@ function Tooltip(props: any) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<div className="flex min-w-[180px] flex-col gap-2 rounded-xl border bg-background p-3 text-sm shadow-xl">
|
||||
<div className="flex min-w-[180px] flex-col gap-2 rounded-xl border bg-card p-3 text-sm shadow-xl">
|
||||
<div className="text-xs text-muted-foreground">{payload.date}</div>
|
||||
<div>
|
||||
<div className="text-xs text-muted-foreground">
|
||||
|
||||
@@ -33,7 +33,7 @@ function Tooltip({ payload }: any) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<div className="flex min-w-[180px] flex-col gap-2 rounded-xl border bg-background p-3 text-sm shadow-xl">
|
||||
<div className="flex min-w-[180px] flex-col gap-2 rounded-xl border bg-card p-3 text-sm shadow-xl">
|
||||
<div className="flex justify-between gap-8">
|
||||
<div>{formatDate(new Date(date))}</div>
|
||||
</div>
|
||||
|
||||
@@ -15,7 +15,7 @@ const Cell = ({ value, ratio }: { value: number; ratio: number }) => {
|
||||
className={cn('relative h-8 border', ratio !== 0 && 'border-background')}
|
||||
>
|
||||
<div
|
||||
className="absolute inset-0 z-0 bg-blue-600"
|
||||
className="bg-highlight absolute inset-0 z-0"
|
||||
style={{ opacity: ratio }}
|
||||
></div>
|
||||
<div className="relative z-10">{value}</div>
|
||||
@@ -76,7 +76,7 @@ const WeeklyCohortsServer = async ({ projectId }: Props) => {
|
||||
<tbody>
|
||||
{res.map((row) => (
|
||||
<tr key={row.first_seen}>
|
||||
<td className="bg-slate-50 text-sm font-medium text-slate-500">
|
||||
<td className="bg-def-100 text-def-1000 text-sm font-medium">
|
||||
{row.first_seen}
|
||||
</td>
|
||||
<Cell
|
||||
|
||||
@@ -7,9 +7,9 @@ type Props = {
|
||||
const Page = ({ children }: Props) => {
|
||||
return (
|
||||
<>
|
||||
<div className="bg-slate-100">
|
||||
<div className="bg-def-200">
|
||||
<div className="grid h-full md:grid-cols-[min(400px,40vw)_1fr]">
|
||||
<div className="min-h-screen border-r border-r-background bg-gradient-to-r from-background to-slate-200 max-md:hidden">
|
||||
<div className="to-def-200 min-h-screen border-r border-r-background bg-gradient-to-r from-background max-md:hidden">
|
||||
<LiveEventsServer />
|
||||
</div>
|
||||
<div className="min-h-screen">{children}</div>
|
||||
|
||||
@@ -12,15 +12,15 @@ const Page = ({ children }: Props) => {
|
||||
<>
|
||||
<div className="fixed inset-0 hidden md:grid md:grid-cols-[30vw_1fr] lg:grid-cols-[30vw_1fr]">
|
||||
<div className=""></div>
|
||||
<div className="border-l border-border bg-background"></div>
|
||||
<div className="border-l border-border bg-card"></div>
|
||||
</div>
|
||||
<div className="relative min-h-screen bg-background md:bg-transparent">
|
||||
<div className="relative min-h-screen bg-card md:bg-transparent">
|
||||
<FullWidthNavbar>
|
||||
<SkipOnboarding />
|
||||
</FullWidthNavbar>
|
||||
<div className="mx-auto w-full md:max-w-[95vw] lg:max-w-[80vw]">
|
||||
<div className="grid md:grid-cols-[25vw_1fr] lg:grid-cols-[20vw_1fr]">
|
||||
<div className="max-w-screen flex flex-col gap-4 overflow-hidden bg-slate-100 p-4 pr-0 md:bg-transparent md:py-14">
|
||||
<div className="max-w-screen bg-def-200 flex flex-col gap-4 overflow-hidden p-4 pr-0 md:bg-transparent md:py-14">
|
||||
<div>
|
||||
<div className="text-xs font-bold uppercase text-[#7b94ac]">
|
||||
Welcome to Openpanel
|
||||
|
||||
@@ -30,7 +30,7 @@ const ConnectApp = ({ client }: Props) => {
|
||||
className="flex items-center gap-4 rounded-md border p-2 py-2 text-left"
|
||||
key={framework.name}
|
||||
>
|
||||
<div className="h-10 w-10 rounded-md bg-slate-200 p-2">
|
||||
<div className="bg-def-200 h-10 w-10 rounded-md p-2">
|
||||
<img
|
||||
className="h-full w-full object-contain"
|
||||
src={framework.logo}
|
||||
|
||||
@@ -30,7 +30,7 @@ const ConnectBackend = ({ client }: Props) => {
|
||||
className="flex items-center gap-4 rounded-md border p-2 py-2 text-left"
|
||||
key={framework.name}
|
||||
>
|
||||
<div className="h-10 w-10 rounded-md bg-slate-200 p-2">
|
||||
<div className="bg-def-200 h-10 w-10 rounded-md p-2">
|
||||
<img
|
||||
className="h-full w-full object-contain"
|
||||
src={framework.logo}
|
||||
|
||||
@@ -30,7 +30,7 @@ const ConnectWeb = ({ client }: Props) => {
|
||||
className="flex items-center gap-4 rounded-md border p-2 py-2 text-left"
|
||||
key={framework.name}
|
||||
>
|
||||
<div className="h-10 w-10 rounded-md bg-slate-200 p-2">
|
||||
<div className="bg-def-200 h-10 w-10 rounded-md p-2">
|
||||
<img
|
||||
className="h-full w-full object-contain"
|
||||
src={framework.logo}
|
||||
|
||||
@@ -36,7 +36,7 @@ const Connect = ({ project }: Props) => {
|
||||
</OnboardingDescription>
|
||||
}
|
||||
>
|
||||
<div className="flex flex-col gap-4 rounded-xl border bg-slate-100 p-4 md:p-6">
|
||||
<div className="bg-def-200 flex flex-col gap-4 rounded-xl border p-4 md:p-6">
|
||||
<div className="flex items-center gap-2 text-2xl capitalize">
|
||||
<LockIcon />
|
||||
Credentials
|
||||
|
||||
@@ -54,7 +54,7 @@ const VerifyListener = ({ client, events: _events, onVerified }: Props) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<Loader2 size={40} className="shrink-0 animate-spin text-blue-600" />
|
||||
<Loader2 size={40} className="text-highlight shrink-0 animate-spin" />
|
||||
);
|
||||
};
|
||||
|
||||
@@ -70,7 +70,7 @@ const VerifyListener = ({ client, events: _events, onVerified }: Props) => {
|
||||
<div
|
||||
className={cn(
|
||||
'my-6 flex gap-6 rounded-xl p-4 md:p-6',
|
||||
isConnected ? 'bg-emerald-100' : 'bg-blue-100'
|
||||
isConnected ? 'bg-emerald-100' : 'bg-highlight'
|
||||
)}
|
||||
>
|
||||
{renderIcon()}
|
||||
|
||||
@@ -59,9 +59,9 @@ const Steps = ({ className }: Props) => {
|
||||
const currentIndex = steps.findIndex((i) => i.status === 'current');
|
||||
return (
|
||||
<div className="relative">
|
||||
<div className="absolute bottom-4 left-4 top-4 w-px bg-slate-300"></div>
|
||||
<div className="bg-def-200 absolute bottom-4 left-4 top-4 w-px"></div>
|
||||
<div
|
||||
className="absolute left-4 top-4 w-px bg-blue-600"
|
||||
className="bg-highlight absolute left-4 top-4 w-px"
|
||||
style={{
|
||||
height: `calc(${((currentIndex + 1) / steps.length) * 100}% - 3.5rem)`,
|
||||
}}
|
||||
@@ -77,7 +77,7 @@ const Steps = ({ className }: Props) => {
|
||||
className={cn(
|
||||
'flex flex-shrink-0 items-center gap-2 self-start px-3 py-1.5',
|
||||
step.status === 'current' &&
|
||||
'rounded-xl border border-border bg-background',
|
||||
'rounded-xl border border-border bg-card',
|
||||
step.status === 'completed' &&
|
||||
index !== currentIndex - 1 &&
|
||||
'max-md:hidden'
|
||||
@@ -87,18 +87,16 @@ const Steps = ({ className }: Props) => {
|
||||
<div
|
||||
className={cn(
|
||||
'relative flex h-8 w-8 shrink-0 items-center justify-center rounded-full text-sm text-white'
|
||||
// step.status === 'completed' && 'bg-blue-600 ring-blue-500/50',
|
||||
// step.status === 'pending' && 'bg-slate-400 ring-slate-500/50'
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
'absolute inset-0 z-0 rounded-full bg-blue-600',
|
||||
step.status === 'pending' && 'bg-slate-400'
|
||||
'bg-highlight absolute inset-0 z-0 rounded-full',
|
||||
step.status === 'pending' && 'bg-def-400'
|
||||
)}
|
||||
></div>
|
||||
{step.status === 'current' && (
|
||||
<div className="absolute inset-1 z-0 animate-ping-slow rounded-full bg-blue-600"></div>
|
||||
<div className="bg-highlight absolute inset-1 z-0 animate-ping-slow rounded-full"></div>
|
||||
)}
|
||||
<div className="relative">
|
||||
{step.status === 'completed' && <CheckCheckIcon size={14} />}
|
||||
|
||||
@@ -25,7 +25,7 @@ export default function RootLayout({
|
||||
return (
|
||||
<html lang="en" suppressHydrationWarning>
|
||||
<body
|
||||
className={cn('grainy min-h-screen bg-secondary font-sans antialiased')}
|
||||
className={cn('grainy bg-def-100 min-h-screen font-sans antialiased')}
|
||||
>
|
||||
<NextTopLoader
|
||||
showSpinner={false}
|
||||
|
||||
@@ -75,7 +75,7 @@ export function ChartSSR({
|
||||
<path
|
||||
d={pathLine}
|
||||
fill="none"
|
||||
className="text-blue-600"
|
||||
className="text-highlight"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
vectorEffect="non-scaling-stroke"
|
||||
|
||||
@@ -24,7 +24,7 @@ export const CheckboxItem = forwardRef<HTMLButtonElement, Props>(
|
||||
<div>
|
||||
<label
|
||||
className={cn(
|
||||
'flex items-center gap-4 px-4 py-6 transition-colors hover:bg-slate-100',
|
||||
'hover:bg-def-200 flex items-center gap-4 px-4 py-6 transition-colors',
|
||||
disabled && 'cursor-not-allowed opacity-50'
|
||||
)}
|
||||
htmlFor={id}
|
||||
|
||||
@@ -23,7 +23,7 @@ export function FullPageEmptyState({
|
||||
)}
|
||||
>
|
||||
<div className="flex w-full max-w-xl flex-col items-center justify-center p-8">
|
||||
<div className="mb-6 flex h-24 w-24 items-center justify-center rounded-full bg-background shadow-sm">
|
||||
<div className="mb-6 flex h-24 w-24 items-center justify-center rounded-full bg-card shadow-sm">
|
||||
<Icon size={60} strokeWidth={1} />
|
||||
</div>
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ type Props = {
|
||||
|
||||
const FullWidthNavbar = ({ children, className }: Props) => {
|
||||
return (
|
||||
<div className={cn('border-b border-border bg-background', className)}>
|
||||
<div className={cn('border-b border-border bg-card', className)}>
|
||||
<div className="mx-auto flex h-14 w-full items-center justify-between px-4 md:max-w-[95vw] lg:max-w-[80vw]">
|
||||
<Logo />
|
||||
{children}
|
||||
|
||||
@@ -25,7 +25,7 @@ export const Fullscreen = (props: Props) => {
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
isFullscreen && 'fixed inset-0 z-50 overflow-auto bg-slate-100'
|
||||
isFullscreen && 'bg-def-200 fixed inset-0 z-50 overflow-auto'
|
||||
)}
|
||||
>
|
||||
{props.children}
|
||||
|
||||
@@ -81,7 +81,7 @@ export function OverviewLiveHistogram({
|
||||
{staticArray.map((percent, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="flex-1 animate-pulse rounded bg-slate-200 dark:bg-slate-800"
|
||||
className="bg-def-200 flex-1 animate-pulse rounded"
|
||||
style={{ height: `${percent}%` }}
|
||||
/>
|
||||
))}
|
||||
@@ -102,7 +102,7 @@ export function OverviewLiveHistogram({
|
||||
<div
|
||||
className={cn(
|
||||
'flex-1 rounded transition-all ease-in-out hover:scale-110',
|
||||
minute.count === 0 ? 'bg-slate-200' : 'bg-blue-600'
|
||||
minute.count === 0 ? 'bg-def-200' : 'bg-highlight'
|
||||
)}
|
||||
style={{
|
||||
height:
|
||||
|
||||
@@ -199,7 +199,7 @@ export default function OverviewMetrics({ projectId }: OverviewMetricsProps) {
|
||||
key={index}
|
||||
className={cn(
|
||||
'col-span-2 flex-1 p-4 shadow-[0_0_0_0.5px] shadow-border md:col-span-1',
|
||||
index === metric && 'bg-slate-50'
|
||||
index === metric && 'bg-def-100'
|
||||
)}
|
||||
onClick={() => {
|
||||
setMetric(index);
|
||||
|
||||
@@ -47,7 +47,7 @@ export function ProfileAvatar({
|
||||
: size === 'xs'
|
||||
? 'text-[8px]'
|
||||
: 'text-base',
|
||||
'bg-slate-200 text-slate-800'
|
||||
'bg-def-200 text-muted-foreground'
|
||||
)}
|
||||
>
|
||||
{firstName?.at(0) ?? '🫣'}
|
||||
|
||||
@@ -23,7 +23,7 @@ function ProjectCard({ id, name, organizationSlug }: IServiceProject) {
|
||||
<ProjectChart id={id} />
|
||||
</Suspense>
|
||||
</div>
|
||||
<div className="flex justify-end gap-4 text-sm text-muted-foreground">
|
||||
<div className="flex justify-end gap-4 text-sm">
|
||||
<Suspense>
|
||||
<ProjectMetrics id={id} />
|
||||
</Suspense>
|
||||
@@ -47,8 +47,8 @@ async function ProjectChart({ id }: { id: string }) {
|
||||
function Metric({ value, label }: { value: React.ReactNode; label: string }) {
|
||||
return (
|
||||
<div className="flex flex-col gap-2 md:flex-row">
|
||||
<div>{label}</div>
|
||||
<span className="font-medium text-black">{value}</span>
|
||||
<div className="text-muted-foreground">{label}</div>
|
||||
<span className="font-medium">{value}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ export function ChartLoading({ className }: ChartLoadingProps) {
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'aspect-video max-h-[300px] min-h-[200px] w-full animate-pulse rounded bg-slate-200',
|
||||
'bg-def-200 aspect-video max-h-[300px] min-h-[200px] w-full animate-pulse rounded',
|
||||
className
|
||||
)}
|
||||
/>
|
||||
|
||||
@@ -115,7 +115,7 @@ export function MetricCard({
|
||||
export function MetricCardEmpty() {
|
||||
return (
|
||||
<div className="card h-24 p-4">
|
||||
<div className="flex h-full items-center justify-center text-slate-600">
|
||||
<div className="flex h-full items-center justify-center text-muted-foreground">
|
||||
No data
|
||||
</div>
|
||||
</div>
|
||||
@@ -125,9 +125,9 @@ export function MetricCardEmpty() {
|
||||
export function MetricCardLoading() {
|
||||
return (
|
||||
<div className="flex h-[70px] flex-col justify-between">
|
||||
<div className="h-4 w-1/2 animate-pulse rounded bg-slate-200"></div>
|
||||
<div className="h-8 w-1/3 animate-pulse rounded bg-slate-200"></div>
|
||||
<div className="h-3 w-1/5 animate-pulse rounded bg-slate-200"></div>
|
||||
<div className="bg-def-200 h-4 w-1/2 animate-pulse rounded"></div>
|
||||
<div className="bg-def-200 h-8 w-1/3 animate-pulse rounded"></div>
|
||||
<div className="bg-def-200 h-3 w-1/5 animate-pulse rounded"></div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ export function ReportAreaChart({
|
||||
strokeDasharray="3 3"
|
||||
horizontal={true}
|
||||
vertical={false}
|
||||
className="stroke-slate-300"
|
||||
className="stroke-def-200"
|
||||
/>
|
||||
</AreaChart>
|
||||
)}
|
||||
|
||||
@@ -41,7 +41,7 @@ export function ReportBarChart({ data }: ReportBarChartProps) {
|
||||
{...(isClickable ? { onClick: () => onClick(serie) } : {})}
|
||||
>
|
||||
<div
|
||||
className="absolute bottom-0 left-0 top-0 rounded bg-slate-100"
|
||||
className="bg-def-200 absolute bottom-0 left-0 top-0 rounded"
|
||||
style={{
|
||||
width: `${(serie.metrics.sum / maxCount) * 100}%`,
|
||||
}}
|
||||
|
||||
@@ -39,7 +39,7 @@ export function ReportChartTooltip({
|
||||
const hidden = sorted.slice(limit);
|
||||
|
||||
return (
|
||||
<div className="flex min-w-[180px] flex-col gap-2 rounded-xl border bg-background p-3 text-sm shadow-xl">
|
||||
<div className="flex min-w-[180px] flex-col gap-2 rounded-xl border bg-card p-3 text-sm shadow-xl">
|
||||
{visible.map((item, index) => {
|
||||
// If we have a <Cell /> component, payload can be nested
|
||||
const payload = item.payload.payload ?? item.payload;
|
||||
|
||||
@@ -50,7 +50,7 @@ export function ReportHistogramChart({
|
||||
<CartesianGrid
|
||||
strokeDasharray="3 3"
|
||||
vertical={false}
|
||||
className="stroke-slate-300"
|
||||
className="stroke-def-200"
|
||||
/>
|
||||
<Tooltip content={<ReportChartTooltip />} cursor={<BarHover />} />
|
||||
<XAxis
|
||||
|
||||
@@ -55,7 +55,7 @@ export function ReportLineChart({
|
||||
strokeDasharray="3 3"
|
||||
horizontal={true}
|
||||
vertical={false}
|
||||
className="stroke-slate-300"
|
||||
className="stroke-def-200"
|
||||
/>
|
||||
{references.map((ref) => (
|
||||
<ReferenceLine
|
||||
|
||||
@@ -100,7 +100,7 @@ export function FunnelSteps({
|
||||
)}
|
||||
key={step.event.id}
|
||||
>
|
||||
<div className="card divide-y divide-border bg-background">
|
||||
<div className="card divide-y divide-border bg-card">
|
||||
<div className="p-4">
|
||||
<p className="text-muted-foreground">Step {index + 1}</p>
|
||||
<h3 className="font-bold">
|
||||
@@ -109,7 +109,7 @@ export function FunnelSteps({
|
||||
</div>
|
||||
<div className="relative aspect-square">
|
||||
<FunnelChart from={step.prevPercent} to={step.percent} />
|
||||
<div className="absolute left-0 right-0 top-0 flex flex-col bg-background/40 p-4">
|
||||
<div className="absolute left-0 right-0 top-0 flex flex-col bg-card/40 p-4">
|
||||
<div className="font-medium uppercase text-muted-foreground">
|
||||
Sessions
|
||||
</div>
|
||||
|
||||
@@ -105,8 +105,8 @@ export function FunnelSteps({
|
||||
nameKey="label"
|
||||
dataKey="value"
|
||||
>
|
||||
<Cell strokeWidth={0} className="fill-blue-600" />
|
||||
<Cell strokeWidth={0} className="fill-slate-200" />
|
||||
<Cell strokeWidth={0} className="fill-highlight" />
|
||||
<Cell strokeWidth={0} className="fill-def-200" />
|
||||
</Pie>
|
||||
</PieChart>
|
||||
<div
|
||||
|
||||
@@ -43,7 +43,7 @@ export function ReportBreakdowns() {
|
||||
<div className="flex flex-col gap-4">
|
||||
{selectedBreakdowns.map((item, index) => {
|
||||
return (
|
||||
<div key={item.name} className="rounded-lg border bg-slate-50">
|
||||
<div key={item.name} className="bg-def-100 rounded-lg border">
|
||||
<div className="flex items-center gap-2 p-2 px-4">
|
||||
<ColorSquare>{index}</ColorSquare>
|
||||
<Combobox
|
||||
|
||||
@@ -54,7 +54,7 @@ export function ReportEvents() {
|
||||
<div className="flex flex-col gap-4">
|
||||
{selectedEvents.map((event) => {
|
||||
return (
|
||||
<div key={event.id} className="rounded-lg border bg-slate-50">
|
||||
<div key={event.id} className="bg-def-100 rounded-lg border">
|
||||
<div className="flex items-center gap-2 p-2">
|
||||
<ColorSquare>{event.id}</ColorSquare>
|
||||
<Combobox
|
||||
@@ -135,7 +135,7 @@ export function ReportEvents() {
|
||||
]}
|
||||
label="Segment"
|
||||
>
|
||||
<button className="flex items-center gap-1 rounded-md border border-border bg-background p-1 px-2 text-xs font-medium leading-none">
|
||||
<button className="flex items-center gap-1 rounded-md border border-border bg-card p-1 px-2 text-xs font-medium leading-none">
|
||||
{event.segment === 'user' ? (
|
||||
<>
|
||||
<Users size={12} /> Unique users
|
||||
|
||||
@@ -90,7 +90,7 @@ export function FilterItem({ filter, event }: FilterProps) {
|
||||
return (
|
||||
<div
|
||||
key={filter.name}
|
||||
className="px-4 py-2 shadow-[inset_6px_0_0] shadow-slate-200 first:border-t"
|
||||
className="shadow-def-200 px-4 py-2 shadow-[inset_6px_0_0] first:border-t"
|
||||
>
|
||||
<div className="mb-2 flex items-center gap-2">
|
||||
<ColorSquare className="bg-emerald-500">
|
||||
|
||||
@@ -54,7 +54,7 @@ export function FiltersCombobox({ event }: FiltersComboboxProps) {
|
||||
);
|
||||
}}
|
||||
>
|
||||
<button className="flex items-center gap-1 rounded-md border border-border bg-background p-1 px-2 text-xs font-medium leading-none">
|
||||
<button className="flex items-center gap-1 rounded-md border border-border bg-card p-1 px-2 text-xs font-medium leading-none">
|
||||
<FilterIcon size={12} /> Add filter
|
||||
</button>
|
||||
</Combobox>
|
||||
|
||||
@@ -9,7 +9,7 @@ interface ReportEventFiltersProps {
|
||||
export function FiltersList({ event }: ReportEventFiltersProps) {
|
||||
return (
|
||||
<div>
|
||||
<div className="flex flex-col divide-y bg-slate-50">
|
||||
<div className="bg-def-100 flex flex-col divide-y">
|
||||
{event.filters.map((filter) => {
|
||||
return <FilterItem key={filter.name} filter={filter} event={event} />;
|
||||
})}
|
||||
|
||||
@@ -16,7 +16,7 @@ export default function Syntax({ code }: SyntaxProps) {
|
||||
return (
|
||||
<div className="group relative">
|
||||
<button
|
||||
className="absolute right-1 top-1 rounded bg-background p-2 opacity-0 transition-opacity group-hover:opacity-100"
|
||||
className="absolute right-1 top-1 rounded bg-card p-2 opacity-0 transition-opacity group-hover:opacity-100"
|
||||
onClick={() => {
|
||||
clipboard(code);
|
||||
}}
|
||||
|
||||
@@ -17,7 +17,7 @@ const AlertDialogOverlay = React.forwardRef<
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<AlertDialogPrimitive.Overlay
|
||||
className={cn(
|
||||
'fixed inset-0 z-50 bg-background/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
|
||||
'fixed inset-0 z-50 bg-card/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
@@ -35,7 +35,7 @@ const AlertDialogContent = React.forwardRef<
|
||||
<AlertDialogPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg md:w-full',
|
||||
'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-card p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg md:w-full',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
|
||||
@@ -8,7 +8,7 @@ const alertVariants = cva(
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: 'bg-background text-foreground',
|
||||
default: 'bg-card text-foreground',
|
||||
destructive:
|
||||
'border-destructive text-destructive dark:border-destructive [&>svg]:text-destructive',
|
||||
},
|
||||
|
||||
@@ -13,7 +13,7 @@ const badgeVariants = cva(
|
||||
default:
|
||||
'border-transparent bg-primary text-primary-foreground hover:bg-primary/80',
|
||||
secondary:
|
||||
'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
||||
'bg-def-100 hover:bg-def-100/80 border-transparent text-secondary-foreground',
|
||||
destructive:
|
||||
'border-transparent bg-destructive-foreground text-destructive hover:bg-destructive/80',
|
||||
success:
|
||||
|
||||
@@ -15,13 +15,12 @@ const buttonVariants = cva(
|
||||
variants: {
|
||||
variant: {
|
||||
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
|
||||
cta: 'bg-blue-600 text-primary-foreground hover:bg-blue-500',
|
||||
cta: 'bg-highlight text-white hover:bg-highlight',
|
||||
destructive:
|
||||
'bg-destructive text-destructive-foreground hover:bg-destructive/90',
|
||||
outline:
|
||||
'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
|
||||
secondary:
|
||||
'bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
||||
'border border-input bg-card hover:bg-accent hover:text-accent-foreground',
|
||||
secondary: 'bg-def-100 text-secondary-foreground hover:bg-def-100/80',
|
||||
ghost: 'hover:bg-accent hover:text-accent-foreground',
|
||||
link: 'text-primary underline-offset-4 hover:underline',
|
||||
},
|
||||
|
||||
@@ -39,7 +39,7 @@ const DialogContent = React.forwardRef<
|
||||
<DialogPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg md:w-full',
|
||||
'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] border bg-card p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg md:w-full',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
|
||||
@@ -13,7 +13,7 @@ export function GradientBackground({
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'rounded-md bg-gradient-to-tr from-slate-100 to-white',
|
||||
'from-def-200 rounded-md bg-gradient-to-tr to-white',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
|
||||
@@ -6,7 +6,7 @@ import type { VariantProps } from 'class-variance-authority';
|
||||
import { cva } from 'class-variance-authority';
|
||||
|
||||
const inputVariant = cva(
|
||||
'flex w-full rounded-md border border-input bg-background ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50',
|
||||
'flex w-full rounded-md border border-input bg-card ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50',
|
||||
{
|
||||
variants: {
|
||||
size: {
|
||||
|
||||
@@ -23,7 +23,7 @@ export function KeyValue({ href, onClick, name, value }: KeyValueProps) {
|
||||
<div className="bg-black/5 p-1 px-2">{name}</div>
|
||||
<div
|
||||
className={cn(
|
||||
'overflow-hidden text-ellipsis whitespace-nowrap bg-background p-1 px-2 font-mono text-blue-700',
|
||||
'text-highlight overflow-hidden text-ellipsis whitespace-nowrap bg-card p-1 px-2 font-mono',
|
||||
clickable && 'group-hover:underline'
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -13,7 +13,7 @@ const Progress = React.forwardRef<
|
||||
<ProgressPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'relative h-4 w-full min-w-16 overflow-hidden rounded bg-slate-200 shadow-sm',
|
||||
'bg-def-200 relative h-4 w-full min-w-16 overflow-hidden rounded shadow-sm',
|
||||
size == 'sm' && 'h-2',
|
||||
size == 'lg' && 'h-8',
|
||||
className
|
||||
|
||||
@@ -31,7 +31,7 @@ const SheetOverlay = React.forwardRef<
|
||||
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
|
||||
|
||||
const sheetVariants = cva(
|
||||
'fixed z-50 flex flex-col gap-4 overflow-y-auto rounded-lg bg-background p-6 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500 data-[state=open]:animate-in data-[state=closed]:animate-out max-sm:w-[calc(100%-theme(spacing.8))]',
|
||||
'fixed z-50 flex flex-col gap-4 overflow-y-auto rounded-lg bg-card p-6 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500 data-[state=open]:animate-in data-[state=closed]:animate-out max-sm:w-[calc(100%-theme(spacing.8))]',
|
||||
{
|
||||
variants: {
|
||||
side: {
|
||||
@@ -70,7 +70,7 @@ const SheetContent = React.forwardRef<
|
||||
<SheetPrimitive.Close id="close-sheet" className="hidden" />
|
||||
<SheetPrimitive.Close
|
||||
onClick={onClose}
|
||||
className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary"
|
||||
className="data-[state=open]:bg-def-100 absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none"
|
||||
>
|
||||
<XIcon className="h-4 w-4" />
|
||||
<span className="sr-only">Close</span>
|
||||
|
||||
@@ -13,7 +13,7 @@ const Toaster = ({ ...props }: ToasterProps) => {
|
||||
toastOptions={{
|
||||
classNames: {
|
||||
toast:
|
||||
'group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg',
|
||||
'group toast group-[.toaster]:bg-card group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg',
|
||||
description: 'group-[.toast]:text-muted-foreground',
|
||||
actionButton:
|
||||
'group-[.toast]:bg-primary group-[.toast]:text-primary-foreground',
|
||||
|
||||
@@ -10,7 +10,7 @@ const Switch = React.forwardRef<
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SwitchPrimitives.Root
|
||||
className={cn(
|
||||
'peer inline-flex h-4 w-7 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-blue-600 data-[state=unchecked]:bg-input',
|
||||
'data-[state=checked]:bg-highlight peer inline-flex h-4 w-7 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=unchecked]:bg-input',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
@@ -18,7 +18,7 @@ const Switch = React.forwardRef<
|
||||
>
|
||||
<SwitchPrimitives.Thumb
|
||||
className={cn(
|
||||
'pointer-events-none block h-3 w-3 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-3 data-[state=unchecked]:translate-x-0'
|
||||
'pointer-events-none block h-3 w-3 rounded-full bg-card shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-3 data-[state=unchecked]:translate-x-0'
|
||||
)}
|
||||
/>
|
||||
</SwitchPrimitives.Root>
|
||||
|
||||
@@ -75,7 +75,7 @@ const TableHead = React.forwardRef<
|
||||
<th
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'h-10 border-b border-border bg-slate-100 px-4 text-left align-middle text-sm font-medium text-muted-foreground shadow-[0_0_0_0.5px] shadow-border [&:has([role=checkbox])]:pr-0',
|
||||
'bg-def-200 h-10 border-b border-border px-4 text-left align-middle text-sm font-medium text-muted-foreground shadow-[0_0_0_0.5px] shadow-border [&:has([role=checkbox])]:pr-0',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
|
||||
@@ -26,7 +26,7 @@ const TabsTrigger = React.forwardRef<
|
||||
<TabsPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm',
|
||||
'inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-card data-[state=active]:text-foreground data-[state=active]:shadow-sm',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
|
||||
@@ -1,24 +1,22 @@
|
||||
import * as React from "react"
|
||||
import * as React from 'react';
|
||||
import { cn } from '@/utils/cn';
|
||||
|
||||
import { cn } from "@/utils/cn"
|
||||
|
||||
export interface TextareaProps
|
||||
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}
|
||||
export type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>;
|
||||
|
||||
const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
||||
({ className, ...props }, ref) => {
|
||||
return (
|
||||
<textarea
|
||||
className={cn(
|
||||
"flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
||||
'flex min-h-[80px] w-full rounded-md border border-input bg-card px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
|
||||
className
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
);
|
||||
}
|
||||
)
|
||||
Textarea.displayName = "Textarea"
|
||||
);
|
||||
Textarea.displayName = 'Textarea';
|
||||
|
||||
export { Textarea }
|
||||
export { Textarea };
|
||||
|
||||
@@ -29,7 +29,7 @@ const toastVariants = cva(
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: 'border bg-background text-foreground',
|
||||
default: 'border bg-card text-foreground',
|
||||
destructive:
|
||||
'destructive group border-destructive bg-destructive text-destructive-foreground',
|
||||
},
|
||||
@@ -62,7 +62,7 @@ const ToastAction = React.forwardRef<
|
||||
<ToastPrimitives.Action
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium ring-offset-background transition-colors hover:bg-secondary focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive',
|
||||
'hover:bg-def-100 inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium ring-offset-background transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
|
||||
@@ -15,7 +15,7 @@ const Toaster = ({ ...props }: ToasterProps) => {
|
||||
toastOptions={{
|
||||
classNames: {
|
||||
toast:
|
||||
'group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg',
|
||||
'group toast group-[.toaster]:bg-card group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg',
|
||||
description: 'group-[.toast]:text-muted-foreground',
|
||||
actionButton:
|
||||
'group-[.toast]:bg-primary group-[.toast]:text-primary-foreground',
|
||||
|
||||
@@ -20,7 +20,7 @@ export const WidgetTableHead = ({
|
||||
return (
|
||||
<thead
|
||||
className={cn(
|
||||
'sticky top-0 z-10 border-b border-border bg-slate-50 text-sm text-slate-500 [&_th:last-child]:text-right [&_th]:whitespace-nowrap [&_th]:p-4 [&_th]:py-2 [&_th]:text-left [&_th]:font-medium',
|
||||
'bg-def-100 text-def-1000 sticky top-0 z-10 border-b border-border text-sm [&_th:last-child]:text-right [&_th]:whitespace-nowrap [&_th]:p-4 [&_th]:py-2 [&_th]:text-left [&_th]:font-medium',
|
||||
className
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -37,7 +37,7 @@ export function WidgetTitle({
|
||||
)}
|
||||
>
|
||||
{Icon && (
|
||||
<div className="absolute left-0 rounded-lg bg-slate-100 p-2">
|
||||
<div className="bg-def-200 absolute left-0 rounded-lg p-2">
|
||||
<Icon size={18} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -27,7 +27,7 @@ const Testimonial = () => {
|
||||
});
|
||||
return (
|
||||
<ModalContent className="p-0">
|
||||
<div className="w-full rounded-t-lg border-b border-border bg-secondary p-4">
|
||||
<div className="bg-def-100 w-full rounded-t-lg border-b border-border p-4">
|
||||
<h1 className="mb-2 text-2xl font-bold">Review time 🫶</h1>
|
||||
<p className="mb-2">
|
||||
Thank you so much for using Openpanel — it truly means a great deal to
|
||||
|
||||
@@ -4,89 +4,79 @@
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 222.2 84% 4.9%;
|
||||
--highlight: 220, 84%, 53%; /* #2266ec */
|
||||
|
||||
--slate-50: 210 40% 98%;
|
||||
--slate-100: 210 40% 96.1%;
|
||||
--slate-200: 210 40% 91.4%;
|
||||
--slate-300: 210 40% 83.9%;
|
||||
--slate-400: 210 40% 65.1%;
|
||||
--slate-500: 210 40% 46.9%;
|
||||
--slate-600: 210 40% 30.6%;
|
||||
--slate-700: 210 40% 17.5%;
|
||||
--slate-800: 210 40% 11.2%;
|
||||
--slate-900: 210 40% 8.2%;
|
||||
--slate-950: 210 40% 7.2%;
|
||||
--def-100: 210 40% 98%; /* #F0F4F9 */
|
||||
--def-200: 210 40% 96.1%; /* #E7ECF2 */
|
||||
--def-300: 210 15.14% 89.41%; /* #DDE3E9 */
|
||||
--def-400: 210 9.08% 75.05%; /* #B3BDC7 */
|
||||
|
||||
--card: 0 0% 100%;
|
||||
--card-foreground: 222.2 84% 4.9%;
|
||||
--background: 0 0% 100%; /* #FFFFFF */
|
||||
--foreground: 222.2 84% 4.9%; /* #0C162A */
|
||||
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 222.2 84% 4.9%;
|
||||
--card: 0 0% 100%; /* #FFFFFF */
|
||||
--card-foreground: 222.2 84% 4.9%; /* #0C162A */
|
||||
|
||||
--primary: 222.2 47.4% 11.2%;
|
||||
--primary-foreground: 210 40% 98%;
|
||||
--popover: 0 0% 100%; /* #FFFFFF */
|
||||
--popover-foreground: 222.2 84% 4.9%; /* #0C162A */
|
||||
|
||||
--secondary: 210 40% 96.1%;
|
||||
--secondary-foreground: 222.2 47.4% 11.2%;
|
||||
--primary: 222.2 47.4% 11.2%; /* #163049 */
|
||||
--primary-foreground: 210 40% 98%; /* #F0F4F9 */
|
||||
|
||||
--muted: 210 40% 96.1%;
|
||||
--muted-foreground: 215.4 16.3% 46.9%;
|
||||
--secondary: 210 40% 96.1%; /* #E7ECF2 */
|
||||
--secondary-foreground: 222.2 47.4% 11.2%; /* #163049 */
|
||||
|
||||
--accent: 210 40% 96.1%;
|
||||
--accent-foreground: 222.2 47.4% 11.2%;
|
||||
--muted: 210 40% 96.1%; /* #E7ECF2 */
|
||||
--muted-foreground: 215.4 16.3% 46.9%; /* #798290 */
|
||||
|
||||
--destructive: 0 84.2% 60.2%;
|
||||
--destructive-foreground: 0 100% 97.25%;
|
||||
--accent: 210 40% 96.1%; /* #E7ECF2 */
|
||||
--accent-foreground: 222.2 47.4% 11.2%; /* #163049 */
|
||||
|
||||
--border: 214.3 31.8% 91.4%;
|
||||
--input: 214.3 31.8% 91.4%;
|
||||
--ring: 212.73deg 26.83% 83.92%;
|
||||
--destructive: 0 84.2% 60.2%; /* #F2677D */
|
||||
--destructive-foreground: 0 100% 97.25%; /* #F8F9FB */
|
||||
|
||||
--border: 214.3 31.8% 91.4%; /* #E8EBF1 */
|
||||
--input: 214.3 31.8% 91.4%; /* #E8EBF1 */
|
||||
--ring: 212.73deg 26.83% 83.92%; /* #CDD6E2 */
|
||||
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: 222.86 32.05% 12.02%;
|
||||
--foreground: 210 40% 98%;
|
||||
--highlight: 221.44 100% 62.04%;
|
||||
|
||||
--slate-950: 210 40% 98%;
|
||||
--slate-900: 210 40% 96.1%;
|
||||
--slate-800: 210 40% 91.4%;
|
||||
--slate-700: 210 40% 83.9%;
|
||||
--slate-600: 210 40% 65.1%;
|
||||
--slate-500: 210 40% 46.9%;
|
||||
--slate-400: 210 40% 30.6%;
|
||||
--slate-300: 210 40% 17.5%;
|
||||
--slate-200: 210 40% 11.2%;
|
||||
--slate-100: 210 40% 8.2%;
|
||||
--slate-50: 210 40% 7.2%;
|
||||
--def-100: 0 0% 8%; /* #0f0f0f */
|
||||
--def-200: 0 0% 13.12%; /* #212121 */
|
||||
--def-300: 0 0% 15.1%; /* #262626 */
|
||||
--def-400: 0 0% 25.23%; /* #404040 */
|
||||
|
||||
--card: 222.2 84% 4.9%;
|
||||
--card-foreground: 210 40% 98%;
|
||||
--background: 0 0% 12.02%; /* #1e1e1e */
|
||||
--foreground: 0 0% 98%; /* #fafafa */
|
||||
|
||||
--popover: 222.2 84% 4.9%;
|
||||
--popover-foreground: 210 40% 98%;
|
||||
--card: 0 0% 10%; /* #1a1a1a */
|
||||
--card-foreground: 0 0% 98%; /* #fafafa */
|
||||
|
||||
--primary: 210 40% 98%;
|
||||
--primary-foreground: 222.2 47.4% 11.2%;
|
||||
--popover: 0 0% 10%; /* #1a1a1a */
|
||||
--popover-foreground: 0 0% 98%; /* #fafafa */
|
||||
|
||||
--secondary: 217.2 32.6% 17.5%;
|
||||
--secondary-foreground: 210 40% 98%;
|
||||
--primary: 0 0% 98%; /* #fafafa */
|
||||
--primary-foreground: 0 0% 11.2%; /* #1c1c1c */
|
||||
|
||||
--muted: 217.2 32.6% 17.5%;
|
||||
--muted-foreground: 215 20.2% 65.1%;
|
||||
--secondary: 0 0% 15.1%; /* #262626 */
|
||||
--secondary-foreground: 0 0% 98%; /* #fafafa */
|
||||
|
||||
--accent: 217.2 32.6% 17.5%;
|
||||
--accent-foreground: 210 40% 98%;
|
||||
--muted: 0 0% 15.1%; /* #262626 */
|
||||
--muted-foreground: 0 0% 65%; /* #fafafa */
|
||||
|
||||
--destructive: 0 62.8% 30.6%;
|
||||
--destructive-foreground: 210 40% 98%;
|
||||
--accent: 0 0% 15.1%; /* #262626 */
|
||||
--accent-foreground: 0 0% 98%; /* #fafafa */
|
||||
|
||||
--border: 217.2 32.6% 17.5%;
|
||||
--input: 217.2 32.6% 17.5%;
|
||||
--ring: 212.7 26.8% 83.9%;
|
||||
--destructive: 0 0% 30.6%; /* #4e4e4e */
|
||||
--destructive-foreground: 0 0% 98%; /* #fafafa */
|
||||
|
||||
--border: 0 0% 15.1%; /* #262626 */
|
||||
--input: 0 0% 15.1%; /* #262626 */
|
||||
--ring: 0 0% 83.9%; /* #d6d6d6 */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +85,7 @@
|
||||
@apply border-border;
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
@apply bg-card text-foreground;
|
||||
}
|
||||
|
||||
.h1 {
|
||||
@@ -144,7 +134,7 @@
|
||||
}
|
||||
|
||||
.card {
|
||||
@apply border border-border bg-background;
|
||||
@apply border border-border bg-card;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -74,18 +74,14 @@ const config = {
|
||||
ring: 'hsl(var(--ring))',
|
||||
background: 'hsl(var(--background))',
|
||||
foreground: 'hsl(var(--foreground))',
|
||||
slate: {
|
||||
50: 'hsl(var(--slate-50))',
|
||||
100: 'hsl(var(--slate-100))',
|
||||
200: 'hsl(var(--slate-200))',
|
||||
300: 'hsl(var(--slate-300))',
|
||||
400: 'hsl(var(--slate-400))',
|
||||
500: 'hsl(var(--slate-500))',
|
||||
600: 'hsl(var(--slate-600))',
|
||||
700: 'hsl(var(--slate-700))',
|
||||
800: 'hsl(var(--slate-800))',
|
||||
900: 'hsl(var(--slate-900))',
|
||||
950: 'hsl(var(--slate-950))',
|
||||
'def-100': 'hsl(var(--def-100))',
|
||||
'def-200': 'hsl(var(--def-200))',
|
||||
'def-300': 'hsl(var(--def-300))',
|
||||
'def-400': 'hsl(var(--def-400))',
|
||||
'def-500': 'hsl(var(--def-500))',
|
||||
'def-600': 'hsl(var(--def-600))',
|
||||
highlight: {
|
||||
DEFAULT: 'hsl(var(--highlight))',
|
||||
},
|
||||
primary: {
|
||||
DEFAULT: 'hsl(var(--primary))',
|
||||
|
||||
Reference in New Issue
Block a user