From a0a3c8231ae77cd379eb39ba68ef437b15b0a4e5 Mon Sep 17 00:00:00 2001 From: Viren070 Date: Sun, 15 Jun 2025 16:30:52 +0100 Subject: [PATCH] feat: add alert and socials options to schema, implement SocialIcon component, and update TemplateOption to render new option types --- packages/core/src/db/schemas.ts | 30 +++++++ .../src/components/shared/social-icon.tsx | 90 +++++++++++++++++++ .../src/components/shared/template-option.tsx | 20 +++++ 3 files changed, 140 insertions(+) create mode 100644 packages/frontend/src/components/shared/social-icon.tsx diff --git a/packages/core/src/db/schemas.ts b/packages/core/src/db/schemas.ts index 1a71b7e3..9a26ef0a 100644 --- a/packages/core/src/db/schemas.ts +++ b/packages/core/src/db/schemas.ts @@ -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. diff --git a/packages/frontend/src/components/shared/social-icon.tsx b/packages/frontend/src/components/shared/social-icon.tsx new file mode 100644 index 00000000..a642a7b9 --- /dev/null +++ b/packages/frontend/src/components/shared/social-icon.tsx @@ -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} + + ) : ( + + ); +} + +const SocialIconComponent = ({ id, url, className }: SocialIconProps) => { + const getIcon = () => { + switch (id) { + case 'website': + return ; + case 'discord': + return ; + case 'github': + return ; + case 'github-sponsors': + return ; + case 'ko-fi': + return ; + case 'patreon': + return ; + case 'buymeacoffee': + return ; + default: + return null; + } + }; + return ( + + {getIcon()} + + ); +}; diff --git a/packages/frontend/src/components/shared/template-option.tsx b/packages/frontend/src/components/shared/template-option.tsx index c3972a6d..7c6937ca 100644 --- a/packages/frontend/src/components/shared/template-option.tsx +++ b/packages/frontend/src/components/shared/template-option.tsx @@ -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 = ({ constraints, forced, default: defaultValue, + intent, + socials, emptyIsUndefined = false, } = option; const isDisabled = disabled || !!forced; switch (type) { + case 'socials': + return ( +
+ {socials?.map((social) => ( + + ))} +
+ ); + case 'alert': + return ( + {description}} + /> + ); case 'password': return (