fixing small bugs; improving background handling and removing dead code
Build and Release to Staging / Build Vision Start (push) Successful in 1m6s
Build and Release to Staging / Build Vision Start Image (push) Successful in 2m41s
Build and Release to Staging / Deploy Vision Start (staging) (push) Successful in 18s

This commit is contained in:
ivanch committed 2026-10-28 21:52:07 -03:00
1 parent 99dbea0615
commit 62e187b9f5
24 files changed
+439 -250

No files matched your search

+28 -6
View File
@@ -21,6 +21,8 @@ interface IconMetadata {
const getIconPickUrl = (iconData: IconMetadata): string =>
`https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/${iconData.base}/${iconData.name}.${iconData.base}`;
const isIconUrl = (value: string): boolean => /^(https?:|data:image\/)/i.test(value.trim());
const WebsiteEditModal: React.FC<WebsiteEditModalProps> = ({ website, edit, onClose, onSave, onDelete }) => {
const [name, setName] = useState(website ? website.name : '');
const [url, setUrl] = useState(website ? website.url : '');
@@ -28,6 +30,7 @@ const WebsiteEditModal: React.FC<WebsiteEditModalProps> = ({ website, edit, onCl
const [iconQuery, setIconQuery] = useState('');
const [filteredIcons, setFilteredIcons] = useState<IconMetadata[]>([]);
const [iconMetadata, setIconMetadata] = useState<IconMetadata[]>([]);
const [previewFailed, setPreviewFailed] = useState(false);
const metadataRequest = useRef<AbortController | null>(null);
const debounceRef = useRef<number | null>(null);
@@ -105,13 +108,30 @@ const WebsiteEditModal: React.FC<WebsiteEditModalProps> = ({ website, edit, onCl
alert('Please enter a valid website URL (http, https, ftp, or mailto).');
return;
}
onSave({ id: website?.id, name: name.trim(), url: normalizedUrl, icon });
onSave({ id: website?.id, name: name.trim(), url: normalizedUrl, icon: resolveIcon(icon) });
};
const resolveIcon = (value: string): string => {
const trimmed = value.trim();
if (!trimmed || isIconUrl(trimmed)) return trimmed;
const query = trimmed.toLowerCase();
for (const ic of iconMetadata) {
if (ic.name.toLowerCase() === query) return getIconPickUrl(ic);
const color = ic.colors.find(c => c.toLowerCase() === query);
if (color) return getIconPickUrl({ ...ic, name: color });
}
return trimmed;
};
const updateIcon = (value: string) => {
setIcon(value);
setPreviewFailed(false);
};
const fetchIcon = async () => {
if (url) {
const fetchedIcon = await getWebsiteIcon(url);
setIcon(fetchedIcon);
if (fetchedIcon) updateIcon(fetchedIcon);
}
};
@@ -125,8 +145,8 @@ const WebsiteEditModal: React.FC<WebsiteEditModalProps> = ({ website, edit, onCl
onDelete={edit ? onDelete : undefined}
>
<div className="flex justify-center mb-4">
{icon ? (
<img src={icon} alt="Website Icon" className="h-24 w-24 object-contain" />
{isIconUrl(icon) && !previewFailed ? (
<img src={icon.trim()} alt="Website Icon" className="h-24 w-24 object-contain" onError={() => setPreviewFailed(true)} />
) : (
<div className="liquid-surface h-24 w-24 rounded-2xl flex items-center justify-center">
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1" strokeLinecap="round" strokeLinejoin="round" className="text-white/50">
@@ -158,7 +178,7 @@ const WebsiteEditModal: React.FC<WebsiteEditModalProps> = ({ website, edit, onCl
placeholder="Icon URL or name"
value={icon}
onChange={(e) => {
setIcon(e.target.value);
updateIcon(e.target.value);
setIconQuery(e.target.value);
}}
onFocus={ensureIconMetadata}
@@ -170,7 +190,7 @@ const WebsiteEditModal: React.FC<WebsiteEditModalProps> = ({ website, edit, onCl
<div
key={`${iconData.name}-${index}`}
onClick={() => {
setIcon(getIconPickUrl(iconData));
updateIcon(getIconPickUrl(iconData));
setIconQuery('');
setFilteredIcons([]);
}}
@@ -179,6 +199,8 @@ const WebsiteEditModal: React.FC<WebsiteEditModalProps> = ({ website, edit, onCl
<img
src={getIconPickUrl(iconData)}
alt={iconData.name}
loading="lazy"
decoding="async"
className="h-6 w-6 mr-2"
/>
<span>{iconData.name}</span>