diff --git a/deno.json b/deno.json index 9cb3a6d1..45a61d77 100644 --- a/deno.json +++ b/deno.json @@ -14,7 +14,7 @@ "daisyui": "npm:daisyui@4.6.0" }, "tasks": { - "start": "deno task bundle && deno run -A --unstable --env --watch=tailwind.css,sections/,functions/,loaders/,actions/,workflows/,accounts/,.env dev.ts", + "start": "deno task generate-icons && deno task bundle && deno run -A --unstable --env --watch=tailwind.css,sections/,functions/,loaders/,actions/,workflows/,accounts/,.env dev.ts", "gen": "deno run -A dev.ts --gen-only", "play": "USE_LOCAL_STORAGE_ONLY=true deno task start", "component": "deno eval 'import \"deco/scripts/component.ts\"'", @@ -26,7 +26,8 @@ "bundle": "deno eval 'import \"deco/scripts/apps/bundle.ts\"' deco-sites/storefront", "cache_clean": "rm deno.lock; deno cache -r main.ts", "build": "deno run -A dev.ts build", - "preview": "deno run -A main.ts" + "preview": "deno run -A main.ts", + "generate-icons": "deno run -A --unstable static/generate-icons.ts" }, "githooks": { "pre-commit": "check" diff --git a/loaders/availableIcons.ts b/loaders/availableIcons.ts new file mode 100644 index 00000000..629e7c4a --- /dev/null +++ b/loaders/availableIcons.ts @@ -0,0 +1,28 @@ +import { allowCorsFor, FnContext } from "deco/mod.ts"; +import { AvailableIcons } from "../static/adminIcons.ts"; + +const icons = Object.keys(AvailableIcons).map((iconName) => ({ + component: AvailableIcons[iconName as keyof typeof AvailableIcons], + label: iconName, +})); + +// Used to load all available icons that will be used for IconSelect widgets. +export default function IconsLoader( + _props: unknown, + req: Request, + ctx: FnContext, +) { + // Allow Cors + Object.entries(allowCorsFor(req)).map(([name, value]) => { + ctx.response.headers.set(name, value); + }); + + // Mapping icons to { value, label, icon } + const iconsMap = icons.map((icon) => ({ + icon: icon.component, + label: icon.label, + value: icon.label, + })); + + return iconsMap; +} diff --git a/loaders/icons.ts b/loaders/icons.ts new file mode 100644 index 00000000..77b5dbf9 --- /dev/null +++ b/loaders/icons.ts @@ -0,0 +1,51 @@ +import { allowCorsFor, FnContext } from "deco/mod.ts"; +import { + AlignCenter, + AlignLeft, + AlignRight, + Center, + Default, + Left, + Lettercase, + Lowercase, + Right, + Uppercase, +} from "../static/adminIcons.ts"; + +const icons = [ + { component: Left, label: "Left", prop: "alignment" }, + { component: Center, label: "Center", prop: "alignment" }, + { component: Right, label: "Right", prop: "alignment" }, + { component: AlignLeft, label: "Left", prop: "textAlignment" }, + { component: AlignCenter, label: "Center", prop: "textAlignment" }, + { component: AlignRight, label: "Right", prop: "textAlignment" }, + { component: Default, label: "Default", prop: "case" }, + { component: Lowercase, label: "Lowercase", prop: "case" }, + { component: Lettercase, label: "Titlecase", prop: "case" }, + { component: Uppercase, label: "Uppercase", prop: "case" }, + { component: "S", label: "Small", prop: "fontSize" }, + { component: "M", label: "Normal", prop: "fontSize" }, + { component: "L", label: "Large", prop: "fontSize" }, +]; + +// Used to load icons that will be used for ButtonGroup widgets. +// The file adminIcons.ts contains all available icons in a string format, and this loader maps them to the format expected by the button-group widget. +export default function IconsLoader( + _props: unknown, + req: Request, + ctx: FnContext, +) { + // Allow Cors + Object.entries(allowCorsFor(req)).map(([name, value]) => { + ctx.response.headers.set(name, value); + }); + + // Mapping icons to { value, label } + const iconsMap = icons.map((icon) => ({ + value: icon.component, + label: icon.label, + prop: icon.prop, + })); + + return iconsMap; +} diff --git a/manifest.gen.ts b/manifest.gen.ts index 593c62e4..e82b0919 100644 --- a/manifest.gen.ts +++ b/manifest.gen.ts @@ -4,6 +4,8 @@ import * as $$$$$$$$$$$0 from "./apps/decohub.ts"; import * as $$$$$$$$$$$1 from "./apps/site.ts"; +import * as $$$2 from "./loaders/availableIcons.ts"; +import * as $$$3 from "./loaders/icons.ts"; import * as $$$0 from "./loaders/Layouts/ProductCard.tsx"; import * as $$$1 from "./loaders/List/Sections.tsx"; import * as $$$$$$0 from "./sections/Animation/Animation.tsx"; @@ -61,6 +63,8 @@ import * as $$$$$$51 from "./sections/Theme/Theme.tsx"; const manifest = { "loaders": { + "deco-sites/storefront/loaders/availableIcons.ts": $$$2, + "deco-sites/storefront/loaders/icons.ts": $$$3, "deco-sites/storefront/loaders/Layouts/ProductCard.tsx": $$$0, "deco-sites/storefront/loaders/List/Sections.tsx": $$$1, }, diff --git a/sections/Content/Benefits.tsx b/sections/Content/Benefits.tsx index eceae97f..25d22afb 100644 --- a/sections/Content/Benefits.tsx +++ b/sections/Content/Benefits.tsx @@ -1,6 +1,16 @@ import Icon, { AvailableIcons } from "$store/components/ui/Icon.tsx"; import Header from "$store/components/ui/SectionHeader.tsx"; +interface Benefit { + label: string; + /** + * @format icon-select + * @options deco-sites/storefront/loaders/availableIcons.ts + */ + icon: AvailableIcons; + description: string; +} + export interface Props { /** * @default Benefits @@ -10,11 +20,7 @@ export interface Props { * @default Check out the benefits */ description?: string; - benefits?: Array<{ - label: string; - icon: AvailableIcons; - description: string; - }>; + benefits?: Array; layout?: { variation?: "Simple" | "With border" | "Color reverse"; headerAlignment?: "center" | "left"; diff --git a/sections/Newsletter/Newsletter.tsx b/sections/Newsletter/Newsletter.tsx index a08ad699..429434a9 100644 --- a/sections/Newsletter/Newsletter.tsx +++ b/sections/Newsletter/Newsletter.tsx @@ -7,19 +7,35 @@ export interface Form { helpText?: string; } +interface Content { + border?: boolean; + /** + * @format button-group + * @options deco-sites/storefront/loaders/icons.ts + */ + alignment?: "Left" | "Center" | "Right"; + bgColor?: "Normal" | "Reverse"; +} + +interface Header { + /** + * @format button-group + * @options deco-sites/storefront/loaders/icons.ts + */ + fontSize?: "Small" | "Normal" | "Large"; +} + +interface Layout { + header?: Header; + content?: Content; +} + export interface Props { title?: string; /** @format textarea */ description?: string; form?: Form; - layout?: { - headerFontSize?: "Large" | "Normal"; - content?: { - border?: boolean; - alignment?: "Center" | "Left" | "Side to side"; - bgColor?: "Normal" | "Reverse"; - }; - }; + layout?: Layout; } const DEFAULT_PROPS: Props = { @@ -32,10 +48,12 @@ const DEFAULT_PROPS: Props = { 'Ao se inscrever, você concorda com nossa Política de privacidade.', }, layout: { - headerFontSize: "Large", + header: { + fontSize: "Large", + }, content: { border: false, - alignment: "Center", + alignment: "Left", }, }, }; @@ -51,7 +69,7 @@ export default function Newsletter(props: Props) { description={description} alignment={layout?.content?.alignment === "Left" ? "left" : "center"} colorReverse={isReverse} - fontSize={layout?.headerFontSize} + fontSize={layout?.header?.fontSize} /> ); @@ -112,7 +130,7 @@ export default function Newsletter(props: Props) { )} - {layout?.content?.alignment === "Side to side" && ( + {layout?.content?.alignment === "Right" && (
diff --git a/sections/Theme/Theme.tsx b/sections/Theme/Theme.tsx index 0b049675..17241025 100644 --- a/sections/Theme/Theme.tsx +++ b/sections/Theme/Theme.tsx @@ -9,54 +9,54 @@ import Color from "npm:colorjs.io"; export interface ThemeColors { /** - * @format color + * @format color-input * @title Base */ "base-100"?: string; - /** @format color */ + /** @format color-input */ "primary"?: string; - /** @format color */ + /** @format color-input */ "secondary"?: string; /** * @title Accent - * @format color */ + * @format color-input */ "tertiary"?: string; - /** @format color */ + /** @format color-input */ "neutral"?: string; - /** @format color */ + /** @format color-input */ "success"?: string; - /** @format color */ + /** @format color-input */ "warning"?: string; - /** @format color */ + /** @format color-input */ "error"?: string; - /** @format color */ + /** @format color-input */ "info"?: string; } export interface ComplementaryColors { - /** @format color */ + /** @format color-input */ "base-200"?: string; - /** @format color */ + /** @format color-input */ "base-300"?: string; - /** @format color */ + /** @format color-input */ "base-content"?: string; - /** @format color */ + /** @format color-input */ "primary-content"?: string; - /** @format color */ + /** @format color-input */ "secondary-content"?: string; /** * @title Accent Content - * @format color */ + * @format color-input */ "tertiary-content"?: string; - /** @format color */ + /** @format color-input */ "neutral-content"?: string; - /** @format color */ + /** @format color-input */ "success-content"?: string; - /** @format color */ + /** @format color-input */ "warning-content"?: string; - /** @format color */ + /** @format color-input */ "error-content"?: string; - /** @format color */ + /** @format color-input */ "info-content"?: string; } diff --git a/static/adminIcons.ts b/static/adminIcons.ts new file mode 100644 index 00000000..70f23dc3 --- /dev/null +++ b/static/adminIcons.ts @@ -0,0 +1,163 @@ +export const ChevronLeft = ``; +export const ChevronRight = ``; +export const ChevronUp = ``; +export const ChevronDown = ``; +export const QuestionMarkCircle = ``; +export const User = ``; +export const ShoppingCart = ``; +export const Bars3 = ``; +export const Heart = ``; +export const MagnifyingGlass = ``; +export const XMark = ``; +export const Plus = ``; +export const Minus = ``; +export const MapPin = ``; +export const Phone = ``; +export const Elos = ``; +export const Mastercards = ``; +export const Visas = ``; +export const Pixs = ` `; +export const Instagram = ``; +export const Truck = ``; +export const Discount = ``; +export const Return = ``; +export const CreditCards = ``; +export const Deco = ``; +export const Discord = ``; +export const FilterList = ``; +export const Trash = ``; +export const WhatsApp = ``; +export const ArrowsPointingOut = ``; +export const Star = ``; +export const Ruler = ``; +export const Message = ``; +export const Close = ``; +export const Zoom = ``; +export const Twitter = ` + + `; +export const Facebook = ` + + `; +export const Linkedin = ` + + + + + + `; +export const Tiktok = ` + + `; +export const Elo = ` + + + + + `; +export const Diners = ` + + + + `; +export const Mastercard = ` + + `; +export const Pix = ` + + + + + + + + + `; +export const Visa = ` + + + + + `; +export const Alert = ` + + `; +export const AlertInfo = ` + + `; +export const AlertSuccess = ` + + `; +export const AlertWarning = ` + + `; +export const AlertError = ` + + `; +export const share = ` + + + `; + +export const AvailableIcons = { ChevronLeft, ChevronRight, ChevronUp, ChevronDown, QuestionMarkCircle, User, ShoppingCart, Bars3, Heart, MagnifyingGlass, XMark, Plus, Minus, MapPin, Phone, Elos, Mastercards, Visas, Pixs, Instagram, Truck, Discount, Return, CreditCards, Deco, Discord, FilterList, Trash, WhatsApp, ArrowsPointingOut, Star, Ruler, Message, Close, Zoom, Twitter, Facebook, Linkedin, Tiktok, Elo, Diners, Mastercard, Pix, Visa, Alert, AlertInfo, AlertSuccess, AlertWarning, AlertError, share }; + +// Icons for ButtonGroup widget + +export const Left = ` + + +`; + +export const Center = ` + + + + `; + +export const Right = ` + + + `; + +export const SideToSide = ` + + + + + + + `; + +export const Default = ` + + `; + +export const AlignJustified = ` + + `; + +export const AlignLeft = ` + + `; + +export const AlignCenter = ` + + `; + +export const AlignRight = ` + + `; + +export const Uppercase = ` + + `; + +export const Lettercase = ` + + `; + +export const Lowercase = ` + + `; + diff --git a/static/generate-icons.ts b/static/generate-icons.ts new file mode 100644 index 00000000..edd353c8 --- /dev/null +++ b/static/generate-icons.ts @@ -0,0 +1,50 @@ +import { existsSync } from 'https://deno.land/std/fs/mod.ts'; + +const svgFilePath = "static/sprites.svg"; +const outputFilePath = "static/adminIcons.ts"; + +async function generateIconsFile() { + const svgContent = await Deno.readTextFile(svgFilePath); + let existingContent = ''; + let existingIcons = new Set(); + let newIcons = []; + + // Verifies if adminIcons.ts already exists and reads the icons from there + if (existsSync(outputFilePath)) { + existingContent = await Deno.readTextFile(outputFilePath); + const regexExtract = /export const (\w+) =/g; + let matchExtract; + while ((matchExtract = regexExtract.exec(existingContent)) !== null) { + existingIcons.add(matchExtract[1]); + } + } + + const regex = /(.+?)<\/symbol>/gs; + let matchSymbol; + while ((matchSymbol = regex.exec(svgContent)) !== null) { + const [_, id, attributes, content] = matchSymbol; + // Adds only new icons + if (!existingIcons.has(id)) { + newIcons.push(id); + const iconString = `export const ${id} = \`${content}\`;\n`; + existingContent += iconString; + } + } + + // If there are new icons, update AvailableIcons and the file + if (newIcons.length > 0) { + // Remove the existing AvailableIcons constant from the content + existingContent = existingContent.replace(/export const AvailableIcons = { [^}]* };/g, ''); + // Adds all existing icons plus the new ones to the AvailableIcons constant + const allIcons = [...existingIcons, ...newIcons]; + const availableIconsString = `export const AvailableIcons = { ${allIcons.join(', ')} };`; + existingContent += `\n${availableIconsString}`; + + await Deno.writeTextFile(outputFilePath, existingContent, { create: true }); + console.log('adminIcons.ts updated successfully with new icons.'); + } else { + console.log('No new icons to add.'); + } +} + +generateIconsFile().catch(console.error); \ No newline at end of file