Skip to content

Commit 9efb877

Browse files
committed
Fix graph centering, update related pages to show only others' pages, improve fullscreen modal, and update unsaved changes styling
- Fixed graph centering issues with stronger center force and proper coordinates - Updated related pages to show 'Related pages by others' and filter out current user's pages - Fixed fullscreen graph modal to render via portal and appear above all UI elements - Changed unsaved changes notice text to green and save icon to check mark - Added mobile slider component for graph settings - Enhanced graph settings with better mobile UX
1 parent 7339c94 commit 9efb877

File tree

9 files changed

+451
-151
lines changed

9 files changed

+451
-151
lines changed

app/api/related-pages/route.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ export async function GET(request: NextRequest) {
5656
const pageTitle = searchParams.get('pageTitle') || '';
5757
const pageContent = searchParams.get('pageContent') || '';
5858
const linkedPageIds = searchParams.get('linkedPageIds')?.split(',').filter(Boolean) || [];
59+
const excludeUsername = searchParams.get('excludeUsername');
5960
const limit = parseInt(searchParams.get('limit') || '10');
6061

6162
if (!pageId) {
@@ -67,6 +68,7 @@ export async function GET(request: NextRequest) {
6768

6869
console.log(`📄 [RELATED_PAGES_API] Finding related pages for ${pageId}`);
6970
console.log(`📄 [RELATED_PAGES_API] Title: "${pageTitle}", Content length: ${pageContent.length}`);
71+
console.log(`📄 [RELATED_PAGES_API] Excluding username: "${excludeUsername || 'none'}"`);
7072

7173
// Extract meaningful words from title and content
7274
const titleWords = extractMeaningfulWords(pageTitle);
@@ -94,8 +96,12 @@ export async function GET(request: NextRequest) {
9496
for (const doc of pagesSnapshot.docs) {
9597
const pageData = doc.data();
9698

97-
// Skip the current page, already linked pages, deleted pages, and pages without titles
98-
if (doc.id === pageId || linkedPageIds.includes(doc.id) || !pageData.title || pageData.deleted) {
99+
// Skip the current page, already linked pages, deleted pages, pages without titles, and excluded username's pages
100+
if (doc.id === pageId ||
101+
linkedPageIds.includes(doc.id) ||
102+
!pageData.title ||
103+
pageData.deleted ||
104+
(excludeUsername && pageData.username === excludeUsername)) {
99105
continue;
100106
}
101107

@@ -127,7 +133,7 @@ export async function GET(request: NextRequest) {
127133
.slice(0, limit)
128134
.map(({ similarity, ...page }) => page); // Remove similarity from final result
129135

130-
console.log(`📄 [RELATED_PAGES_API] Found ${relatedPages.length} related pages`);
136+
console.log(`📄 [RELATED_PAGES_API] Found ${relatedPages.length} related pages (excluding ${excludeUsername ? `pages by ${excludeUsername}` : 'no user filter'})`);
131137

132138
return NextResponse.json({
133139
relatedPages,

app/components/features/RelatedPagesSection.tsx

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
TooltipProvider,
1010
TooltipTrigger
1111
} from "../ui/tooltip";
12+
import { useCurrentAccount } from '../../providers/CurrentAccountProvider';
1213

1314
// Import related pages function with working algorithm
1415
const getRelatedPagesAsync = async (pageId: string, pageTitle: string, pageContent: string, linkedPageIds: string[] = [], limit: number = 10) => {
@@ -106,6 +107,7 @@ export default function RelatedPagesSection({ page, linkedPageIds = [] }: Relate
106107
const [relatedPages, setRelatedPages] = useState<any[]>([]);
107108
const [loading, setLoading] = useState(true);
108109
const [mounted, setMounted] = useState(false);
110+
const { currentAccount } = useCurrentAccount();
109111

110112
// Set mounted state
111113
useEffect(() => {
@@ -138,6 +140,10 @@ export default function RelatedPagesSection({ page, linkedPageIds = [] }: Relate
138140
params.set('linkedPageIds', linkedPageIds.join(','));
139141
}
140142

143+
if (currentAccount?.username) {
144+
params.set('excludeUsername', currentAccount.username);
145+
}
146+
141147
const response = await fetch(`/api/related-pages?${params.toString()}`);
142148

143149
if (!response.ok) {
@@ -155,7 +161,7 @@ export default function RelatedPagesSection({ page, linkedPageIds = [] }: Relate
155161
};
156162

157163
fetchRelatedPages();
158-
}, [page?.id, page?.title, page?.content, linkedPageIds, mounted]);
164+
}, [page?.id, page?.title, page?.content, linkedPageIds, mounted, currentAccount?.username]);
159165

160166
if (!mounted) {
161167
return null;
@@ -169,7 +175,7 @@ export default function RelatedPagesSection({ page, linkedPageIds = [] }: Relate
169175
{/* Header */}
170176
<div className="flex items-center gap-2 mb-4">
171177
<h3 className="text-sm font-medium">
172-
Related Pages
178+
Related pages by others
173179
</h3>
174180
<TooltipProvider>
175181
<Tooltip>
@@ -187,7 +193,7 @@ export default function RelatedPagesSection({ page, linkedPageIds = [] }: Relate
187193
{loading ? (
188194
<div className="flex items-center gap-2 text-sm text-muted-foreground">
189195
<Loader2 className="h-3 w-3 animate-spin" />
190-
<span>Loading related pages...</span>
196+
<span>Loading related pages by others...</span>
191197
</div>
192198
) : relatedPages.length > 0 ? (
193199
<div className="flex flex-wrap gap-2">
@@ -220,7 +226,7 @@ export default function RelatedPagesSection({ page, linkedPageIds = [] }: Relate
220226
</div>
221227
) : (
222228
<div className="text-sm text-muted-foreground">
223-
No related pages found
229+
No related pages by others found
224230
</div>
225231
)}
226232
</div>

app/components/pages/GraphSettingsPanel.tsx

Lines changed: 63 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"use client";
22

33
import React from 'react';
4+
import MobileSlider from '../ui/MobileSlider';
45

56
interface GraphPhysicsSettings {
67
chargeStrength: number;
@@ -23,7 +24,7 @@ interface GraphSettingsPanelProps {
2324
* Physics settings panel for graph visualization
2425
* Used in fullscreen mode to preview changes in real-time
2526
*/
26-
export default function GraphSettingsPanel({
27+
export default function GraphSettingsPanel({
2728
settings = {
2829
chargeStrength: -300,
2930
linkDistance: 100,
@@ -40,8 +41,10 @@ export default function GraphSettingsPanel({
4041
onSettingsChange({ [key]: value });
4142
};
4243

44+
45+
4346
return (
44-
<div className="p-6">
47+
<div className="p-6" style={{ touchAction: 'pan-y' }}>
4548
<div className="flex items-center justify-between mb-6">
4649
<h3 className="text-lg font-semibold">Physics Settings</h3>
4750
<button
@@ -52,108 +55,69 @@ export default function GraphSettingsPanel({
5255
</button>
5356
</div>
5457

55-
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
56-
{/* Charge Strength */}
57-
<div className="space-y-2">
58-
<label className="text-sm font-medium">
59-
Node Repulsion: {settings.chargeStrength}
60-
</label>
61-
<input
62-
type="range"
63-
min="-500"
64-
max="-50"
65-
step="10"
66-
value={settings.chargeStrength}
67-
onChange={(e) => handleSettingChange('chargeStrength', parseInt(e.target.value))}
68-
className="w-full"
69-
/>
70-
<p className="text-xs text-muted-foreground">How strongly nodes push away from each other</p>
71-
</div>
58+
<div className="grid grid-cols-1 md:grid-cols-2 gap-6" style={{ touchAction: 'manipulation' }}>
59+
<MobileSlider
60+
label="Node Repulsion"
61+
value={settings.chargeStrength}
62+
min={-500}
63+
max={-50}
64+
step={10}
65+
onChange={(value) => handleSettingChange('chargeStrength', value)}
66+
description="How strongly nodes push away from each other"
67+
/>
7268

73-
{/* Link Distance */}
74-
<div className="space-y-2">
75-
<label className="text-sm font-medium">
76-
Link Distance: {settings.linkDistance}
77-
</label>
78-
<input
79-
type="range"
80-
min="50"
81-
max="200"
82-
step="10"
83-
value={settings.linkDistance}
84-
onChange={(e) => handleSettingChange('linkDistance', parseInt(e.target.value))}
85-
className="w-full"
86-
/>
87-
<p className="text-xs text-muted-foreground">Preferred distance between connected nodes</p>
88-
</div>
69+
<MobileSlider
70+
label="Link Distance"
71+
value={settings.linkDistance}
72+
min={50}
73+
max={200}
74+
step={10}
75+
onChange={(value) => handleSettingChange('linkDistance', value)}
76+
description="Preferred distance between connected nodes"
77+
/>
8978

90-
{/* Center Strength */}
91-
<div className="space-y-2">
92-
<label className="text-sm font-medium">
93-
Center Pull: {settings.centerStrength.toFixed(2)}
94-
</label>
95-
<input
96-
type="range"
97-
min="0.1"
98-
max="1.0"
99-
step="0.1"
100-
value={settings.centerStrength}
101-
onChange={(e) => handleSettingChange('centerStrength', parseFloat(e.target.value))}
102-
className="w-full"
103-
/>
104-
<p className="text-xs text-muted-foreground">How strongly nodes are pulled to center</p>
105-
</div>
79+
<MobileSlider
80+
label="Center Pull"
81+
value={settings.centerStrength}
82+
min={0.1}
83+
max={1.0}
84+
step={0.1}
85+
onChange={(value) => handleSettingChange('centerStrength', value)}
86+
formatValue={(val) => val.toFixed(2)}
87+
description="How strongly nodes are pulled to center"
88+
/>
10689

107-
{/* Collision Radius */}
108-
<div className="space-y-2">
109-
<label className="text-sm font-medium">
110-
Node Size: {settings.collisionRadius}
111-
</label>
112-
<input
113-
type="range"
114-
min="20"
115-
max="50"
116-
step="2"
117-
value={settings.collisionRadius}
118-
onChange={(e) => handleSettingChange('collisionRadius', parseInt(e.target.value))}
119-
className="w-full"
120-
/>
121-
<p className="text-xs text-muted-foreground">Collision radius around nodes</p>
122-
</div>
90+
<MobileSlider
91+
label="Node Size"
92+
value={settings.collisionRadius}
93+
min={20}
94+
max={50}
95+
step={2}
96+
onChange={(value) => handleSettingChange('collisionRadius', value)}
97+
description="Collision radius around nodes"
98+
/>
12399

124-
{/* Alpha Decay */}
125-
<div className="space-y-2">
126-
<label className="text-sm font-medium">
127-
Simulation Speed: {settings.alphaDecay.toFixed(3)}
128-
</label>
129-
<input
130-
type="range"
131-
min="0.01"
132-
max="0.1"
133-
step="0.005"
134-
value={settings.alphaDecay}
135-
onChange={(e) => handleSettingChange('alphaDecay', parseFloat(e.target.value))}
136-
className="w-full"
137-
/>
138-
<p className="text-xs text-muted-foreground">How quickly the simulation settles</p>
139-
</div>
100+
<MobileSlider
101+
label="Simulation Speed"
102+
value={settings.alphaDecay}
103+
min={0.01}
104+
max={0.1}
105+
step={0.005}
106+
onChange={(value) => handleSettingChange('alphaDecay', value)}
107+
formatValue={(val) => val.toFixed(3)}
108+
description="How quickly the simulation settles"
109+
/>
140110

141-
{/* Velocity Decay */}
142-
<div className="space-y-2">
143-
<label className="text-sm font-medium">
144-
Damping: {settings.velocityDecay.toFixed(2)}
145-
</label>
146-
<input
147-
type="range"
148-
min="0.1"
149-
max="0.9"
150-
step="0.05"
151-
value={settings.velocityDecay}
152-
onChange={(e) => handleSettingChange('velocityDecay', parseFloat(e.target.value))}
153-
className="w-full"
154-
/>
155-
<p className="text-xs text-muted-foreground">How much velocity is retained each frame</p>
156-
</div>
111+
<MobileSlider
112+
label="Damping"
113+
value={settings.velocityDecay}
114+
min={0.1}
115+
max={0.9}
116+
step={0.05}
117+
onChange={(value) => handleSettingChange('velocityDecay', value)}
118+
formatValue={(val) => val.toFixed(2)}
119+
description="How much velocity is retained each frame"
120+
/>
157121
</div>
158122

159123
<div className="mt-6 text-xs text-muted-foreground">

app/components/pages/PageFooter.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import CustomDateField from "./CustomDateField";
88
import LocationField from "./LocationField";
99
import dynamic from "next/dynamic";
1010
import { Button } from "../ui/button";
11-
import { Reply, Save, RotateCcw, Trash2 } from "lucide-react";
11+
import { Reply, Save, RotateCcw, Trash2, Check } from "lucide-react";
1212

1313

1414
// Dynamically import AddToPageButton to avoid SSR issues
@@ -159,7 +159,7 @@ export default function PageFooter({
159159
onClick={onSave}
160160
disabled={isSaving}
161161
>
162-
<Save className="h-5 w-5" />
162+
<Check className="h-5 w-5" />
163163
{isSaving ? "Saving..." : "Save Changes"}
164164
</Button>
165165
<Button
@@ -173,7 +173,7 @@ export default function PageFooter({
173173
Revert Changes
174174
</Button>
175175
</div>
176-
<p className="text-sm text-blue-700 dark:text-blue-300 mt-2 text-center">
176+
<p className="text-sm text-green-700 dark:text-green-300 mt-2 text-center">
177177
You have unsaved changes. Save them or revert to the last saved version.
178178
</p>
179179
</div>

0 commit comments

Comments
 (0)