Icons support Dashboard, Material, and various color options

This commit is contained in:
Jordan Roher 2023-04-21 14:15:25 -07:00
parent c2a96dfe46
commit 7bc5e1caae
6 changed files with 96 additions and 30 deletions

View File

@ -3,8 +3,11 @@
# Escape slashes
LOGO=${LOGO//\//\\/}
sed -i -e 's/PAGETITLE = "My Website"/'"${TITLE}"'/g' /app/index.html
sed -i -e 's/HTMLTITLE/'"${TITLE}"'/g' /app/src/variables.ts
# HTML replacement
sed -i -e 's/HTMLTITLE/'"${TITLE}"'/g' /app/index.html
# TypeScript replacement
sed -i -e 's/PAGETITLE = "My Website"/'"${TITLE}"'/g' /app/src/variables.ts
sed -i -e 's/PAGEICON = "\/logo\.png"/'"${LOGO}"'/g' /app/src/variables.ts
exec "$@"

View File

@ -49,9 +49,22 @@ Use [Dashboard icons](https://github.com/walkxcode/dashboard-icons) by specifyin
Use any [Material Design icon](https://icon-sets.iconify.design/mdi/) by prefixing the name with `mdi-`.
Fill the icon by providing an "iconColor" from the [list of Tailwind colors](https://tailwindcss.com/docs/background-color). Do not prefix with "bg-".
Set a background by providing an "iconBG" from the [list of Tailwind colors](https://tailwindcss.com/docs/background-color). Do not prefix with "bg-".
Turn off the bubble and shadow by setting `"iconBubble": false`.
Turn off background color by setting `"iconBG": "transparent"`.
Hide the icon entirely by setting `"icon": ""`.
```bash
# Specify an icon in config.json
"icon": "mdi-cloud"
"icon": "mdi-cloud",
"iconColor": "blue-500", # optional, defaults to a contrasting color
"iconBG": "gray-200", # optional, defaults to a complementary color
"iconBubble": false, # optional, defaults to true
```
# Docker compose

View File

@ -23,16 +23,20 @@ const iconLevel = 300;
const getIconColor = (index: number) => `bg-${iconColors[iconColors.length % index]}-${iconLevel}`;
interface IProps {
name: string;
index: number;
icon?: string;
iconColor?: string;
iconBG?: string;
iconBubble?: boolean;
uri?: string;
}
export const Icon: React.FunctionComponent<IProps> = ({ uri, icon, index }) => {
export const Icon: React.FunctionComponent<IProps> = ({ name, uri, icon, index, iconBG, iconBubble, iconColor }) => {
if (is.null(icon)) {
if (!is.null(uri)) {
return (
<a href={uri} target="_blank">
<a href={uri} target="_blank" rel="noreferrer" title={name}>
<IconBlank index={index} />
</a>
);
@ -43,13 +47,13 @@ export const Icon: React.FunctionComponent<IProps> = ({ uri, icon, index }) => {
if (!is.null(uri)) {
return (
<a href={uri} target="_blank">
<IconBase icon={icon as string} />
<a href={uri} target="_blank" rel="noreferrer" title={name}>
<IconBase icon={icon as string} iconBG={iconBG} iconColor={iconColor} iconBubble={iconBubble} />
</a>
);
}
return <IconBase icon={icon as string} />;
return <IconBase icon={icon as string} iconBG={iconBG} iconColor={iconColor} iconBubble={iconBubble} />;
};
interface IIconBlankProps {
@ -68,9 +72,14 @@ const IconBlank: React.FunctionComponent<IIconBlankProps> = ({ index }) => {
interface IIconBaseProps {
icon: string;
iconColor?: string;
iconBG?: string;
iconBubble?: boolean;
}
const IconBase: React.FunctionComponent<IIconBaseProps> = ({ icon }) => {
const IconBase: React.FunctionComponent<IIconBaseProps> = ({ icon, iconBG, iconBubble, iconColor }) => {
if (icon.startsWith("http") || icon.startsWith("/")) {
/* Relative or absolute icon URI */
return (
<img
src={icon}
@ -78,4 +87,42 @@ const IconBase: React.FunctionComponent<IIconBaseProps> = ({ icon }) => {
className=" block w-16 h-16 rounded-2xl border border-black/5 shadow-sm overflow-hidden"
/>
);
}
if (icon.startsWith("mdi-")) {
/* Material Design icon */
const iconName = icon.replace("mdi-", "").replace(".svg", "");
let iconClassName =
iconBubble === false
? "block w-16 h-16 overflow-hidden"
: "block w-16 h-16 rounded-2xl border border-black/5 shadow-sm overflow-hidden";
if (is.null(iconBG)) {
iconClassName += ` bg-slate-200`;
} else {
iconClassName += ` bg-${iconBG}`;
}
return (
<div className={iconClassName}>
<div
className={`block w-16 h-16 bg-${iconColor} overflow-hidden`}
style={{
mask: `url(https://cdn.jsdelivr.net/npm/@mdi/svg@latest/svg/${iconName}.svg) no-repeat center / contain`,
WebkitMask: `url(https://cdn.jsdelivr.net/npm/@mdi/svg@latest/svg/${iconName}.svg) no-repeat center / contain`,
}}
/>
</div>
);
}
/* Dashboard icon */
const iconName = icon.replace(".png", "").replace(".jpg", "").replace(".svg", "");
return (
<img
src={`https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/${iconName}.png`}
alt=""
className="block w-16 h-16 rounded-2xl border border-black/5 shadow-sm overflow-hidden"
/>
);
};

View File

@ -23,13 +23,23 @@ interface IServiceProps {
}
const Service: React.FunctionComponent<IServiceProps> = ({ service, index }) => {
const { name, uri, description, icon } = service;
const { name, uri, description, icon, iconBG, iconBubble, iconColor } = service;
return (
<li className="p-4 flex gap-4">
{!is.null(icon) && (
<span className="flex-shrink-0 block">
<Icon icon={icon} uri={uri} index={index} />
<Icon
name={name}
icon={icon}
uri={uri}
index={index}
iconColor={iconColor}
iconBG={iconBG}
iconBubble={iconBubble}
/>
</span>
)}
<div>
<h3 className="text-lg mt-1 font-semibold line-clamp-1">
<a href={uri} target="_blank">

View File

@ -9,4 +9,7 @@ export interface IService {
description?: string;
icon?: string;
iconColor?: string;
iconBG?: string;
iconBubble?: boolean;
}

View File

@ -3,21 +3,11 @@ export default {
content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
safelist: [
/* Built from icon.tsx */
"bg-blue-300",
"bg-rose-300",
"bg-green-300",
"bg-red-300",
"bg-yellow-300",
"bg-cyan-300",
"bg-pink-300",
"bg-orange-300",
"bg-sky-300",
"bg-slate-300",
"bg-emerald-300",
"bg-zinc-300",
"bg-neutral-300",
"bg-amber-300",
"bg-violet-300",
{
pattern:
/bg-(black|white|slate|gray|zinc|neutral|stone|red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose)-(50|100|200|300|400|500|600|700|800|900|950)/,
},
"bg-transparent",
],
theme: {
extend: {