refactor switch component + update styles

This commit is contained in:
Jamie Pine 2022-10-21 21:50:47 -07:00
parent f92303c7d6
commit a9e263e2f6
39 changed files with 332 additions and 309 deletions

View file

@ -35,5 +35,11 @@
"editor.defaultFormatter": "rust-lang.rust-analyzer"
},
"rust-analyzer.procMacro.enable": true,
"rust-analyzer.diagnostics.experimental.enable": false
"rust-analyzer.diagnostics.experimental.enable": false,
"tailwindCSS.experimental.classRegex": [
["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"],
"tw`([^`]*)",
"tw\\.[^`]+`([^`]*)`",
"tw\\(.*?\\).*?`([^`]*)"
],
}

View file

@ -88,7 +88,7 @@ export function HomeCTA() {
<Button
onClick={() => setShowWaitlistInput(true)}
className="z-30 border-0 cursor-pointer"
variant="primary"
variant="accent"
>
Join Waitlist
</Button>
@ -150,7 +150,7 @@ export function HomeCTA() {
'opacity-50 cursor-default': loading
})}
disabled={loading}
variant="primary"
variant="accent"
type="submit"
>
{loading ? (

View file

@ -110,7 +110,7 @@ function Page() {
<Button
onClick={scrollToPositions}
className="z-30 border-0 cursor-pointer"
variant="primary"
variant="accent"
>
See Open Positions
</Button>

View file

@ -27,7 +27,7 @@ function Page({ is404 }: { is404: boolean }) {
>
Back
</Button>
<Button href="/" className="mt-2 cursor-pointer !text-white" variant="primary">
<Button href="/" className="mt-2 cursor-pointer !text-white" variant="accent">
Discover Spacedrive
</Button>
</div>

View file

@ -20,7 +20,7 @@ export function AppLayout() {
<div
className={clsx(
// App level styles
'flex overflow-hidden text-ink select-none cursor-default',
'flex h-screen overflow-hidden text-ink select-none cursor-default',
os === 'macOS' && 'rounded-[10px] has-blur-effects',
os !== 'browser' && os !== 'windows' && 'border border-app-divider/30'
)}

View file

@ -18,7 +18,7 @@ export function ErrorFallback({ error, resetErrorBoundary }: FallbackProps) {
<h1 className="text-2xl font-bold">We're past the event horizon...</h1>
<pre className="m-2">Error: {error.message}</pre>
<div className="flex flex-row space-x-2">
<Button variant="primary" className="mt-2" onClick={resetErrorBoundary}>
<Button variant="accent" className="mt-2" onClick={resetErrorBoundary}>
Reload
</Button>
<Button

View file

@ -12,7 +12,7 @@ export default function NotFound() {
<p className="m-3 text-sm font-semibold uppercase text-ink-faint">Error: 404</p>
<h1 className="text-4xl font-bold">You chose nothingness.</h1>
<div className="flex flex-row space-x-2">
<Button variant="primary" className="mt-4" onClick={() => navigate(-1)}>
<Button variant="accent" className="mt-4" onClick={() => navigate(-1)}>
Go Back
</Button>
</div>

View file

@ -1,20 +1,11 @@
import { ChevronLeftIcon, ChevronRightIcon, TagIcon } from '@heroicons/react/24/outline';
import { KeyIcon as KeyIconSolid, TagIcon as TagIconSolid } from '@heroicons/react/24/solid';
import {
OperatingSystem,
getExplorerStore,
useExplorerStore,
useLibraryMutation
} from '@sd/client';
import { Dropdown, OverlayPanel } from '@sd/ui';
import { TagIcon as TagIconSolid } from '@heroicons/react/24/solid';
import { getExplorerStore, useExplorerStore, useLibraryMutation } from '@sd/client';
import { Button, Input, OverlayPanel, cva, tw } from '@sd/ui';
import clsx from 'clsx';
import {
Aperture,
ArrowsClockwise,
Cloud,
FilmStrip,
IconProps,
Image,
Key,
List,
MonitorPlay,
@ -22,7 +13,7 @@ import {
SidebarSimple,
SquaresFour
} from 'phosphor-react';
import { DetailedHTMLProps, HTMLAttributes, forwardRef, useEffect, useRef } from 'react';
import { forwardRef, useEffect, useRef } from 'react';
import { useForm } from 'react-hook-form';
import { useNavigate } from 'react-router-dom';
@ -44,24 +35,41 @@ export interface TopBarButtonProps {
onClick?: () => void;
}
const topBarButtonStyle = cva(
'mr-[1px] flex py-0.5 px-0.5 text-md font-medium rounded-md transition-colors duration-100 outline-none hover:bg-app-selected',
{
variants: {
active: {
true: 'bg-app-selected',
false: 'bg-transparent'
},
group: {
true: 'rounded-l-none rounded-r-none'
},
left: {
true: 'rounded-l-md'
},
right: {
true: 'rounded-r-md'
}
}
}
);
const TopBarButton = forwardRef<HTMLButtonElement, TopBarButtonProps>(
({ icon: Icon, left, right, group, active, className, ...props }, ref) => {
return (
<button
<Button
{...props}
ref={ref}
className={clsx(
'mr-[1px] flex py-0.5 px-0.5 text-md font-medium rounded-md open:bg-selected transition-colors duration-100 outline-none !cursor-normal',
{
'rounded-r-none rounded-l-none': group && !left && !right,
'rounded-r-none': group && left,
'rounded-l-none': group && right
},
'border-none',
topBarButtonStyle({ left, right, group, active }),
className
)}
>
<Icon weight={'regular'} className="m-0.5 w-5 h-5 text-ink-dull" />
</button>
</Button>
);
}
);
@ -86,7 +94,7 @@ const SearchBar = forwardRef<HTMLInputElement, DefaultProps>((props, forwardedRe
return (
<form onSubmit={handleSubmit(() => null)} className="relative flex h-7">
<input
<Input
ref={(el) => {
ref(el);
@ -94,7 +102,7 @@ const SearchBar = forwardRef<HTMLInputElement, DefaultProps>((props, forwardedRe
else if (forwardedRef) forwardedRef.current = el;
}}
placeholder="Search"
className="peer w-32 h-[30px] focus:w-52 text-sm p-3 rounded-lg outline-none focus:ring-2 border shadow transition-all bg-app-input border-app-border"
className="w-32 transition-all focus:w-52"
{...searchField}
/>
@ -105,13 +113,12 @@ const SearchBar = forwardRef<HTMLInputElement, DefaultProps>((props, forwardedRe
)}
>
{platform === 'browser' ? (
<Shortcut chars="/" aria-label={'Press slash to focus search bar'} />
<Shortcut chars="⌘F" aria-label={'Press Command-F to focus search bar'} />
) : os === 'macOS' ? (
<Shortcut chars="⌘F" aria-label={'Press Command-F to focus search bar'} />
) : (
<Shortcut chars="CTRL+F" aria-label={'Press CTRL-F to focus search bar'} />
)}
{/* <Shortcut chars="S" /> */}
</div>
</form>
);
@ -126,29 +133,12 @@ export const TopBar: React.FC<TopBarProps> = (props) => {
const os = useOperatingSystem(true);
const store = useExplorerStore();
const { mutate: generateThumbsForLocation } = useLibraryMutation(
'jobs.generateThumbsForLocation',
{
onMutate: (data) => {
// console.log('GenerateThumbsForLocation', data);
}
}
);
const { mutate: identifyUniqueFiles } = useLibraryMutation('jobs.identifyUniqueFiles', {
onMutate: (data) => {
// console.log('IdentifyUniqueFiles', data);
},
onError: (error) => {
console.error('IdentifyUniqueFiles', error);
}
});
const { mutate: objectValidator } = useLibraryMutation('jobs.objectValidator', {
onMutate: (data) => {
// console.log('ObjectValidator', data);
}
});
// const { mutate: generateThumbsForLocation } = useLibraryMutation(
// 'jobs.generateThumbsForLocation'
// );
// const { mutate: identifyUniqueFiles } = useLibraryMutation('jobs.identifyUniqueFiles');
// const { mutate: objectValidator } = useLibraryMutation('jobs.objectValidator');
const navigate = useNavigate();
@ -218,7 +208,7 @@ export const TopBar: React.FC<TopBarProps> = (props) => {
// in case you wanna turn it back on
// honestly its just work to revert
className={clsx(
'flex h-[2.95rem] -mt-0.5 max-w z-10 pl-3 flex-shrink-0 items-center border-transparent border-b app-background overflow-hidden rounded-tl-md transition-[background-color] transition-[border-color] duration-250 ease-out',
'flex h-[2.95rem] -mt-0.5 max-w z-10 pl-3 flex-shrink-0 items-center border-transparent border-b app-background overflow-hidden transition-[background-color] transition-[border-color] duration-250 ease-out',
props.showSeparator && 'top-bar-blur'
)}
>

View file

@ -1,10 +1,24 @@
import { ExplorerItem, getExplorerStore } from '@sd/client';
import { cva, tw } from '@sd/ui';
import clsx from 'clsx';
import { HTMLAttributes } from 'react';
import FileThumb from './FileThumb';
import { isObject } from './utils';
const NameArea = tw.div`flex justify-center`;
const nameContainerStyles = cva(
'px-1.5 py-[1px] truncate text-center rounded-md text-xs font-medium text-gray-550 cursor-default',
{
variants: {
selected: {
true: 'bg-accent text-white'
}
}
}
);
interface Props extends HTMLAttributes<HTMLDivElement> {
data: ExplorerItem;
selected: boolean;
@ -51,7 +65,7 @@ function FileItem({ data, selected, index, ...rest }: Props) {
>
<FileThumb
className={clsx(
'border-4 border-gray-250 shadow shadow-black/40 object-cover max-w-full max-h-full w-auto overflow-hidden',
'border-4 border-app-line shadow shadow-black/40 object-cover max-w-full max-h-full w-auto overflow-hidden',
isVid && 'border-black rounded border-x-0 border-y-[9px]'
)}
data={data}
@ -65,19 +79,12 @@ function FileItem({ data, selected, index, ...rest }: Props) {
)}
</div>
</div>
<div className="flex justify-center">
<span
className={clsx(
'px-1.5 py-[1px] truncate text-center rounded-md text-xs font-medium text-gray-550 cursor-default ',
{
'bg-accent !text-white': selected
}
)}
>
<NameArea>
<span className={nameContainerStyles({ selected })}>
{data?.name}
{data?.extension && `.${data.extension}`}
</span>
</div>
</NameArea>
</div>
);
}

View file

@ -67,7 +67,7 @@ export const Inspector = (props: Props) => {
data={props.data}
/>
</div>
<div className="flex flex-col w-full pt-0.5 pb-1 overflow-hidden bg-app-box/50 rounded-lg shadow select-text shadow-black/40 border border-app-border/30">
<div className="flex flex-col w-full pt-0.5 pb-1 overflow-hidden bg-app-box/50 rounded-lg shadow select-text shadow-app-shade/20 border border-app-line/60">
<h3 className="pt-2 pb-1 pl-3 text-base font-bold">
{props.data?.name}
{props.data?.extension && `.${props.data.extension}`}

View file

@ -149,7 +149,7 @@ export const VirtualizedList: React.FC<Props> = ({ data, context, onScroll }) =>
const item = data[index];
const isSelected = explorerStore.selectedRowIndex === index;
return (
<div key={index} className="w-32 h-32">
<div key={index} className="">
<div className="flex">
{item && (
<WrappedItem

View file

@ -1 +1 @@
export const Divider = () => <div className="w-full my-1 h-[1px] bg-app-border" />;
export const Divider = () => <div className="w-full my-1 h-[1px] bg-app-line/60" />;

View file

@ -1,24 +1,11 @@
import { InformationCircleIcon } from '@heroicons/react/24/outline';
import {
EllipsisVerticalIcon,
EyeIcon,
EyeSlashIcon,
KeyIcon,
LockClosedIcon,
LockOpenIcon,
PlusIcon,
TrashIcon,
XMarkIcon
} from '@heroicons/react/24/solid';
import { Button, CategoryHeading, Input, Select, SelectOption } from '@sd/ui';
import clsx from 'clsx';
import { Eject, EjectSimple, Plus } from 'phosphor-react';
import { EyeIcon, EyeSlashIcon } from '@heroicons/react/24/solid';
import { Button, CategoryHeading, Input, Select, SelectOption, Switch, cva, tw } from '@sd/ui';
import { useEffect, useRef, useState } from 'react';
import { Toggle } from '../primitive';
import { DefaultProps } from '../primitive/types';
import { Tooltip } from '../tooltip/Tooltip';
import { Key } from './Key';
const KeyHeading = tw(CategoryHeading)`mb-1`;
export function KeyMounter() {
const ref = useRef<HTMLInputElement>(null);
@ -42,7 +29,7 @@ export function KeyMounter() {
return (
<div className="p-3 pt-3 mb-1">
<CategoryHeading>Mount key</CategoryHeading>
<KeyHeading>Mount key</KeyHeading>
<div className="flex space-x-2">
<div className="relative flex flex-grow">
<Input
@ -55,9 +42,8 @@ export function KeyMounter() {
/>
<Button
onClick={() => setShowKey(!showKey)}
noBorder
padding="thin"
className="absolute right-[5px] top-[5px]"
className="border-none absolute right-[5px] top-[5px]"
>
<CurrentEyeIcon className="w-4 h-4" />
</Button>
@ -65,10 +51,29 @@ export function KeyMounter() {
</div>
<div className="flex flex-row items-center mt-3 mb-1">
<Toggle className="dark:bg-gray-400/30" size="sm" value={toggle} onChange={setToggle} />
<div className="space-x-2">
<Switch
className="bg-app-selected"
size="sm"
checked={toggle}
onCheckedChange={setToggle}
/>
<Switch
className="bg-app-selected"
size="md"
checked={toggle}
onCheckedChange={setToggle}
/>
<Switch
className="bg-app-selected"
size="lg"
checked={toggle}
onCheckedChange={setToggle}
/>
</div>
<span className="ml-3 mt-[1px] font-medium text-xs">Sync with Library</span>
<Tooltip label="This key will be mounted on all devices running your Library">
<InformationCircleIcon className="w-4 h-4 ml-1.5 text-gray-400" />
<InformationCircleIcon className="w-4 h-4 ml-1.5 text-ink-faint" />
</Tooltip>
</div>
@ -87,10 +92,10 @@ export function KeyMounter() {
</Select>
</div>
</div>
<p className="pt-1.5 ml-0.5 text-[8pt] leading-snug text-gray-300 opacity-50 w-[90%]">
<p className="pt-1.5 ml-0.5 text-[8pt] leading-snug text-ink-faint w-[90%]">
Files encrypted with this key will be revealed and decrypted on the fly.
</p>
<Button className="w-full mt-2" variant="primary">
<Button className="w-full mt-2" variant="accent">
Mount Key
</Button>
</div>

View file

@ -123,10 +123,9 @@ function LibraryScopedSection() {
});
}}
className={clsx(
'w-full px-2 py-1.5 mt-1 text-xs font-bold text-center text-ink-faint border border-dashed rounded border-sidebar-border cursor-normal transition'
// os === 'macOS'
// ? 'dark:text-gray-450 dark:border-gray-450 hover:dark:border-gray-400 dark:border-opacity-60'
// : 'dark:text-gray-450 dark:border-gray-550 hover:dark:border-gray-500'
'w-full px-2 py-1.5 mt-1 text-xs font-bold text-center text-ink-faint',
'rounded border border-dashed border-sidebar-line hover:border-sidebar-selected',
'cursor-normal transition'
)}
>
Add Location
@ -173,13 +172,13 @@ export function Sidebar() {
<Dropdown.Root
className="mt-2"
itemsClassName="bg-app-box border-sidebar-border"
itemsClassName="bg-app-box border-sidebar-line"
button={
<Dropdown.Button
variant="gray"
className={clsx(
`w-full mb-1 mt-1 -mr-0.5 shadow-xs rounded`,
`!bg-sidebar-box !border-sidebar-border hover:!border-sidebar-selected !text-ink`,
`!bg-sidebar-box !border-sidebar-line hover:!border-sidebar-selected !text-ink`,
(library === null || isLoadingLibraries) && '!text-ink-faint',
macOnly(os, '!bg-opacity-80 !border-opacity-40')
)}

View file

@ -10,7 +10,7 @@ export default function OnboardingPage() {
<h1 className="text-red-500">Welcome to Spacedrive</h1>
<CreateLibraryDialog onSubmit={() => navigate('overview')}>
<Button variant="primary" size="sm">
<Button variant="accent" size="sm">
Create your library
</Button>
</CreateLibraryDialog>

View file

@ -1,42 +0,0 @@
import { Switch } from '@headlessui/react';
import clsx from 'clsx';
export interface ToggleProps {
value: boolean;
onChange?: (newValue: boolean) => void;
size?: 'sm' | 'md';
className?: string;
}
export const Toggle: React.FC<ToggleProps> = (props) => {
const { value: isEnabled = false, onChange = (val) => null, size = 'sm' } = props;
return (
<Switch
checked={isEnabled}
onChange={onChange}
className={clsx(
'transition relative flex-shrink-0 inline-flex items-center h-6 w-11 rounded-full bg-gray-200 dark:bg-gray-550',
props.className,
{
'!bg-accent dark:!bg-accent': isEnabled,
'h-[20px] w-[35px]': size === 'sm',
'h-8 w-[55px]': size === 'md'
}
)}
>
<span
className={clsx(
'transition inline-block w-4 h-4 transform bg-white rounded-full',
isEnabled ? 'translate-x-6' : 'translate-x-1',
{
'w-3 h-3': size === 'sm',
'h-6 w-6': size === 'md',
'translate-x-5': size === 'sm' && isEnabled,
'translate-x-7': size === 'md' && isEnabled
}
)}
/>
</Switch>
);
};

View file

@ -2,7 +2,7 @@ export default function PhotosScreen() {
return (
<div className="flex flex-col w-full h-screen p-5 custom-scroll page-scroll app-background">
<div className="flex flex-col space-y-5 pb-7">
<p className="px-5 py-3 mb-3 text-sm border rounded-md border-app-border bg-app-box ">
<p className="px-5 py-3 mb-3 text-sm border rounded-md border-app-line bg-app-box ">
<b>Note: </b>This is a pre-alpha build of Spacedrive, many features are yet to be
functional.
</p>

View file

@ -1,6 +1,6 @@
import { Switch } from '@sd/ui';
import { useState } from 'react';
import { Toggle } from '../../../components/primitive';
import { InputContainer } from '../../../components/primitive/InputContainer';
import { SettingsContainer } from '../../../components/settings/SettingsContainer';
import { SettingsHeader } from '../../../components/settings/SettingsHeader';
@ -17,14 +17,14 @@ export default function AppearanceSettings() {
title="UI Animations"
description="Dialogs and other UI elements will animate when opening and closing."
>
<Toggle value={uiAnimations} onChange={setUiAnimations} className="m-2 ml-4" />
<Switch value={uiAnimations} onChange={setUiAnimations} className="m-2 ml-4" />
</InputContainer>
<InputContainer
mini
title="Blur Effects"
description="Some components will have a blur effect applied to them."
>
<Toggle value={blurEffects} onChange={setBlurEffects} className="m-2 ml-4" />
<Switch value={blurEffects} onChange={setBlurEffects} className="m-2 ml-4" />
</InputContainer>
</SettingsContainer>
);

View file

@ -1,10 +1,9 @@
import { useBridgeQuery, usePlatform } from '@sd/client';
import { Input } from '@sd/ui';
import { Input, Switch } from '@sd/ui';
import { Database } from 'phosphor-react';
import tw from 'tailwind-styled-components';
import Card from '../../../components/layout/Card';
import { Toggle } from '../../../components/primitive';
import { SettingsContainer } from '../../../components/settings/SettingsContainer';
import { SettingsHeader } from '../../../components/settings/SettingsHeader';
@ -44,7 +43,7 @@ export default function GeneralSettings() {
</div>
</div>
<div className="flex items-center mt-5 space-x-3">
<Toggle size="sm" value />
<Switch size="sm" checked />
<span className="text-sm text-gray-200">Run daemon when app closed</span>
</div>
<div className="mt-3">

View file

@ -1,6 +1,6 @@
import { Switch } from '@sd/ui';
import { useState } from 'react';
import { Toggle } from '../../../components/primitive';
import { InputContainer } from '../../../components/primitive/InputContainer';
import { SettingsContainer } from '../../../components/settings/SettingsContainer';
import { SettingsHeader } from '../../../components/settings/SettingsHeader';
@ -15,7 +15,11 @@ export default function AppearanceSettings() {
title="Sync with Library"
description="If enabled your keybindings will be synced with library, otherwise they will apply only to this client."
>
<Toggle value={syncWithLibrary} onChange={setSyncWithLibrary} className="m-2 ml-4" />
<Switch
checked={syncWithLibrary}
onCheckedChange={setSyncWithLibrary}
className="m-2 ml-4"
/>
</InputContainer>
</SettingsContainer>
);

View file

@ -1,10 +1,9 @@
import { useBridgeMutation } from '@sd/client';
import { useCurrentLibrary } from '@sd/client';
import { Button, Input } from '@sd/ui';
import { Button, Input, Switch } from '@sd/ui';
import { useEffect, useState } from 'react';
import { useDebounce } from 'use-debounce';
import { Toggle } from '../../../components/primitive';
import { InputContainer } from '../../../components/primitive/InputContainer';
import { SettingsContainer } from '../../../components/settings/SettingsContainer';
import { SettingsHeader } from '../../../components/settings/SettingsHeader';
@ -89,7 +88,7 @@ export default function LibraryGeneralSettings() {
description="Enable encryption for this library, this will only encrypt the Spacedrive database, not the files themselves."
>
<div className="flex items-center ml-3">
<Toggle value={encryptLibrary} onChange={setEncryptLibrary} />
<Switch checked={encryptLibrary} onCheckedChange={setEncryptLibrary} />
</div>
</InputContainer>
<InputContainer mini title="Export Library" description="Export this library to a file.">

View file

@ -20,7 +20,7 @@ export default function LocationSettings() {
rightArea={
<div className="flex-row space-x-2">
<Button
variant="primary"
variant="accent"
size="sm"
onClick={() => {
if (!platform.openFilePickerDialog) {

View file

@ -1,15 +1,13 @@
import { TrashIcon } from '@heroicons/react/24/outline';
import { Tag, useLibraryMutation, useLibraryQuery } from '@sd/client';
import { TagUpdateArgs } from '@sd/client';
import { Button, Input } from '@sd/ui';
import { Dialog } from '@sd/ui';
import { Button, Dialog, Input, Switch } from '@sd/ui';
import clsx from 'clsx';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { Controller, useForm } from 'react-hook-form';
import { useDebounce } from 'rooks';
import Card from '../../../components/layout/Card';
import { Toggle } from '../../../components/primitive';
import { InputContainer } from '../../../components/primitive/InputContainer';
import { PopoverPicker } from '../../../components/primitive/PopoverPicker';
import { SettingsContainer } from '../../../components/settings/SettingsContainer';
@ -85,7 +83,7 @@ export default function TagsSettings() {
loading={isLoading}
ctaLabel="Create"
trigger={
<Button variant="primary" size="sm">
<Button variant="accent" size="sm">
Create Tag
</Button>
}
@ -174,7 +172,7 @@ export default function TagsSettings() {
title="Show in Spaces"
description="Show this tag on the spaces screen."
>
<Toggle value />
<Switch checked />
</InputContainer>
</form>
) : (

View file

@ -1,5 +1,6 @@
import { Switch } from '@sd/ui';
import { useNodeStore } from '../../../components/device/Stores';
import { Toggle } from '../../../components/primitive';
import { InputContainer } from '../../../components/primitive/InputContainer';
import { SettingsContainer } from '../../../components/settings/SettingsContainer';
import { SettingsHeader } from '../../../components/settings/SettingsHeader';
@ -17,9 +18,9 @@ export default function ExperimentalSettings() {
description="Shows data about Spacedrive such as Jobs, Job History and Client State."
>
<div className="flex items-center h-full pl-10">
<Toggle
value={isExperimental}
size={'sm'}
<Switch
checked={isExperimental}
size="sm"
onChange={(newValue) => {
setIsExperimental(!isExperimental);
}}

View file

@ -52,7 +52,7 @@ export default function LibrarySettings() {
rightArea={
<div className="flex-row space-x-2">
<CreateLibraryDialog>
<Button variant="primary" size="sm">
<Button variant="accent" size="sm">
Add Library
</Button>
</CreateLibraryDialog>

View file

@ -1,6 +1,5 @@
import { Input } from '@sd/ui';
import { Input, Switch } from '@sd/ui';
import { Toggle } from '../../../components/primitive';
import { InputContainer } from '../../../components/primitive/InputContainer';
import { SettingsContainer } from '../../../components/settings/SettingsContainer';
import { SettingsHeader } from '../../../components/settings/SettingsHeader';
@ -18,7 +17,7 @@ export default function P2PSettings() {
title="Enable Node Discovery"
description="Allow or block this node from calling an external server to assist in forming a peer-to-peer connection. "
>
<Toggle value />
<Switch checked />
</InputContainer>
<InputContainer

View file

@ -13,7 +13,8 @@ body {
.has-blur-effects {
.app-background {
@apply bg-app/90;
// adjust macOS blur intensity here
@apply bg-app/[0.88];
}
}

View file

@ -23,6 +23,7 @@
"@radix-ui/react-dialog": "^1.0.0",
"@radix-ui/react-dropdown-menu": "^1.0.0",
"@radix-ui/react-select": "^1.0.0",
"@radix-ui/react-switch": "^1.0.1",
"@radix-ui/react-tabs": "^1.0.0",
"@sd/assets": "workspace:*",
"@tailwindcss/forms": "^0.5.3",

View file

@ -1,5 +1,4 @@
import { VariantProps, cva } from 'class-variance-authority';
import clsx from 'clsx';
import { VariantProps, cva, cx } from 'class-variance-authority';
import { forwardRef } from 'react';
import { Link, LinkProps } from 'react-router-dom';
@ -36,40 +35,28 @@ const styles = cva(
thin: '!p-1',
sm: '!p-1.5'
},
noBorder: {
true: 'border-0'
},
size: {
md: 'py-1 px-3 text-md font-medium',
sm: 'py-1 px-2 text-sm font-medium'
},
justify: {
left: 'justify-left',
center: ''
},
variant: {
default: [
'bg-app-button bg-transparent active:bg-app-selected hover:bg-app-hover',
'border-transparent hover:border-app-border active:border-app-border'
'border-transparent hover:border-app-line active:border-app-line'
],
gray: [
'bg-gray-100 shadow-sm hover:bg-gray-200 active:bg-gray-100',
'border-gray-200 hover:border-app-border active:border-gray-200',
'text-gray-700 hover:text-gray-900 active:text-gray-600'
'bg-app-button shadow-sm active:bg-app-hover',
'border-app-line hover:border-app-line'
],
primary: [
'bg-primary-600 text-white shadow-sm active:bg-primary-600 hover:bg-primary border-primary-500 hover:border-primary-500 active:border-primary-700'
accent: [
'bg-accent text-white shadow-sm active:bg-accent hover:bg-accent/90 border-accent-deep hover:border-accent-deep active:border-accent-deep'
],
colored: ['text-white shadow-sm hover:bg-opacity-90 active:bg-opacity-100'],
selected: [
'bg-gray-100 dark:bg-gray-500 text-black hover:text-black active:text-black dark:hover:text-white dark:text-white'
],
bare: ''
}
},
defaultVariants: {
size: 'md',
justify: 'center',
variant: 'default'
}
}
@ -79,10 +66,10 @@ export const Button = forwardRef<
HTMLButtonElement | HTMLAnchorElement,
ButtonProps | LinkButtonProps
>(({ className, ...props }, ref) => {
className = clsx(styles(props), className);
className = cx(styles(props), className);
return hasHref(props) ? (
<a {...props} ref={ref as any} className={clsx(className, 'no-underline inline-block')} />
<a {...props} ref={ref as any} className={cx(className, 'no-underline inline-block')} />
) : (
<button {...(props as ButtonProps)} ref={ref as any} className={className} />
);
@ -92,7 +79,7 @@ export const ButtonLink = forwardRef<
HTMLLinkElement,
ButtonBaseProps & LinkProps & React.RefAttributes<HTMLAnchorElement>
>(({ className, to, ...props }, ref) => {
className = clsx(
className = cx(
styles(props),
'no-underline disabled:opacity-50 disabled:cursor-not-allowed',
className

View file

@ -99,7 +99,7 @@ export const Root = (props: PropsWithChildren<DropdownRootProps>) => {
>
<Menu.Items
className={clsx(
'absolute z-50 min-w-fit w-full border divide-y divide-app-border/50 rounded shadow-xl top-full ring-1 ring-black ring-opacity-5 focus:outline-none bg-app-box border-app-border',
'absolute z-50 min-w-fit w-full border divide-y divide-app-border/50 rounded shadow-xl top-full ring-1 ring-black ring-opacity-5 focus:outline-none bg-app-box border-app-line',
props.itemsClassName,
{ 'left-0': props.align === 'left' },
{ 'right-0': props.align === 'right' }

View file

@ -1,67 +1,51 @@
import { VariantProps, cva } from 'class-variance-authority';
import clsx from 'clsx';
import { PropsWithChildren, forwardRef } from 'react';
const variants = {
default: `
shadow-sm
bg-white
hover:bg-white
focus:hover:bg-white
focus:bg-white
dark:bg-gray-550
dark:hover:bg-gray-550
dark:focus:bg-gray-800
dark:focus:hover:bg-gray-800
export interface InputBaseProps extends VariantProps<typeof inputStyles> {}
border-gray-100
hover:border-gray-200
focus:border-white
dark:border-gray-500
dark:hover:border-gray-500
dark:focus:border-gray-900
export type InputProps = InputBaseProps & React.InputHTMLAttributes<HTMLInputElement>;
focus:ring-primary-100
dark:focus:ring-gray-550
export type TextareaProps = InputBaseProps & React.TextareaHTMLAttributes<HTMLTextAreaElement>;
dark:text-white
placeholder-gray-300
`
};
const inputStyles = cva(
[
'px-3 py-1 text-sm rounded-md border leading-7',
'outline-none shadow-sm focus:ring-2 transition-all'
],
{
variants: {
variant: {
default: [
'bg-app-input focus:bg-app-focus placeholder-ink-faint border-app-line',
'focus:ring-app-selected/30 focus:border-app-divider/80'
]
},
size: {
sm: 'text-sm',
md: 'text-base'
}
},
defaultVariants: {
variant: 'default'
}
}
);
interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
variant?: keyof typeof variants;
}
export const Input = forwardRef<HTMLInputElement, InputProps>(
({ size, variant, ...props }, ref) => {
return (
<input
ref={ref}
{...props}
className={clsx(inputStyles({ size, variant }), props.className)}
/>
);
}
);
export const Input = forwardRef<HTMLInputElement, InputProps>(({ ...props }, ref) => {
return (
<input
ref={ref}
{...props}
className={clsx(
`px-3 py-1 text-sm rounded-md border leading-7 outline-none shadow-xs focus:ring-2 transition-all`,
variants[props.variant || 'default'],
props.className
)}
/>
);
});
interface TextAreaProps extends React.InputHTMLAttributes<HTMLTextAreaElement> {
variant?: keyof typeof variants;
}
export const TextArea = ({ size, ...props }: TextAreaProps) => {
return (
<textarea
{...props}
className={clsx(
`px-2 py-1 rounded-md border leading-5 outline-none shadow-xs focus:ring-2 transition-all`,
variants[props.variant || 'default'],
size && '',
props.className
)}
/>
);
export const TextArea = ({ size, variant, ...props }: TextareaProps) => {
return <textarea {...props} className={clsx(inputStyles({ size, variant }), props.className)} />;
};
export function Label(props: PropsWithChildren<{ slug?: string }>) {

View file

@ -12,12 +12,11 @@ interface Props extends DropdownMenu.MenuContentProps {
const MENU_CLASSES = `
flex flex-col
min-w-[11rem] z-50 m-2 space-y-1
text-left text-sm dark:text-gray-100 text-gray-800
bg-gray-50 border-gray-200 dark:bg-gray-600
border border-gray-300 dark:border-gray-500
shadow-2xl shadow-gray-300 dark:shadow-gray-950
select-none cursor-default rounded-lg
!bg-opacity-90 backdrop-blur
text-left text-sm text-ink
bg-app-overlay/90 backdrop-blur
border border-app-line
shadow-2xl shadow-black/40
`;
export const OverlayPanel = ({

View file

@ -20,7 +20,7 @@ export function Select(props: PropsWithChildren<SelectProps>) {
>
<SelectPrimitive.Trigger
className={clsx(
'inline-flex items-center pl-2 py-0.5 bg-gray-500 border rounded-md shadow outline-none border-gray-450/30 shadow-gray-900/10',
'inline-flex items-center pl-2 py-0.5 bg-app-box border rounded-md shadow outline-none border-app-line shadow-app-shade/10',
props.className
)}
>
@ -34,12 +34,12 @@ export function Select(props: PropsWithChildren<SelectProps>) {
</SelectPrimitive.Trigger>
<SelectPrimitive.Portal className="relative">
<SelectPrimitive.Content className="absolute z-50 w-full p-1 border border-gray-200 rounded-md shadow-2xl bg-gray-50 dark:bg-black/50 backdrop-blur dark:border-gray-500 shadow-gray-300 dark:shadow-gray-950">
<SelectPrimitive.ScrollUpButton className="flex items-center justify-center text-gray-700 dark:text-gray-300">
<SelectPrimitive.Content className="absolute z-50 w-full p-1 border rounded-md shadow-2xl bg-app-box border-app-line backdrop-blur shadow-app-shade/20 ">
<SelectPrimitive.ScrollUpButton className="flex ">
<ChevronDownIcon />
</SelectPrimitive.ScrollUpButton>
<SelectPrimitive.Viewport>{props.children}</SelectPrimitive.Viewport>
<SelectPrimitive.ScrollDownButton className="flex items-center justify-center text-gray-700 dark:text-gray-300"></SelectPrimitive.ScrollDownButton>
<SelectPrimitive.ScrollDownButton className="flex "></SelectPrimitive.ScrollDownButton>
</SelectPrimitive.Content>
</SelectPrimitive.Portal>
</SelectPrimitive.Root>
@ -50,7 +50,7 @@ export function SelectOption(props: PropsWithChildren<{ value: string }>) {
return (
<SelectPrimitive.Item
className={clsx(
'relative flex items-center pl-6 px-1 py-0.5 dark:text-white pr-4 text-xs rounded font-sm cursor-pointer focus:bg-gray-100 dark:focus:bg-primary-500',
'relative flex items-center pl-6 px-1 py-0.5 dark:text-white pr-4 text-xs rounded font-sm cursor-pointer focus:bg-gray-100 dark:focus:bg-accent',
'radix-disabled:opacity-50',
'focus:outline-none select-none'
)}

View file

@ -0,0 +1,57 @@
import * as SwitchPrimitive from '@radix-ui/react-switch';
import { VariantProps, cva, cx } from 'class-variance-authority';
import { forwardRef } from 'react';
export type SwitchProps = VariantProps<typeof switchStyles> &
React.ButtonHTMLAttributes<HTMLButtonElement> &
SwitchPrimitive.SwitchProps;
const switchStyles = cva(
[
'transition relative flex-shrink-0 inline-flex',
'items-center rounded-full p-1',
'bg-app-line radix-state-checked:bg-accent'
],
{
variants: {
size: {
sm: 'h-[20px] w-[34px]',
md: 'h-[25px] w-[47px]',
lg: 'h-[30px] w-[55px]'
}
},
defaultVariants: {
size: 'lg'
}
}
);
const thumbStyles = cva(
[
'transition inline-block w-4 h-4',
'transform rounded-full bg-white',
'shadow-sm shadow-app-shade/40'
],
{
variants: {
size: {
sm: 'w-[12px] h-[12px] radix-state-checked:translate-x-[15px]',
md: 'w-[19px] h-[19px] radix-state-checked:translate-x-[20px]',
lg: 'w-6 h-6 radix-state-checked:translate-x-[23px]'
}
},
defaultVariants: {
size: 'lg'
}
}
);
export const Switch = forwardRef<HTMLButtonElement, SwitchProps>(function Switch(
props,
forwardedRef
) {
return (
<SwitchPrimitive.Root {...props} ref={forwardedRef} className={cx(switchStyles(props))}>
<SwitchPrimitive.Thumb className={cx(thumbStyles(props))} />
</SwitchPrimitive.Root>
);
});

View file

@ -3,15 +3,15 @@ import * as TabsPrimitive from '@radix-ui/react-tabs';
import { tw } from './utils';
export const Root = tw(TabsPrimitive.Root)`
flex flex-col
flex flex-col
`;
export const Content = tw(TabsPrimitive.TabsContent)``;
export const List = tw(TabsPrimitive.TabsList)`
flex flex-row p-2 items-center space-x-1 border-b border-gray-500/30
flex flex-row p-2 items-center space-x-1 border-b border-app-line/70
`;
export const Trigger = tw(TabsPrimitive.TabsTrigger)`
text-white px-1.5 py-0.5 rounded text-sm font-medium radix-state-active:bg-primary
px-1.5 py-0.5 rounded text-sm font-medium radix-state-active:bg-accent radix-state-active:text-white
`;

View file

@ -6,7 +6,8 @@ export * as ContextMenu from './ContextMenu';
export * from './OverlayPanel';
export * from './Input';
export * from './Select';
export * from './Switch';
export * as Tabs from './Tabs';
export * from './Typography';
export * from './utils';
export { cva } from 'class-variance-authority';
export { cva, cx } from 'class-variance-authority';

View file

@ -1,8 +1,5 @@
// Notes
// shadow should be used as shadow-black/40
.vanilla-light {
// global
--color-black: 0, 0%, 0%;
@ -12,27 +9,31 @@
--color-accent-faint: 208, 100%, 67%;
--color-accent-deep: 208, 100%, 47%;
// text
--color-ink: 215, 5%, 20%;
--color-ink-dull: 215, 5%, 30%;
--color-ink-faint: 215, 5%, 60%;
--color-ink: 230, 5%, 20%;
--color-ink-dull: 230, 5%, 30%;
--color-ink-faint: 230, 5%, 60%;
// sidebar
--color-sidebar: 215, 5%, 98%;
--color-sidebar-box: 215, 5%, 100%;
--color-sidebar-border: 215, 10%, 85%;
--color-sidebar-divider: 215, 15%, 90%;
--color-sidebar-button: 215, 15%, 100%;
--color-sidebar-selected: 215, 10%, 90%;
--color-sidebar-separator: 215, 15%, 100%;
--color-sidebar: 230, 5%, 98%;
--color-sidebar-box: 230, 5%, 100%;
--color-sidebar-line: 230, 10%, 85%;
--color-sidebar-divider: 230, 15%, 90%;
--color-sidebar-button: 230, 15%, 100%;
--color-sidebar-selected: 230, 10%, 90%;
--color-sidebar-separator: 230, 15%, 100%;
--color-sidebar-shade: 230, 15%, 100%;
// main
--color-app: 215, 5%, 100%;
--color-app-box: 215, 5%, 98%;
--color-app-input: 215, 5%, 100%;
--color-app-border: 215, 5%, 94%;
--color-app-button: 215, 5%, 100%;
--color-app-divider: 215, 5%, 100%;
--color-app-selected: 215, 5%, 80%;
--color-app-hover: 215, 5%, 100%;
--color-app-separator: 215, 5%, 100%;
--color-app: 230, 5%, 100%;
--color-app-box: 230, 5%, 98%;
--color-app-overlay: 230, 5%, 100%;
--color-app-input: 230, 5%, 100%;
--color-app-focus: 230, 5%, 98%;
--color-app-line: 230, 5%, 85%;
--color-app-button: 230, 5%, 100%;
--color-app-divider: 230, 5%, 85%;
--color-app-selected: 230, 5%, 93%;
--color-app-hover: 230, 5%, 100%;
--color-app-shade: 230, 15%, 50%;
}
@ -45,26 +46,29 @@
--color-accent-faint: 208, 100%, 67%;
--color-accent-deep: 208, 100%, 47%;
// text
--color-ink: 215, 0%, 100%;
--color-ink-dull: 215, 10%, 70%;
--color-ink-faint: 215, 10%, 25%;
--color-ink: 230, 0%, 100%;
--color-ink-dull: 230, 10%, 70%;
--color-ink-faint: 230, 10%, 55%;
// sidebar
--color-sidebar: 215, 15%, 7%;
--color-sidebar-box: 215, 15%, 13%;
--color-sidebar-border: 215, 15%, 23%;
--color-sidebar-divider: 215, 15%, 23%;
--color-sidebar-button: 215, 15%, 23%;
--color-sidebar-selected: 215, 15%, 16%;
--color-sidebar-separator: 215, 15%, 23%;
--color-sidebar: 230, 15%, 7%;
--color-sidebar-box: 230, 15%, 13%;
--color-sidebar-line: 230, 15%, 23%;
--color-sidebar-divider: 230, 15%, 23%;
--color-sidebar-button: 230, 15%, 23%;
--color-sidebar-selected: 230, 15%, 16%;
--color-sidebar-separator: 230, 15%, 23%;
--color-sidebar-shade: 230, 15%, 23%;
// main
--color-app: 215, 15%, 13%;
--color-app-box: 215, 15%, 20%;
--color-app-input: 215, 15%, 23%;
--color-app-border: 215, 15%, 30%;
--color-app-button: 215, 15%, 23%;
--color-app-divider: 215, 15%, 23%;
--color-app-selected: 215, 15%, 23%;
--color-app-hover: 215, 15%, 23%;
--color-app-separator: 215, 15%, 23%;
--color-app: 230, 15%, 13%;
--color-app-box: 230, 15%, 20%;
--color-app-overlay: 230, 14%, 17%;
--color-app-input: 230, 15%, 20%;
--color-app-focus: 230, 15%, 10%;
--color-app-line: 230, 15%, 26%;
--color-app-button: 230, 15%, 23%;
--color-app-divider: 230, 15%, 5%;
--color-app-selected: 230, 15%, 23%;
--color-app-hover: 230, 15%, 20%;
--color-app-shade: 230, 15%, 0%;
}

View file

@ -50,22 +50,25 @@ module.exports = function (app, options) {
sidebar: {
DEFAULT: alpha('--color-sidebar'),
box: alpha('--color-sidebar-box'),
border: alpha('--color-sidebar-border'),
line: alpha('--color-sidebar-line'),
divider: alpha('--color-sidebar-divider'),
button: alpha('--color-sidebar-button'),
selected: alpha('--color-sidebar-selected'),
separator: alpha('--color-sidebar-separator')
separator: alpha('--color-sidebar-separator'),
shade: alpha('--color-sidebar-shade')
},
app: {
DEFAULT: alpha('--color-app'),
box: alpha('--color-app-box'),
overlay: alpha('--color-app-overlay'),
input: alpha('--color-app-input'),
border: alpha('--color-app-border'),
focus: alpha('--color-app-focus'),
line: alpha('--color-app-line'),
divider: alpha('--color-app-divider'),
button: alpha('--color-app-button'),
selected: alpha('--color-app-selected'),
separator: alpha('--color-app-separator'),
hover: alpha('--color-app-hover')
hover: alpha('--color-app-hover'),
shade: alpha('--color-app-shade')
}
},
extend: {

View file

@ -525,6 +525,7 @@ importers:
'@radix-ui/react-dialog': ^1.0.0
'@radix-ui/react-dropdown-menu': ^1.0.0
'@radix-ui/react-select': ^1.0.0
'@radix-ui/react-switch': ^1.0.1
'@radix-ui/react-tabs': ^1.0.0
'@sd/assets': workspace:*
'@sd/config': workspace:*
@ -572,6 +573,7 @@ importers:
'@radix-ui/react-dialog': 1.0.2_rj7ozvcq3uehdlnj3cbwzbi5ce
'@radix-ui/react-dropdown-menu': 1.0.0_rj7ozvcq3uehdlnj3cbwzbi5ce
'@radix-ui/react-select': 1.1.1_rj7ozvcq3uehdlnj3cbwzbi5ce
'@radix-ui/react-switch': 1.0.1_biqbaboplfbrettd7655fr4n2y
'@radix-ui/react-tabs': 1.0.1_biqbaboplfbrettd7655fr4n2y
'@sd/assets': link:../assets
'@tailwindcss/forms': 0.5.3_tailwindcss@3.1.8
@ -4168,6 +4170,24 @@ packages:
react: 18.2.0
dev: false
/@radix-ui/react-switch/1.0.1_biqbaboplfbrettd7655fr4n2y:
resolution: {integrity: sha512-tTxGluMtwrc5ffgAiOSMrYIx0r3vSTcgM4Vl8rqfpXcHt6ryB9B0OlFKUOiDpKASXlhvzfHf4Y0AYKJdpzjL8w==}
peerDependencies:
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
dependencies:
'@babel/runtime': 7.19.4
'@radix-ui/primitive': 1.0.0
'@radix-ui/react-compose-refs': 1.0.0_react@18.2.0
'@radix-ui/react-context': 1.0.0_react@18.2.0
'@radix-ui/react-primitive': 1.0.1_biqbaboplfbrettd7655fr4n2y
'@radix-ui/react-use-controllable-state': 1.0.0_react@18.2.0
'@radix-ui/react-use-previous': 1.0.0_react@18.2.0
'@radix-ui/react-use-size': 1.0.0_react@18.2.0
react: 18.2.0
react-dom: 18.2.0_react@18.2.0
dev: false
/@radix-ui/react-tabs/1.0.1_biqbaboplfbrettd7655fr4n2y:
resolution: {integrity: sha512-mVNEwHwgjy2G9F7b39f9VY+jF0QUZykTm0Sdv+Uz6KC4KOEIa4HLDiHU8MeEZluRtZE3aqGYDhl93O7QbJDwhg==}
peerDependencies:
@ -8475,6 +8495,7 @@ packages:
normalize-range: 0.1.2
picocolors: 1.0.0
postcss-value-parser: 4.2.0
dev: false
/autoprefixer/10.4.12_postcss@8.4.18:
resolution: {integrity: sha512-WrCGV9/b97Pa+jtwf5UGaRjgQIg7OK3D06GnoYoZNcG1Xb8Gt3EfuKjlhh9i/VtT16g6PYjZ69jdJ2g8FxSC4Q==}