generated from Dicken/dickendock
round70: Icons ruckeln nicht mehr nach - Raster wartet auf alle Datenquellen bevor es rendert
This commit is contained in:
@@ -235,6 +235,14 @@ export interface MobileAndroidHomeProps {
|
||||
onToggleFavorite: (item: SearchResult) => void;
|
||||
onAddReadLater: (url: string) => void;
|
||||
isOnline: boolean;
|
||||
/**
|
||||
* Wird erst true, wenn ALLE für das Raster nötigen Daten (Dienste,
|
||||
* Lesezeichen, Kategorien, Zuletzt-besucht, Einstellungen/Layout)
|
||||
* mindestens einmal geladen sind - siehe Kommentar in HomePage.tsx. Bis
|
||||
* dahin wird ein einfacher Platzhalter statt des Rasters gezeigt, damit
|
||||
* nicht einzelne Kacheln nacheinander "nachrücken".
|
||||
*/
|
||||
isReady: boolean;
|
||||
}
|
||||
|
||||
export function MobileAndroidHome({
|
||||
@@ -249,6 +257,7 @@ export function MobileAndroidHome({
|
||||
onToggleFavorite,
|
||||
onAddReadLater,
|
||||
isOnline,
|
||||
isReady,
|
||||
}: MobileAndroidHomeProps) {
|
||||
const [searchOpen, setSearchOpen] = useState(false);
|
||||
const [query, setQuery] = useState("");
|
||||
@@ -537,46 +546,63 @@ export function MobileAndroidHome({
|
||||
|
||||
{/* Haupt-Raster */}
|
||||
<div data-drop-area="grid" className="min-h-[40vh] px-4 pb-32 pt-2">
|
||||
<div className="grid grid-cols-4 gap-x-3 gap-y-5">
|
||||
{recentVisits.length > 0 ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setOpenFolderId("__recent__")}
|
||||
className="flex flex-col items-center gap-1.5"
|
||||
>
|
||||
<span
|
||||
className="flex h-14 w-14 items-center justify-center rounded-[20px] bg-white/60 text-black/50
|
||||
shadow-[0_2px_10px_rgba(0,0,0,0.18)] ring-1 ring-white/40 backdrop-blur-sm
|
||||
dark:bg-white/10 dark:text-white/50 dark:ring-white/10"
|
||||
>
|
||||
<FontAwesomeIcon icon={faClockRotateLeft} />
|
||||
</span>
|
||||
<span className="line-clamp-2 w-full text-center text-[11px] leading-tight text-black/70 dark:text-white/70">
|
||||
Zuletzt besucht
|
||||
</span>
|
||||
</button>
|
||||
) : null}
|
||||
<button type="button" onClick={() => setOpenFolderId("__readlater__")} className="flex flex-col items-center gap-1.5">
|
||||
<span
|
||||
className="flex h-14 w-14 items-center justify-center rounded-[20px] bg-white/60 text-black/50
|
||||
shadow-[0_2px_10px_rgba(0,0,0,0.18)] ring-1 ring-white/40 backdrop-blur-sm
|
||||
dark:bg-white/10 dark:text-white/50 dark:ring-white/10"
|
||||
>
|
||||
<FontAwesomeIcon icon={faBookmark} />
|
||||
</span>
|
||||
<span className="line-clamp-2 w-full text-center text-[11px] leading-tight text-black/70 dark:text-white/70">
|
||||
Später lesen
|
||||
</span>
|
||||
</button>
|
||||
{isReady ? (
|
||||
<>
|
||||
<div className="grid grid-cols-4 gap-x-3 gap-y-5">
|
||||
{recentVisits.length > 0 ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setOpenFolderId("__recent__")}
|
||||
className="flex flex-col items-center gap-1.5"
|
||||
>
|
||||
<span
|
||||
className="flex h-14 w-14 items-center justify-center rounded-[20px] bg-white/60 text-black/50
|
||||
shadow-[0_2px_10px_rgba(0,0,0,0.18)] ring-1 ring-white/40 backdrop-blur-sm
|
||||
dark:bg-white/10 dark:text-white/50 dark:ring-white/10"
|
||||
>
|
||||
<FontAwesomeIcon icon={faClockRotateLeft} />
|
||||
</span>
|
||||
<span className="line-clamp-2 w-full text-center text-[11px] leading-tight text-black/70 dark:text-white/70">
|
||||
Zuletzt besucht
|
||||
</span>
|
||||
</button>
|
||||
) : null}
|
||||
<button type="button" onClick={() => setOpenFolderId("__readlater__")} className="flex flex-col items-center gap-1.5">
|
||||
<span
|
||||
className="flex h-14 w-14 items-center justify-center rounded-[20px] bg-white/60 text-black/50
|
||||
shadow-[0_2px_10px_rgba(0,0,0,0.18)] ring-1 ring-white/40 backdrop-blur-sm
|
||||
dark:bg-white/10 dark:text-white/50 dark:ring-white/10"
|
||||
>
|
||||
<FontAwesomeIcon icon={faBookmark} />
|
||||
</span>
|
||||
<span className="line-clamp-2 w-full text-center text-[11px] leading-tight text-black/70 dark:text-white/70">
|
||||
Später lesen
|
||||
</span>
|
||||
</button>
|
||||
|
||||
{layout.grid.map((slot) => renderTile(slot, "grid"))}
|
||||
</div>
|
||||
{layout.grid.map((slot) => renderTile(slot, "grid"))}
|
||||
</div>
|
||||
|
||||
{layout.grid.length === 0 ? (
|
||||
<p className="mt-8 text-center text-sm text-black/40 dark:text-white/40">
|
||||
Markiere Dienste/Lesezeichen im Adminbereich als Favorit – sie erscheinen dann hier.
|
||||
</p>
|
||||
) : null}
|
||||
{layout.grid.length === 0 ? (
|
||||
<p className="mt-8 text-center text-sm text-black/40 dark:text-white/40">
|
||||
Markiere Dienste/Lesezeichen im Adminbereich als Favorit – sie erscheinen dann hier.
|
||||
</p>
|
||||
) : null}
|
||||
</>
|
||||
) : (
|
||||
// Platzhalter statt des Rasters, solange noch nicht ALLE nötigen
|
||||
// Daten da sind (siehe isReady-Kommentar an der Prop weiter oben) -
|
||||
// verhindert, dass z. B. "Zuletzt besucht" erst nachträglich
|
||||
// auftaucht und alle Icons danach verschiebt (siehe Bugreport).
|
||||
<div className="grid grid-cols-4 gap-x-3 gap-y-5" aria-hidden="true">
|
||||
{Array.from({ length: 8 }).map((_, i) => (
|
||||
<div key={i} className="flex flex-col items-center gap-1.5">
|
||||
<div className="h-14 w-14 animate-pulse rounded-[20px] bg-black/10 dark:bg-white/10" />
|
||||
<div className="h-2.5 w-10 animate-pulse rounded bg-black/10 dark:bg-white/10" />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Dock */}
|
||||
@@ -588,7 +614,9 @@ export function MobileAndroidHome({
|
||||
className="flex min-h-[4.5rem] min-w-[5rem] items-center gap-3 rounded-[28px] border border-white/40
|
||||
bg-white/70 px-4 py-3 shadow-xl backdrop-blur-xl dark:border-white/10 dark:bg-neutral-900/70"
|
||||
>
|
||||
{layout.dock.length === 0 ? (
|
||||
{!isReady ? (
|
||||
<div className="h-9 w-9 animate-pulse rounded-xl bg-black/10 dark:bg-white/10" aria-hidden="true" />
|
||||
) : layout.dock.length === 0 ? (
|
||||
<span className="px-2 text-xs text-black/30 dark:text-white/30">Icon hierher ziehen zum Anheften</span>
|
||||
) : (
|
||||
layout.dock.map((slot) => renderTile(slot, "dock", "small"))
|
||||
|
||||
@@ -128,9 +128,9 @@ export function HomePage() {
|
||||
const { data: services, isLoading: servicesLoading, isError: servicesError } = useServices();
|
||||
const { data: bookmarks, isLoading: bookmarksLoading } = useBookmarks();
|
||||
const { data: devices } = useDevices();
|
||||
const { data: settings } = useSettings();
|
||||
const { data: categories } = useCategories();
|
||||
const { data: recentVisits } = useRecentVisits();
|
||||
const { data: settings, isLoading: settingsLoading } = useSettings();
|
||||
const { data: categories, isLoading: categoriesLoading } = useCategories();
|
||||
const { data: recentVisits, isLoading: recentVisitsLoading } = useRecentVisits();
|
||||
const { data: readLaterItems } = useReadLater();
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const searchContainerRef = useRef<HTMLDivElement>(null);
|
||||
@@ -334,6 +334,17 @@ export function HomePage() {
|
||||
}, [settings?.mobileHomeStyle]);
|
||||
const effectiveMobileHomeStyle = settings?.mobileHomeStyle ?? cachedMobileHomeStyle ?? "classic";
|
||||
const useAndroidHome = isMobile && effectiveMobileHomeStyle === "android";
|
||||
// WICHTIG: Dienste/Lesezeichen/Kategorien/"Zuletzt besucht"/Einstellungen
|
||||
// laden über getrennte, unabhängig voneinander abgeschlossene
|
||||
// Netzwerk-Anfragen - kämen sie einzeln nacheinander im Raster an, würde
|
||||
// z. B. die "Zuletzt besucht"-Kachel nachträglich auftauchen und alle
|
||||
// Icons danach verschieben (genau das im Bugreport beschriebene
|
||||
// "Verschieben, weil manche Icons schneller da sind als andere"). Daher
|
||||
// wird das komplette Raster erst gerendert, wenn ALLE beteiligten
|
||||
// Abfragen mindestens einmal durch sind - dann in einem Rutsch, ohne
|
||||
// Nachrücken einzelner Kacheln.
|
||||
const androidHomeDataReady =
|
||||
!servicesLoading && !bookmarksLoading && !categoriesLoading && !recentVisitsLoading && !settingsLoading;
|
||||
|
||||
const addReadLaterMutation = useMutation({
|
||||
mutationFn: (url: string) => saveReadLaterRequest(url),
|
||||
@@ -354,6 +365,7 @@ export function HomePage() {
|
||||
onToggleFavorite={(item) => toggleFavorite.mutate(item)}
|
||||
onAddReadLater={(url) => addReadLaterMutation.mutate(url)}
|
||||
isOnline={isOnline}
|
||||
isReady={androidHomeDataReady}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user