Skip to content

Commit 40f939d

Browse files
committed
refactor: flatten right sidebar cards, update color system to use solid backgrounds, improve visual hierarchy
- Remove Card/CardHeader/CardTitle wrappers from PagePropertiesCard, ArrowPropertiesCard, and NotePropertiesCard - Replace with unwrapped divs and uppercase micro-labels (text-[10px] tracking-wider) - Add horizontal dividers (bg-border/40 h-px) between property sections - Reduce spacing from space-y-4 to space-y-3 and label gaps from space-y-2 to space-y-1 - Update PageEditorPathCard to use smaller
1 parent 6e8cffc commit 40f939d

14 files changed

Lines changed: 183 additions & 140 deletions

new-deepnotes/apps/web/src/features/pages/PageEditorPathCard.vue

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,8 @@ defineEmits<{
4040

4141
<template>
4242
<Card>
43-
<CardHeader>
44-
<CardTitle class="text-base">Path and prefs</CardTitle>
45-
<CardDescription>
46-
Breadcrumb toward your personal main page, plus starting-page bump and favorites (legacy
47-
<code class="font-mono text-xs">users.pages</code> / <code class="font-mono text-xs">pages.bump</code>).
48-
</CardDescription>
43+
<CardHeader class="pb-2">
44+
<CardTitle class="text-sm">Path</CardTitle>
4945
</CardHeader>
5046
<CardContent class="space-y-3 text-sm">
5147
<p v-if="pathLoading" class="text-muted-foreground">Loading path…</p>

new-deepnotes/apps/web/src/features/pages/PageEditorView.vue

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -813,8 +813,7 @@ onMounted(() => {
813813

814814
<!-- === Right sidebar === -->
815815
<template #right-sidebar>
816-
<div class="space-y-3">
817-
<PagePropertiesCard
816+
<PagePropertiesCard
818817
v-if="!selectedNoteId && !selectedArrowId"
819818
:page-id="pageId"
820819
:relative-title="currentPageRelativeTitle"
@@ -910,7 +909,6 @@ onMounted(() => {
910909

911910
<PageEditorBacklinksCard :page-id="pageId" />
912911
</template>
913-
</div>
914912
</template>
915913

916914
<!-- === Floating overlay === -->

new-deepnotes/apps/web/src/features/pages/PagePropertiesCard.vue

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
<script setup lang="ts">
22
import { computed } from 'vue'
3-
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
43
import { Button } from '@/components/ui/button'
54
import { Input } from '@/components/ui/input'
65
import { Label } from '@/components/ui/label'
@@ -31,14 +30,10 @@ function handleCopyId() {
3130
</script>
3231

3332
<template>
34-
<Card>
35-
<CardHeader class="pb-2">
36-
<CardTitle class="text-sm">Page Properties</CardTitle>
37-
</CardHeader>
38-
<CardContent class="space-y-4 text-xs">
33+
<div class="space-y-3 text-xs">
3934
<!-- Relative Title -->
40-
<div class="space-y-2">
41-
<Label>Relative Title</Label>
35+
<div class="space-y-1">
36+
<Label class="text-[10px] uppercase tracking-wider text-muted-foreground">Relative Title</Label>
4237
<Input
4338
:model-value="relativeTitle"
4439
placeholder="Page title"
@@ -48,9 +43,11 @@ function handleCopyId() {
4843
/>
4944
</div>
5045

46+
<div class="bg-border/40 h-px" />
47+
5148
<!-- Absolute Title -->
52-
<div class="space-y-2">
53-
<Label>Absolute Title</Label>
49+
<div class="space-y-1">
50+
<Label class="text-[10px] uppercase tracking-wider text-muted-foreground">Absolute Title</Label>
5451
<Input
5552
:model-value="absoluteTitle"
5653
placeholder="Full page title"
@@ -60,9 +57,11 @@ function handleCopyId() {
6057
/>
6158
</div>
6259

60+
<div class="bg-border/40 h-px" />
61+
6362
<!-- Page ID -->
64-
<div class="space-y-2">
65-
<Label>Page ID</Label>
63+
<div class="space-y-1">
64+
<Label class="text-[10px] uppercase tracking-wider text-muted-foreground">Page ID</Label>
6665
<div class="flex gap-2">
6766
<Input
6867
:model-value="pageId"
@@ -80,6 +79,8 @@ function handleCopyId() {
8079
</div>
8180
</div>
8281

82+
<div class="bg-border/40 h-px" />
83+
8384
<!-- Copy Link -->
8485
<Button
8586
variant="outline"
@@ -103,6 +104,5 @@ function handleCopyId() {
103104
<Star v-else class="h-3 w-3 mr-2" />
104105
{{ isFavorite ? 'Remove from favorites' : 'Add to favorites' }}
105106
</Button>
106-
</CardContent>
107-
</Card>
107+
</div>
108108
</template>

new-deepnotes/apps/web/src/features/spatial/ArrowPropertiesCard.vue

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
<script setup lang="ts">
22
import { computed } from 'vue'
3-
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
43
import { Button } from '@/components/ui/button'
54
import { Label } from '@/components/ui/label'
65
import { Switch } from '@/components/ui/switch'
@@ -75,14 +74,10 @@ function handleColorSelect(colorName: string) {
7574
</script>
7675

7776
<template>
78-
<Card v-if="arrowId" data-testid="arrow-properties-card">
79-
<CardHeader class="pb-2">
80-
<CardTitle class="text-sm">Arrow Properties</CardTitle>
81-
</CardHeader>
82-
<CardContent class="space-y-4 text-xs">
77+
<div v-if="arrowId" data-testid="arrow-properties-card" class="space-y-3 text-xs">
8378
<!-- Body Type -->
84-
<div class="space-y-2">
85-
<Label>Body Type</Label>
79+
<div class="space-y-1">
80+
<Label class="text-[10px] uppercase tracking-wider text-muted-foreground">Body Type</Label>
8681
<Select
8782
:model-value="bodyType"
8883
:disabled="readOnly"
@@ -98,9 +93,11 @@ function handleColorSelect(colorName: string) {
9893
</Select>
9994
</div>
10095

96+
<div class="bg-border/40 h-px" />
97+
10198
<!-- Arrow Heads -->
102-
<div class="space-y-2">
103-
<Label>Arrow Heads</Label>
99+
<div class="space-y-1">
100+
<Label class="text-[10px] uppercase tracking-wider text-muted-foreground">Arrow Heads</Label>
104101
<div class="flex gap-2">
105102
<div class="flex-1">
106103
<Select
@@ -147,9 +144,11 @@ function handleColorSelect(colorName: string) {
147144
Swap arrowheads
148145
</Button>
149146

147+
<div class="bg-border/40 h-px" />
148+
150149
<!-- Anchors -->
151-
<div class="space-y-2">
152-
<Label>Anchors</Label>
150+
<div class="space-y-1">
151+
<Label class="text-[10px] uppercase tracking-wider text-muted-foreground">Anchors</Label>
153152
<div class="flex gap-2">
154153
<div class="flex-1">
155154
<Select
@@ -186,9 +185,11 @@ function handleColorSelect(colorName: string) {
186185
</div>
187186
</div>
188187

188+
<div class="bg-border/40 h-px" />
189+
189190
<!-- Body Style -->
190-
<div class="space-y-2">
191-
<Label>Body Style</Label>
191+
<div class="space-y-1">
192+
<Label class="text-[10px] uppercase tracking-wider text-muted-foreground">Body Style</Label>
192193
<Select
193194
:model-value="bodyStyle"
194195
:disabled="readOnly"
@@ -205,10 +206,12 @@ function handleColorSelect(colorName: string) {
205206
</Select>
206207
</div>
207208

209+
<div class="bg-border/40 h-px" />
210+
208211
<!-- Color -->
209212
<div class="space-y-2">
210213
<div class="flex items-center justify-between">
211-
<Label>Color</Label>
214+
<Label class="text-[10px] uppercase tracking-wider text-muted-foreground">Color</Label>
212215
<div class="flex items-center gap-2">
213216
<Switch
214217
:model-value="colorInherit"
@@ -230,6 +233,8 @@ function handleColorSelect(colorName: string) {
230233
</div>
231234
</div>
232235

236+
<div class="bg-border/40 h-px" />
237+
233238
<!-- Copy link / Set as default -->
234239
<div class="space-y-2">
235240
<Button
@@ -254,7 +259,7 @@ function handleColorSelect(colorName: string) {
254259
</div>
255260

256261
<!-- Timestamps -->
257-
<div v-if="createdAt || editedAt" class="space-y-1 text-[11px] text-muted-foreground">
262+
<div v-if="createdAt || editedAt" class="space-y-1 rounded-md bg-muted/40 px-2 py-1.5 text-[11px] text-muted-foreground">
258263
<div v-if="createdAt">
259264
<span class="font-medium text-foreground">Created:</span> {{ formatTimestamp(createdAt) }}
260265
</div>
@@ -263,15 +268,16 @@ function handleColorSelect(colorName: string) {
263268
</div>
264269
</div>
265270

271+
<div class="bg-border/40 h-px" />
272+
266273
<!-- Read-only -->
267274
<div class="flex items-center gap-2">
268275
<Switch
269276
:model-value="readOnlyArrow"
270277
:disabled="readOnly"
271278
@update:model-value="emit('update:read-only', Boolean($event))"
272279
/>
273-
<Label>Read-only</Label>
280+
<Label class="text-xs">Read-only</Label>
274281
</div>
275-
</CardContent>
276-
</Card>
282+
</div>
277283
</template>

new-deepnotes/apps/web/src/features/spatial/DisplayArrow.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ describe("DisplayArrow", () => {
176176
const visiblePath = wrapper.findAll('path').find((p) =>
177177
p.attributes('stroke-linecap') === 'round',
178178
);
179-
expect(visiblePath?.attributes('stroke')).toBe('var(--primary)');
179+
expect(visiblePath?.attributes('stroke')).toBe('#2196f3');
180180
});
181181

182182
it("uses arrow color stroke when not selected", () => {
@@ -188,7 +188,7 @@ describe("DisplayArrow", () => {
188188
const visiblePath = wrapper.findAll('path').find((p) =>
189189
p.attributes('stroke-linecap') === 'round',
190190
);
191-
expect(visiblePath?.attributes('stroke')).toBe('#ef4444');
191+
expect(visiblePath?.attributes('stroke')).toBe('#B80909');
192192
});
193193

194194
it("renders target head marker when targetHead is open", () => {

new-deepnotes/apps/web/src/features/spatial/DisplayArrow.vue

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import type { NoteModel } from "./note-model";
55
import NoteTiptapEditor from "./NoteTiptapEditor.vue";
66
import { useNoteHeights } from "./useNoteHeights";
77
import { computeArrowEndpoints } from "./arrow-geometry";
8-
import { resolveNoteColorVariants } from "./color-utils";
8+
import { resolveArrowColor } from "./color-utils";
99
1010
const props = defineProps<{
1111
id: string;
@@ -24,9 +24,8 @@ const emit = defineEmits<{
2424
2525
const labelFragment = computed(() => props.model.label.value);
2626
27-
const colorVariants = computed(() => {
28-
const c = props.model.color.value;
29-
return resolveNoteColorVariants(c ?? "currentColor");
27+
const arrowColor = computed(() => {
28+
return resolveArrowColor(props.model.color.value);
3029
});
3130
3231
const { heights: noteHeights } = useNoteHeights();
@@ -38,6 +37,13 @@ const isLooseTarget = computed(() =>
3837
props.model.looseEndpoint.value === "target" || !props.targetModel,
3938
);
4039
40+
const strokeDasharray = computed(() => {
41+
const style = props.model.bodyStyle.value;
42+
if (style === "dashed") return "8 6";
43+
if (style === "dotted") return "2 4";
44+
return "none";
45+
});
46+
4147
const geometry = computed(() => {
4248
const s = props.sourceModel;
4349
const t = props.targetModel;
@@ -194,7 +200,7 @@ function onPointerDown(e: PointerEvent) {
194200
refY="5"
195201
orient="auto-start-reverse"
196202
>
197-
<path d="M 0 1 L 9 5 L 0 9" fill="none" :stroke="colorVariants.base" stroke-width="1.5" />
203+
<path d="M 0 1 L 9 5 L 0 9" fill="none" :stroke="arrowColor" stroke-width="1.5" />
198204
</marker>
199205
<marker
200206
:id="`arrowhead-source-${model.source.value}-${model.target.value}`"
@@ -204,7 +210,7 @@ function onPointerDown(e: PointerEvent) {
204210
refY="5"
205211
orient="auto-start-reverse"
206212
>
207-
<path d="M 0 1 L 9 5 L 0 9" fill="none" :stroke="colorVariants.base" stroke-width="1.5" />
213+
<path d="M 0 1 L 9 5 L 0 9" fill="none" :stroke="arrowColor" stroke-width="1.5" />
208214
</marker>
209215
</defs>
210216

@@ -222,8 +228,9 @@ function onPointerDown(e: PointerEvent) {
222228
<path
223229
:d="geometry.pathD"
224230
fill="none"
225-
:stroke="selected ? 'var(--primary)' : colorVariants.base"
226-
:stroke-width="selected ? 3 : 2"
231+
:stroke="selected ? '#2196f3' : arrowColor"
232+
:stroke-width="selected ? 4 : 4"
233+
:stroke-dasharray="strokeDasharray"
227234
stroke-linecap="round"
228235
:marker-end="model.targetHead.value ? `url(#arrowhead-target-${model.source.value}-${model.target.value})` : ''"
229236
:marker-start="model.sourceHead.value ? `url(#arrowhead-source-${model.source.value}-${model.target.value})` : ''"
@@ -259,7 +266,7 @@ function onPointerDown(e: PointerEvent) {
259266
:cx="geometry.localX1"
260267
:cy="geometry.localY1"
261268
r="4"
262-
:fill="colorVariants.base"
269+
:fill="arrowColor"
263270
stroke="white"
264271
stroke-width="1.5"
265272
/>
@@ -268,7 +275,7 @@ function onPointerDown(e: PointerEvent) {
268275
:cx="geometry.localX2"
269276
:cy="geometry.localY2"
270277
r="4"
271-
:fill="colorVariants.base"
278+
:fill="arrowColor"
272279
stroke="white"
273280
stroke-width="1.5"
274281
/>
@@ -282,7 +289,7 @@ function onPointerDown(e: PointerEvent) {
282289
height="32"
283290
class="pointer-events-auto"
284291
>
285-
<div class="h-full w-full" @focusin="emit('edit-start')">
292+
<div class="bg-background/90 dark:bg-background/90 h-full w-full rounded px-1 shadow-sm" @focusin="emit('edit-start')">
286293
<NoteTiptapEditor
287294
:fragment="labelFragment"
288295
:editable="!props.model.readOnly.value"

new-deepnotes/apps/web/src/features/spatial/DisplayNote.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -134,12 +134,12 @@ describe("DisplayNote", () => {
134134
const model = createNoteModel(ydoc, "note-1", { colorInherit: true });
135135

136136
wrapper = mount(DisplayNote, {
137-
props: { id: "note-1", model, zoom: 1, parentColor: "#ef4444" },
137+
props: { id: "note-1", model, zoom: 1, parentColor: "#6C1313" },
138138
});
139139

140140
const el = wrapper.find('[data-testid="display-note"]');
141141
const style = el.attributes("style");
142-
expect(style).toContain("border-color: #ef4444");
142+
expect(style).toContain("background-color: #6C1313");
143143
});
144144

145145
it("uses own color when color.inherit is false", () => {
@@ -152,7 +152,7 @@ describe("DisplayNote", () => {
152152

153153
const el = wrapper.find('[data-testid="display-note"]');
154154
const style = el.attributes("style");
155-
expect(style).toContain("border-color: #3b82f6");
155+
expect(style).toContain("background-color: #102C7A");
156156
});
157157

158158
function mockPointerCapture(el: { element: Element }) {

0 commit comments

Comments
 (0)