Files
webstudio/apps/builder/app/dashboard/header.tsx
T
Oleg Isonen 918ca2fa6f feat: Custom font family (#3845)
Closes https://github.com/webstudio-is/webstudio/issues/3817

## Description

This allows to enter any font family as well as adds safe default
chinese fonts.

Todo
- [x] use combobox
- [x] allow preview on hover
- [x] allow user to type fallback via comma, don't add a fallback to a
custom font
- [x] validate input?
- [x] add fonts
- [x] add global values

## Steps for reproduction

1. click button
2. expect xyz

## Code Review

- [ ] hi @kof, I need you to do
  - conceptual review (architecture, feature-correctness)
  - detailed review (read every line)
  - test it on preview

## Before requesting a review

- [ ] made a self-review
- [ ] added inline comments where things may be not obvious (the "why",
not "what")

## Before merging

- [ ] tested locally and on preview environment (preview dev login:
5de6)
- [ ] updated [test
cases](https://github.com/webstudio-is/webstudio/blob/main/apps/builder/docs/test-cases.md)
document
- [ ] added tests
- [ ] if any new env variables are added, added them to `.env` file
2024-08-01 18:12:13 +02:00

132 lines
3.3 KiB
TypeScript

import {
ChevronDownIcon,
UpgradeIcon,
WebstudioIcon,
} from "@webstudio-is/icons";
import {
DropdownMenu,
DropdownMenuTrigger,
DropdownMenuContent,
DropdownMenuPortal,
DropdownMenuItem,
DropdownMenuLabel,
Flex,
Avatar,
css,
rawTheme,
theme,
Button,
ProBadge,
DropdownMenuSeparator,
Text,
} from "@webstudio-is/design-system";
import { useNavigate } from "@remix-run/react";
import { logoutPath, userPlanSubscriptionPath } from "~/shared/router-utils";
import type { User } from "~/shared/db/user.server";
import type { UserPlanFeatures } from "~/shared/db/user-plan-features.server";
const containerStyle = css({
px: theme.spacing[13],
bc: theme.colors.backgroundPanel,
height: theme.spacing[15],
boxShadow: theme.shadows.brandElevationBig,
});
const getAvatarLetter = (title?: string) => {
return (title || "X").charAt(0).toLocaleUpperCase();
};
const defaultUserName = "James Bond";
const Menu = ({
user,
userPlanFeatures,
}: {
user: User;
userPlanFeatures: UserPlanFeatures;
}) => {
const navigate = useNavigate();
const nameOrEmail = user.username ?? user.email ?? defaultUserName;
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button color="ghost" aria-label="Menu Button" css={{ height: "100%" }}>
<Flex gap="1" align="center">
{userPlanFeatures.hasProPlan && (
<>
<ProBadge>{userPlanFeatures.planName}</ProBadge>
<div />
</>
)}
<Avatar
src={user?.image || undefined}
fallback={getAvatarLetter(nameOrEmail)}
alt={nameOrEmail}
/>
<ChevronDownIcon
width={15}
height={15}
color={rawTheme.colors.foregroundMain}
/>
</Flex>
</Button>
</DropdownMenuTrigger>
<DropdownMenuPortal>
<DropdownMenuContent align="end">
<DropdownMenuLabel>
{user.username ?? defaultUserName}
<Text>{user.email}</Text>
</DropdownMenuLabel>
{userPlanFeatures.hasSubscription && (
<DropdownMenuItem
onSelect={() => navigate(userPlanSubscriptionPath())}
>
Manage Subscription
</DropdownMenuItem>
)}
{userPlanFeatures.hasProPlan === false && (
<DropdownMenuItem
onSelect={() => {
window.open("https://webstudio.is/pricing");
}}
css={{
gap: theme.spacing[3],
}}
>
<UpgradeIcon />
<div>Upgrade to Pro</div>
</DropdownMenuItem>
)}
<DropdownMenuSeparator />
<DropdownMenuItem onSelect={() => navigate(logoutPath())}>
Sign Out
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenuPortal>
</DropdownMenu>
);
};
export const Header = ({
user,
userPlanFeatures,
}: {
user: User;
userPlanFeatures: UserPlanFeatures;
}) => {
return (
<Flex
as="header"
align="center"
justify="between"
className={containerStyle()}
>
<WebstudioIcon size={22} />
<Menu user={user} userPlanFeatures={userPlanFeatures} />
</Flex>
);
};