diff --git a/apps/platform/trpc/routers/convoRouter/convoRouter.ts b/apps/platform/trpc/routers/convoRouter/convoRouter.ts
index ae08642e..b03516f5 100644
--- a/apps/platform/trpc/routers/convoRouter/convoRouter.ts
+++ b/apps/platform/trpc/routers/convoRouter/convoRouter.ts
@@ -1426,7 +1426,9 @@ export const convoRouter = router({
},
with: {
author: {
- columns: {},
+ columns: {
+ publicId: true
+ },
with: {
orgMember: {
columns: {
diff --git a/apps/web/components.json b/apps/web/components.json
index 60709867..7e061b10 100644
--- a/apps/web/components.json
+++ b/apps/web/components.json
@@ -1,6 +1,6 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
- "style": "default",
+ "style": "new-york",
"rsc": false,
"tsx": true,
"tailwind": {
diff --git a/apps/web/package.json b/apps/web/package.json
index 3978ad3f..7b4064f5 100644
--- a/apps/web/package.json
+++ b/apps/web/package.json
@@ -15,15 +15,16 @@
"@radix-ui/react-avatar": "^1.0.4",
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-dropdown-menu": "^2.0.6",
+ "@radix-ui/react-hover-card": "^1.0.7",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-popover": "^1.0.7",
"@radix-ui/react-scroll-area": "^1.0.5",
"@radix-ui/react-select": "^2.0.0",
"@radix-ui/react-separator": "^1.0.3",
"@radix-ui/react-slot": "^1.0.2",
+ "@radix-ui/react-switch": "^1.0.3",
"@radix-ui/react-toggle": "^1.0.3",
"@radix-ui/react-toggle-group": "^1.0.4",
- "@radix-ui/react-switch": "^1.0.3",
"@radix-ui/react-tooltip": "^1.0.7",
"@radix-ui/themes": "^3.0.2",
"@simplewebauthn/browser": "^10.0.0",
diff --git a/apps/web/src/app/[orgShortCode]/_components/sidebar-content.tsx b/apps/web/src/app/[orgShortCode]/_components/sidebar-content.tsx
index 3b92bd08..e4a35c91 100644
--- a/apps/web/src/app/[orgShortCode]/_components/sidebar-content.tsx
+++ b/apps/web/src/app/[orgShortCode]/_components/sidebar-content.tsx
@@ -3,7 +3,6 @@
import useLoading from '@/src/hooks/use-loading';
import { cn, generateAvatarUrl, getInitials } from '@/src/lib/utils';
import { useGlobalStore } from '@/src/providers/global-store-provider';
-import { Button } from '@/src/components/shadcn-ui/button';
import {
Avatar,
AvatarFallback,
@@ -25,31 +24,20 @@ import {
import {
Check,
- AddressBook,
SignOut,
- ChatCircle,
MoonStars,
Gear,
- SpinnerGap,
Sun,
- CaretRight,
- CaretLeft,
- SquaresFour,
- Shield,
- CaretUp,
Book,
QuestionMark,
MapPin,
Activity,
Megaphone,
- PushPin,
- CaretDoubleLeft,
CaretUpDown,
Plus,
Palette,
Monitor,
Question,
- Paperclip,
User
} from '@phosphor-icons/react';
import { env } from 'next-runtime-env';
@@ -59,11 +47,11 @@ import { useMemo } from 'react';
import { toast } from 'sonner';
import { useQueryClient } from '@tanstack/react-query';
import React from 'react';
-import { SidebarNavButton } from './sidebar-nav-button';
+
import { useTheme } from 'next-themes';
import { sidebarSubmenuOpenAtom } from './atoms';
import { useAtom } from 'jotai';
-import { usePreferencesState } from '@/src/stores/preferences-store';
+
import {
ToggleGroup,
ToggleGroupItem
@@ -102,7 +90,7 @@ export default function SidebarContent() {
UnInbox
- v0.1.23
+ v0.1.0
);
diff --git a/apps/web/src/app/[orgShortCode]/_components/sidebar-nav-button.tsx b/apps/web/src/app/[orgShortCode]/_components/sidebar-nav-button.tsx
index 79d91a41..5ad2edaf 100644
--- a/apps/web/src/app/[orgShortCode]/_components/sidebar-nav-button.tsx
+++ b/apps/web/src/app/[orgShortCode]/_components/sidebar-nav-button.tsx
@@ -53,14 +53,14 @@ export function SidebarNavButton({
{children ? (
{
setExpanded(!expanded);
}}>
@@ -89,14 +89,14 @@ export function SidebarNavButton({
asChild>
{icon}
-
-
+
+
{label}
{badge &&
{badge}}
diff --git a/apps/web/src/app/[orgShortCode]/_components/sidebar.tsx b/apps/web/src/app/[orgShortCode]/_components/sidebar.tsx
index 6bc81204..7f5720ad 100644
--- a/apps/web/src/app/[orgShortCode]/_components/sidebar.tsx
+++ b/apps/web/src/app/[orgShortCode]/_components/sidebar.tsx
@@ -2,13 +2,7 @@
import { cn } from '@/src/lib/utils';
import { usePreferencesState } from '@/src/stores/preferences-store';
-import {
- CaretDoubleLeft,
- CaretLineRight,
- Cross,
- PushPin,
- X
-} from '@phosphor-icons/react';
+import { CaretDoubleLeft, PushPin, X } from '@phosphor-icons/react';
import SidebarContent from './sidebar-content';
import { sidebarSubmenuOpenAtom } from './atoms';
import { useAtom } from 'jotai';
diff --git a/apps/web/src/app/[orgShortCode]/convo/[convoId]/_components/top-bar.tsx b/apps/web/src/app/[orgShortCode]/convo/[convoId]/_components/top-bar.tsx
index 81a2ac41..22161932 100644
--- a/apps/web/src/app/[orgShortCode]/convo/[convoId]/_components/top-bar.tsx
+++ b/apps/web/src/app/[orgShortCode]/convo/[convoId]/_components/top-bar.tsx
@@ -34,7 +34,7 @@ export default function TopBar({
const toggleConvoHiddenState = useToggleConvoHidden$Cache();
return (
-
+
state.currentOrg.shortCode);
+
+ const timeAgo = useTimeAgo(convo.lastUpdatedAt);
+
+ const authorAsParticipant = useMemo(() => {
+ return (
+ convo.participants.find(
+ (participant) =>
+ participant.publicId === convo.entries[0]?.author.publicId
+ ) ?? convo.participants[0]
+ );
+ }, [convo.participants, convo.entries]);
+
+ const authorAvatarData = useMemo(() => {
+ return formatParticipantData(authorAsParticipant!);
+ }, [authorAsParticipant]);
+
+ const participantData = useMemo(() => {
+ const allParticipants = convo.participants
+ .map((participant) => formatParticipantData(participant))
+ .filter(Boolean) as NonNullable<
+ ReturnType
+ >[];
+ const participantsWithoutAuthor = allParticipants.filter(
+ (participant) =>
+ participant.participantPublicId !== authorAsParticipant?.publicId
+ );
+ const author = allParticipants.find(
+ (participant) =>
+ participant.participantPublicId === authorAsParticipant?.publicId
+ )!;
+ return [author].concat(participantsWithoutAuthor);
+ }, [convo.participants, authorAsParticipant]);
+
+ const participantNames = useMemo(() => {
+ return participantData.map((participant) => participant.name);
+ }, [participantData]);
+
+ const currentPath = usePathname();
+ const link = `/${orgShortCode}/convo/${convo.publicId}`;
+
+ const isActive = currentPath === link;
+
+ return (
+
+
+
+
+
+ {participantNames.join(', ')}
+
+
+ {timeAgo}
+
+
+
+
+ {convo.subjects[0]?.subject}
+
+
+
+
+ {authorAvatarData && (
+
+ )}
+
+
+
+ {convo.entries[0]?.bodyPlainText ?? ''}
+
+
+
+
+ );
+}
diff --git a/apps/web/src/app/[orgShortCode]/convo/_components/convo-list.tsx b/apps/web/src/app/[orgShortCode]/convo/_components/convo-list.tsx
index 84471e78..08e3e277 100644
--- a/apps/web/src/app/[orgShortCode]/convo/_components/convo-list.tsx
+++ b/apps/web/src/app/[orgShortCode]/convo/_components/convo-list.tsx
@@ -1,21 +1,19 @@
'use client';
-import { type RouterOutputs, api } from '@/src/lib/trpc';
+import { api } from '@/src/lib/trpc';
import { useGlobalStore } from '@/src/providers/global-store-provider';
-import { useState, useEffect, useMemo, useRef } from 'react';
+import { useEffect, useRef } from 'react';
import { useVirtualizer } from '@tanstack/react-virtual';
-import useTimeAgo from '@/src/hooks/use-time-ago';
-import { formatParticipantData } from '../utils';
-import Link from 'next/link';
-import AvatarPlus from '@/src/components/avatar-plus';
-import { Button } from '@/src/components/shadcn-ui/button';
import { ms } from '@u22n/utils/ms';
+import { ConvoItem } from './convo-list-item';
-export default function ConvoList() {
+type Props = {
+ hidden: boolean;
+};
+
+export function ConvoList(props: Props) {
const orgShortCode = useGlobalStore((state) => state.currentOrg.shortCode);
const scrollableRef = useRef(null);
- const [showHidden, setShowHidden] = useState(false);
-
const {
data: convos,
fetchNextPage,
@@ -25,7 +23,7 @@ export default function ConvoList() {
} = api.convos.getOrgMemberConvos.useInfiniteQuery(
{
orgShortCode,
- includeHidden: showHidden ? true : undefined
+ includeHidden: props.hidden ? true : undefined
},
{
getNextPageParam: (lastPage) => lastPage.cursor ?? undefined,
@@ -62,24 +60,16 @@ export default function ConvoList() {
]);
return (
-
+
{isLoading ? (
Loading...
) : (
<>
- {/* TODO: Replace this according to designs later */}
-
-
-
{convosVirtualizer.getVirtualItems().map((virtualItem) => {
const isLoader = virtualItem.index > allConvos.length - 1;
@@ -113,81 +103,3 @@ export default function ConvoList() {
);
}
-
-function ConvoItem({
- convo
-}: {
- convo: RouterOutputs['convos']['getOrgMemberConvos']['data'][number];
-}) {
- const orgShortCode = useGlobalStore((state) => state.currentOrg.shortCode);
-
- const timeAgo = useTimeAgo(convo.lastUpdatedAt);
-
- const author = convo.entries[0]?.author ?? convo.participants[0];
-
- const authorPublicId = useMemo(() => {
- if (!author) return null;
- return (
- author.orgMember?.publicId ??
- author.team?.publicId ??
- author.contact?.publicId ??
- null
- );
- }, [author]);
-
- const authorName = useMemo(() => {
- if (!author) return null;
- return (
- author.team?.name ??
- author.contact?.setName ??
- author.contact?.name ??
- `${author.orgMember?.profile.firstName ?? ''} ${author.orgMember?.profile.lastName ?? ''}`.trim() ??
- 'Participant'
- );
- }, [author]);
-
- const participantData = useMemo(() => {
- const allParticipants = convo.participants
- .map((participant) => formatParticipantData(participant))
- .filter(Boolean) as NonNullable<
- ReturnType
- >[];
- const participantsWithoutAuthor = allParticipants.filter(
- (participant) => participant.typePublicId !== authorPublicId
- );
- const author = allParticipants.find(
- (participant) => participant.typePublicId === authorPublicId
- )!;
- return [author].concat(participantsWithoutAuthor);
- }, [convo.participants, authorPublicId]);
-
- return (
-
-
-
-
- {convo.subjects[0]?.subject}
-
-
-
- {authorName}:{' '}
-
- {convo.entries[0]?.bodyPlainText ?? ''}
-
-
-
-
-
- {timeAgo}
-
-
-
-
- );
-}
diff --git a/apps/web/src/app/[orgShortCode]/convo/layout.tsx b/apps/web/src/app/[orgShortCode]/convo/layout.tsx
index 28e4e323..d65d3ac6 100644
--- a/apps/web/src/app/[orgShortCode]/convo/layout.tsx
+++ b/apps/web/src/app/[orgShortCode]/convo/layout.tsx
@@ -1,24 +1,112 @@
'use client';
import { Button } from '@/src/components/shadcn-ui/button';
-import ConvoList from './_components/convo-list';
+import { ConvoList } from './_components/convo-list';
import { usePreferencesState } from '@/src/stores/preferences-store';
+import { useIsMobile } from '@/src/hooks/is-mobile';
+import {
+ CaretRight,
+ ChatCircle,
+ Eye,
+ EyeSlash,
+ List,
+ User
+} from '@phosphor-icons/react';
+import {
+ Breadcrumb,
+ BreadcrumbEllipsis,
+ BreadcrumbItem,
+ BreadcrumbLink,
+ BreadcrumbList,
+ BreadcrumbSeparator
+} from '@/src/components/shadcn-ui/breadcrumb';
+import { useState } from 'react';
+import Link from 'next/link';
+import { useGlobalStore } from '@/src/providers/global-store-provider';
export default function Layout({
children
}: Readonly<{ children: React.ReactNode }>) {
- const {
- sidebarDocked,
- sidebarExpanded,
- setSidebarExpanded,
- setSidebarDocking
- } = usePreferencesState();
+ const orgShortCode = useGlobalStore((state) => state.currentOrg.shortCode);
+ const { setSidebarExpanded } = usePreferencesState();
+ const isMobile = useIsMobile();
+ const [showHidden, setShowHidden] = useState(false);
+
return (
-
- {/*
*/}
-
+
+
+ {isMobile && (
+
+ )}
+
+
+
+
+
+
+
+
+
+ {/*
+
+
+
+ My personal space
+ */}
+
+
+
+
+
+
+
+
+ {showHidden ? 'Hidden Conversations' : 'Conversations'}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {children}
-
{children}
);
}
diff --git a/apps/web/src/app/[orgShortCode]/layout.tsx b/apps/web/src/app/[orgShortCode]/layout.tsx
index 120207c8..452ce8f4 100644
--- a/apps/web/src/app/[orgShortCode]/layout.tsx
+++ b/apps/web/src/app/[orgShortCode]/layout.tsx
@@ -20,7 +20,7 @@ export default function Layout({
if (storeDataLoading) {
return (
-
+
);
}
@@ -64,7 +64,7 @@ export default function Layout({
return (
-
+
diff --git a/apps/web/src/app/[orgShortCode]/settings/_components/settings-sidebar.tsx b/apps/web/src/app/[orgShortCode]/settings/_components/settings-sidebar.tsx
index e64fdfb5..b1201897 100644
--- a/apps/web/src/app/[orgShortCode]/settings/_components/settings-sidebar.tsx
+++ b/apps/web/src/app/[orgShortCode]/settings/_components/settings-sidebar.tsx
@@ -97,7 +97,7 @@ export default function SettingsSidebar() {
return (
+ className="bg-base-2 dark:bg-slatedark-2 h-full w-[400px] flex-col p-2 px-4">
;
avatarTimestamp: Date | null;
name: string;
+ color?: AvatarProps['color'];
}[];
};
-export default function AvatarPlus({
- imageSize,
- size,
- users
-}: AvatarPlusProps) {
+export default function AvatarPlus({ size, users }: AvatarPlusProps) {
const [primary, ...rest] = users;
if (!primary) {
return null;
}
return (
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+ {`${rest.length}`}
+
+
+
+
+
{rest.map((user) => (
-
-
-
+
))}
-
-
+
+
);
}
diff --git a/apps/web/src/components/avatar.tsx b/apps/web/src/components/avatar.tsx
new file mode 100644
index 00000000..38bc5e3d
--- /dev/null
+++ b/apps/web/src/components/avatar.tsx
@@ -0,0 +1,137 @@
+'use client';
+
+import * as React from 'react';
+import { cva, type VariantProps } from 'class-variance-authority';
+import { cn, generateAvatarUrl, getInitials } from '@/src/lib/utils';
+import { type TypeId, inferTypeId } from '@u22n/utils/typeid';
+import {
+ Tooltip,
+ TooltipContent,
+ TooltipProvider,
+ TooltipTrigger
+} from './shadcn-ui/tooltip';
+import {
+ Avatar as AvatarShad,
+ AvatarFallback,
+ AvatarImage
+} from './shadcn-ui/avatar';
+import {
+ AddressBook,
+ BuildingOffice,
+ User,
+ UsersThree
+} from '@phosphor-icons/react';
+
+export type AvatarProps = {
+ avatarProfilePublicId: TypeId<
+ 'orgMemberProfile' | 'org' | 'teams' | 'contacts'
+ >;
+ avatarTimestamp: Date | null;
+ name: string;
+ hideTooltip?: boolean;
+ tooltipOverride?: string;
+} & VariantProps
;
+
+const avatarVariants = cva(
+ 'flex items-center justify-center font-medium aspect-square bg-base-5 text-base-11 h-6 w-6 text-sm rounded-md',
+ {
+ variants: {
+ size: {
+ sm: 'h-4 w-4 text-[9px] rounded-sm',
+ md: 'h-6 w-6 text-xs rounded-md',
+ lg: 'h-8 w-8 text-sm rounded-lg',
+ xl: 'h-10 w-10 text-md rounded-lg'
+ },
+ color: {
+ base: 'bg-base-5 text-base-11',
+ bronze: 'bg-bronze-5 text-bronze-11',
+ gold: 'bg-gold-5 text-gold-11',
+ brown: 'bg-brown-5 text-brown-11',
+ orange: 'bg-orange-5 text-orange-11',
+ tomato: 'bg-tomato-5 text-tomato-11',
+ red: 'bg-red-5 text-red-11',
+ ruby: 'bg-ruby-5 text-ruby-11',
+ crimson: 'bg-crimson-5 text-crimson-11',
+ pink: 'bg-pink-5 text-pink-11',
+ plum: 'bg-plum-5 text-plum-11',
+ purple: 'bg-purple-5 text-purple-11',
+ violet: 'bg-violet-5 text-violet-11',
+ iris: 'bg-iris-5 text-iris-11',
+ indigo: 'bg-indigo-5 text-indigo-11',
+ blue: 'bg-blue-5 text-blue-11',
+ cyan: 'bg-cyan-5 text-cyan-11',
+ teal: 'bg-teal-5 text-teal-11',
+ jade: 'bg-jade-5 text-jade-11',
+ green: 'bg-green-5 text-green-11',
+ grass: 'bg-grass-5 text-grass-11'
+ }
+ },
+ defaultVariants: {
+ size: 'md',
+ color: 'base'
+ }
+ }
+);
+
+export function Avatar(props: AvatarProps) {
+ const avatarUrl =
+ generateAvatarUrl({
+ publicId: props.avatarProfilePublicId,
+ avatarTimestamp: props.avatarTimestamp,
+ size: props.size ?? 'lg'
+ }) ?? '';
+ const altText = props.name;
+ const withoutTooltip = props.hideTooltip ?? false;
+
+ function AvatarIcon() {
+ const type = inferTypeId(props.avatarProfilePublicId);
+ switch (type) {
+ case 'orgMemberProfile':
+ return ;
+ case 'org':
+ return ;
+ case 'teams':
+ return ;
+ case 'contacts':
+ return ;
+ default:
+ return null;
+ }
+ }
+
+ return withoutTooltip ? (
+
+
+ {getInitials(altText)}
+
+ ) : (
+
+
+
+
+
+ {getInitials(altText)}
+
+
+
+
+ {altText}
+
+
+
+ );
+}
diff --git a/apps/web/src/components/shadcn-ui/avatar.tsx b/apps/web/src/components/shadcn-ui/avatar.tsx
index 9221512b..c5231b36 100644
--- a/apps/web/src/components/shadcn-ui/avatar.tsx
+++ b/apps/web/src/components/shadcn-ui/avatar.tsx
@@ -3,6 +3,8 @@ import * as AvatarPrimitive from '@radix-ui/react-avatar';
import { cn } from '@/src/lib/utils';
+//! This component has been modified
+
const Avatar = React.forwardRef<
React.ElementRef,
React.ComponentPropsWithoutRef
@@ -37,7 +39,7 @@ const AvatarFallback = React.forwardRef<
& {
+ separator?: React.ReactNode;
+ }
+>(({ ...props }, ref) => (
+
+));
+Breadcrumb.displayName = 'Breadcrumb';
+
+const BreadcrumbList = React.forwardRef<
+ HTMLOListElement,
+ React.ComponentPropsWithoutRef<'ol'>
+>(({ className, ...props }, ref) => (
+
+));
+BreadcrumbList.displayName = 'BreadcrumbList';
+
+const BreadcrumbItem = React.forwardRef<
+ HTMLLIElement,
+ React.ComponentPropsWithoutRef<'li'>
+>(({ className, ...props }, ref) => (
+
+));
+BreadcrumbItem.displayName = 'BreadcrumbItem';
+
+const BreadcrumbLink = React.forwardRef<
+ HTMLAnchorElement,
+ React.ComponentPropsWithoutRef<'a'> & {
+ asChild?: boolean;
+ }
+>(({ asChild, className, ...props }, ref) => {
+ const Comp = asChild ? Slot : 'a';
+
+ return (
+
+ );
+});
+BreadcrumbLink.displayName = 'BreadcrumbLink';
+
+const BreadcrumbPage = React.forwardRef<
+ HTMLSpanElement,
+ React.ComponentPropsWithoutRef<'span'>
+>(({ className, ...props }, ref) => (
+
+));
+BreadcrumbPage.displayName = 'BreadcrumbPage';
+
+const BreadcrumbSeparator = ({
+ children,
+ className,
+ ...props
+}: React.ComponentProps<'li'>) => (
+ svg]:size-3.5', className)}
+ {...props}>
+ {children ?? }
+
+);
+BreadcrumbSeparator.displayName = 'BreadcrumbSeparator';
+
+const BreadcrumbEllipsis = ({
+ className,
+ ...props
+}: React.ComponentProps<'span'>) => (
+
+
+ More
+
+);
+BreadcrumbEllipsis.displayName = 'BreadcrumbElipssis';
+
+export {
+ Breadcrumb,
+ BreadcrumbList,
+ BreadcrumbItem,
+ BreadcrumbLink,
+ BreadcrumbPage,
+ BreadcrumbSeparator,
+ BreadcrumbEllipsis
+};
diff --git a/apps/web/src/components/shadcn-ui/button.tsx b/apps/web/src/components/shadcn-ui/button.tsx
index e6a1ad0e..f93f465e 100644
--- a/apps/web/src/components/shadcn-ui/button.tsx
+++ b/apps/web/src/components/shadcn-ui/button.tsx
@@ -5,14 +5,14 @@ import { cva, type VariantProps } from 'class-variance-authority';
import { cn } from '@/src/lib/utils';
const buttonVariants = cva(
- 'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 disabled:pointer-events-none disabled:opacity-50',
+ 'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 disabled:pointer-events-none disabled:opacity-50 ring-base-5',
{
variants: {
variant: {
- default: 'bg-sand-12 text-sand-1 hover:bg-sand-11',
- destructive: 'bg-red-9 text-sand-1 hover:bg-red-8',
+ default: 'bg-accent-9 text-base-1 hover:bg-accent-10',
+ destructive: 'bg-red-9 text-base-1 hover:bg-red-10',
outline:
- 'border border-input bg-sand-1 hover:bg-sand-3 hover:text-sand-12',
+ 'border border-input border-base-7 hover:border-base-8 bg-base-1 hover:bg-base-3 hover:text-base-12 text-base-11',
secondary:
'bg-secondary text-secondary-foreground hover:bg-secondary/80',
ghost: 'hover:bg-accent hover:text-accent-foreground',
@@ -20,10 +20,11 @@ const buttonVariants = cva(
child: ''
},
size: {
- default: 'h-10 px-4 py-2',
- sm: 'h-9 rounded-md px-3',
- lg: 'h-11 rounded-md px-8',
- icon: 'h-10 w-10'
+ default: 'h-10 px-4 py-2 rounded-lg',
+ xs: 'h-8 rounded-lg px-2.5',
+ sm: 'h-9 rounded-lg px-3',
+ lg: 'h-11 rounded-lg px-8',
+ icon: 'min-h-8 min-w-8 w-8 h-8 rounded-lg'
}
},
defaultVariants: {
diff --git a/apps/web/src/components/shadcn-ui/hover-card.tsx b/apps/web/src/components/shadcn-ui/hover-card.tsx
new file mode 100644
index 00000000..9f288c09
--- /dev/null
+++ b/apps/web/src/components/shadcn-ui/hover-card.tsx
@@ -0,0 +1,27 @@
+import * as React from 'react';
+import * as HoverCardPrimitive from '@radix-ui/react-hover-card';
+
+import { cn } from '@/src/lib/utils';
+
+const HoverCard = HoverCardPrimitive.Root;
+
+const HoverCardTrigger = HoverCardPrimitive.Trigger;
+
+const HoverCardContent = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, align = 'center', sideOffset = 4, ...props }, ref) => (
+
+));
+HoverCardContent.displayName = HoverCardPrimitive.Content.displayName;
+
+export { HoverCard, HoverCardTrigger, HoverCardContent };
diff --git a/apps/web/src/components/shadcn-ui/tooltip.tsx b/apps/web/src/components/shadcn-ui/tooltip.tsx
index 7f90f759..3bf9ad0b 100644
--- a/apps/web/src/components/shadcn-ui/tooltip.tsx
+++ b/apps/web/src/components/shadcn-ui/tooltip.tsx
@@ -17,7 +17,7 @@ const TooltipContent = React.forwardRef<
ref={ref}
sideOffset={sideOffset}
className={cn(
- 'bg-popover text-popover-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 overflow-hidden rounded-md border px-3 py-1.5 text-sm shadow-md',
+ 'bg-base-12 text-base-1 animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 overflow-hidden rounded-md px-3 py-1.5 text-xs',
className
)}
{...props}
diff --git a/apps/web/tailwind.config.ts b/apps/web/tailwind.config.ts
index e3ced48e..86ef067e 100644
--- a/apps/web/tailwind.config.ts
+++ b/apps/web/tailwind.config.ts
@@ -28,6 +28,8 @@ const config = {
},
extend: {
colors: {
+ accent: colors.alias('cyan'),
+ base: colors.alias('slate'),
border: 'hsl(var(--border))',
input: 'hsl(var(--input))',
ring: 'hsl(var(--ring))',
@@ -49,10 +51,6 @@ const config = {
DEFAULT: 'hsl(var(--muted))',
foreground: 'hsl(var(--muted-foreground))'
},
- accent: {
- DEFAULT: 'hsl(var(--accent))',
- foreground: 'hsl(var(--accent-foreground))'
- },
popover: {
DEFAULT: 'hsl(var(--popover))',
foreground: 'hsl(var(--popover-foreground))'
diff --git a/packages/utils/typeid.ts b/packages/utils/typeid.ts
index 1e8a0b86..0882548d 100644
--- a/packages/utils/typeid.ts
+++ b/packages/utils/typeid.ts
@@ -32,6 +32,12 @@ export const idTypes = {
} as const;
type IdType = typeof idTypes;
+type ReversedIdType = { [K in keyof IdType as IdType[K]]: K };
+
+const reversedIdTypes = Object.fromEntries(
+ Object.entries(idTypes).map(([x, y]) => [y, x])
+) as ReversedIdType;
+
type IdTypePrefixes = keyof typeof idTypes;
export type TypeId = `${IdType[T]}_${string}`;
@@ -66,3 +72,7 @@ export const validateTypeId = (
prefix: T,
data: unknown
): data is TypeId => typeIdValidator(prefix).safeParse(data).success;
+
+export const inferTypeId = (
+ input: `${T}_${string}`
+) => reversedIdTypes[TypeID.fromString(input).getType() as T];
diff --git a/packages/utils/uiColors.ts b/packages/utils/uiColors.ts
index 6576747d..f4f91e63 100644
--- a/packages/utils/uiColors.ts
+++ b/packages/utils/uiColors.ts
@@ -1,21 +1,24 @@
export const uiColors = [
- 'red',
+ 'bronze',
+ 'gold',
+ 'brown',
'orange',
- 'amber',
- 'yellow',
- 'lime',
- 'green',
- 'emerald',
- 'teal',
- 'cyan',
- 'sky',
- 'blue',
- 'indigo',
- 'violet',
- 'purple',
- 'fuchsia',
+ 'tomato',
+ 'red',
+ 'ruby',
+ 'crimson',
'pink',
- 'rose'
+ 'plum',
+ 'purple',
+ 'violet',
+ 'iris',
+ 'indigo',
+ 'blue',
+ 'cyan',
+ 'teal',
+ 'jade',
+ 'green',
+ 'grass'
] as const;
export type UiColor = (typeof uiColors)[number];
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index abf86486..c9c7ca24 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -275,6 +275,9 @@ importers:
'@radix-ui/react-dropdown-menu':
specifier: ^2.0.6
version: 2.0.6(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-hover-card':
+ specifier: ^1.0.7
+ version: 1.0.7(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@radix-ui/react-label':
specifier: ^2.0.2
version: 2.0.2(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)