Skip to content

Commit 3b5d462

Browse files
committed
New Project Dialogue
1 parent 2df722b commit 3b5d462

File tree

6 files changed

+223
-31
lines changed

6 files changed

+223
-31
lines changed

src/App.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { AppWindow } from "./components/AppWindow";
22
import { Hero } from "./components/Hero";
3+
import { NewProject } from "./components/NewProject";
34
import { Projects } from "./components/Projects";
45

56
export function App() {
@@ -8,6 +9,7 @@ export function App() {
89
<AppWindow>
910
<Hero />
1011
<Projects />
12+
<NewProject />
1113
</AppWindow>
1214
</div>
1315
</>);

src/components/Actions/index.tsx

Lines changed: 6 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,21 @@
11
import { useCallback, useEffect, useState } from "react";
22
import { GitPullRequestArrow, Plus } from "lucide-react";
33

4-
import type { ProjectData } from "../../defs/ProjectData";
5-
6-
import { generateId } from "../../utils/generatorTools";
74
import {
85
checkUpdates,
9-
getData,
10-
openProject,
11-
storeData,
126
updateTools,
137
} from "../../utils/desktopTools";
148

159
import "./style.css";
1610

1711
export function Actions() {
1812
const [updatesAvailable, setUpdatesAvailable] = useState(false);
19-
const openNewProject = useCallback(() => {
20-
const projectId = generateId();
21-
22-
const newProject: ProjectData = {
23-
id: projectId,
24-
name: `Project ${projectId.toUpperCase()}`,
25-
};
2613

27-
(async () => {
28-
const launcherData = await getData();
29-
if (!launcherData) return;
30-
31-
const newLauncherData = {
32-
...launcherData,
33-
projects: [
34-
newProject,
35-
...launcherData.projects,
36-
]
37-
};
38-
39-
await storeData(JSON.stringify(newLauncherData));
40-
await openProject(projectId);
41-
42-
location.reload();
43-
})();
14+
const scrollNewProject = useCallback(() => {
15+
document.getElementById("new-project")?.scrollIntoView({
16+
behavior: "smooth",
17+
block: "end",
18+
});
4419
}, []);
4520

4621
const startUpdate = useCallback(() => {
@@ -71,7 +46,7 @@ export function Actions() {
7146

7247
return (<>
7348
<div className="actions">
74-
<button className="action" onClick={openNewProject}>
49+
<button className="action" onClick={scrollNewProject}>
7550
<Plus className="action-icon" />
7651
<span className="action-name">
7752
New Project

src/components/Input/index.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import type { InputHTMLAttributes } from "react";
2+
import "./style.css";
3+
4+
export function Input({
5+
updateValue,
6+
...props
7+
}: {
8+
updateValue: (value: string) => void;
9+
} & InputHTMLAttributes<HTMLInputElement>) {
10+
return (<>
11+
<input
12+
className="input"
13+
onInput={(event) => {
14+
const target = event.target as HTMLInputElement;
15+
updateValue(target.value);
16+
}}
17+
{...props}
18+
/>
19+
</>);
20+
}
21+

src/components/Input/style.css

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
.input-button,
2+
.input {
3+
height: 2.5rem;
4+
padding: 0.5rem;
5+
border: none;
6+
border-radius: 0.5rem;
7+
outline: none;
8+
background: #ffffff11;
9+
color: #ffffff;
10+
font-weight: 300;
11+
}
12+
13+
.input {
14+
width: 100%;
15+
font-size: 0.75rem;
16+
cursor: text;
17+
}
18+
19+
.input-button {
20+
cursor: pointer;
21+
padding: 0.5rem 1.5rem;
22+
}
23+
24+
.input-button:disabled {
25+
opacity: 0.5;
26+
cursor: not-allowed;
27+
}
28+
29+
.input:hover,
30+
.input-button:not(:disabled):hover {
31+
background: #ffffff22;
32+
}
33+
34+
.input:focus {
35+
background: #ffffff33;
36+
}
37+
38+
.input-button:not(:disabled):active {
39+
scale: 0.5;
40+
}
41+
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import { useCallback, useState } from "react";
2+
import { ChevronUp } from "lucide-react";
3+
4+
import type { ProjectData } from "../../defs/ProjectData";
5+
6+
import {
7+
getData,
8+
openProject,
9+
storeData,
10+
} from "../../utils/desktopTools";
11+
12+
import { Input } from "../Input";
13+
14+
import "./style.css";
15+
16+
export function NewProject() {
17+
const [projectData, setProjectData] = useState<ProjectData>({
18+
id: "",
19+
name: "",
20+
});
21+
22+
const scrollUp = useCallback(() => {
23+
document.getElementById("hero")?.scrollIntoView({
24+
behavior: "smooth",
25+
block: "end",
26+
});
27+
}, []);
28+
29+
const openNewProject = useCallback(() => {
30+
(async () => {
31+
const launcherData = await getData();
32+
if (!launcherData) return;
33+
34+
const newLauncherData = {
35+
...launcherData,
36+
projects: [
37+
projectData,
38+
...launcherData.projects,
39+
]
40+
};
41+
42+
await storeData(JSON.stringify(newLauncherData));
43+
await openProject(projectData.id);
44+
45+
scrollUp();
46+
})();
47+
}, [projectData, scrollUp]);
48+
49+
const updateValueGenerator = useCallback((key: string) => {
50+
return (value: string) => {
51+
setProjectData((prevData) => ({
52+
...prevData,
53+
[key]: value,
54+
}));
55+
};
56+
}, []);
57+
58+
return (<>
59+
<div id="new-project" className="new-project">
60+
<button className="new-project-scroll" onClick={scrollUp}>
61+
<ChevronUp className="new-project-scroll-icon" />
62+
63+
<span className="new-project-scroll-text">
64+
Welcome Screen
65+
</span>
66+
67+
<ChevronUp className="new-project-scroll-icon" />
68+
</button>
69+
70+
<div className="new-project-inputs">
71+
<Input
72+
updateValue={updateValueGenerator("id")}
73+
placeholder="Project ID"
74+
/>
75+
76+
<Input
77+
updateValue={updateValueGenerator("name")}
78+
placeholder="Project Name"
79+
/>
80+
81+
<button
82+
className="input-button"
83+
onClick={openNewProject}
84+
disabled={!(!!projectData.id && !!projectData.name)}
85+
>
86+
Create Project
87+
</button>
88+
</div>
89+
</div>
90+
</>);
91+
}
92+
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
.new-project {
2+
width: 100%;
3+
min-height: 100%;
4+
height: 100%;
5+
position: relative;
6+
display: flex;
7+
flex-direction: column;
8+
align-items: center;
9+
justify-content: start;
10+
pointer-events: none;
11+
}
12+
13+
.new-project > * {
14+
pointer-events: auto;
15+
}
16+
17+
.new-project-scroll {
18+
position: absolute;
19+
top: 1rem;
20+
padding: 0.5rem 1rem;
21+
border: none;
22+
border-radius: 1rem;
23+
outline: none;
24+
background: var(--color-black);
25+
cursor: pointer;
26+
opacity: 0.5;
27+
display: flex;
28+
align-items: center;
29+
justify-content: center;
30+
gap: 0.25rem;
31+
z-index: 10;
32+
}
33+
34+
.new-project-scroll:hover {
35+
opacity: 1;
36+
}
37+
38+
.new-project-scroll:active {
39+
scale: 0.5;
40+
}
41+
42+
.new-project-scroll-icon {
43+
height: 1rem;
44+
width: 1rem;
45+
}
46+
47+
.new-project-inputs {
48+
width: 100%;
49+
padding: 2rem;
50+
padding-top: 4rem;
51+
display: flex;
52+
flex-direction: column;
53+
gap: 1rem;
54+
align-items: center;
55+
pointer-events: none;
56+
}
57+
58+
.new-project-inputs > * {
59+
pointer-events: all;
60+
}
61+

0 commit comments

Comments
 (0)