Skip to content

Commit a325bf7

Browse files
authored
Merge pull request #2 from pythonicode/feat/project-library
Add a project library with named projects stored in IndexedDB
2 parents 3e5a40e + 8e716b6 commit a325bf7

16 files changed

Lines changed: 1077 additions & 408 deletions

‎src/App.css‎

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,153 @@
3939
margin: 0;
4040
}
4141

42+
.topbar-project-name {
43+
min-width: 0;
44+
width: clamp(120px, 18vw, 240px);
45+
padding: 4px 8px;
46+
font: inherit;
47+
font-size: 13px;
48+
color: var(--text-h);
49+
background: transparent;
50+
border: 1px solid transparent;
51+
border-radius: 6px;
52+
text-overflow: ellipsis;
53+
}
54+
55+
.topbar-project-name:hover,
56+
.topbar-project-name:focus {
57+
border-color: var(--border);
58+
background: var(--bg);
59+
outline: none;
60+
}
61+
62+
.modal-projects {
63+
width: min(560px, calc(100vw - 32px));
64+
max-height: min(680px, calc(100vh - 48px));
65+
}
66+
67+
.project-library-body {
68+
overflow-y: auto;
69+
}
70+
71+
.project-library-empty {
72+
margin: 0;
73+
font: 13px var(--mono);
74+
color: var(--text);
75+
}
76+
77+
.project-library-list {
78+
display: flex;
79+
flex-direction: column;
80+
gap: 8px;
81+
margin: 0;
82+
padding: 0;
83+
list-style: none;
84+
}
85+
86+
.project-library-item {
87+
display: flex;
88+
align-items: center;
89+
gap: 8px;
90+
padding: 8px;
91+
border: 1px solid var(--border);
92+
border-radius: 8px;
93+
}
94+
95+
.project-library-item.is-current {
96+
border-color: var(--accent);
97+
}
98+
99+
.project-library-open {
100+
display: flex;
101+
flex: 1;
102+
align-items: center;
103+
gap: 12px;
104+
min-width: 0;
105+
padding: 0;
106+
font: inherit;
107+
color: inherit;
108+
text-align: left;
109+
background: none;
110+
border: 0;
111+
cursor: pointer;
112+
}
113+
114+
.project-library-thumb {
115+
flex-shrink: 0;
116+
width: 64px;
117+
height: 48px;
118+
overflow: hidden;
119+
background: var(--bg);
120+
border: 1px solid var(--border);
121+
border-radius: 4px;
122+
}
123+
124+
.project-library-thumb img {
125+
display: block;
126+
width: 100%;
127+
height: 100%;
128+
object-fit: cover;
129+
}
130+
131+
.project-library-text {
132+
display: flex;
133+
flex-direction: column;
134+
gap: 2px;
135+
min-width: 0;
136+
}
137+
138+
.project-library-name {
139+
font-size: 14px;
140+
font-weight: 600;
141+
line-height: 1.3;
142+
color: var(--text-h);
143+
overflow-wrap: anywhere;
144+
}
145+
146+
.project-library-badge {
147+
display: inline-block;
148+
margin-left: 6px;
149+
padding: 1px 6px;
150+
font-size: 11px;
151+
font-weight: 500;
152+
vertical-align: middle;
153+
color: #fff;
154+
background: var(--accent);
155+
border-radius: 999px;
156+
}
157+
158+
.project-library-meta {
159+
font-size: 12px;
160+
color: var(--text);
161+
}
162+
163+
.project-library-rename {
164+
flex: 1;
165+
min-width: 0;
166+
}
167+
168+
.project-library-rename input {
169+
width: 100%;
170+
padding: 6px 8px;
171+
font: inherit;
172+
color: var(--text-h);
173+
background: var(--bg);
174+
border: 1px solid var(--border);
175+
border-radius: 6px;
176+
}
177+
178+
.project-library-actions {
179+
display: flex;
180+
flex-shrink: 0;
181+
gap: 4px;
182+
}
183+
184+
.button-danger {
185+
color: #b91c1c;
186+
border-color: rgba(225, 29, 72, 0.35);
187+
}
188+
42189
.topbar-actions {
43190
display: flex;
44191
align-items: center;

‎src/App.tsx‎

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,13 @@ import BottomToolBar from './components/BottomToolBar'
88
import TouchHints from './components/TouchHints'
99
import ToastBanner from './components/ToastBanner'
1010
import PwaUpdateBanner from './components/PwaUpdateBanner'
11-
import ReplaceProjectModal from './components/ReplaceProjectModal'
1211
import { useLayoutMode } from './hooks/useLayoutMode'
1312
import { useEffect, useRef } from 'react'
1413
import { useAppStore } from './store'
15-
import { currentProjectHasContent, runProjectOpen } from './utils/project'
1614

1715
function App() {
1816
const layoutMode = useLayoutMode()
1917
const setActiveTool = useAppStore((s) => s.setActiveTool)
20-
const pendingProjectOpen = useAppStore((s) => s.pendingProjectOpen)
21-
const setPendingProjectOpen = useAppStore((s) => s.setPendingProjectOpen)
2218
const prevLayoutRef = useRef(layoutMode)
2319

2420
useEffect(() => {
@@ -49,21 +45,6 @@ function App() {
4945
</div>
5046
{layoutMode === 'touch' && <BottomToolBar />}
5147
<StatusBar layoutMode={layoutMode} />
52-
{pendingProjectOpen && (
53-
<ReplaceProjectModal
54-
layoutMode={layoutMode}
55-
title="Open another project?"
56-
description="Opening a project replaces your current work. Save it first if you want to keep a copy."
57-
confirmLabel="Open project"
58-
canSave={currentProjectHasContent()}
59-
onConfirm={() => {
60-
const request = pendingProjectOpen
61-
setPendingProjectOpen(null)
62-
void runProjectOpen(request)
63-
}}
64-
onClose={() => setPendingProjectOpen(null)}
65-
/>
66-
)}
6748
</div>
6849
)
6950
}

‎src/components/CanvasArea.tsx‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { useAppStore } from '../store'
77
import { stageRef } from '../stageRef'
88
import { simplifyPath } from '../utils/geometry'
99
import { importDroppedFiles, importImageFile } from '../utils/files'
10-
import { requestOpenProject } from '../utils/project'
10+
import { openSampleProject } from '../utils/project'
1111
import type { LayoutMode } from '../hooks/useLayoutMode'
1212
import { usePinchZoom } from '../hooks/usePinchZoom'
1313
import MapImageLayer from './canvas/MapImageLayer'
@@ -517,7 +517,7 @@ export default function CanvasArea({
517517
const handleLoadSample = useCallback(async () => {
518518
setLoadingSample(true)
519519
try {
520-
await requestOpenProject({ kind: 'sample' })
520+
await openSampleProject()
521521
} finally {
522522
setLoadingSample(false)
523523
}

0 commit comments

Comments
 (0)