mirror of
https://github.com/aykhans/slash-e.git
synced 2025-04-18 21:19:44 +00:00
feat: add favicon cache
This commit is contained in:
parent
d7c7de24c1
commit
07d6492a6f
@ -23,7 +23,8 @@
|
|||||||
"react-i18next": "^13.0.1",
|
"react-i18next": "^13.0.1",
|
||||||
"react-redux": "^8.0.1",
|
"react-redux": "^8.0.1",
|
||||||
"react-router-dom": "^6.13.0",
|
"react-router-dom": "^6.13.0",
|
||||||
"tailwindcss": "^3.3.2"
|
"tailwindcss": "^3.3.2",
|
||||||
|
"zustand": "^4.3.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/lodash-es": "^4.17.5",
|
"@types/lodash-es": "^4.17.5",
|
||||||
|
19
web/pnpm-lock.yaml
generated
19
web/pnpm-lock.yaml
generated
@ -56,6 +56,9 @@ dependencies:
|
|||||||
tailwindcss:
|
tailwindcss:
|
||||||
specifier: ^3.3.2
|
specifier: ^3.3.2
|
||||||
version: 3.3.2
|
version: 3.3.2
|
||||||
|
zustand:
|
||||||
|
specifier: ^4.3.8
|
||||||
|
version: 4.3.8(react@18.2.0)
|
||||||
|
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@types/lodash-es':
|
'@types/lodash-es':
|
||||||
@ -3109,3 +3112,19 @@ packages:
|
|||||||
resolution: {integrity: sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==}
|
resolution: {integrity: sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==}
|
||||||
engines: {node: '>= 14'}
|
engines: {node: '>= 14'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/zustand@4.3.8(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-4h28KCkHg5ii/wcFFJ5Fp+k1J3gJoasaIbppdgZFO4BPJnsNxL0mQXBSFgOgAdCdBj35aDTPvdAJReTMntFPGg==}
|
||||||
|
engines: {node: '>=12.7.0'}
|
||||||
|
peerDependencies:
|
||||||
|
immer: '>=9.0'
|
||||||
|
react: '>=16.8'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
immer:
|
||||||
|
optional: true
|
||||||
|
react:
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
react: 18.2.0
|
||||||
|
use-sync-external-store: 1.2.0(react@18.2.0)
|
||||||
|
dev: false
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
import { Tooltip } from "@mui/joy";
|
import { Tooltip } from "@mui/joy";
|
||||||
import copy from "copy-to-clipboard";
|
import copy from "copy-to-clipboard";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import toast from "react-hot-toast";
|
import toast from "react-hot-toast";
|
||||||
import { shortcutService } from "../services";
|
import { shortcutService } from "../services";
|
||||||
import { useAppSelector } from "../stores";
|
import { useAppSelector } from "../stores";
|
||||||
|
import useFaviconStore from "../stores/v1/favicon";
|
||||||
import { absolutifyLink } from "../helpers/utils";
|
import { absolutifyLink } from "../helpers/utils";
|
||||||
import * as api from "../helpers/api";
|
|
||||||
import { showCommonDialog } from "./Alert";
|
import { showCommonDialog } from "./Alert";
|
||||||
import Icon from "./Icon";
|
import Icon from "./Icon";
|
||||||
import Dropdown from "./common/Dropdown";
|
import Dropdown from "./common/Dropdown";
|
||||||
import VisibilityIcon from "./VisibilityIcon";
|
import VisibilityIcon from "./VisibilityIcon";
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
shortcut: Shortcut;
|
shortcut: Shortcut;
|
||||||
@ -21,18 +21,16 @@ const ShortcutView = (props: Props) => {
|
|||||||
const { shortcut, handleEdit } = props;
|
const { shortcut, handleEdit } = props;
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const user = useAppSelector((state) => state.user.user as User);
|
const user = useAppSelector((state) => state.user.user as User);
|
||||||
|
const faviconStore = useFaviconStore();
|
||||||
const [favicon, setFavicon] = useState<string | undefined>(undefined);
|
const [favicon, setFavicon] = useState<string | undefined>(undefined);
|
||||||
const havePermission = user.role === "ADMIN" || shortcut.creatorId === user.id;
|
const havePermission = user.role === "ADMIN" || shortcut.creatorId === user.id;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
api
|
faviconStore.getOrFetchUrlFavicon(shortcut.link).then((url) => {
|
||||||
.getUrlFavicon(shortcut.link)
|
if (url) {
|
||||||
.then(({ data }) => {
|
setFavicon(url);
|
||||||
setFavicon(data);
|
}
|
||||||
})
|
});
|
||||||
.catch(() => {
|
|
||||||
// do nothing.
|
|
||||||
});
|
|
||||||
}, [shortcut.link]);
|
}, [shortcut.link]);
|
||||||
|
|
||||||
const handleCopyButtonClick = (shortcut: Shortcut) => {
|
const handleCopyButtonClick = (shortcut: Shortcut) => {
|
||||||
|
41
web/src/stores/v1/favicon.ts
Normal file
41
web/src/stores/v1/favicon.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import { create } from "zustand";
|
||||||
|
import { persist } from "zustand/middleware";
|
||||||
|
import * as api from "../../helpers/api";
|
||||||
|
|
||||||
|
interface FaviconState {
|
||||||
|
cache: {
|
||||||
|
[key: string]: string;
|
||||||
|
};
|
||||||
|
getOrFetchUrlFavicon: (url: string) => Promise<string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const useFaviconStore = create<FaviconState>()(
|
||||||
|
persist(
|
||||||
|
(set, get) => ({
|
||||||
|
cache: {},
|
||||||
|
getOrFetchUrlFavicon: async (url: string) => {
|
||||||
|
const cache = get().cache;
|
||||||
|
if (cache[url]) {
|
||||||
|
return cache[url];
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { data: favicon } = await api.getUrlFavicon(url);
|
||||||
|
if (favicon) {
|
||||||
|
cache[url] = favicon;
|
||||||
|
set(cache);
|
||||||
|
return favicon;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
name: "favicon_cache",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
export default useFaviconStore;
|
Loading…
x
Reference in New Issue
Block a user