From 17486be77136c35a980ab77d530c199ee04c9213 Mon Sep 17 00:00:00 2001 From: dr-frmr Date: Fri, 20 Sep 2024 15:39:26 -0400 Subject: [PATCH 01/19] fixes: give widgets bottom margin for full visibility, fix widget drag-and-drop! --- .../app_store/app_store/src/http_api.rs | 1 + .../homepage/ui/src/components/Widgets.tsx | 92 ++++++++++--------- kinode/packages/homepage/ui/src/index.css | 33 +++---- .../homepage/ui/src/pages/Homepage.tsx | 29 +++--- kinode/packages/kino_updates/blog/src/lib.rs | 1 + 5 files changed, 79 insertions(+), 77 deletions(-) diff --git a/kinode/packages/app_store/app_store/src/http_api.rs b/kinode/packages/app_store/app_store/src/http_api.rs index 157dffe5..7a625bc7 100644 --- a/kinode/packages/app_store/app_store/src/http_api.rs +++ b/kinode/packages/app_store/app_store/src/http_api.rs @@ -77,6 +77,7 @@ fn make_widget() -> String { body { overflow: hidden; background: transparent; + margin-bottom: 30px; } #latest-apps { diff --git a/kinode/packages/homepage/ui/src/components/Widgets.tsx b/kinode/packages/homepage/ui/src/components/Widgets.tsx index 1877b332..4445b59c 100644 --- a/kinode/packages/homepage/ui/src/components/Widgets.tsx +++ b/kinode/packages/homepage/ui/src/components/Widgets.tsx @@ -1,7 +1,6 @@ import useHomepageStore, { HomepageApp } from "../store/homepageStore" import Widget from "./Widget" import usePersistentStore from "../store/persistentStore" -import { DragDropContext, Draggable, DropResult, Droppable } from '@hello-pangea/dnd' import { useEffect, useState } from "react" const Widgets = () => { @@ -9,6 +8,9 @@ const Widgets = () => { const { widgetSettings, widgetOrder, setWidgetOrder } = usePersistentStore(); const [orderedWidgets, setOrderedWidgets] = useState([]); + const [draggedIndex, setDraggedIndex] = useState(null); + const [dragOverIndex, setDragOverIndex] = useState(null); + useEffect(() => { const visibleWidgets = apps.filter((app) => app.widget && !widgetSettings[app.id]?.hide); const orderedVisibleWidgets = visibleWidgets.sort((a, b) => { @@ -17,51 +19,59 @@ const Widgets = () => { setOrderedWidgets(orderedVisibleWidgets); }, [apps, widgetSettings, widgetOrder]); - const onDragEnd = (result: DropResult) => { - if (!result.destination) { - return; - } + const handleDragStart = (e: React.DragEvent, index: number) => { + e.dataTransfer.setData("text/plain", index.toString()); + setDraggedIndex(index); + }; - const reorderedWidgets = Array.from(orderedWidgets); - const [reorderedItem] = reorderedWidgets.splice(result.source.index, 1); - reorderedWidgets.splice(result.destination.index, 0, reorderedItem); + const handleDragOver = (e: React.DragEvent, index: number) => { + e.preventDefault(); + setDragOverIndex(index); + }; - const newWidgetOrder = reorderedWidgets.map(widget => widget.id); + const handleDragEnd = () => { + setDraggedIndex(null); + setDragOverIndex(null); + }; + + const handleDrop = (e: React.DragEvent, dropIndex: number) => { + e.preventDefault(); + const dragIndex = parseInt(e.dataTransfer.getData("text/plain"), 10); + if (dragIndex === dropIndex) return; + + const newSortedWidgets = [...orderedWidgets]; + const [movedWidget] = newSortedWidgets.splice(dragIndex, 1); + newSortedWidgets.splice(dropIndex, 0, movedWidget); + + const newWidgetOrder = newSortedWidgets.map((wid) => wid.id); setWidgetOrder(newWidgetOrder); - setOrderedWidgets(reorderedWidgets); - } + handleDragEnd(); + }; return ( - - - {(provided, _snapshot) => ( -
- {orderedWidgets.map((app, index) => ( - - {(provided, _snapshot) => ( -
- -
- )} -
- ))} - {provided.placeholder} -
- )} -
-
+
+ {orderedWidgets.map((wid, index) => ( +
handleDragStart(e, index)} + onDragOver={(e) => handleDragOver(e, index)} + onDragEnd={handleDragEnd} + onDrop={(e) => handleDrop(e, index)} + className={`widget-wrapper ${draggedIndex === index ? "dragging" : "" + } ${dragOverIndex === index ? "drag-over" : ""}`} + > + +
⋮⋮
+
+ ))} +
); } diff --git a/kinode/packages/homepage/ui/src/index.css b/kinode/packages/homepage/ui/src/index.css index ec11d6de..feac298b 100644 --- a/kinode/packages/homepage/ui/src/index.css +++ b/kinode/packages/homepage/ui/src/index.css @@ -62,13 +62,6 @@ header button { margin-left: 4px; } -#widgets-header { - color: light-dark(var(--off-white), var(--tasteful-dark)); - border-color: light-dark(var(--off-white), var(--tasteful-dark)); - padding: 1em 0em 1em 0em; - border-bottom: 1px solid light-dark(var(--tasteful-dark), var(--off-white)); -} - @media (prefers-color-scheme: light) { .kino-bird { filter: invert(1); @@ -77,19 +70,6 @@ header button { @media (prefers-color-scheme: dark) {} -[data-rfd-droppable-context-id] { - display: flex; - flex-direction: row; - flex-wrap: wrap; - gap: 10px; - justify-content: center; - background-color: light-dark(#4f000055, var(--tasteful-dark)); - padding: 10px; - border-radius: 10px; - margin: 0 auto; - margin-bottom: 10px; -} - .no-ui { position: absolute; bottom: 0; @@ -111,6 +91,7 @@ header button { } #widgets { + margin-top: 1em; width: 100%; display: flex; flex-direction: row; @@ -302,10 +283,19 @@ footer { transition: transform 0.2s ease; } +.widget-wrapper { + position: relative; + transition: transform 0.2s ease; +} + .app-wrapper:hover .drag-handle { opacity: 1; } +.widget-wrapper:hover .drag-handle { + opacity: 1; +} + .drag-handle { position: absolute; top: 5px; @@ -313,6 +303,9 @@ footer { cursor: move; opacity: 0; transition: opacity 0.2s ease; + color: var(--white); + font-size: 1.2em; + text-shadow: -1px 1px 0px #000; } .dragging { diff --git a/kinode/packages/homepage/ui/src/pages/Homepage.tsx b/kinode/packages/homepage/ui/src/pages/Homepage.tsx index 6f17c040..96c53237 100644 --- a/kinode/packages/homepage/ui/src/pages/Homepage.tsx +++ b/kinode/packages/homepage/ui/src/pages/Homepage.tsx @@ -48,10 +48,10 @@ function Homepage() { {new Date().getHours() < 4 ? "Good evening" : new Date().getHours() < 12 - ? "Good morning" - : new Date().getHours() < 18 - ? "Good afternoon" - : "Good evening"} + ? "Good morning" + : new Date().getHours() < 18 + ? "Good afternoon" + : "Good evening"} , {our} [kinode v{version}] + { + e.preventDefault(); + setShowWidgetsSettings(true); + }} + > + [⚙] +