feat: add alert and socials options to schema, implement SocialIcon component, and update TemplateOption to render new option types

This commit is contained in:
Viren070
2025-06-15 16:30:52 +01:00
parent 048c612896
commit a0a3c8231a
3 changed files with 140 additions and 0 deletions
+30
View File
@@ -176,6 +176,8 @@ const OptionDefinition = z.object({
'select',
'multi-select',
'url',
'alert',
'socials',
]),
required: z.boolean().optional(),
default: z.any().optional(),
@@ -189,6 +191,34 @@ const OptionDefinition = z.object({
})
)
.optional(),
intent: z
.enum([
'alert',
'info',
'success',
'warning',
'info-basic',
'success-basic',
'warning-basic',
'alert-basic',
])
.optional(),
socials: z
.array(
z.object({
id: z.enum([
'website',
'github',
'discord',
'ko-fi',
'patreon',
'buymeacoffee',
'github-sponsors',
]),
url: z.string().url(),
})
)
.optional(),
constraints: z
.object({
min: z.number().min(1).optional(), // for string inputs, consider this the minimum length.
@@ -0,0 +1,90 @@
import { cn } from '@/components/ui/core/styling';
import { FiGithub } from 'react-icons/fi';
import { AiOutlineDiscord } from 'react-icons/ai';
import { FaPatreon } from 'react-icons/fa6';
import { SiBuymeacoffee, SiGithubsponsors, SiKofi } from 'react-icons/si';
import { Tooltip } from '../ui/tooltip';
import { FaGlobe } from 'react-icons/fa6';
type SocialIconProps = {
id:
| 'github'
| 'discord'
| 'ko-fi'
| 'patreon'
| 'buymeacoffee'
| 'github-sponsors'
| 'website';
url: string;
className?: string;
};
export function SocialIcon({ id, url, className }: SocialIconProps) {
const getTooltip = () => {
switch (id) {
case 'github':
return "View the addon's GitHub repository";
case 'discord':
return "Join the Developer's Discord";
case 'github-sponsors':
return 'Sponsor the Developer on GitHub';
case 'ko-fi':
return 'Support the Developer on Ko-fi';
case 'patreon':
return 'Support the Developer on Patreon';
case 'buymeacoffee':
return 'Support the Developer on Buy Me a Coffee';
default:
return null;
}
};
const tooltip = getTooltip();
return tooltip ? (
<Tooltip
side="top"
trigger={<SocialIconComponent id={id} url={url} className={className} />}
>
{tooltip}
</Tooltip>
) : (
<SocialIconComponent id={id} url={url} className={className} />
);
}
const SocialIconComponent = ({ id, url, className }: SocialIconProps) => {
const getIcon = () => {
switch (id) {
case 'website':
return <FaGlobe className="w-7 h-7" />;
case 'discord':
return <AiOutlineDiscord className="w-7 h-7" />;
case 'github':
return <FiGithub className="w-7 h-7" />;
case 'github-sponsors':
return <SiGithubsponsors className="w-7 h-7" />;
case 'ko-fi':
return <SiKofi className="w-7 h-7" />;
case 'patreon':
return <FaPatreon className="w-7 h-7" />;
case 'buymeacoffee':
return <SiBuymeacoffee className="w-7 h-7" />;
default:
return null;
}
};
return (
<a
href={url}
target="_blank"
rel="noopener noreferrer"
className={cn(
'inline-flex items-center justify-center text-gray-400 transition-colors hover:opacity-80 hover:text-[--brand]',
className
)}
>
{getIcon()}
</a>
);
};
@@ -6,6 +6,8 @@ import { Combobox } from '../ui/combobox';
import { Option } from '@aiostreams/core';
import React from 'react';
import MarkdownLite from './markdown-lite';
import { Alert } from '../ui/alert';
import { SocialIcon } from './social-icon';
// this component, accepts an option and returns a component that renders the option.
// string - TextInput
// number - NumberInput
@@ -38,12 +40,30 @@ const TemplateOption: React.FC<TemplateOptionProps> = ({
constraints,
forced,
default: defaultValue,
intent,
socials,
emptyIsUndefined = false,
} = option;
const isDisabled = disabled || !!forced;
switch (type) {
case 'socials':
return (
<div className="flex items-center justify-center w-full gap-6 mt-2">
{socials?.map((social) => (
<SocialIcon key={social.id} id={social.id} url={social.url} />
))}
</div>
);
case 'alert':
return (
<Alert
intent={intent}
title={name}
description={<MarkdownLite>{description}</MarkdownLite>}
/>
);
case 'password':
return (
<div>