Skip to content

Commit

Permalink
Select project UI (#369)
Browse files Browse the repository at this point in the history
  • Loading branch information
Kitenite authored Sep 17, 2024
1 parent 91aa5c8 commit 3e15bc8
Show file tree
Hide file tree
Showing 46 changed files with 197 additions and 7 deletions.
Binary file modified app/bun.lockb
Binary file not shown.
2 changes: 2 additions & 0 deletions app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@
"css-to-tailwind-translator": "^1.2.8",
"culori": "^4.0.1",
"electron-updater": "^6.2.1",
"embla-carousel-react": "^8.3.0",
"embla-carousel-wheel-gestures": "^8.0.1",
"fflate": "^0.8.2",
"framer-motion": "^11.2.12",
"js-string-escape": "^1.0.1",
Expand Down
1 change: 1 addition & 0 deletions app/src/lib/routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { sendAnalytics } from '../utils';
export enum Route {
EDITOR = 'editor',
LOGIN = 'login',
PROJECTS = 'projects',
}

export class RouteManager {
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEditorEngine } from '@/routes/project';
import { useEditorEngine } from '@/routes/editor';
import { useEffect } from 'react';
import { HexAlphaColorPicker } from 'react-colorful';
import { Popover } from 'react-tiny-popover';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { formatColorInput, stringToHex } from '@/lib/editor/styles/colors';
import { constructChangeCurried } from '@/lib/editor/styles/inputs';
import { ElementStyle } from '@/lib/editor/styles/models';
import { useEditorEngine } from '@/routes/project';
import { useEditorEngine } from '@/routes/editor';
import { Cross2Icon, PlusIcon } from '@radix-ui/react-icons';
import { observer } from 'mobx-react-lite';
import { useEffect, useState } from 'react';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { constructChangeCurried } from '@/lib/editor/styles/inputs';
import { ElementStyle } from '@/lib/editor/styles/models';
import { parsedValueToString, stringToParsedValue } from '@/lib/editor/styles/numberUnit';
import { appendCssUnit } from '@/lib/editor/styles/units';
import { useEditorEngine } from '@/routes/project';
import { useEditorEngine } from '@/routes/editor';
import { observer } from 'mobx-react-lite';
import React, { useEffect, useState } from 'react';

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
7 changes: 5 additions & 2 deletions app/src/routes/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { useRouteManager } from '@/components/RouteProvider';
import { Route } from '@/lib/routes';
import { observer } from 'mobx-react-lite';
import { useRouteManager } from '../components/RouteProvider';
import ProjectEditor from './editor';
import Login from './login';
import ProjectEditor from './project';
import Projects from './projects';

const Routes = observer(() => {
const routeManager = useRouteManager();
Expand All @@ -12,6 +13,8 @@ const Routes = observer(() => {
return <ProjectEditor />;
case Route.LOGIN:
return <Login />;
case Route.PROJECTS:
return <Projects />;
default:
return <div>404: Unknown route</div>;
}
Expand Down
137 changes: 137 additions & 0 deletions app/src/routes/projects/Carousel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import { ChevronDownIcon, ChevronUpIcon } from '@radix-ui/react-icons';
import useEmblaCarousel from 'embla-carousel-react';
import { WheelGesturesPlugin } from 'embla-carousel-wheel-gestures';
import React, { useCallback, useEffect, useRef, useState } from 'react';

type CarouselProps = {
slides: { id: number; imgSrc: string; title: string }[];
};

const EmblaCarousel: React.FC<CarouselProps> = ({ slides }) => {
const [emblaRef, emblaApi] = useEmblaCarousel(
{
axis: 'y',
loop: false,
align: 'center',
dragFree: false,
skipSnaps: false,
containScroll: 'trimSnaps',
},
[WheelGesturesPlugin()],
);
const [prevBtnEnabled, setPrevBtnEnabled] = useState(false);
const [nextBtnEnabled, setNextBtnEnabled] = useState(false);
const [scrollProgress, setScrollProgress] = useState(0);
const containerRef = useRef<HTMLDivElement>(null);

const scrollPrev = useCallback(() => emblaApi && emblaApi.scrollPrev(), [emblaApi]);
const scrollNext = useCallback(() => emblaApi && emblaApi.scrollNext(), [emblaApi]);

const onSelect = useCallback(() => {
if (!emblaApi) {
return;
}
setPrevBtnEnabled(emblaApi.canScrollPrev());
setNextBtnEnabled(emblaApi.canScrollNext());
}, [emblaApi]);

const onScroll = useCallback(() => {
if (!emblaApi) {
return;
}
const progress = emblaApi.scrollProgress();
setScrollProgress(progress);
}, [emblaApi]);

useEffect(() => {
if (!emblaApi) {
return;
}
onSelect();
onScroll();
emblaApi.on('select', onSelect);
emblaApi.on('scroll', onScroll);
emblaApi.on('reInit', onSelect);
}, [emblaApi, onSelect, onScroll]);

const calculateImageSize = (imageNaturalWidth: number, imageNaturalHeight: number) => {
if (!containerRef.current) {
return { width: 'auto', height: 'auto' };
}

const containerWidth = containerRef.current.clientWidth;
const containerHeight = containerRef.current.clientHeight;
const targetSize = Math.min(containerWidth, containerHeight) * 0.6;

const imageAspectRatio = imageNaturalWidth / imageNaturalHeight;
const containerAspectRatio = containerWidth / containerHeight;

if (imageAspectRatio > containerAspectRatio) {
return { width: targetSize, height: 'auto' };
} else {
return { width: 'auto', height: targetSize };
}
};

return (
<div className="embla relative h-full overflow-hidden" ref={containerRef}>
<div className="embla__viewport h-full" ref={emblaRef}>
<div className="embla__container h-full">
{slides.map((slide) => (
<div
key={slide.id}
className="embla__slide h-full relative flex items-center justify-center"
style={{
flex: '0 0 100%',
minWidth: 0,
}}
>
<img
src={slide.imgSrc}
alt={slide.title}
className="rounded-lg object-contain"
style={{
maxWidth: '60%',
maxHeight: '60%',
}}
onLoad={(e) => {
const img = e.target as HTMLImageElement;
const { width, height } = calculateImageSize(
img.naturalWidth,
img.naturalHeight,
);
img.style.width =
typeof width === 'number' ? `${width}px` : width;
img.style.height =
typeof height === 'number' ? `${height}px` : height;
}}
/>
</div>
))}
</div>
</div>
<div className="embla__buttons absolute left-24 top-1/2 transform -translate-y-1/2 flex flex-col gap-4 z-10">
<button
className="embla__button embla__button--prev"
onClick={scrollPrev}
disabled={!prevBtnEnabled}
>
<ChevronUpIcon
className={`w-8 h-8 ${prevBtnEnabled ? 'text-white' : 'text-gray-400'}`}
/>
</button>
<button
className="embla__button embla__button--next"
onClick={scrollNext}
disabled={!nextBtnEnabled}
>
<ChevronDownIcon
className={`w-8 h-8 ${nextBtnEnabled ? 'text-white' : 'text-gray-400'}`}
/>
</button>
</div>
</div>
);
};

export default EmblaCarousel;
45 changes: 45 additions & 0 deletions app/src/routes/projects/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Button } from '@/components/ui/button';
import { DotsVerticalIcon, Pencil2Icon } from '@radix-ui/react-icons';
import EmblaCarousel from './Carousel';

export default function Projects() {
const slides = [
{ id: 0, imgSrc: 'https://picsum.photos/id/237/200/300', title: '0' },
{ id: 1, imgSrc: 'https://picsum.photos/id/238/300/200', title: '1' },
{ id: 2, imgSrc: 'https://picsum.photos/id/239/500/500', title: '2' },
];

return (
<div className="flex h-[calc(100vh-2.5rem)] w-full relative">
<div className="absolute top-0 w-full h-8 flex justify-center items-center px-32">
<div className="bg-bg h-full w-48"> </div>
<div className="bg-bg mx-auto h-full w-48"> </div>
<div className="bg-bg h-full w-48"> </div>
</div>
<div className="w-3/5 h-full">
<EmblaCarousel slides={slides} />
</div>
<div className="w-2/5 h-full flex flex-col justify-center items-start p-20 gap-4 font-light">
<p className="text-text-active text-4xl ">Airbnb.com</p>
<div className="text-text flex gap-7 text-sm">
<p>Last edited 3 days ago </p>
<p> localhost: 3000</p>
</div>
<div className="flex gap-4">
<Button
size="default"
variant={'outline'}
className="gap-4 bg-bg-active border border-border-active"
>
<Pencil2Icon />
<p> Edit App </p>
</Button>
<Button size="default" variant={'ghost'} className="gap-4">
<DotsVerticalIcon />
<p> Project settings</p>
</Button>
</div>
</div>
</div>
);
}
2 changes: 1 addition & 1 deletion cli/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "onlook",
"description": "The Onlook Command Line Interface",
"version": "0.0.7",
"version": "0.0.8",
"main": "dist/index.js",
"bin": {
"onlook": "dist/index.cjs"
Expand Down
4 changes: 3 additions & 1 deletion cli/src/create/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { exec } from 'child_process';
import * as degit from 'degit';
import * as fs from 'fs';
import ora from 'ora';
import * as path from 'path';
import { promisify } from 'util';
import { NEXT_TEMPLATE_REPO } from './constant';

// @ts-ignore
import degit from 'degit';

const execAsync = promisify(exec);

export async function create(projectName: string) {
Expand Down

0 comments on commit 3e15bc8

Please sign in to comment.