Add ability to favorite backgrounds

This commit is contained in:
Georgi Gardev
2023-11-18 19:28:51 +02:00
parent 6dd6243c7b
commit f4e029c4af
8 changed files with 133 additions and 47 deletions
+6 -40
View File
@@ -1,54 +1,20 @@
import { Random } from 'unsplash-js/dist/methods/photos/types';
import { createLocalStore } from '~/lib/create-local-store';
import { random } from '~/lib/math';
import { getRandomBackground, unsplashApi } from '~/api/unsplash';
import { createEffect, createSignal } from 'solid-js';
import { useSettings } from '~/state/SettingsProvider';
import style from './Background.module.css';
import { BACKGROUND_FETCH_MINS } from '~/config';
import { createEffect, createMemo, createSignal } from 'solid-js';
type BackgroundStorage = {
fetched_at: number;
backgrounds: Random[] | null;
};
export function Background() {
const [backgrounds, setBackgrounds] = createLocalStore<BackgroundStorage>(
'start-page-background',
{
fetched_at: 0,
backgrounds: null,
}
);
const shouldFetch =
!backgrounds?.backgrounds ||
backgrounds.fetched_at < new Date().getTime() - 1000 * 60 * BACKGROUND_FETCH_MINS;
if (shouldFetch) {
getRandomBackground().then((r) =>
setBackgrounds({
fetched_at: new Date().getTime(),
backgrounds: (r?.response as Random[]) ?? null,
})
);
}
const backgroundUrls = createMemo(() => {
const backgroundLength = backgrounds?.backgrounds?.length ?? 0;
const background = random(backgroundLength - 1);
return backgrounds?.backgrounds?.[background].urls;
});
const { currentBackground } = useSettings();
const [fullLoaded, setFullLoaded] = createSignal(false);
createEffect(() => {
if (!backgroundUrls()) {
if (!currentBackground()) {
return null;
}
var curImg = new Image();
curImg.src = backgroundUrls()!.full;
curImg.src = currentBackground()!.urls.full;
curImg.onload = () => setFullLoaded(true);
});
@@ -56,7 +22,7 @@ export function Background() {
<>
<img
class={style.Background}
src={fullLoaded() ? backgroundUrls()?.full : backgroundUrls()?.thumb}
src={fullLoaded() ? currentBackground()?.urls.full : currentBackground()?.urls.thumb}
/>
{!fullLoaded() ? <div class={style.Overlay}></div> : null}
</>
+7 -2
View File
@@ -43,13 +43,18 @@
height: 100%;
}
.Settings {
cursor: pointer;
.SettingsWrapper {
display: flex;
align-items: center;
gap: .5rem;
margin-top: clamp(.5rem, 1vw, 1.5rem);
margin-right: 1.5rem;
align-self: flex-end;
}
.SettingsWrapper > * {
cursor: pointer;
}
@media (max-width: 600px) {
.Sidebar {
+14 -1
View File
@@ -1,6 +1,11 @@
import { Tooltip } from '@hope-ui/solid';
import { IoSave } from 'solid-icons/io';
import { createTagOrder } from '~/api/get-apps';
import { useSettings } from '~/state/SettingsProvider';
import { Settings } from '../widgets/Settings';
import style from './Sidebar.module.css';
import { HiSolidStar } from 'solid-icons/hi';
type SidebarProps = {
activeTag?: string | null;
@@ -9,6 +14,7 @@ type SidebarProps = {
export function Sidebar(props: SidebarProps) {
const tagOrder = createTagOrder();
const { onSaveBackground } = useSettings();
return (
<div class={style.Sidebar}>
@@ -23,7 +29,14 @@ export function Sidebar(props: SidebarProps) {
</li>
))}
</ul>
<Settings className={style.Settings} />
<div class={style.SettingsWrapper}>
<Tooltip withArrow placement="top" label="Save background">
<HiSolidStar size={18} onClick={onSaveBackground} />
</Tooltip>
<Tooltip withArrow placement="top" label="Settings">
<Settings />
</Tooltip>
</div>
</div>
);
}
+11
View File
@@ -41,6 +41,17 @@ export function Settings(props: SettingsProps) {
>
Show locations
</Checkbox>
<Checkbox
checked={appSettings.useSavedBackgrounds}
onChange={(e) =>
setAppSettings((prev) => ({
...prev,
useSavedBackgrounds: (e.target as any).checked,
}))
}
>
Use saved backgrounds
</Checkbox>
<a
style={{ display: 'flex', 'align-items': 'center', gap: '8px', cursor: 'pointer' }}
onClick={() => {
+8
View File
@@ -0,0 +1,8 @@
import { random } from './math';
export function sample<T>(list: T[]): T {
if (list.length === 1) {
return list[0];
}
return list[random(list.length - 1)];
}
+44 -4
View File
@@ -1,27 +1,67 @@
import { JSX, createContext, useContext } from 'solid-js';
import { Accessor, JSX, createContext, createMemo, useContext } from 'solid-js';
import { SetStoreFunction } from 'solid-js/store';
import { Random } from 'unsplash-js/dist/methods/photos/types';
import { sample } from '~/lib/array';
import { createLocalStore } from '~/lib/create-local-store';
import { SavedBackgrounds } from '~/types';
import { createBackgrounds } from './create-backgrounds';
import { random } from '~/lib/math';
type Settings = { showLocations: boolean; viewAsTable: boolean };
type Settings = { showLocations: boolean; viewAsTable: boolean; useSavedBackgrounds: boolean };
type SettingsContextType = {
appSettings: Settings;
setAppSettings: SetStoreFunction<Settings>;
savedBackgrounds: SavedBackgrounds;
onSaveBackground(): void;
currentBackground: Accessor<Random | undefined>;
};
const SettingsContext = createContext<SettingsContextType>({
appSettings: { showLocations: false, viewAsTable: false },
appSettings: { showLocations: false, viewAsTable: false, useSavedBackgrounds: false },
setAppSettings: () => {},
currentBackground: () => undefined,
savedBackgrounds: [],
onSaveBackground: () => {},
});
export function SettingsProvider(props: { children: JSX.Element }) {
const [appSettings, setAppSettings] = createLocalStore<Settings>('start-page-app-settings', {
showLocations: false,
viewAsTable: false,
useSavedBackgrounds: false,
});
const [savedBackgrounds, setSavedBackgrounds] = createLocalStore<SavedBackgrounds>(
'start-page-saved-backgrounds',
[]
);
const { currentBackground: currentRandomBackground } = createBackgrounds();
const onSaveBackground = () => {
setSavedBackgrounds((prev) => {
if (prev.find((background) => background.id === currentRandomBackground()?.id)) {
return prev;
}
return [...prev, currentRandomBackground()!];
});
};
const currentBackground = createMemo(() =>
appSettings.useSavedBackgrounds ? sample(savedBackgrounds) : currentRandomBackground()
);
return (
<SettingsContext.Provider value={{ appSettings, setAppSettings }}>
<SettingsContext.Provider
value={{
currentBackground,
savedBackgrounds,
onSaveBackground,
appSettings,
setAppSettings,
}}
>
{props.children}
</SettingsContext.Provider>
);
+34
View File
@@ -0,0 +1,34 @@
import { createMemo } from 'solid-js';
import { Random } from 'unsplash-js/dist/methods/photos/types';
import { getRandomBackground } from '~/api/unsplash';
import { BACKGROUND_FETCH_MINS } from '~/config';
import { sample } from '~/lib/array';
import { createLocalStore } from '~/lib/create-local-store';
import { random } from '~/lib/math';
import { BackgroundStorage } from '~/types';
export function createBackgrounds() {
const [backgrounds, setBackgrounds] = createLocalStore<BackgroundStorage>(
'start-page-background',
{ fetched_at: 0, backgrounds: null }
);
const shouldFetch =
!backgrounds?.backgrounds ||
backgrounds.fetched_at < new Date().getTime() - 1000 * 60 * BACKGROUND_FETCH_MINS;
if (shouldFetch) {
getRandomBackground().then((r) =>
setBackgrounds({
fetched_at: new Date().getTime(),
backgrounds: (r?.response as Random[]) ?? null,
})
);
}
const currentBackground = createMemo<Random | undefined>(() =>
sample(backgrounds?.backgrounds ?? [])
);
return { backgrounds, currentBackground };
}
+9
View File
@@ -1,3 +1,5 @@
import { Random } from 'unsplash-js/dist/methods/photos/types';
export type AppDefinition = {
name: string;
url: string;
@@ -31,3 +33,10 @@ export type WeatherData = {
sunrise: number;
sunset: number;
};
export type BackgroundStorage = {
fetched_at: number;
backgrounds: Random[] | null;
};
export type SavedBackgrounds = Random[];