Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/whole-beans-hide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@ainsleydev/sveltekit-helper": minor
---

Adding notification components
8 changes: 7 additions & 1 deletion packages/sveltekit-helper/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@
"svelte": "./dist/components/payload/index.js",
"default": "./dist/components/payload/index.js"
},
"./components/notifications": {
"types": "./dist/components/notifications/index.d.ts",
"svelte": "./dist/components/notifications/index.js",
"default": "./dist/components/notifications/index.js"
},
"./utils/forms": {
"types": "./dist/utils/forms/index.d.ts",
"import": "./dist/utils/forms/index.js"
Expand Down Expand Up @@ -72,7 +77,8 @@
}
},
"dependencies": {
"svelte-hamburgers": "^5.0.0"
"svelte-hamburgers": "^5.0.0",
"@lucide/svelte": "^0.562.0"
},
"devDependencies": {
"@ainsleydev/eslint-config": "workspace:*",
Expand Down
4 changes: 4 additions & 0 deletions packages/sveltekit-helper/src/components/Grid/Column.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ const { ...restProps } = $props();
Content
</Column>
```

CSS Custom Properties:
- `--col-gap`: Horizontal padding on desktop (default: 1rem)
- `--col-gap-mobile`: Horizontal padding on mobile (default: var(--col-gap, 0.5rem))
-->
<div class="col" {...restProps}>
<slot />
Expand Down
22 changes: 22 additions & 0 deletions packages/sveltekit-helper/src/components/Grid/Container.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,28 @@ const { ...restProps } = $props();

Centre content such as rows & columns horizontally with predefined max-width.
Uses CSS Grid to provide breakout and full-width layout options.

@example
```svelte
<Container>
<Row>
<Column class="col-12">Content</Column>
</Row>
</Container>
```

@example
```svelte
<Container>
<div class="breakout">Full breakout content</div>
<div class="full-width">Full width content</div>
</Container>
```

CSS Custom Properties:
- `--container-max-width`: Maximum content width (default: 1328px)
- `--container-breakout-max-width`: Maximum breakout width (default: 1500px)
- `--container-padding`: Horizontal padding (default: 1rem)
-->
<div class="container" {...restProps}>
<slot />
Expand Down
4 changes: 4 additions & 0 deletions packages/sveltekit-helper/src/components/Grid/Row.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ const { noGaps = false, ...restProps }: RowProps = $props();
<Column></Column>
</Row>
```

CSS Custom Properties:
- `--row-gap`: Gap between columns (default: 1rem)
- `--row-gap-mobile`: Gap on mobile screens (default: var(--row-gap, 0.5rem))
-->
<div class="row" class:row--no-gaps={noGaps} {...restProps}>
<slot />
Expand Down
9 changes: 9 additions & 0 deletions packages/sveltekit-helper/src/components/Hamburger.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,15 @@ export type HamburgerProps = {
```svelte
<Hamburger gap="1rem">
```

CSS Custom Properties:
- `--hamburger-gap`: Distance from top and right edges (default: 0.8rem)
- `--hamburger-z-index`: Stacking order (default: 10000)
- `--hamburger-colour`: Icon color (default: var(--colour-base-light))
- `--hamburger-layer-width`: Width of each line (default: 24px)
- `--hamburger-layer-height`: Height of each line (default: 2px)
- `--hamburger-layer-spacing`: Gap between lines (default: 5px)
- `--hamburger-border-radius`: Rounding of lines (default: 2px)
-->
<div class="hamburger-wrapper {className}" style="--hamburger-gap: {gap}" aria-label="Toggle Menu">
<SvelteHamburger
Expand Down
15 changes: 15 additions & 0 deletions packages/sveltekit-helper/src/components/Sidebar.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,21 @@ export type SidebarProps = {
<nav>...</nav>
</Sidebar>
```

CSS Custom Properties:
- `--sidebar-width`: Mobile sidebar width (default: 50vw)
- `--sidebar-min-width`: Minimum sidebar width (default: 270px)
- `--sidebar-top`: Desktop sticky position from top (default: 160px)
- `--sidebar-overlay-opacity`: Overlay opacity when open (default: 0.3)
- `--sidebar-background`: Sidebar background color (default: var(--colour-base-black))
- `--sidebar-border-colour`: Border color (default: rgba(255, 255, 255, 0.1))
- `--sidebar-overlay-colour`: Overlay background color (default: var(--colour-grey-900))
- `--sidebar-inner-padding`: Content padding (default: 2rem 1.8rem 0 1.8rem)
- `--sidebar-toggle-background`: Toggle button background (default: var(--colour-base-black))
- `--sidebar-toggle-colour`: Toggle button text color (default: var(--colour-base-light))
- `--sidebar-toggle-padding`: Toggle button padding (default: 0.25rem 1.5rem)
- `--sidebar-toggle-radius`: Toggle button border radius (default: 0.375rem)
- `--sidebar-toggle-font-size`: Toggle button font size (default: 0.9rem)
-->
<aside
class="sidebar sidebar--{toggleStyle} sidebar--{position} {className}"
Expand Down
2 changes: 2 additions & 0 deletions packages/sveltekit-helper/src/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
export { default as Sidebar } from './Sidebar.svelte';
export { default as Hamburger } from './Hamburger.svelte';
export { Alert, Notice } from './notifications';
export type { AlertProps, AlertType, NoticeProps, NoticeType } from './notifications';
167 changes: 167 additions & 0 deletions packages/sveltekit-helper/src/components/notifications/Alert.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
<script lang="ts" module>
import type { Icon as IconType } from '@lucide/svelte';
import type { Snippet } from 'svelte';

export type AlertType = 'info' | 'warning' | 'success' | 'error';

export type AlertProps = {
type?: AlertType;
title?: string;
children?: Snippet;
visible?: boolean;
dismiss?: boolean;
icon?: typeof IconType;
};
</script>

<script lang="ts">
import { X } from '@lucide/svelte'
import { fade } from 'svelte/transition'

import { alertIcons } from './alertIcons.js'

let {
type = 'info',
title = '',
children,
visible = $bindable(true),
dismiss = false,
icon: customIcon,
...restProps
}: AlertProps = $props()

const iconDetail = $derived(alertIcons[type])
const Icon = $derived(customIcon || iconDetail.icon)
const hide = () => (visible = false)
const ariaLive = $derived(type === 'error' ? 'assertive' : 'polite')
</script>

<!--
@component

Full-width alert component for displaying important messages with optional body text.
Supports title, children content, and custom icons with dismissible functionality.

@example
```svelte
<Alert type="info" title="New features available">
Check out the latest updates in your dashboard.
</Alert>

<Alert type="warning" title="Maintenance scheduled" dismiss />

<Alert type="error" title="Payment failed" dismiss>
Your card was declined. Please update your payment method.
</Alert>
```

CSS Custom Properties:
- `--_alert-gap`: Gap between icon and content (default: 12px)
- `--_alert-padding`: Internal padding (default: 24px)
- `--_alert-border-radius`: Border radius (default: 6px)
- `--_alert-bg`: Background color (default: rgba(255, 255, 255, 0.02))
- `--_alert-content-gap`: Gap between title and text (default: 8px)
- `--_alert-title-font-weight`: Title font weight (default: var(--font-weight-semibold))
- `--_alert-title-colour`: Title text color (default: rgba(255, 255, 255, 1))
- `--_alert-text-line-height`: Text line height (default: 1.4)
- `--_alert-text-colour`: Text color (default: rgba(255, 255, 255, 50%))
- `--_alert-icon-colour`: Icon color (set automatically based on type)
-->
{#if visible}
<div
class="alert alert--{type}"
role="alert"
aria-live={ariaLive}
aria-atomic="true"
style="--_alert-icon-colour: {iconDetail.colour}"
transition:fade={{ duration: 300 }}
{...restProps}
>
<!-- Icon -->
<figure class="alert__icon">
<Icon size={24} color={iconDetail.colour} strokeWidth={1.2}></Icon>
</figure>
<!-- Content -->
<div class="alert__content">
{#if title}
<p class="alert__title">
{title}
</p>
{/if}
{#if children}
<p class="alert__text">
{@render children()}
</p>
{/if}
</div>
<!-- Dismiss -->
{#if dismiss}
<button class="alert__dismiss" onclick={hide} aria-label="Close Alert">
<X size={24} color={iconDetail.colour} />
</button>
{/if}
</div>
{/if}

<style lang="scss">
@use '../../scss' as a;

.alert {
$self: &;

position: relative;
display: flex;
gap: var(--_alert-gap, a.$size-12);
width: 100%;
border-radius: var(--_alert-border-radius, 6px);
padding: var(--_alert-padding, a.$size-24);
background-color: var(--_alert-bg, rgba(255, 255, 255, 0.02));

&__icon {
display: flex;
align-items: center;
justify-content: center;
margin: 0;
flex-shrink: 0;
}

&__content {
display: grid;
gap: var(--_alert-content-gap, a.$size-8);
}

&__title {
font-weight: var(--_alert-title-font-weight, var(--font-weight-semibold));
margin: 0;
line-height: 1;
color: var(--_alert-title-colour, rgba(255, 255, 255, 1));

&:empty {
display: none;
}
}

&__text {
margin: 0;
line-height: var(--_alert-text-line-height, 1.4);
color: var(--_alert-text-colour, rgba(255, 255, 255, 50%));
}

&__dismiss {
cursor: pointer;
margin-left: auto;
display: flex;
align-items: center;
justify-content: center;
background: none;
border: none;
padding: 0;
color: var(--_alert-icon-colour);
}

:global(svg) {
min-width: 1.4rem;
min-height: 1.4rem;
}
}
</style>
Loading
Loading