70 |
prev()}
72 | class="i-bxs:chevron-left transition self-center fs-1.6rem hover:color-blu hover:shadow-xl hover:scale-140 cursor-pointer"
73 | />
74 |
91 |
next()}
93 | class="i-bxs:chevron-right transition self-center fs-1.6rem hover:color-blu hover:shadow-xl hover:scale-140 cursor-pointer"
94 | />
95 |
96 |
97 | >
98 | );
99 | };
100 |
101 | const Sortable = (props) => {
102 | const sortable = createSortable(props.item);
103 |
104 | return (
105 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 | );
120 | };
121 |
122 | export const DND = () => {
123 | const [items, setItems] = createSignal([1, 2]);
124 | const [activeItem, setActiveItem] = createSignal(null);
125 | const ids = () => items();
126 |
127 | const onDragStart = ({ draggable }) => setActiveItem(draggable.id);
128 |
129 | const onDragEnd = ({ draggable, droppable }) => {
130 | if (draggable && droppable) {
131 | const currentItems = ids();
132 | const fromIndex = currentItems.indexOf(draggable.id);
133 | const toIndex = currentItems.indexOf(droppable.id);
134 | if (fromIndex !== toIndex) {
135 | const updatedItems = currentItems.slice();
136 | updatedItems.splice(toIndex, 0, ...updatedItems.splice(fromIndex, 1));
137 | setItems(updatedItems);
138 | }
139 | }
140 | setActiveItem(null);
141 | };
142 |
143 | return (
144 |
145 |
146 |
147 |
148 | {(item) => }
149 |
150 |
155 |
156 |
157 |
158 |
159 |
160 |
161 | );
162 | };
163 |
--------------------------------------------------------------------------------
/src/components/passwordInput.tsx:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | import Monkey from "../assets/monkey_surprised.svg";
3 | import MonkeyHappy from "../assets/monkey_happy.svg";
4 | import MonkeyHands from "../assets/monkey_hands.svg";
5 | import { Component, Show } from "solid-js";
6 | import { atom, Atom } from "solid-use";
7 | import { useProfile } from "../contexts/supabase";
8 |
9 | const PasswordInput: Component<{ password: Atom
}> = (props) => {
10 | const showPassword = atom(false);
11 |
12 | return (
13 |
14 |
Password
15 |
props.password(e.currentTarget.value)}
18 | class="input input border-blu/60 focus:border-blu h-48px"
19 | />
20 |
showPassword(!showPassword())} class="cursor-pointer">
21 | {/*
22 | // @ts-ignore */}
23 | }
26 | >
27 | {/*
28 | // @ts-ignore */}
29 |
30 |
31 | {/*
32 | // @ts-ignore */}
33 |
40 |
41 |
42 | );
43 | };
44 |
45 |
46 | export const SecretPhraseInput: Component<{}> = (props) => {
47 | const showPassword = atom(false);
48 | const { secretPhrase } = useProfile();
49 |
50 | return (
51 |
52 |
Secret phrase
53 |
59 |
showPassword(!showPassword())} class="cursor-pointer">
60 | {/*
61 | // @ts-ignore */}
62 | }
65 | >
66 | {/*
67 | // @ts-ignore */}
68 |
69 |
70 | {/*
71 | // @ts-ignore */}
72 |
79 |
80 |
81 | );
82 | };
83 |
84 | export default PasswordInput;
85 |
--------------------------------------------------------------------------------
/src/components/sidebar.tsx:
--------------------------------------------------------------------------------
1 | import { Component, createEffect, For, Show } from "solid-js";
2 |
3 | import Logo from "../assets/logo.svg";
4 | import { Atom, atom } from "solid-use";
5 | import { Link, Navigate, NavLink, useLocation, useNavigate } from "solid-app-router";
6 | import HashAvatar from "./avatar";
7 | import { useProfile } from "../contexts/supabase";
8 |
9 | export const Sidebar: Component<{ toggle: Atom }> = (props) => {
10 | const { secretPhrase, credits } = useProfile();
11 | const hide = atom(true);
12 | const navigate = useNavigate();
13 |
14 |
15 | const handleLogout = () => {
16 | secretPhrase(null);
17 | navigate("/");
18 | };
19 |
20 | createEffect(() => {
21 | if (!props.toggle()) {
22 | setTimeout(() => {
23 | hide(true);
24 | }, 500);
25 | } else {
26 | hide(false);
27 | }
28 | });
29 |
30 | return (
31 |
32 |
33 |
34 |
39 | {/* Logo */}
40 |
41 |
42 |
43 | {/*
44 | // @ts-ignore */}
45 |
46 | OpenDream
47 |
48 |
49 |
50 |
51 | {/* Avatar and username + company */}
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
{credits()}
61 |
62 |
63 |
64 | {/* Sidebar Menu*/}
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 | {/* Logout button */}
73 |
74 |
75 | Logout
76 |
77 |
78 |
79 |
80 | );
81 | };
82 |
83 | const SidebarItem: Component<{ href?: string; title: string; icon: string }> = (props) => {
84 | const isHover = atom(false)
85 |
86 | if (!props.href) {
87 | props.href = props.title.toLowerCase();
88 | }
89 |
90 | return (
91 | isHover(true)}
93 | onMouseLeave={() => isHover(false)}
94 | href={props.href}
95 | class="flex transition pl-2.8rem hover:bg-gradient-to-r hover:from-transparent hover:to-blu/20 fw-500 fs-1.2rem rounded-16px py-1rem min-w-16rem shadow-blue/80 shadow-sm hover:shadow-lg"
96 | activeClass="hover:shadow-none bg-blu/90 color-white"
97 | >
98 |
99 |
100 | {props.title}
101 |
102 |
103 | );
104 | };
105 |
106 | const Hamburger: Component<{open: Atom}> = (props) => {
107 |
108 | const handleClick = () => {
109 | props.open(!props.open());
110 | console.log(props.open());
111 | };
112 |
113 | return (
114 | <>
115 |
131 | >
132 | );
133 | };
134 |
--------------------------------------------------------------------------------
/src/contexts/config.tsx:
--------------------------------------------------------------------------------
1 | import { createContext, useContext } from "solid-js";
2 | import { atom, Atom } from "solid-use";
3 | import { createStore } from "solid-js/store";
4 | import { DiffusionConfig, IOConfig, Job, Result } from "selas/index";
5 |
6 |
7 |
8 | const ConfigContext = createContext<{ioConfig: Atom, diffusionConfig: Atom}>();
9 |
10 | export function ConfigProvider(props) {
11 | const ioConfig = atom({} as IOConfig);
12 | const diffusionConfig = atom({} as DiffusionConfig);
13 |
14 | return {props.children} ;
15 | }
16 |
17 | export const useConfig = () => {
18 | return useContext(ConfigContext);
19 | };
20 |
--------------------------------------------------------------------------------
/src/contexts/data.tsx:
--------------------------------------------------------------------------------
1 | import { createContext, useContext } from "solid-js";
2 | import { Atom } from "solid-use";
3 | import { createStore } from "solid-js/store";
4 | import Dexie, { Table } from "dexie";
5 | import { Job, Result } from "selas/index";
6 | import { createDexieArrayQuery } from "solid-dexie";
7 |
8 | export class ScryprDexie extends Dexie {
9 | results: Table;
10 | jobs: Table;
11 |
12 | constructor() {
13 | super("scrypr");
14 | this.version(1).stores({
15 | results: "++id, job_id, user_id, uri, blurhash, text_data, data_type, created_at",
16 | jobs: "++id, created_at, status, user_id, accepted_at, completed_at, worker_name",
17 | });
18 | }
19 | }
20 |
21 | const DataContext = createContext<{
22 | db: ScryprDexie;
23 | results: Result[];
24 | jobs: Job[];
25 | addResult: (r: Result) => Promise;
26 | addJob: (j: Job) => Promise;
27 | }>();
28 |
29 | export function DataProvider(props) {
30 | const db = new ScryprDexie();
31 |
32 | const results = createDexieArrayQuery(() => db.results.orderBy("created_at").toArray());
33 |
34 | const jobs = createDexieArrayQuery(() => db.jobs.toArray());
35 |
36 | const addResult = async (result: Result) => {
37 | const id = await db.results.add(result);
38 | };
39 |
40 | const addJob = async (job: Job) => {
41 | const id = await db.jobs.add(job);
42 | };
43 |
44 | return {props.children} ;
45 | }
46 |
47 | export const useData = () => {
48 | return useContext(DataContext);
49 | };
50 |
--------------------------------------------------------------------------------
/src/contexts/supabase.tsx:
--------------------------------------------------------------------------------
1 | import { Component, createEffect, JSX } from "solid-js";
2 | import { createContext } from "solid-js";
3 | import type { AuthChangeEvent, Session, SupabaseClient, User } from "@supabase/supabase-js";
4 | import { createRenderEffect, onCleanup, useContext } from "solid-js";
5 | import { Atom, atom } from "solid-use";
6 |
7 | export const SupabaseContext = createContext();
8 |
9 | interface Props {
10 | client: SupabaseClient;
11 | children?: JSX.Element;
12 | }
13 |
14 |
15 | const ProfileContext = createContext<{secretPhrase: Atom, firstConnect: Atom, credits: Atom}>();
16 |
17 | export function ProfileProvider(props) {
18 | const secretPhrase = atom(localStorage.getItem("openDreamSecretPhrase"))
19 | const firstConnect = atom(false);
20 | const credits = atom(0);
21 |
22 |
23 | createEffect(() => {
24 | if (secretPhrase()) {
25 | localStorage.setItem("openDreamSecretPhrase", secretPhrase());
26 | }
27 | else {
28 | localStorage.removeItem("openDreamSecretPhrase");
29 | }
30 | })
31 |
32 |
33 | return (
34 |
35 | {props.children}
36 |
37 | )
38 | }
39 |
40 | export const useProfile = () => { return useContext(ProfileContext); }
41 |
42 |
43 | export const SupabaseProvider: Component = (props) => {
44 | return {props.children} ;
45 | };
46 |
47 | export const createSupabase = () => {
48 | const ctx = useContext(SupabaseContext);
49 |
50 | if (!ctx) throw new Error("createSupabase must be used within a SupabaseContext.Provider");
51 |
52 | return ctx;
53 | };
54 |
55 | export function createSupabaseAuth(): SupabaseClient["auth"] {
56 | const supabase = createSupabase();
57 | return supabase.auth;
58 | }
59 |
60 | export function createSupabaseStorage(): SupabaseClient["storage"] {
61 | const supabase = createSupabase();
62 | return supabase.storage;
63 | }
64 |
65 | export function createSupabaseFrom(): SupabaseClient["from"] {
66 | const supabase = createSupabase();
67 | return supabase.from;
68 | }
69 |
70 | type AuthChangeHandler = (event: AuthChangeEvent, session: Session | null) => void;
71 |
72 | export function createOnAuthStateChange(callback: AuthChangeHandler): void {
73 | const client = createSupabase();
74 |
75 | const { data: authListener } = client.auth.onAuthStateChange((event, session) => {
76 | callback(event, session);
77 | });
78 |
79 | createRenderEffect(() => {
80 | client.auth.getSession().then(({ data }) => {
81 | if (data.session) callback("SIGNED_IN", data.session);
82 | });
83 |
84 | onCleanup(() => {
85 | authListener.subscription?.unsubscribe();
86 | });
87 | });
88 |
89 | }
90 |
91 |
--------------------------------------------------------------------------------
/src/fonts/Dinish-Italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LAION-AI/opendream/14d5b436cbd918f8f5199268c2d43cd1653f4e40/src/fonts/Dinish-Italic.woff
--------------------------------------------------------------------------------
/src/fonts/Dinish-Italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LAION-AI/opendream/14d5b436cbd918f8f5199268c2d43cd1653f4e40/src/fonts/Dinish-Italic.woff2
--------------------------------------------------------------------------------
/src/fonts/Dinish-Regular.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LAION-AI/opendream/14d5b436cbd918f8f5199268c2d43cd1653f4e40/src/fonts/Dinish-Regular.otf
--------------------------------------------------------------------------------
/src/fonts/Dinish-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LAION-AI/opendream/14d5b436cbd918f8f5199268c2d43cd1653f4e40/src/fonts/Dinish-Regular.woff
--------------------------------------------------------------------------------
/src/fonts/Dinish-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LAION-AI/opendream/14d5b436cbd918f8f5199268c2d43cd1653f4e40/src/fonts/Dinish-Regular.woff2
--------------------------------------------------------------------------------
/src/fonts/DinishCondensed-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LAION-AI/opendream/14d5b436cbd918f8f5199268c2d43cd1653f4e40/src/fonts/DinishCondensed-Bold.woff
--------------------------------------------------------------------------------
/src/fonts/DinishCondensed-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LAION-AI/opendream/14d5b436cbd918f8f5199268c2d43cd1653f4e40/src/fonts/DinishCondensed-Bold.woff2
--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
1 | /* @refresh reload */
2 | import { Router } from "solid-app-router";
3 | import { render } from "solid-js/web";
4 |
5 | import "@unocss/reset/tailwind.css";
6 | import "uno.css";
7 |
8 | import App from "./App";
9 |
10 | render(
11 | () => (
12 |
13 |
14 |
15 | ),
16 | document.getElementById("root") as HTMLElement
17 | );
18 |
--------------------------------------------------------------------------------
/src/pages/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "nuxt.isNuxtApp": false
3 | }
--------------------------------------------------------------------------------
/src/pages/hamburger.css:
--------------------------------------------------------------------------------
1 | .menu {
2 | background-color: transparent;
3 | border: none;
4 | cursor: pointer;
5 | display: flex;
6 | padding: 0;
7 | }
8 | .line {
9 | fill: none;
10 | stroke: black;
11 | stroke-width: 6;
12 | transition: stroke-dasharray 600ms cubic-bezier(0.4, 0, 0.2, 1), stroke-dashoffset 600ms cubic-bezier(0.4, 0, 0.2, 1);
13 | }
14 | .line1 {
15 | stroke-dasharray: 60 207;
16 | stroke-width: 6;
17 | }
18 | .line2 {
19 | stroke-dasharray: 60 60;
20 | stroke-width: 6;
21 | }
22 | .line3 {
23 | stroke-dasharray: 60 207;
24 | stroke-width: 6;
25 | }
26 | .opened .line1 {
27 | stroke-dasharray: 90 207;
28 | stroke-dashoffset: -134;
29 | stroke-width: 6;
30 | }
31 | .opened .line2 {
32 | stroke-dasharray: 1 60;
33 | stroke-dashoffset: -30;
34 | stroke-width: 6;
35 | }
36 | .opened .line3 {
37 | stroke-dasharray: 90 207;
38 | stroke-dashoffset: -134;
39 | stroke-width: 6;
40 | }
41 |
--------------------------------------------------------------------------------
/src/pages/landing.tsx:
--------------------------------------------------------------------------------
1 | import { Component, Show } from "solid-js";
2 |
3 | import "./hamburger.css";
4 |
5 | import Logo from "../assets/logo.svg";
6 | import laion_logo from "../assets/laion_logo.png";
7 | import fire from "../assets/fire_emoji.gif";
8 | import blob from "../assets/blob.png";
9 |
10 | import { atom } from "solid-use";
11 | import { Link } from "solid-app-router";
12 | import DropdownAvatar from "../components/dropdown";
13 | import { useProfile } from "../contexts/supabase";
14 | import { AnimationImage } from "../components/animation";
15 | import { SecretPhraseInput } from "../components/passwordInput";
16 |
17 | const Landing: Component<{}> = (props) => {
18 | return (
19 |
20 |
21 |
22 |
23 | );
24 | };
25 |
26 | const Navbar: Component<{}> = (props) => {
27 | return (
28 |
29 |
30 | {/*
31 | //@ts-ignore */}
32 |
33 |
34 | OpenDream
35 |
36 |
37 |
38 |
39 |
40 |
41 | );
42 | };
43 |
44 | const Hamburger: Component<{}> = (props) => {
45 | const open = atom(false);
46 |
47 | const handleClick = () => {
48 | open(!open());
49 | };
50 |
51 | return (
52 | <>
53 |
69 |
70 |
71 |
72 |
73 | Sign In
74 |
75 |
76 | Sign Up
77 |
78 |
79 |
80 |
81 | >
82 | );
83 | };
84 |
85 | const Buttons: Component<{}> = (props) => {
86 | const { secretPhrase } = useProfile();
87 |
88 | return (
89 |
93 |
94 | Go to OpenDream!
95 |
96 |
97 | }
98 | >
99 |
100 |
101 | Log In
102 |
103 |
104 |
105 | );
106 | };
107 |
108 | const Hero: Component<{}> = (props) => {
109 | const { secretPhrase } = useProfile();
110 |
111 | return (
112 |
113 |
114 |
115 |
116 |
117 |
Create without limits
118 |
119 |
120 |
with the Open Source community
121 |
122 |
123 | OpenDream is an image generation tool powered by artificial intelligence. Laion AI is giving this tool to
124 | the public for free in exchange for annotations.
125 |
126 |
127 |
128 |
129 | Start right now
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 | );
141 | };
142 |
143 | export default Landing;
144 |
--------------------------------------------------------------------------------
/src/pages/login.tsx:
--------------------------------------------------------------------------------
1 | import { Link, useNavigate } from "solid-app-router";
2 | import { Component } from "solid-js";
3 | import { atom } from "solid-use";
4 |
5 | import Logo from "../assets/logo.svg";
6 |
7 | import PasswordInput from "../components/passwordInput";
8 | import { createSupabase, useProfile } from "../contexts/supabase";
9 |
10 | const Login: Component<{}> = (props) => {
11 | const supabase = createSupabase();
12 | const password = atom("");
13 | const navigate = useNavigate();
14 | const { secretPhrase, firstConnect, credits } = useProfile();
15 |
16 | const handleSignin = async (e: Event) => {
17 | e.preventDefault();
18 |
19 | const { data, error } = await supabase.rpc("check_credits", {phrase_arg: password()});
20 |
21 | if (error) {
22 | alert(error.message);
23 | }
24 | else if (data===null) {
25 | alert("Invalid secret phrase");
26 | }
27 | else {
28 | secretPhrase(password());
29 | credits(data);
30 | navigate("/space/create");
31 | }
32 |
33 | };
34 |
35 | const handleRegister = async (e: Event) => {
36 | e.preventDefault();
37 | // const { data, error } = await supabase.from("users").insert({}).select();
38 | const { data, error } = await supabase.rpc("create_user");
39 |
40 |
41 | if (error) {
42 | alert(error.message);
43 | } else {
44 | secretPhrase(data);
45 | firstConnect(true);
46 | navigate("/space/create");
47 | }
48 | };
49 |
50 | return (
51 |
52 |
53 |
54 | {/*
55 | // @ts-ignore */}
56 |
57 |
58 |
Login to OpenDream
59 |
67 |
68 |
83 |
84 | );
85 | };
86 |
87 | export default Login;
88 |
--------------------------------------------------------------------------------
/src/pages/recovery.tsx:
--------------------------------------------------------------------------------
1 | import { Component } from "solid-js";
2 |
3 |
4 | const Recovery: Component<{}> = (props) => {
5 |
6 | return
;
7 | };
8 |
9 | export default Recovery;
--------------------------------------------------------------------------------
/src/pages/space/annotation.tsx:
--------------------------------------------------------------------------------
1 | import { Component, For, Show } from "solid-js";
2 | import { atom, Atom } from "solid-use";
3 |
4 | const Annotation: Component<{}> = (props) => {
5 | const currentRating = atom(null);
6 | const showHistory = atom(false);
7 |
8 | return (
9 |
10 |
11 |
Annotation
12 |
13 | Please annotate the aesthetic rating of the image below on a scale from 1 to 10, where 1 is the least
14 | aesthetic and 10 is the most aesthetic.
15 |
16 |
17 | {/* History button */}
18 |
showHistory(!showHistory())}>
19 |
24 |
25 |
26 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | {(item) => }
51 |
52 |
53 |
Submit
54 |
55 | {/*
*/}
56 |
57 | );
58 | };
59 |
60 | const HistoricBar: Component<{}> = (props) => {
61 | return (
62 |
63 |
66 |
67 |
Annotation History
68 |
69 |
70 | );
71 | };
72 |
73 | const RatingButton: Component<{ number: number; currentRating: Atom
}> = (props) => {
74 | return (
75 | props.currentRating(props.number)}
82 | >
83 | {props.number}
84 |
85 | );
86 | };
87 |
88 | export default Annotation;
89 |
--------------------------------------------------------------------------------
/src/pages/space/create.tsx:
--------------------------------------------------------------------------------
1 | import { Component, createEffect, For, onMount, Show, Suspense } from "solid-js";
2 | import { createSelasClient, Job, Result, TextPrompt } from "selas";
3 | import { Atom, atom } from "solid-use";
4 | import { useData } from "../../contexts/data";
5 | import { createMemo } from "solid-js";
6 | import { createDexieArrayQuery } from "solid-dexie";
7 | import { DND } from "../../components/options";
8 | import { useConfig } from "../../contexts/config";
9 |
10 | const Create: Component<{}> = (props) => {
11 | const selas = createSelasClient();
12 | const { jobs, results, addJob, addResult } = useData();
13 |
14 | return (
15 |
22 | );
23 | };
24 |
25 | const SimplePrompt: Component<{ prompt: Atom }> = (props) => {
26 | const { diffusionConfig } = useConfig();
27 | const { jobs, results, addJob, addResult } = useData();
28 | const selas = createSelasClient();
29 | const prompt = atom("A cute calico cat in the grass on a beautiful day, artstation, storybook art");
30 |
31 | const handleNewResult = async (payload) => {
32 | const result: Result = payload.new;
33 | await addResult(result);
34 | };
35 |
36 | onMount(async () => {
37 | const selasEmail = import.meta.env.VITE_SELAS_EMAIL;
38 | const selasPassword = import.meta.env.VITE_SELAS_PASSWORD;
39 | await selas.signIn(selasEmail, selasPassword);
40 | });
41 |
42 |
43 |
44 | const submitJob = async (e: Event) => {
45 | e.preventDefault();
46 | const {diffusionConfig} = useConfig();
47 |
48 | const postJob = async () => {
49 | const currentConfig = diffusionConfig();
50 |
51 | const { data: job } = await selas.postJob({diffusion: currentConfig});
52 |
53 | await addJob(job);
54 | await selas.subscribeToResults(job.id, handleNewResult);
55 | };
56 |
57 | for (let i = 0; i < parseInt("1"); i++) postJob();
58 | };
59 |
60 | return (
61 |
62 |
63 |
64 | Write a detailed description of the image you want
65 |
66 |
67 |
78 |
79 |
80 | );
81 | };
82 |
83 | const AdvancedOptions: Component<{}> = (props) => {
84 | const show = atom(true);
85 |
86 | return (
87 |
88 |
show(!show())}
90 | class="flex items-center gap-0.4rem color-blue/90 font-mono fs-0.8rem cursor-pointer mb-1.4rem"
91 | >
92 |
93 |
advanced options
94 |
95 |
96 |
97 |
98 |
99 |
100 | );
101 | };
102 |
103 | const InitImageOptions: Component = () => {
104 | return (
105 |
106 |
Starting Image
107 |
108 |
109 |
110 | );
111 | };
112 |
113 | const FormatOptions: Component<{}> = (props) => {
114 | return (
115 |
116 |
117 |
Image
118 | {/* WIDTH */}
119 |
120 |
121 |
width
122 |
123 |
127 | 512
128 |
129 |
133 | 768
134 |
135 |
136 |
137 | {/* HEIGHT */}
138 |
139 |
height
140 |
141 |
145 | 512
146 |
147 |
151 | 768
152 |
153 |
154 |
155 | {/* IMAGE FORMAT */}
156 | {/*
*/}
157 |
158 |
159 |
160 | );
161 | };
162 |
163 | const JobOptions: Component<{ batchSize: Atom; jobNumber: Atom }> = (props) => {
164 | return (
165 |
166 |
167 |
Job
168 |
169 | {/* BATCH SIZE */}
170 |
174 | {/* Job SIZE */}
175 |
176 |
Number of Jobs
177 |
178 |
179 |
180 |
181 |
182 | );
183 | };
184 |
185 | const CircleNav: Component<{ value: Atom }> = (props) => {
186 | const currentDigit = props.value;
187 |
188 | const Circle = (props: { digit: string; currentDigit: Atom; final?: boolean }) => {
189 | const isActive = createMemo(() => props.digit <= props.currentDigit());
190 |
191 | return (
192 | {
195 | props.currentDigit(props.digit);
196 | }}
197 | >
198 |
199 |
202 |
203 |
210 | }
211 | >
212 |
216 | {props.digit}
217 |
218 |
219 |
220 | );
221 | };
222 |
223 | return (
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 | );
233 | };
234 |
235 | const SelectExtension: Component<{ extension: Atom }> = (props) => {
236 | return (
237 |
238 |
239 | {" "}
240 | Change published status{" "}
241 |
242 |
243 |
244 |
245 |
246 |
253 |
258 |
259 |
Published
260 |
261 |
268 | Change published status
269 |
276 |
281 |
282 |
283 |
284 |
285 |
286 |
293 |
294 |
295 |
296 |
Published
297 |
298 |
305 |
310 |
311 |
312 |
313 |
This job posting can be viewed by anyone who has the link.
314 |
315 |
316 |
317 |
318 |
319 | );
320 | };
321 |
322 | const ResultGallery: Component = (props) => {
323 | const { results } = useData();
324 |
325 | return (
326 |
327 |
328 | {(result) => }
329 |
330 |
331 | );
332 | };
333 |
334 | const ResultCard: Component<{ result: Result }> = (props) => {
335 | const { db } = useData();
336 |
337 | const job = createDexieArrayQuery(() => db.jobs.where("id").equals(props.result.job_id).toArray());
338 |
339 | return (
340 |
341 |
342 |
343 |
347 |
348 |
349 |
354 | {/*
355 | //@ts-ignore */}
356 |
{job[0].config.diffusion.prompts[0].text}
357 |
358 |
{job[0].config.diffusion.steps} steps
359 |
360 |
361 |
362 |
{job[0].job_cost}
363 |
364 | {/*
365 | //@ts-ignore */}
366 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 | );
380 | };
381 |
382 | const JobCard: Component<{ job: Job }> = (props) => {
383 | return ;
384 | };
385 |
386 | export default Create;
387 |
--------------------------------------------------------------------------------
/src/pages/space/gallery.tsx:
--------------------------------------------------------------------------------
1 | import { Component } from "solid-js";
2 |
3 | const Gallery: Component<{}> = (props) => {
4 |
5 | return
;
6 | };
7 |
8 | export default Gallery;
--------------------------------------------------------------------------------
/src/pages/space/horde.tsx:
--------------------------------------------------------------------------------
1 | import { Component, For } from "solid-js";
2 | import { atom, Atom } from "solid-use";
3 |
4 | const Horde: Component<{}> = (props) => {
5 |
6 | return (
7 |
8 |
Coming from the Horde?
9 |
10 | Configure your horde settings below. That way you can have kudos and credits automatically transferred to your account.
11 |
12 |
13 | );
14 | };
15 |
16 |
17 |
18 | export default Horde;
19 |
--------------------------------------------------------------------------------
/src/shims.d.ts:
--------------------------------------------------------------------------------
1 | import { AttributifyAttributes } from "@unocss/preset-attributify";
2 |
3 | declare module "solid-js" {
4 | namespace JSX {
5 | interface HTMLAttributes extends AttributifyAttributes {}
6 | interface AnchorHTMLAttributes extends AttributifyAttributes {}
7 | }
8 | }
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": false,
4 | "target": "ESNext",
5 | "module": "ESNext",
6 | "moduleResolution": "node",
7 | "allowSyntheticDefaultImports": true,
8 | "esModuleInterop": true,
9 | "jsx": "preserve",
10 | "jsxImportSource": "solid-js",
11 | "types": ["vite/client"],
12 | "noEmit": true,
13 | "isolatedModules": true
14 | }
15 | }
--------------------------------------------------------------------------------
/unocss.config.ts:
--------------------------------------------------------------------------------
1 | import presetAttributify from "@unocss/preset-attributify";
2 | import presetIcons from "@unocss/preset-icons";
3 | import presetUno from "@unocss/preset-uno";
4 | import presetTagify from "@unocss/preset-tagify";
5 | import presetWindi from "@unocss/preset-wind";
6 | import presetWebFonts from "@unocss/preset-web-fonts";
7 | import { presetForms } from "@julr/unocss-preset-forms";
8 | import { presetScalpel } from "unocss-preset-scalpel";
9 | import { presetExtra } from "unocss-preset-extra";
10 | import { presetScrollbar } from "unocss-preset-scrollbar";
11 | import { defineConfig, presetTypography, transformerDirectives, transformerVariantGroup } from "unocss";
12 | import { presetBetterNestedColors } from "unocss-preset-better-nested-colors";
13 |
14 | export default defineConfig({
15 | presets: [
16 | presetUno(),
17 | presetAttributify(),
18 | presetWindi(),
19 | presetTagify(),
20 | presetScalpel(),
21 | presetForms(),
22 | presetTypography(),
23 | presetExtra(),
24 | presetScrollbar(), // @ts-ignore
25 | presetIcons({
26 | extraProperties: {
27 | display: "inline-block",
28 | "vertical-align": "middle",
29 | },
30 | }),
31 | ],
32 | transformers: [transformerDirectives(), transformerVariantGroup()],
33 | theme: {
34 | colors: {
35 | green: "#00E94F",
36 | pink: "#E08AF4",
37 | teal: "#00D1B0",
38 | blue: "#1D374E",
39 | blu: "#1D374E",
40 | },
41 | },
42 | shortcuts: [
43 | {
44 | input:
45 | "w-full border-radius-4px focus:ring-0 border-2px border-overlay0/25 px-0.8rem py-0.6rem mt-0.1rem bg-base/20",
46 | btn: "inline-flex items-center rounded-md border border-transparent px-6 py-3 text-base font-medium text-white shadow-sm hover:bg-blue/80 focus:outline-none focus:ring-2 focus:ring-blue focus:ring-offset-2",
47 | sexybar:
48 | "scrollbar scrollbar-thumb-color-overlay2/30 scrollbar-track-color-overlay0/30 scrollbar-rounded scrollbar-w-8px scrollbar-radius-4px scrollbar-track-radius-4",
49 | },
50 | ],
51 | rules: [
52 | [
53 | /^text-(.*)$/,
54 | ([, c], { theme }) => {
55 | // @ts-ignore
56 | if (theme.colors[c])
57 | // @ts-ignore
58 | return { color: theme.colors[c] };
59 | },
60 | ],
61 | ],
62 | });
63 |
--------------------------------------------------------------------------------
/vercel.json:
--------------------------------------------------------------------------------
1 | {
2 | "routes": [
3 | {
4 | "handle": "filesystem"
5 | },
6 | {
7 | "src": "^(?!\\/api).*",
8 | "dest": "/"
9 | }
10 | ],
11 | "build": {
12 | "env": {
13 | "ENABLE_VC_BUILD": "1"
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite';
2 | import solidPlugin from 'vite-plugin-solid';
3 | import Unocss from 'unocss/vite';
4 | import solidSvg from "vite-plugin-solid-svg";
5 |
6 | import unoConfig from './unocss.config'
7 |
8 |
9 | export default defineConfig({
10 | plugins: [
11 | solidPlugin(),
12 | solidSvg(),
13 | Unocss(unoConfig)
14 | ],
15 | optimizeDeps: {
16 | extensions: ['jsx'],
17 | }
18 | });
19 |
20 |
--------------------------------------------------------------------------------