Skip to content

Commit

Permalink
Responsive Window Dimensions Lock (#665)
Browse files Browse the repository at this point in the history
  • Loading branch information
abhiroopc84 authored Oct 26, 2024
1 parent c14f166 commit 0fd7dac
Show file tree
Hide file tree
Showing 5 changed files with 217 additions and 108 deletions.
24 changes: 14 additions & 10 deletions app/src/components/icons.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import clsx from 'clsx';
import { cn } from '@/lib/utils';
import {
ArrowDownIcon,
ArrowLeftIcon,
Expand All @@ -14,14 +14,15 @@ import {
BoxIcon,
ButtonIcon,
ChatBubbleIcon,
CheckIcon,
CheckCircledIcon,
CheckIcon,
CheckboxIcon,
ChevronDownIcon,
ChevronRightIcon,
ChevronUpIcon,
CircleBackslashIcon,
ClipboardIcon,
ClipboardCopyIcon,
ClipboardIcon,
CodeIcon,
Component1Icon,
ComponentInstanceIcon,
Expand All @@ -35,6 +36,7 @@ import {
Cross1Icon,
Cross2Icon,
CrossCircledIcon,
CursorArrowIcon,
DesktopIcon,
DiscordLogoIcon,
DotsVerticalIcon,
Expand All @@ -49,15 +51,18 @@ import {
GearIcon,
GitHubLogoIcon,
GroupIcon,
HandIcon,
ImageIcon,
InputIcon,
LaptopIcon,
LayersIcon,
Link2Icon,
ListBulletIcon,
LockClosedIcon,
LockOpen1Icon,
MagicWandIcon,
MinusIcon,
MinusCircledIcon,
MinusIcon,
MobileIcon,
MoonIcon,
Pencil1Icon,
Expand All @@ -72,28 +77,25 @@ import {
ScissorsIcon,
SectionIcon,
ShadowIcon,
SquareIcon,
SunIcon,
TextIcon,
TextAlignCenterIcon,
TextAlignLeftIcon,
TextAlignRightIcon,
TextIcon,
TrashIcon,
VideoIcon,
ViewGridIcon,
ViewHorizontalIcon,
ViewVerticalIcon,
CursorArrowIcon,
HandIcon,
SquareIcon,
ChevronUpIcon,
} from '@radix-ui/react-icons';
import clsx from 'clsx';
import H1Icon from './Icons/header-level-icons/h1Icon';
import H2Icon from './Icons/header-level-icons/h2Icon';
import H3Icon from './Icons/header-level-icons/h3Icon';
import H4Icon from './Icons/header-level-icons/h4Icon';
import H5Icon from './Icons/header-level-icons/h5Icon';
import H6Icon from './Icons/header-level-icons/h6Icon';
import { cn } from '@/lib/utils';

export interface IconProps {
className?: string;
Expand Down Expand Up @@ -853,4 +855,6 @@ export const Icons: { [key: string]: React.FC<IconProps> } = {
CursorArrow: CursorArrowIcon,
Hand: HandIcon,
Square: SquareIcon,
LockOpen: LockOpen1Icon,
LockClosed: LockClosedIcon,
};
14 changes: 14 additions & 0 deletions app/src/lib/sizePresets.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { IconProps, Icons } from '@/components/icons';

export interface SizePreset {
name: string;
width: number;
height: number;
icon: React.FC<IconProps>;
}

export const SIZE_PRESETS: SizePreset[] = [
{ name: 'Desktop', width: 1440, height: 1024, icon: Icons.Desktop },
{ name: 'Laptop', width: 1280, height: 832, icon: Icons.Laptop },
{ name: 'Mobile', width: 320, height: 568, icon: Icons.Mobile },
];
104 changes: 65 additions & 39 deletions app/src/routes/editor/WebviewArea/BrowserControl.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { Icons } from '@/components/icons';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import { SIZE_PRESETS, SizePreset } from '@/lib/sizePresets';
import { cn } from '@/lib/utils';
import clsx from 'clsx';
import { useEffect, useState } from 'react';
import { Links } from '/common/constants';
import { Icons } from '@/components/icons';

interface BrowserControlsProps {
webviewRef: React.RefObject<Electron.WebviewTag> | null;
Expand All @@ -17,13 +19,10 @@ interface BrowserControlsProps {
darkmode: boolean;
setDarkmode: React.Dispatch<React.SetStateAction<boolean>>;
onlookEnabled: boolean;
}

interface SizePreset {
name: string;
width: number;
height: number;
icon: React.ReactNode;
selectedPreset: SizePreset | null;
setSelectedPreset: React.Dispatch<React.SetStateAction<SizePreset | null>>;
lockedPreset: SizePreset | null;
setLockedPreset: React.Dispatch<React.SetStateAction<SizePreset | null>>;
}

function BrowserControls({
Expand All @@ -37,17 +36,14 @@ function BrowserControls({
darkmode,
setDarkmode,
onlookEnabled,
selectedPreset,
setSelectedPreset,
lockedPreset,
setLockedPreset,
}: BrowserControlsProps) {
const [urlInputValue, setUrlInputValue] = useState(webviewSrc);
const [selectedPreset, setSelectedPreset] = useState<string>('Desktop');
const [isPopoverOpen, setIsPopoverOpen] = useState(false);

const PRESETS: SizePreset[] = [
{ name: 'Desktop', width: 1440, height: 1024, icon: <Icons.Desktop /> },
{ name: 'Laptop', width: 1280, height: 832, icon: <Icons.Laptop /> },
{ name: 'Mobile', width: 320, height: 568, icon: <Icons.Mobile /> },
];

useEffect(() => {
setUrlInputValue(webviewSrc);
}, [webviewSrc]);
Expand Down Expand Up @@ -115,13 +111,20 @@ function BrowserControls({
webview.executeJavaScript(`window.api?.toggleTheme()`).then((res) => setDarkmode(res));
}

function resizeToPreset(width: number, height: number, presetName: string) {
function resizeToPreset(preset: SizePreset) {
const webview = webviewRef?.current as Electron.WebviewTag | null;
if (webview) {
setWebviewSize({ width, height });
setSelectedPreset(presetName);
setIsPopoverOpen(false);
setWebviewSize({ width: preset.width, height: preset.height });
setSelectedPreset(preset);
}
}

function handlePresetLock(preset: SizePreset | null) {
if (lockedPreset) {
setLockedPreset(null);
return;
}
setLockedPreset(preset);
}

function canGoBack() {
Expand All @@ -140,6 +143,24 @@ function BrowserControls({
}
}

const PresetLockButton = ({ preset }: { preset: SizePreset | null }) => {
return (
<Button
disabled={selectedPreset !== preset}
size={'icon'}
variant={'ghost'}
className={cn(
'absolute right-0 top-1/2 -translate-y-1/2 hover:bg-transparent active:bg-transparent',
!lockedPreset && 'text-foreground-tertiary',
selectedPreset !== preset && 'hidden',
)}
onClick={() => handlePresetLock(preset)}
>
{lockedPreset ? <Icons.LockClosed /> : <Icons.LockOpen />}
</Button>
);
};

return (
<div
className={clsx(
Expand Down Expand Up @@ -192,26 +213,31 @@ function BrowserControls({
Preset Dimensions
</h3>
<div>
{PRESETS.map((preset) => (
<button
key={preset.name}
onClick={() =>
resizeToPreset(preset.width, preset.height, preset.name)
}
className={clsx(
'w-full flex flex-row gap-2 px-3 py-3 transition-colors duration-200 items-center',
selectedPreset === preset.name
? 'bg-background-tertiary text-foreground-primary'
: 'bg-transparent text-foreground-secondary',
'hover:bg-background-tertiary/50 hover:text-foreground-primary',
)}
>
{preset.icon}
<span className="justify-self-start text-smallPlus">
{preset.name}
</span>
<span className="text-foreground-tertiary text-mini">{`${preset.width} × ${preset.height}`}</span>
</button>
{SIZE_PRESETS.map((preset) => (
<div key={preset.name} className="relative">
<button
onClick={() => resizeToPreset(preset)}
className={clsx(
'w-full flex flex-row gap-2 px-3 py-3 transition-colors duration-200 items-center',
selectedPreset === preset
? 'bg-background-tertiary text-foreground-primary'
: 'bg-transparent text-foreground-secondary',
'hover:bg-background-tertiary/50 hover:text-foreground-primary',
{
'cursor-not-allowed':
lockedPreset && lockedPreset !== preset,
},
)}
disabled={!!lockedPreset && lockedPreset !== preset}
>
<preset.icon />
<span className="justify-self-start text-smallPlus">
{preset.name}
</span>
<span className="text-foreground-tertiary text-mini">{`${preset.width} × ${preset.height}`}</span>
</button>
<PresetLockButton preset={preset} />
</div>
))}
</div>
</PopoverContent>
Expand Down
11 changes: 11 additions & 0 deletions app/src/routes/editor/WebviewArea/Frame.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useEditorEngine } from '@/components/Context';
import { Icons } from '@/components/icons';
import { Button } from '@/components/ui/button';
import { WebviewMessageBridge } from '@/lib/editor/messageBridge';
import { SizePreset } from '@/lib/sizePresets';
import clsx from 'clsx';
import { observer } from 'mobx-react-lite';
import { useEffect, useRef, useState } from 'react';
Expand Down Expand Up @@ -33,6 +34,8 @@ const Frame = observer(
const [domFailed, setDomFailed] = useState(false);
const [shouldShowDomFailed, setShouldShowDomFailed] = useState(false);
const [onlookEnabled, setOnlookEnabled] = useState(false);
const [selectedPreset, setSelectedPreset] = useState<SizePreset | null>(null);
const [lockedPreset, setLockedPreset] = useState<SizePreset | null>(null);

const [webviewSize, setWebviewSize] = useState(settings.dimension);
const [webviewSrc, setWebviewSrc] = useState<string>(settings.url);
Expand Down Expand Up @@ -151,12 +154,20 @@ const Frame = observer(
darkmode={darkmode}
setDarkmode={setDarkmode}
onlookEnabled={onlookEnabled}
selectedPreset={selectedPreset}
setSelectedPreset={setSelectedPreset}
lockedPreset={lockedPreset}
setLockedPreset={setLockedPreset}
/>
<div className="relative">
<ResizeHandles
webviewRef={webviewRef}
webviewSize={webviewSize}
setWebviewSize={setWebviewSize}
selectedPreset={selectedPreset}
setSelectedPreset={setSelectedPreset}
lockedPreset={lockedPreset}
setLockedPreset={setLockedPreset}
/>
<webview
id={settings.id}
Expand Down
Loading

0 comments on commit 0fd7dac

Please sign in to comment.