Skip to content

Commit

Permalink
Add Supabase backend (#64)
Browse files Browse the repository at this point in the history
* Add a supabase backend

* Add Discord button

* Update docs
  • Loading branch information
Kitenite authored Jul 16, 2024
1 parent 17368e7 commit 95af0f7
Show file tree
Hide file tree
Showing 29 changed files with 456 additions and 138 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,6 @@ yarn.lock
/test-results/
/playwright-report/
/playwright/.cache/

# Env variables
.env
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ The code for the plugins are under `plugins`.
* [ ] Variables
* [ ] Code Editor

See the [roadmap](readme/ROADMAP.md) for a detailed list of project goals and improvements.
See the [roadmap](https://github.com/onlook-dev/studio/wiki/Road-Map) for a detailed list of project goals and improvements.

See the [open issues](https://github.com/onlook-dev/studio/issues) for a full list of proposed features (and known issues).

Expand Down Expand Up @@ -196,5 +196,5 @@ Distributed under the Apache 2.0 License. See [LICENSE.md](LICENSE.md) for more
[Vite.js]: https://img.shields.io/badge/vite-%23646CFF.svg?logo=vite&logoColor=white
[Vite-url]: https://vitejs.dev/

[product-screenshot]: readme/assets/brand.png
[product-screenshot]: assets/brand.png

2 changes: 2 additions & 0 deletions app/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SUPABASE_API_URL=http://127.0.0.1:54321
SUPABASE_ANON_KEY=
Binary file modified app/bun.lockb
Binary file not shown.
4 changes: 4 additions & 0 deletions app/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,8 @@ export enum MainChannels {
CLOSE_TUNNEL = 'close-tunnel',
}

export enum Links {
DISCORD = 'https://discord.gg/hERDfFZCsH',
}

export const APP_NAME = 'Onlook';
5 changes: 3 additions & 2 deletions app/electron/main/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'dotenv/config';
import { BrowserWindow, app, shell } from 'electron';
import { createRequire } from 'node:module';
import os from 'node:os';
Expand All @@ -10,6 +11,7 @@ const require = createRequire(import.meta.url);
const __dirname = path.dirname(fileURLToPath(import.meta.url));

process.env.APP_ROOT = path.join(__dirname, '../..');
process.env.WEBVIEW_PRELOAD_PATH = path.join(__dirname, '../preload/webview.js');

export const MAIN_DIST = path.join(process.env.APP_ROOT, 'dist-electron');
export const RENDERER_DIST = path.join(process.env.APP_ROOT, 'dist');
Expand All @@ -36,7 +38,6 @@ if (!app.requestSingleInstanceLock()) {

let win: BrowserWindow | null = null;
const preload = path.join(__dirname, '../preload/index.js');
const webviewPreload = path.join(__dirname, '../preload/webview.js');
const indexHtml = path.join(RENDERER_DIST, 'index.html');

function loadWindowContent(win: BrowserWindow) {
Expand Down Expand Up @@ -109,4 +110,4 @@ function listenForAppEvents() {
}

listenForAppEvents();
listenForIpcMessages(webviewPreload);
listenForIpcMessages();
6 changes: 1 addition & 5 deletions app/electron/main/ipcEvents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,9 @@ import { TunnelService } from './tunnel';
import { MainChannels } from '/common/constants';
import { CodeResult, TemplateNode, WriteStyleParams } from '/common/models';

export function listenForIpcMessages(webviewPreload: string) {
export function listenForIpcMessages() {
const tunnelService = new TunnelService();

ipcMain.handle(MainChannels.WEBVIEW_PRELOAD_PATH, () => {
return webviewPreload;
});

ipcMain.handle(MainChannels.OPEN_CODE_BLOCK, (e: Electron.IpcMainInvokeEvent, args) => {
const templateNode = args as TemplateNode;
openInVsCode(templateNode);
Expand Down
19 changes: 12 additions & 7 deletions app/electron/preload/browserview/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,18 @@ import { MainChannels } from '/common/constants';

declare global {
interface Window {
Main: typeof api;
ipcRenderer: typeof ipcRenderer;
api: typeof api;
env: typeof env;
store: typeof store;
}
}

const env = {
WEBVIEW_PRELOAD_PATH: process.env.WEBVIEW_PRELOAD_PATH,
SUPABASE_API_URL: process.env.SUPABASE_API_URL,
SUPABASE_ANON_KEY: process.env.SUPABASE_ANON_KEY,
};

const store = {
get(val: any) {
return ipcRenderer.sendSync('electron-store-get', val);
Expand All @@ -21,8 +28,6 @@ const store = {
};

const api = {
store: store,

sendMessage<T>(channel: MainChannels, args: T[]) {
ipcRenderer.send(channel, args);
},
Expand Down Expand Up @@ -53,6 +58,6 @@ const api = {
},
};

contextBridge.exposeInMainWorld('Main', api);
// WARN: Using the ipcRenderer directly in the browser through the contextBridge is insecure
// contextBridge.exposeInMainWorld('ipcRenderer', ipcRenderer);
contextBridge.exposeInMainWorld('api', api);
contextBridge.exposeInMainWorld('store', store);
contextBridge.exposeInMainWorld('env', env);
2 changes: 2 additions & 0 deletions app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,12 @@
"@radix-ui/react-toast": "^1.2.1",
"@radix-ui/react-toggle": "^1.1.0",
"@radix-ui/react-toggle-group": "^1.1.0",
"@supabase/supabase-js": "^2.44.4",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"css-to-tailwind-translator": "^1.2.8",
"culori": "^4.0.1",
"dotenv": "^16.4.5",
"electron-updater": "^6.1.8",
"fflate": "^0.8.2",
"framer-motion": "^11.2.12",
Expand Down
2 changes: 1 addition & 1 deletion app/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import AppBar from './AppBar';
import AppBar from './components/AppBar';
import { ThemeProvider } from './components/theme-provider';
import ProjectEditor from './routes/project';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FaceIcon } from '@radix-ui/react-icons';
import supabase from '@/lib/backend';
import { useState } from 'react';
import {
AlertDialog,
Expand All @@ -10,26 +10,61 @@ import {
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger,
} from './ui/alert-dialog';
import { Button } from './ui/button';
import { Textarea } from './ui/textarea';
import { ToggleGroup, ToggleGroupItem } from './ui/toggle-group';
} from '../ui/alert-dialog';
import { Button } from '../ui/button';
import { Textarea } from '../ui/textarea';
import { ToggleGroup, ToggleGroupItem } from '../ui/toggle-group';
import { useToast } from '../ui/use-toast';

function FeedbackDialog() {
const [mood, setMood] = useState('');
const [feedback, setFeedback] = useState('');
const [comment, setComment] = useState('');
const [error, setError] = useState('');
const [open, setOpen] = useState(false);
const { toast } = useToast();

function clearContent() {
setMood('');
setComment('');
setError('');
}

async function handleSubmit() {
try {
if (!supabase) {
throw new Error('No backend connected');
}
const { data, error } = await supabase.from('feedback').insert([
{
mood,
comment,
},
]);
if (error) {
throw error.message;
}
setOpen(false);
clearContent();
toast({
title: 'Feedback submitted 🎉',
description: 'Thank you for helping us improve the product!',
});
} catch (error: any) {
console.error('Error submitting feedback:', error);
setError('Error submitting feedback: ' + error.message || error);
}
}
return (
<AlertDialog>
<AlertDialog open={open}>
<AlertDialogTrigger asChild>
<div className="flex mx-2 rounded-sm bg-gradient-to-r p-[1px] from-[#6EE7B7] via-[#3B82F6] to-[#9333EA]">
<div className="flex ml-1 mr-2 rounded-sm bg-gradient-to-r p-[1px] from-[#6EE7B7] via-[#3B82F6] to-[#9333EA]">
<Button
size={'sm'}
variant={'ghost'}
className="h-6 relative bg-black text-white rounded-sm"
onClick={() => setOpen(true)}
>
<FaceIcon className="w-3 h-3 mr-2" />
Give Feedback
Feedback
</Button>
</div>
</AlertDialogTrigger>
Expand Down Expand Up @@ -65,17 +100,20 @@ function FeedbackDialog() {
</ToggleGroup>
<Textarea
placeholder="Write your feedback here"
value={feedback}
onChange={(e) => setFeedback(e.target.value)}
value={comment}
onChange={(e) => setComment(e.target.value)}
></Textarea>
{error && <p className="text-red-500 text-sm text-center">{error}</p>}
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction
disabled={!mood && !feedback}
<AlertDialogCancel
onClick={() => {
console.log({ mood, feedback });
setOpen(false);
setError('');
}}
>
Cancel
</AlertDialogCancel>
<AlertDialogAction disabled={!mood && !comment} onClick={handleSubmit}>
Submit
</AlertDialogAction>
</AlertDialogFooter>
Expand Down
15 changes: 13 additions & 2 deletions app/src/AppBar.tsx → app/src/components/AppBar/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import FeedbackDialog from '@/components/FeedbackDialog';
import { HomeIcon, PlusIcon } from '@radix-ui/react-icons';
import { DiscordLogoIcon, HomeIcon, PlusIcon } from '@radix-ui/react-icons';
import { Button } from '../ui/button';
import FeedbackDialog from './FeedbackDialog';
import { Links } from '/common/constants';

function AppBar() {
const squareClass = `flex items-center justify-center hover:bg-stone-900 h-10 w-12`;
Expand All @@ -17,6 +19,15 @@ function AppBar() {
<PlusIcon />
</button>
<div className="appbar w-full h-full"></div>
<Button
size="sm"
variant="ghost"
onClick={() => {
window.open(Links.DISCORD, '_blank');
}}
>
<DiscordLogoIcon />
</Button>
<FeedbackDialog />
</div>
);
Expand Down
11 changes: 11 additions & 0 deletions app/src/lib/backend/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { createClient } from '@supabase/supabase-js';

let supabase: ReturnType<typeof createClient> | undefined;

try {
supabase = createClient(window.env.SUPABASE_API_URL || '', window.env.SUPABASE_ANON_KEY || '');
} catch (error) {
console.error('Error initializing Supabase:', error);
}

export default supabase;
2 changes: 1 addition & 1 deletion app/src/routes/project/PublishModal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ const PublishModal = observer(() => {

async function writeCodeBlock() {
setLoading(true);
const res = await window.Main.invoke(MainChannels.WRITE_CODE_BLOCK, codeResult);
const res = await window.api.invoke(MainChannels.WRITE_CODE_BLOCK, codeResult);
handleWriteSucceeded();
}

Expand Down
13 changes: 2 additions & 11 deletions app/src/routes/project/WebviewArea/Frame.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { useEffect, useRef, useState } from 'react';
import { useEditorEngine } from '..';
import BrowserControls from './BrowserControl';
import GestureScreen from './GestureScreen';
import { MainChannels } from '/common/constants';

const Webview = observer(
({
Expand All @@ -21,17 +20,15 @@ const Webview = observer(
const [webviewSrc, setWebviewSrc] = useState<string>(metadata.src);
const [selected, setSelected] = useState<boolean>(false);
const [hovered, setHovered] = useState<boolean>(false);
const [webviewPreloadPath, setWebviewPreloadPath] = useState<string>('');
const webviewPreloadPath = window.env.WEBVIEW_PRELOAD_PATH;

useEffect(setupFrame, [webviewRef, webviewPreloadPath]);
useEffect(setupFrame, [webviewRef]);
useEffect(
() => setSelected(editorEngine.webviews.isSelected(metadata.id)),
[editorEngine.webviews.webviews],
);

function setupFrame() {
fetchPreloadPath();

const webview = webviewRef?.current as Electron.WebviewTag | null;
if (!webview) {
return;
Expand Down Expand Up @@ -73,12 +70,6 @@ const Webview = observer(
editorEngine.webviews.setDom(metadata.id, rootNode);
}

function fetchPreloadPath() {
window.Main.invoke(MainChannels.WEBVIEW_PRELOAD_PATH).then((preloadPath: any) => {
setWebviewPreloadPath(preloadPath);
});
}

return (
<div className="flex flex-col space-y-4">
<BrowserControls
Expand Down
File renamed without changes
File renamed without changes.
File renamed without changes
File renamed without changes
28 changes: 28 additions & 0 deletions backend/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
## Why a backend stack?

This is our server stack built in Supabase which you can also run locally or self-host.

Used to enable online capabilities such as managing users, collaborating, persisting data, etc.

We will offer this as a hosted instance at some point. Ideally, the product should still work offline with no backend connection.

## Usage

### Running locally
1. Make sure you have [Docker] installed
2. Install necessary packages

```bash
npm install
```

3. Run the supabase instance locally

```bash
npm run start
```
4. Set up the latest snapshot of the database

```bash
npm run reset
```
Binary file added backend/bun.lockb
Binary file not shown.
19 changes: 19 additions & 0 deletions backend/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "@onlook/backend",
"module": "index.ts",
"type": "module",
"scripts": {
"start": "supabase start",
"stop": "supabase stop",
"push": "supabase db push",
"reset": "supabase db reset",
"generate-types": "supabase gen types typescript --local > types/supabase.ts"
},
"devDependencies": {
"@types/bun": "latest",
"supabase": "^1.183.5"
},
"peerDependencies": {
"typescript": "^5.0.0"
}
}
4 changes: 4 additions & 0 deletions backend/supabase/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Supabase
.branches
.temp
.env
Loading

0 comments on commit 95af0f7

Please sign in to comment.