replace google material icons with phosphor icons

This commit is contained in:
Elijah Duffy
2025-07-10 16:25:27 -07:00
parent 355850d1f2
commit 5f4e50a652
7 changed files with 59 additions and 27 deletions

View File

@@ -13,12 +13,6 @@
rel="stylesheet"
/>
<!-- Material Design Icons -->
<link
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined"
rel="stylesheet"
/>
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover">

View File

@@ -2,9 +2,11 @@
import type { Snippet } from 'svelte';
import type { ClassValue, HTMLButtonAttributes, MouseEventHandler } from 'svelte/elements';
import Spinner from './Spinner.svelte';
import type { IconComponentProps } from 'phosphor-svelte';
import { defaultIconProps, type IconDef } from './util';
interface Props extends Omit<HTMLButtonAttributes, 'class'> {
icon?: string;
icon?: IconDef;
animate?: boolean;
loading?: boolean;
class?: ClassValue | null | undefined;
@@ -25,7 +27,13 @@
...others
}: Props = $props();
let iconElement = $state<HTMLSpanElement | null>(null);
type SVGInHTML = HTMLElement & SVGElement;
let iconElement = $state<SVGInHTML | null>(null);
$effect(() => {
if (icon && ref) {
iconElement = ref.querySelector('svg') as SVGInHTML | null;
}
});
const handleButtonClick: MouseEventHandler<HTMLButtonElement> = (event) => {
if (animate) {
@@ -41,8 +49,11 @@
const triggerAnimation = (className: string) => {
if (icon && iconElement) {
iconElement.classList.remove(className);
void iconElement.offsetWidth;
iconElement.classList.add(className);
// make sure we have DOM reflow
requestAnimationFrame(() => {
iconElement?.classList.add(className);
});
}
};
@@ -76,7 +87,7 @@
{type}
bind:this={ref}
class={[
'button group relative flex gap-3 overflow-hidden rounded-sm px-5',
'button group relative flex items-center gap-3 overflow-hidden rounded-sm px-5',
'text-sui-background cursor-pointer py-3 font-medium transition-colors',
!loading ? ' bg-sui-primary hover:bg-sui-secondary' : 'bg-sui-primary/50 cursor-not-allowed ',
classValue
@@ -87,7 +98,7 @@
{@render children()}
{#if icon && !loading}
<span class="material-symbols-outlined" bind:this={iconElement}>{icon}</span>
<icon.component {...icon.props || defaultIconProps} />
{/if}
{#if loading}
@@ -140,12 +151,12 @@
}
}
:global(button span.animate) {
:global(button svg.animate) {
animation-name: loop;
animation-duration: 0.5s;
}
:global(button span.bounce) {
:global(button svg.bounce) {
animation-name: bounce;
animation-duration: 180ms;
animation-timing-function: ease-in-out;

View File

@@ -7,6 +7,7 @@
import { validate } from '@svelte-toolkit/validate';
import { generateIdentifier } from './util';
import type { ClassValue } from 'svelte/elements';
import { Check, Minus } from 'phosphor-svelte';
interface Props {
name?: string;
@@ -31,6 +32,7 @@
let id = $derived(generateIdentifier('checkbox', name));
let valid = $state(true);
let Icon = $derived(value === 'indeterminate' ? Minus : value ? Check : undefined);
</script>
<div class={['flex items-center', classValue]}>
@@ -69,10 +71,8 @@
onchange?.(value);
}}
>
{#if value === 'indeterminate'}
<span class="material-symbols-outlined">remove</span>
{:else if value === true}
<span class="material-symbols-outlined">check</span>
{#if Icon}
<Icon weight="bold" size="1.1em"></Icon>
{/if}
</button>

View File

@@ -1,9 +1,10 @@
<script lang="ts">
import type { Snippet } from 'svelte';
import type { ClassValue, MouseEventHandler } from 'svelte/elements';
import { defaultIconProps, type IconDef } from './util';
interface Props {
icon?: string;
icon?: IconDef;
iconPosition?: 'left' | 'right';
disabled?: boolean;
class?: ClassValue | null | undefined;
@@ -22,7 +23,9 @@
</script>
{#snippet iconSnippet()}
<span class="material-symbols-outlined">{icon}</span>
{#if icon}
<icon.component {...icon.props || defaultIconProps} />
{/if}
{/snippet}
<button

View File

@@ -13,7 +13,7 @@
| false
| {
text: string;
icon: string;
icon: IconDef;
onclick?: MouseEventHandler<HTMLButtonElement>;
};
@@ -40,6 +40,8 @@
import { tweened } from 'svelte/motion';
import { fade, fly } from 'svelte/transition';
import { validateForm } from '@svelte-toolkit/validate';
import { ArrowLeft, Check } from 'phosphor-svelte';
import type { IconDef } from './util';
let {
pages,
@@ -321,7 +323,7 @@
{#if i >= index}
<span class="mb-[0.0625rem]">{i + 1}</span>
{:else}
<span class="material-symbols-outlined mt-0.5 text-2xl">check_small</span>
<Check class="mt-0.5" size="1.5rem" weight="bold" />
{/if}
</div>
{/each}
@@ -339,7 +341,7 @@
onclick={() => (index -= 1)}
transition:fly={{ x: -200, duration: 200 }}
>
<span class="material-symbols-outlined text-base">arrow_back</span>
<ArrowLeft />
Back
</button>
{/if}

View File

@@ -1,3 +1,22 @@
import type { IconComponentProps } from 'phosphor-svelte';
import type { Component } from 'svelte';
/**
* IconDef is an object that represents an icon element from the phosphor library, alongside an optional set of typed properties.
*/
export type IconDef = {
component: Component;
props?: IconComponentProps;
};
/**
* Defines a set of default properties for icons used in the application.
*/
export const defaultIconProps: IconComponentProps = {
size: '1.2rem',
weight: 'bold'
};
/**
* MaybeGetter is a type that can either be a value of type T or a function that returns a value of type T.
* This is useful for cases where you might want to pass a value directly or a function that computes the

View File

@@ -21,6 +21,7 @@
import {
ArrowUUpLeft,
ArrowUUpRight,
Plus,
TextB,
TextItalic,
TextStrikethrough,
@@ -51,12 +52,14 @@
<div class="component">
<p class="title">Button, Frameless Button, & Link</p>
<div class="flex gap-4">
<Button icon="add" loading={false} onclick={() => alert('Button clicked!')}>Click Me</Button>
<Button icon="add" loading={true} onclick={() => alert('Button clicked!')}
<Button icon={{ component: Plus }} loading={false} onclick={() => alert('Button clicked!')}
>Click Me</Button
>
<Button icon={{ component: Plus }} loading={true} onclick={() => alert('Button clicked!')}
>Loading Button</Button
>
<FramelessButton icon="add">Click Me</FramelessButton>
<FramelessButton icon={{ component: Plus }}>Click Me</FramelessButton>
<Link href="https://svelte.dev">Visit Svelte</Link>
@@ -136,7 +139,7 @@
<DateInput bind:value={dateInputValue} />
<div class="shrink-0">
<Button
icon="add"
icon={{ component: Plus }}
onclick={() => {
dateInputValue = new Date();
console.log('Dateinput value set to:', dateInputValue);