mirror of
https://github.com/webstudio-is/webstudio.git
synced 2026-11-04 19:20:28 +09:00
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
132 lines
3.3 KiB
TypeScript
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>
|
|
);
|
|
};
|