Enhancement: apply layout settings to bookmarks (#1902)

* Apply layout settings to bookmarks

* merge columnMap const

* Remove bookmarksOnTop setting

---------

Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com>
pull/1905/head^2
Georges-Antoine Assi 9 months ago committed by GitHub
parent 4d55f1fba4
commit 9529553102
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -16,4 +16,4 @@
} }
} }
] ]
} }

@ -5,44 +5,64 @@ import { MdKeyboardArrowDown } from "react-icons/md";
import ErrorBoundary from "components/errorboundry"; import ErrorBoundary from "components/errorboundry";
import List from "components/bookmarks/list"; import List from "components/bookmarks/list";
import ResolvedIcon from "components/resolvedicon";
export default function BookmarksGroup({ group, disableCollapse }) { export default function BookmarksGroup({ bookmarks, layout, disableCollapse }) {
const panel = useRef(); const panel = useRef();
return ( return (
<div key={group.name} className="flex-1"> <div
<Disclosure defaultOpen> key={bookmarks.name}
{({ open }) => ( className={classNames(
<> layout?.style === "row" ? "basis-full" : "basis-full md:basis-1/4 lg:basis-1/5 xl:basis-1/6",
<Disclosure.Button disabled={disableCollapse} className="flex w-full select-none items-center group"> layout?.header === false ? "flex-1 px-1 -my-1" : "flex-1 p-1"
<h2 className="text-theme-800 dark:text-theme-300 text-xl font-medium">{group.name}</h2> )}
<MdKeyboardArrowDown className={classNames( >
disableCollapse ? 'hidden' : '', <Disclosure defaultOpen>
'transition-all opacity-0 group-hover:opacity-100 ml-auto text-theme-800 dark:text-theme-300 text-xl', {({ open }) => (
open ? '' : 'rotate-180' <>
)} /> {layout?.header !== false && (
</Disclosure.Button> <Disclosure.Button disabled={disableCollapse} className="flex w-full select-none items-center group">
<Transition {layout?.icon && (
// Otherwise the transition group does display: none and cancels animation <div className="flex-shrink-0 mr-2 w-7 h-7">
className="!block" <ResolvedIcon icon={layout.icon} />
unmount={false} </div>
beforeLeave={() => { )}
panel.current.style.height = `${panel.current.scrollHeight}px`; <h2 className="text-theme-800 dark:text-theme-300 text-xl font-medium">{bookmarks.name}</h2>
setTimeout(() => {panel.current.style.height = `0`}, 1); <MdKeyboardArrowDown
}} className={classNames(
beforeEnter={() => { disableCollapse ? "hidden" : "",
panel.current.style.height = `0px`; "transition-all opacity-0 group-hover:opacity-100 ml-auto text-theme-800 dark:text-theme-300 text-xl",
setTimeout(() => {panel.current.style.height = `${panel.current.scrollHeight}px`}, 1); open ? "" : "rotate-180"
}} )}
> />
<Disclosure.Panel className="transition-all overflow-hidden duration-300 ease-out" ref={panel} static> </Disclosure.Button>
<ErrorBoundary> )}
<List bookmarks={group.bookmarks} /> <Transition
</ErrorBoundary> // Otherwise the transition group does display: none and cancels animation
</Disclosure.Panel> className="!block"
</Transition> unmount={false}
</> beforeLeave={() => {
)} panel.current.style.height = `${panel.current.scrollHeight}px`;
</Disclosure> setTimeout(() => {
panel.current.style.height = `0`;
}, 1);
}}
beforeEnter={() => {
panel.current.style.height = `0px`;
setTimeout(() => {
panel.current.style.height = `${panel.current.scrollHeight}px`;
}, 1);
}}
>
<Disclosure.Panel className="transition-all overflow-hidden duration-300 ease-out" ref={panel} static>
<ErrorBoundary>
<List bookmarks={bookmarks.bookmarks} layout={layout} />
</ErrorBoundary>
</Disclosure.Panel>
</Transition>
</>
)}
</Disclosure>
</div> </div>
); );
} }

@ -1,8 +1,17 @@
import classNames from "classnames";
import { columnMap } from "../../utils/layout/columns";
import Item from "components/bookmarks/item"; import Item from "components/bookmarks/item";
export default function List({ bookmarks }) { export default function List({ bookmarks, layout }) {
return ( return (
<ul className="mt-3 flex flex-col"> <ul
className={classNames(
layout?.style === "row" ? `grid ${columnMap[layout?.columns]} gap-x-2` : "flex flex-col",
"mt-3"
)}
>
{bookmarks.map((bookmark) => ( {bookmarks.map((bookmark) => (
<Item key={`${bookmark.name}-${bookmark.href}`} bookmark={bookmark} /> <Item key={`${bookmark.name}-${bookmark.href}`} bookmark={bookmark} />
))} ))}

@ -1,18 +1,8 @@
import classNames from "classnames"; import classNames from "classnames";
import Item from "components/services/item"; import { columnMap } from "../../utils/layout/columns";
const columnMap = [ import Item from "components/services/item";
"grid-cols-1 md:grid-cols-1 lg:grid-cols-1",
"grid-cols-1 md:grid-cols-1 lg:grid-cols-1",
"grid-cols-1 md:grid-cols-2 lg:grid-cols-2",
"grid-cols-1 md:grid-cols-2 lg:grid-cols-3",
"grid-cols-1 md:grid-cols-2 lg:grid-cols-4",
"grid-cols-1 md:grid-cols-2 lg:grid-cols-5",
"grid-cols-1 md:grid-cols-2 lg:grid-cols-6",
"grid-cols-1 md:grid-cols-2 lg:grid-cols-7",
"grid-cols-1 md:grid-cols-2 lg:grid-cols-8",
];
export default function List({ group, services, layout }) { export default function List({ group, services, layout }) {
return ( return (

@ -209,7 +209,7 @@ function Home({ initialSettings }) {
searchProvider = searchProviders[searchWidget.options?.provider]; searchProvider = searchProviders[searchWidget.options?.provider];
} }
} }
const headerStyle = initialSettings?.headerStyle || "underlined"; const headerStyle = settings?.headerStyle || "underlined";
useEffect(() => { useEffect(() => {
function handleKeyDown(e) { function handleKeyDown(e) {
@ -233,12 +233,12 @@ function Home({ initialSettings }) {
return ( return (
<> <>
<Head> <Head>
<title>{initialSettings.title || "Homepage"}</title> <title>{settings.title || "Homepage"}</title>
{initialSettings.base && <base href={initialSettings.base} />} {settings.base && <base href={settings.base} />}
{initialSettings.favicon ? ( {settings.favicon ? (
<> <>
<link rel="apple-touch-icon" sizes="180x180" href={initialSettings.favicon} /> <link rel="apple-touch-icon" sizes="180x180" href={settings.favicon} />
<link rel="icon" href={initialSettings.favicon} /> <link rel="icon" href={settings.favicon} />
</> </>
) : ( ) : (
<> <>
@ -248,11 +248,8 @@ function Home({ initialSettings }) {
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png?v=4" /> <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png?v=4" />
</> </>
)} )}
<meta <meta name="msapplication-TileColor" content={themes[settings.color || "slate"][settings.theme || "dark"]} />
name="msapplication-TileColor" <meta name="theme-color" content={themes[settings.color || "slate"][settings.theme || "dark"]} />
content={themes[initialSettings.color || "slate"][initialSettings.theme || "dark"]}
/>
<meta name="theme-color" content={themes[initialSettings.color || "slate"][initialSettings.theme || "dark"]} />
</Head> </Head>
<div className="relative container m-auto flex flex-col justify-start z-10 h-full"> <div className="relative container m-auto flex flex-col justify-start z-10 h-full">
<QuickLaunch <QuickLaunch
@ -267,7 +264,7 @@ function Home({ initialSettings }) {
className={classNames( className={classNames(
"flex flex-row flex-wrap justify-between", "flex flex-row flex-wrap justify-between",
headerStyles[headerStyle], headerStyles[headerStyle],
initialSettings.cardBlur !== undefined && headerStyle === "boxed" && `backdrop-blur${initialSettings.cardBlur.length ? '-' : ""}${initialSettings.cardBlur}` settings.cardBlur !== undefined && headerStyle === "boxed" && `backdrop-blur${settings.cardBlur.length ? '-' : ""}${settings.cardBlur}`
)} )}
> >
{widgets && ( {widgets && (
@ -275,7 +272,7 @@ function Home({ initialSettings }) {
{widgets {widgets
.filter((widget) => !rightAlignedWidgets.includes(widget.type)) .filter((widget) => !rightAlignedWidgets.includes(widget.type))
.map((widget, i) => ( .map((widget, i) => (
<Widget key={i} widget={widget} style={{ header: headerStyle, isRightAligned: false, cardBlur: initialSettings.cardBlur }} /> <Widget key={i} widget={widget} style={{ header: headerStyle, isRightAligned: false, cardBlur: settings.cardBlur }} />
))} ))}
<div className={classNames( <div className={classNames(
@ -285,7 +282,7 @@ function Home({ initialSettings }) {
{widgets {widgets
.filter((widget) => rightAlignedWidgets.includes(widget.type)) .filter((widget) => rightAlignedWidgets.includes(widget.type))
.map((widget, i) => ( .map((widget, i) => (
<Widget key={i} widget={widget} style={{ header: headerStyle, isRightAligned: true, cardBlur: initialSettings.cardBlur }} /> <Widget key={i} widget={widget} style={{ header: headerStyle, isRightAligned: true, cardBlur: settings.cardBlur }} />
))} ))}
</div> </div>
</> </>
@ -293,39 +290,42 @@ function Home({ initialSettings }) {
</div> </div>
{services?.length > 0 && ( {services?.length > 0 && (
<div className="flex flex-wrap p-4 sm:p-8 sm:pt-4 items-start pb-2"> <div key="services" className="flex flex-wrap p-4 sm:p-8 sm:pt-4 items-start pb-2">
{services.map((group) => ( {services.map((group) => (
<ServicesGroup <ServicesGroup
key={group.name} key={group.name}
group={group.name} group={group.name}
services={group} services={group}
layout={initialSettings.layout?.[group.name]} layout={settings.layout?.[group.name]}
fiveColumns={settings.fiveColumns} fiveColumns={settings.fiveColumns}
disableCollapse={settings.disableCollapse} /> disableCollapse={settings.disableCollapse}
/>
))} ))}
</div> </div>
)} )}
{bookmarks?.length > 0 && ( {bookmarks?.length > 0 && (
<div className={`grow flex flex-wrap pt-0 p-4 sm:p-8 gap-2 grid-cols-1 lg:grid-cols-2 lg:grid-cols-${Math.min(6, bookmarks.length)}`}> <div key="bookmarks" className="flex flex-wrap p-4 sm:p-8 sm:pt-4 items-start pb-2">
{bookmarks.map((group) => ( {bookmarks.map((group) => (
<BookmarksGroup <BookmarksGroup
key={group.name} key={group.name}
group={group} bookmarks={group}
disableCollapse={settings.disableCollapse} /> layout={settings.layout?.[group.name]}
disableCollapse={settings.disableCollapse}
/>
))} ))}
</div> </div>
)} )}
<div className="flex flex-col mt-auto p-8 w-full"> <div className="flex flex-col mt-auto p-8 w-full">
<div className="flex w-full justify-end"> <div className="flex w-full justify-end">
{!initialSettings?.color && <ColorToggle />} {!settings?.color && <ColorToggle />}
<Revalidate /> <Revalidate />
{!initialSettings?.theme && <ThemeToggle />} {!settings.theme && <ThemeToggle />}
</div> </div>
<div className="flex mt-4 w-full justify-end"> <div className="flex mt-4 w-full justify-end">
{!initialSettings?.hideVersion && <Version />} {!settings.hideVersion && <Version />}
</div> </div>
</div> </div>
</div> </div>

@ -34,6 +34,16 @@ export async function bookmarksResponse() {
if (!bookmarks) return []; if (!bookmarks) return [];
let initialSettings;
try {
initialSettings = await getSettings();
} catch (e) {
console.error("Failed to load settings.yaml, please check for errors");
if (e) console.error(e.toString());
initialSettings = {};
}
// map easy to write YAML objects into easy to consume JS arrays // map easy to write YAML objects into easy to consume JS arrays
const bookmarksArray = bookmarks.map((group) => ({ const bookmarksArray = bookmarks.map((group) => ({
name: Object.keys(group)[0], name: Object.keys(group)[0],
@ -43,7 +53,21 @@ export async function bookmarksResponse() {
})), })),
})); }));
return bookmarksArray; const sortedGroups = [];
const unsortedGroups = [];
const definedLayouts = initialSettings.layout ? Object.keys(initialSettings.layout) : null;
bookmarksArray.forEach((group) => {
if (definedLayouts) {
const layoutIndex = definedLayouts.findIndex(layout => layout === group.name);
if (layoutIndex > -1) sortedGroups[layoutIndex] = group;
else unsortedGroups.push(group);
} else {
unsortedGroups.push(group);
}
});
return [...sortedGroups.filter(g => g), ...unsortedGroups];
} }
export async function widgetsResponse() { export async function widgetsResponse() {

@ -0,0 +1,12 @@
// eslint-disable-next-line import/prefer-default-export
export const columnMap = [
"grid-cols-1 md:grid-cols-1 lg:grid-cols-1",
"grid-cols-1 md:grid-cols-1 lg:grid-cols-1",
"grid-cols-1 md:grid-cols-2 lg:grid-cols-2",
"grid-cols-1 md:grid-cols-2 lg:grid-cols-3",
"grid-cols-1 md:grid-cols-2 lg:grid-cols-4",
"grid-cols-1 md:grid-cols-2 lg:grid-cols-5",
"grid-cols-1 md:grid-cols-2 lg:grid-cols-6",
"grid-cols-1 md:grid-cols-2 lg:grid-cols-7",
"grid-cols-1 md:grid-cols-2 lg:grid-cols-8",
];

@ -59,5 +59,16 @@ module.exports = {
'backdrop-brightness-125', 'backdrop-brightness-125',
'backdrop-brightness-150', 'backdrop-brightness-150',
'backdrop-brightness-200', 'backdrop-brightness-200',
'grid-cols-1',
'md:grid-cols-1',
'md:grid-cols-2',
'lg:grid-cols-1',
'lg:grid-cols-2',
'lg:grid-cols-3',
'lg:grid-cols-4',
'lg:grid-cols-5',
'lg:grid-cols-6',
'lg:grid-cols-7',
'lg:grid-cols-8',
], ],
} }

Loading…
Cancel
Save