Replace SVG icons with Icon component throughout the application

A centralized Icon component is now used to manage all SVG icons, improving code readability and maintainability. It also replaced manually defined SVG paths in various components including cards, buttons, and sections.
This commit is contained in:
Emil Gulamov 2024-03-22 04:43:44 +04:00
parent 7821ef382a
commit 24ae5dc3e2
11 changed files with 37 additions and 193 deletions

View file

@ -1,6 +1,7 @@
---
// Import SecondaryCTA component for use in this module
import SecondaryCTA from "../../ui/buttons/SecondaryCTA.astro";
import Icon from "../../ui/icons/Icon.astro";
// Set heading and sub-heading for the pricing section
const title: string = "Simple, Transparent Pricing";
@ -94,17 +95,7 @@ const professionalToolbox: Product = {
{
starterKit.features.map((feature) => (
<li class="flex items-center gap-1.5">
<svg
class="h-5 w-5 shrink-0"
viewBox="0 0 20 20"
fill="currentColor"
>
<path
fill-rule="evenodd"
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z"
clip-rule="evenodd"
/>
</svg>
<Icon name="checkCircle" />
<span>{feature}</span>
</li>
@ -154,17 +145,7 @@ const professionalToolbox: Product = {
{
professionalToolbox.features.map((feature) => (
<li class="flex items-center gap-1.5">
<svg
class="h-5 w-5 shrink-0"
viewBox="0 0 20 20"
fill="currentColor"
>
<path
fill-rule="evenodd"
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z"
clip-rule="evenodd"
/>
</svg>
<Icon name="checkCircle" />
<span>{feature}</span>
</li>

View file

@ -1,12 +1,13 @@
---
import Icon from "../icons/Icon.astro";
// Define props from Astro
const { id, collapseId, heading, content, first } = Astro.props;
const { id, collapseId, question, answer, first } = Astro.props;
// Define TypeScript interface for props
interface Props {
id: string;
collapseId: string;
heading: string;
content: string;
question: string;
answer: string;
first?: boolean;
}
// Define class names for the accordion and its content
@ -27,32 +28,12 @@ function getAccordionClass(first: boolean = false) {
class="hs-accordion-toggle group inline-flex w-full items-center justify-between gap-x-3 text-balance rounded-lg pb-3 text-start font-bold text-neutral-800 outline-none ring-zinc-500 transition hover:text-neutral-500 focus-visible:ring dark:text-neutral-200 dark:ring-zinc-200 dark:hover:text-neutral-400 dark:focus:outline-none md:text-lg"
aria-controls={collapseId}
>
{heading}
{question}
<!-- SVG Icon that is shown when the accordion is NOT active -->
<svg
class="block h-5 w-5 flex-shrink-0 text-neutral-600 group-hover:text-neutral-500 hs-accordion-active:hidden dark:text-neutral-400"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"><path d="m6 9 6 6 6-6"></path></svg
>
<Icon name="accordionNotActive" />
<!-- SVG Icon that is shown when the accordion is active -->
<svg
class="hidden h-5 w-5 flex-shrink-0 text-neutral-600 group-hover:text-neutral-500 hs-accordion-active:block dark:text-neutral-400"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"><path d="m18 15-6-6-6 6"></path></svg
>
<Icon name="accordionActive" />
</button>
<!-- The collapsible content of the accordion -->
<div
@ -62,7 +43,7 @@ function getAccordionClass(first: boolean = false) {
>
<!-- The content paragraph -->
<p class="text-pretty text-neutral-600 dark:text-neutral-400">
{content}
{answer}
</p>
</div>
</div>

View file

@ -1,4 +1,6 @@
---
import Icon from "../icons/Icon.astro";
const { count, description, index } = Astro.props;
interface Props {
@ -12,24 +14,7 @@ interface Props {
<div
class="mb-2 flex items-end gap-x-2 text-3xl font-bold text-neutral-800 dark:text-neutral-200 sm:text-5xl"
>
{
index === 1 || index === 2 ? (
<svg
class="h-5 w-5 flex-shrink-0 text-[#fa5a15] dark:text-[#fb713b]"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="m5 12 7-7 7 7" />
<path d="M12 19V5" />
</svg>
) : null
}
{index === 1 || index === 2 ? <Icon name="arrowUp" /> : null}
{count}
</div>
<p class="text-sm text-neutral-600 dark:text-neutral-400 sm:text-base">

View file

@ -1,22 +1,13 @@
---
import Icon from "../icons/Icon.astro";
---
<button
type="button"
class="focus-visible:ring-secondary group inline-flex items-center rounded-lg p-2.5 text-neutral-600 outline-none ring-zinc-500 transition duration-300 hover:bg-neutral-100 focus:outline-none focus-visible:outline-none focus-visible:ring-1 dark:text-neutral-400 dark:ring-zinc-200 dark:hover:bg-neutral-700"
data-bookmark-button="bookmark-button"
>
<svg
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="h-6 w-6 fill-none transition duration-300"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
class="fill-current text-neutral-500 transition duration-300 group-hover:text-red-400 group-hover:dark:text-red-400"
d="M21 8.25c0-2.485-2.099-4.5-4.688-4.5-1.935 0-3.597 1.126-4.312 2.733-.715-1.607-2.377-2.733-4.313-2.733C5.1 3.75 3 5.765 3 8.25c0 7.22 9 12 9 12s9-4.78 9-12Z"
></path>
</svg>
<Icon name="bookmark" />
</button>
<script>

View file

@ -1,4 +1,5 @@
---
import Icon from "../icons/Icon.astro";
// Destructure the properties from Astro.props
const { title, id, noArrow } = Astro.props;
// Define TypeScript interface for the properties
@ -16,20 +17,6 @@ const bgColorClasses =
const disableClasses = "disabled:pointer-events-none disabled:opacity-50";
const fontSizeClasses = "2xl:text-base";
const ringClasses = "dark:ring-zinc-200";
// SVG for an arrow icon
const arrowSVG = `<svg
class="h-4 w-4 flex-shrink-0 transition duration-300 group-hover:translate-x-1"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="m9 18 6-6-6-6"></path>
</svg>`;
---
<!-- Button with dynamic title, id, and optional arrow -->
@ -38,7 +25,6 @@ const arrowSVG = `<svg
id={id}
>
{title}
<!-- About Fragment: https://docs.astro.build/en/basics/astro-syntax/#fragments -->
<!-- Display the arrow based on the 'noArrow' property -->
{noArrow ? null : <Fragment set:html={arrowSVG} />}
{noArrow ? null : <Icon name="arrowRight" />}
</button>

View file

@ -1,4 +1,5 @@
---
import Icon from "../icons/Icon.astro";
const { title = "Continue with Github", url } = Astro.props;
interface Props {
@ -13,18 +14,6 @@ const bgColorClasses = "bg-yellow-400 dark:focus:outline-none";
const hoverClasses = "hover:shadow-2xl hover:shadow-yellow-500";
const fontSizeClasses = "2xl:text-base";
const ringClasses = "dark:ring-zinc-200";
const githubSVG = `<svg
class="w-4.5 h-4.5 tarnsition flex-shrink-0 text-neutral-700 duration-300 group-hover:-translate-y-1"
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
fill="currentColor"
viewBox="0 0 16 16"
>
<path
d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.012 8.012 0 0 0 16 8c0-4.42-3.58-8-8-8z"
></path>
</svg>`;
---
<a
@ -33,8 +22,6 @@ const githubSVG = `<svg
target="_blank"
rel="noopener noreferrer"
>
<!-- About Fragment: https://docs.astro.build/en/basics/astro-syntax/#fragments -->
<Fragment set:html={githubSVG} />
<Icon name="github" />
{title}
</a>

View file

@ -1,4 +1,5 @@
---
import Icon from "../icons/Icon.astro";
// Destructure the properties from Astro.props
const { title, url, noArrow } = Astro.props;
// Define TypeScript interface for the properties
@ -16,20 +17,6 @@ const bgColorClasses =
const disableClasses = "disabled:pointer-events-none disabled:opacity-50";
const fontSizeClasses = "2xl:text-base";
const ringClasses = "dark:ring-zinc-200";
// SVG for an arrow icon
const arrowSVG = `<svg
class="h-4 w-4 flex-shrink-0 transition duration-300 group-hover:translate-x-1"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="m9 18 6-6-6-6"></path>
</svg>`;
---
<!-- Link styled as a button, with dynamic title, URL, and optional arrow -->
@ -39,7 +26,6 @@ const arrowSVG = `<svg
>
{title}
<!-- Display the arrow based on the 'noArrow' property -->
<!-- About Fragment: https://docs.astro.build/en/basics/astro-syntax/#fragments -->
{noArrow ? null : <Fragment set:html={arrowSVG} />}
{noArrow ? null : <Icon name="arrowRight" />}
</a>

View file

@ -1,4 +1,5 @@
---
import Icon from "../icons/Icon.astro";
// Destructure the properties from Astro.props
const { pageTitle } = Astro.props;
@ -17,41 +18,17 @@ const socialPlatforms: SocialPlatform[] = [
{
name: "Facebook",
url: `https://www.facebook.com/share.php?u=${Astro.url}&title=${pageTitle}`,
svg: `<svg
role="img"
viewBox="0 0 24 24"
stroke="currentColor"
class="size-4 flex-shrink-0 fill-current"
><title>Facebook</title><path
d="M9.101 23.691v-7.98H6.627v-3.667h2.474v-1.58c0-4.085 1.848-5.978 5.858-5.978.401 0 .955.042 1.468.103a8.68 8.68 0 0 1 1.141.195v3.325a8.623 8.623 0 0 0-.653-.036 26.805 26.805 0 0 0-.733-.009c-.707 0-1.259.096-1.675.309a1.686 1.686 0 0 0-.679.622c-.258.42-.374.995-.374 1.752v1.297h3.919l-.386 2.103-.287 1.564h-3.246v8.245C19.396 23.238 24 18.179 24 12.044c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.628 3.874 10.35 9.101 11.647Z"
></path></svg
>`,
svg: "facebook",
},
{
name: "X",
url: `https://twitter.com/home/?status=${pageTitle}${Astro.url}`,
svg: `<svg
role="img"
viewBox="0 0 24 24"
stroke="currentColor"
class="size-4 flex-shrink-0 fill-current"
><title>X</title><path
d="M18.901 1.153h3.68l-8.04 9.19L24 22.846h-7.406l-5.8-7.584-6.638 7.584H.474l8.6-9.83L0 1.154h7.594l5.243 6.932ZM17.61 20.644h2.039L6.486 3.24H4.298Z"
></path></svg
>`,
svg: "x",
},
{
name: "LinkedIn",
url: `https://www.linkedin.com/shareArticle?mini=true&url=${Astro.url}&title=${pageTitle}`,
svg: `<svg
role="img"
viewBox="0 0 24 24"
stroke="currentColor"
class="size-4 flex-shrink-0 fill-current"
><title>LinkedIn</title><path
d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"
></path></svg
>`,
svg: "linkedIn",
},
];
---
@ -64,19 +41,7 @@ const socialPlatforms: SocialPlatform[] = [
type="button"
class="hs-dropdown-toggle inline-flex items-center gap-x-2 rounded-lg px-4 py-3 text-sm font-medium text-neutral-600 outline-none ring-zinc-500 transition duration-300 hover:bg-neutral-100 hover:text-neutral-700 focus-visible:ring dark:text-neutral-400 dark:ring-zinc-200 dark:hover:bg-neutral-700 dark:hover:text-neutral-300 dark:focus:outline-none"
>
<svg
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="h-4 w-4 group-hover:text-neutral-700"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M7.217 10.907a2.25 2.25 0 1 0 0 2.186m0-2.186c.18.324.283.696.283 1.093s-.103.77-.283 1.093m0-2.186 9.566-5.314m-9.566 7.5 9.566 5.314m0 0a2.25 2.25 0 1 0 3.935 2.186 2.25 2.25 0 0 0-3.935-2.186Zm0-12.814a2.25 2.25 0 1 0 3.933-2.185 2.25 2.25 0 0 0-3.933 2.185Z"
></path>
</svg>
<Icon name="share" />
Share
</button>
@ -92,7 +57,7 @@ const socialPlatforms: SocialPlatform[] = [
class="flex items-center gap-x-3.5 rounded-lg px-3 py-2 text-sm text-neutral-700 hover:bg-neutral-200 focus:bg-neutral-100 focus:outline-none dark:text-neutral-300 dark:hover:bg-neutral-700 dark:hover:text-neutral-300 dark:focus:bg-neutral-700 "
href={platform.url}
>
<Fragment set:html={platform.svg} />
<Icon name={platform.svg} />
Share on {platform.name}
</a>
))

View file

@ -1,6 +1,7 @@
---
// Import necessary modules and utilities
import { Image } from "astro:assets";
import Icon from "../icons/Icon.astro";
import type { CollectionEntry } from "astro:content";
const { insightEntry } = Astro.props;
@ -42,18 +43,7 @@ interface Props {
class="mt-5 inline-flex items-center gap-x-1 font-medium text-[#fa5a15] decoration-2 group-hover:underline dark:text-[#fb713b]"
>
Read more
<svg
class="size-4 flex-shrink-0"
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"><path d="m9 18 6-6-6-6"></path></svg
>
<Icon name="arrowRightStatic" />
</p>
</div>
</a>

View file

@ -1,6 +1,7 @@
---
// Import necessary modules and utilities
import { Image } from "astro:assets";
import Icon from "../icons/Icon.astro";
import type { CollectionEntry } from "astro:content";
const { product } = Astro.props;
@ -11,11 +12,6 @@ interface Props {
// Define classes to be used with the Image component
const imageClass =
"absolute inset-0 h-full w-full object-cover object-center transition duration-[600ms] ease-[cubic-bezier(0.45,0,0.55,1)] group-hover:scale-110";
// AnchorSVG - an SVG icon to be added next to the product's subtitle
const AnchorSVG = `
<svg fill="none" viewBox="0 0 24 24" stroke-width="3" stroke="currentColor" class="ml-0.5 w-3 h-3 md:w-4 md:h-4 inline pb-0.5">
<path stroke-linecap="round" stroke-linejoin="round" d="m4.5 19.5 15-15m0 0H8.25m11.25 0v11.25" />
</svg>`;
---
<!-- A clickable card that leads to the details of the product-->
@ -40,6 +36,6 @@ const AnchorSVG = `
<!-- The product's subtitle and the anchor SVG icon-->
<span
class="relative mb-3 ml-4 inline-block text-sm font-bold text-neutral-50 transition duration-[600ms] ease-[cubic-bezier(0.45,0,0.55,1)] group-hover:scale-110 md:ml-5 md:text-lg"
>{product.data.main.subTitle} <Fragment set:html={AnchorSVG} />
>{product.data.main.subTitle} <Icon name="openInNew" />
</span>
</a>

View file

@ -1,6 +1,7 @@
---
// Import necessary modules and utilities
import { Image } from "astro:assets";
import Icon from "../icons/Icon.astro";
import type { CollectionEntry } from "astro:content";
const { product } = Astro.props;
@ -11,11 +12,6 @@ interface Props {
// Define classes to be used with the Image component
const imageClass =
"absolute inset-0 h-full w-full object-cover object-center transition duration-[600ms] ease-[cubic-bezier(0.45,0,0.55,1)] group-hover:scale-110";
// AnchorSVG - an SVG icon to be added next to the product's subtitle
const AnchorSVG = `
<svg fill="none" viewBox="0 0 24 24" stroke-width="3" stroke="currentColor" class="ml-0.5 w-3 h-3 md:w-4 md:h-4 inline pb-0.5">
<path stroke-linecap="round" stroke-linejoin="round" d="m4.5 19.5 15-15m0 0H8.25m11.25 0v11.25" />
</svg>`;
---
<!-- The anchor tag is the main container for the product card. When clicked, this leads to the details of the product. -->
@ -40,6 +36,6 @@ const AnchorSVG = `
<!-- This container includes product's subtitle and an SVG icon-->
<span
class="relative mb-3 ml-4 inline-block text-sm font-bold text-neutral-50 transition duration-[600ms] ease-[cubic-bezier(0.45,0,0.55,1)] group-hover:scale-110 md:ml-5 md:text-lg"
>{product.data.main.subTitle} <Fragment set:html={AnchorSVG} /></span
>{product.data.main.subTitle} <Icon name="openInNew" /></span
>
</a>