Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 增加 settings 页面和修改 menu 组件 #76

Merged
merged 2 commits into from
Jul 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-popover": "^1.1.1",
"@radix-ui/react-scroll-area": "^1.1.0",
"@radix-ui/react-select": "^2.1.1",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-tooltip": "^1.1.2",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"framer-motion": "10.17.9",
Expand Down
805 changes: 465 additions & 340 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions src/app/edit/(main)/(router)/plugins/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { FC } from 'react';

const Plugins: FC = () => {
return <div className="p-4 h-full">Plugins</div>;
};

export default Plugins;
124 changes: 124 additions & 0 deletions src/app/edit/(main)/(router)/settings/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import { FC, ReactNode } from 'react';
import { PiWarningCircleBold, PiCodeThin } from 'react-icons/pi';
import { VscPreview } from 'react-icons/vsc';

import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select';
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
import { Menu, MenuItem } from '@/components/menu';

const Settings: FC = () => {
const titleStyle = 'my-2 font-bold';

return (
<div className="p-4 h-full">
<div>Settings</div>
<div>
<div className={titleStyle}>WEBCONTAINERS</div>
<div className="flex items-center text-sm text-gray-400 my-1">
<span className="mr-2">Compile trigger</span>
<TooltipProvider delayDuration={500}>
<Tooltip>
<TooltipTrigger>
<PiWarningCircleBold />
</TooltipTrigger>
<TooltipContent className="bg-gray-800 text-white" side={'right'}>
<p>Controls when edited files are synced tothe WebContainers filesystem.</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
<CompileSelector />
</div>
<div>
<div className={titleStyle}>EDITOR SETTINGS</div>
<EditorSettings />
</div>
</div>
);
};

const CompileSelector: FC = () => {
const selectOptions = [
{
text: 'Edit(auto)',
id: 0,
},
{
text: 'Save',
id: 1,
},
{
text: 'KeyStroke',
id: 2,
},
];

return (
<Select defaultValue="Edit(auto)">
<SelectTrigger className="w-[180px]">
<SelectValue placeholder="Theme" />
</SelectTrigger>
<SelectContent>
{selectOptions.map((option) => (
<SelectItem value={option.text} key={option.id}>
{option.text}
</SelectItem>
))}
</SelectContent>
</Select>
);
};

const EditorSettings: FC = () => {
interface settingOption {
text: string;
id: number;
icon: ReactNode;
}

const editorSettingOptions: Array<settingOption> = [
{
text: 'User settings',
id: 0,
icon: <VscPreview />,
},
{
text: 'Workspace settings',
id: 1,
icon: <VscPreview />,
},
{
text: 'User snippets',
id: 2,
icon: <PiCodeThin />,
},
{
text: 'Workspace snippets',
id: 3,
icon: <PiCodeThin />,
},
];

return (
<div>
<Menu>
{editorSettingOptions.map((option) => (
<MenuItem>
<div className="flex items-center">
<span className="mx-2">{option.icon}</span>
<span> {option.text}</span>
</div>
</MenuItem>
))}
</Menu>
</div>
);
};

export default Settings;
6 changes: 3 additions & 3 deletions src/components/avatarPopover/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
} from 'react-icons/ai';

import { Avatar } from '@/components/common/Avatar';
import { Menu, MenuItem } from '@/components/avatarPopover/menu';
import { Menu, MenuItem } from '@/components/menu';

const AvatarPopoverContent: FC = () => {
const menuItemTwStyle = `flex items-center`;
Expand All @@ -24,7 +24,7 @@ const AvatarPopoverContent: FC = () => {
<Avatar className="bg-slate-700 w-20 h-20 mt-5"></Avatar>
<span className="mt-5 text-white select-none">Your Name</span>
<span className="text-xs text-gray-200 select-none mb-5">Your Account</span>
<Menu>
<Menu topLine>
<MenuItem className={menuItemTwStyle} onClick={testHandle}>
<AiOutlineHome className="mx-2" />
Your dashboard
Expand All @@ -42,7 +42,7 @@ const AvatarPopoverContent: FC = () => {
Local projects
</MenuItem>
</Menu>
<Menu>
<Menu topLine>
<MenuItem className={menuItemTwStyle}>
<AiOutlinePoweroff className="mx-2" />
Sign out
Expand Down
30 changes: 0 additions & 30 deletions src/components/avatarPopover/menu/index.tsx

This file was deleted.

37 changes: 37 additions & 0 deletions src/components/menu/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
'use client';

import { FC, ReactNode } from 'react';

import { cn } from '@/utils';

const MenuItem: FC<{
children?: ReactNode;
className?: string;
onClick?: React.MouseEventHandler<HTMLDivElement>;
}> = ({ children, className, onClick }) => {
return (
<div
className={cn('w-full p-1 hover:bg-blue-500 transition-colors cursor-pointer', className)}
onClick={onClick}
>
{children}
</div>
);
};

const Menu: FC<{
children?: ReactNode;
className?: string;
topLine?: boolean | undefined;
}> = ({ children, className, topLine = false }) => {
const hasTopLine = topLine || (typeof topLine === 'undefined' && children);

return (
<div className={cn('relative w-full py-2', className)}>
{hasTopLine && <div className="w-full h-[1px] bg-gray-600 absolute top-0 opacity-50"></div>}
{children}
</div>
);
};

export { Menu, MenuItem };
151 changes: 151 additions & 0 deletions src/components/ui/select/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
'use client';

import * as React from 'react';
import * as SelectPrimitive from '@radix-ui/react-select';
import { Check, ChevronDown, ChevronUp } from 'lucide-react';

import { cn } from '@/utils';

const Select = SelectPrimitive.Root;
const SelectGroup = SelectPrimitive.Group;
const SelectValue = SelectPrimitive.Value;

const SelectTrigger = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
>(({ className, children, ...props }, ref) => (
<SelectPrimitive.Trigger
ref={ref}
className={cn(
'flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1',
className,
)}
{...props}
>
{children}
<SelectPrimitive.Icon asChild>
<ChevronDown className="h-4 w-4 opacity-50" />
</SelectPrimitive.Icon>
</SelectPrimitive.Trigger>
));
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;

const SelectScrollUpButton = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
>(({ className, ...props }, ref) => (
<SelectPrimitive.ScrollUpButton
ref={ref}
className={cn('flex cursor-default items-center justify-center py-1', className)}
{...props}
>
<ChevronUp className="h-4 w-4" />
</SelectPrimitive.ScrollUpButton>
));
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;

const SelectScrollDownButton = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>
>(({ className, ...props }, ref) => (
<SelectPrimitive.ScrollDownButton
ref={ref}
className={cn('flex cursor-default items-center justify-center py-1', className)}
{...props}
>
<ChevronDown className="h-4 w-4" />
</SelectPrimitive.ScrollDownButton>
));
SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;

const SelectContent = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
>(({ className, children, position = 'popper', ...props }, ref) => (
<SelectPrimitive.Portal>
<SelectPrimitive.Content
ref={ref}
className={cn(
'relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md 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-[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',
position === 'popper' &&
'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
className,
)}
position={position}
{...props}
>
<SelectScrollUpButton />
<SelectPrimitive.Viewport
className={cn(
'p-1',
position === 'popper' &&
'h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]',
)}
>
{children}
</SelectPrimitive.Viewport>
<SelectScrollDownButton />
</SelectPrimitive.Content>
</SelectPrimitive.Portal>
));
SelectContent.displayName = SelectPrimitive.Content.displayName;

const SelectLabel = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Label>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
>(({ className, ...props }, ref) => (
<SelectPrimitive.Label
ref={ref}
className={cn('py-1.5 pl-8 pr-2 text-sm font-semibold', className)}
{...props}
/>
));
SelectLabel.displayName = SelectPrimitive.Label.displayName;

const SelectItem = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
>(({ className, children, ...props }, ref) => (
<SelectPrimitive.Item
ref={ref}
className={cn(
'relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
className,
)}
{...props}
>
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<SelectPrimitive.ItemIndicator>
<Check className="h-4 w-4" />
</SelectPrimitive.ItemIndicator>
</span>

<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
</SelectPrimitive.Item>
));
SelectItem.displayName = SelectPrimitive.Item.displayName;

const SelectSeparator = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Separator>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
>(({ className, ...props }, ref) => (
<SelectPrimitive.Separator
ref={ref}
className={cn('-mx-1 my-1 h-px bg-muted', className)}
{...props}
/>
));
SelectSeparator.displayName = SelectPrimitive.Separator.displayName;

export {
Select,
SelectGroup,
SelectValue,
SelectTrigger,
SelectContent,
SelectLabel,
SelectItem,
SelectSeparator,
SelectScrollUpButton,
SelectScrollDownButton,
};
Loading
Loading