fix (kind of) app ordering in dock

This commit is contained in:
dr-frmr 2024-07-29 17:04:38 +03:00
parent b5aeac5b1a
commit 6f646712c8
No known key found for this signature in database
5 changed files with 86 additions and 50 deletions

View File

@ -121,6 +121,7 @@ fn init(our: Address) {
bind_http_path("/apps", true, false).expect("failed to bind /apps");
bind_http_path("/favorite", true, false).expect("failed to bind /favorite");
bind_http_path("/order", true, false).expect("failed to bind /order");
loop {
let Ok(ref message) = await_message() else {
@ -200,8 +201,6 @@ fn init(our: Address) {
);
continue;
};
// POST of a list of package names.
// go through the list and update each app in app_data to have the index of its name in the list as its order
let Some(body) = get_blob() else {
send_response(
StatusCode::BAD_REQUEST,
@ -211,7 +210,7 @@ fn init(our: Address) {
continue;
};
let Ok(favorite_toggle) =
serde_json::from_slice::<(String, u32, bool)>(&body.bytes)
serde_json::from_slice::<(String, bool)>(&body.bytes)
else {
send_response(
StatusCode::BAD_REQUEST,
@ -221,8 +220,7 @@ fn init(our: Address) {
continue;
};
if let Some(app) = app_data.get_mut(&favorite_toggle.0) {
app.order = favorite_toggle.1;
app.favorite = favorite_toggle.2;
app.favorite = favorite_toggle.1;
}
send_response(
StatusCode::OK,
@ -233,6 +231,40 @@ fn init(our: Address) {
vec![],
);
}
"/order" => {
let Ok(Method::POST) = incoming.method() else {
send_response(
StatusCode::BAD_REQUEST,
Some(HashMap::new()),
vec![],
);
continue;
};
let Some(body) = get_blob() else {
send_response(
StatusCode::BAD_REQUEST,
Some(HashMap::new()),
vec![],
);
continue;
};
let Ok(order_list) =
serde_json::from_slice::<Vec<(String, u32)>>(&body.bytes)
else {
send_response(
StatusCode::BAD_REQUEST,
Some(HashMap::new()),
vec![],
);
continue;
};
for (app_id, order) in order_list {
if let Some(app) = app_data.get_mut(&app_id) {
app.order = order;
}
}
send_response(StatusCode::OK, Some(HashMap::new()), vec![]);
}
_ => {
send_response(StatusCode::NOT_FOUND, Some(HashMap::new()), vec![]);
}

View File

@ -26,9 +26,9 @@ const AppDisplay: React.FC<AppDisplayProps> = ({ app }) => {
{app?.path && isHovered && <button className="app-fave-button"
onClick={(e) => {
e.preventDefault()
fetch(`/favorite`, {
fetch('/favorite', {
method: 'POST',
body: JSON.stringify([app?.id, app?.order, !app?.favorite])
body: JSON.stringify([app?.id, !app?.favorite])
}).then(() => {
fetch('/apps', { credentials: 'include' }).then(res => res.json()).catch(() => [])
.then(setApps)

View File

@ -1,55 +1,52 @@
import useHomepageStore, { HomepageApp } from "../store/homepageStore"
import usePersistentStore from "../store/persistentStore"
import AppDisplay from "./AppDisplay"
import { useEffect, useState } from "react"
import { DragDropContext, Draggable, DropResult, Droppable } from '@hello-pangea/dnd'
const AppsDock: React.FC = () => {
const { apps, setApps } = useHomepageStore()
const { apps } = useHomepageStore()
const { appOrder, setAppOrder } = usePersistentStore()
const [dockedApps, setDockedApps] = useState<HomepageApp[]>([])
useEffect(() => {
const orderedApps = apps
.filter(a => a.favorite)
.sort((a, b) => (a.order - b.order))
// Sort apps based on persisted order
const orderedApps = apps.filter(app => app.favorite).sort((a, b) => {
return appOrder.indexOf(a.id) - appOrder.indexOf(b.id);
});
setDockedApps(orderedApps);
setDockedApps(orderedApps)
}, [apps])
// a little function to help us with reordering the result
const reorder = (list: HomepageApp[], startIndex: number, endIndex: number) => {
const result = Array.from(list);
const [removed] = result.splice(startIndex, 1);
result.splice(endIndex, 0, removed);
removed.order = endIndex
return removed;
};
const onDragEnd = (result: DropResult) => {
// dropped outside the list
if (!result.destination) {
return;
}
const app = reorder(
dockedApps,
result.source.index,
result.destination.index
);
fetch('/favorite', {
// Sync the order with the backend
fetch('/order', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
credentials: 'include',
body: JSON.stringify([app.id, app.order, app.favorite])
})
.catch(e => console.error(e))
.then(() => {
fetch('/apps', { credentials: 'include' }).then(res => res.json()).catch(() => [])
.then(setApps)
body: JSON.stringify(orderedApps.map(app => [app.id, appOrder.indexOf(app.id)]))
});
}, [apps, appOrder])
const onDragEnd = (result: DropResult) => {
if (!result.destination) {
return;
}
const reorderedApps = Array.from(dockedApps);
const [reorderedItem] = reorderedApps.splice(result.source.index, 1);
reorderedApps.splice(result.destination.index, 0, reorderedItem);
const newAppOrder = reorderedApps.map(app => app.id);
setAppOrder(newAppOrder);
setDockedApps(reorderedApps);
fetch('/order', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
credentials: 'include',
body: JSON.stringify(reorderedApps.map((app, index) => [app.id, index]))
});
}
@ -60,10 +57,10 @@ const AppsDock: React.FC = () => {
ref={provided.innerRef}
{...provided.droppableProps}
>
{dockedApps.map(app => <Draggable
{dockedApps.map((app, index) => <Draggable
key={app.id}
draggableId={app.id}
index={dockedApps.indexOf(app)}
index={index}
>
{(provided, _snapshot) => (
<div

View File

@ -21,9 +21,13 @@ header h1 {
font-style: italic;
}
@media (prefers-color-scheme: light) {
.kino-bird {
filter: light-dark(invert(1), invert(0));
filter: invert(1);
}
}
@media (prefers-color-scheme: dark) {}
[data-rfd-droppable-context-id] {
display: flex;
@ -34,7 +38,6 @@ header h1 {
background-color: #4f000085;
padding: 10px;
border-radius: 10px;
width: fit-content;
margin: 0 auto;
margin-bottom: 10px;
}

View File

@ -13,6 +13,8 @@ export interface PersistentStore {
setWidgetSettings: (widgetSettings: PersistentStore['widgetSettings']) => void
toggleWidgetVisibility: (package_id: string) => void
setWidgetSize: (package_id: string, size: 'small' | 'large') => void,
appOrder: string[]
setAppOrder: (appOrder: string[]) => void
}
const usePersistentStore = create<PersistentStore>()(
@ -46,6 +48,8 @@ const usePersistentStore = create<PersistentStore>()(
}
})
},
appOrder: [],
setAppOrder: (appOrder: string[]) => set({ appOrder }),
}),
{
name: 'homepage_persistent_store', // unique name for the store