Skip to content

Commit

Permalink
✨ Add Footer component
Browse files Browse the repository at this point in the history
  • Loading branch information
Frontendland committed Sep 30, 2024
1 parent 3b1b54b commit acf1121
Show file tree
Hide file tree
Showing 11 changed files with 610 additions and 4 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ import { Accordion } from 'webcoreui/react'
- [Collapsible](https://github.com/Frontendland/webcoreui/tree/main/src/components/Collapsible)
- [ConditionalWrapper](https://github.com/Frontendland/webcoreui/tree/main/src/components/ConditionalWrapper)
- [DataTable](https://github.com/Frontendland/webcoreui/tree/main/src/components/DataTable)
- [Footer](https://github.com/Frontendland/webcoreui/tree/main/src/components/Footer)
- [Group](https://github.com/Frontendland/webcoreui/tree/main/src/components/Group)
- [Icon](https://github.com/Frontendland/webcoreui/tree/main/src/components/Icon)
- [Input](https://github.com/Frontendland/webcoreui/tree/main/src/components/Input)
Expand Down
91 changes: 91 additions & 0 deletions src/components/Footer/Footer.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
---
import type { FooterProps } from './footer'
import ConditionalWrapper from '../ConditionalWrapper/ConditionalWrapper.astro'
import styles from './footer.module.scss'
interface Props extends FooterProps {}
const {
logo,
columns,
subText,
className,
wrapperClassName,
subTextClassName
} = Astro.props
const classes = [
styles.footer,
className
]
const containerClasses = [
styles.container,
wrapperClassName
]
const subTextClasses = [
styles.subtext,
subTextClassName
]
---

<footer class:list={classes}>
<div class:list={containerClasses}>
<ConditionalWrapper condition={!!(logo?.url || logo?.html)}>
<div slot="wrapper" class={styles.wrapper}>children</div>
{logo?.url && (
<a href="/">
<img
src={logo.url}
alt={logo.alt || 'Logo'}
width={logo.width}
height={logo.height}
loading={logo.eager ? undefined : 'lazy'}
/>
</a>
)}

{logo?.html && (
<a href="/" aria-label={logo.alt || 'Logo'}>
<Fragment set:html={logo.html} />
</a>
)}

{!!columns?.length && (
<ConditionalWrapper condition={columns.length > 1}>
<div slot="wrapper" class={styles.columns}>children</div>
{columns.map(column => (
<ConditionalWrapper condition={!!column.title}>
<div slot="wrapper">children</div>
{column.title && (
<strong class={styles['column-title']}>{column.title}</strong>
)}
<ul class={styles.column}>
{column.items.map(item => (
<li>
<a
href={item.href}
target={item.target}
class:list={[item.active && styles.active]}
>
{item.name}
</a>
</li>
))}
</ul>
</ConditionalWrapper>
))}
</ConditionalWrapper>
)}
</ConditionalWrapper>
{(subText || Astro.slots.has('default')) && (
<div class:list={subTextClasses}>
{subText && <span set:html={subText} />}
<slot />
</div>
)}
</div>
</footer>
94 changes: 94 additions & 0 deletions src/components/Footer/Footer.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<script lang="ts">
import type { FooterProps } from './footer'
import ConditionalWrapper from '../ConditionalWrapper/ConditionalWrapper.svelte'
import { classNames } from '../../utils/classNames'
import styles from './footer.module.scss'
export let logo: FooterProps['logo'] = null
export let columns: FooterProps['columns'] = []
export let subText: FooterProps['subText'] = ''
export let className: FooterProps['className'] = ''
export let wrapperClassName: FooterProps['wrapperClassName'] = ''
export let subTextClassName: FooterProps['subTextClassName'] = ''
const classes = classNames([
styles.footer,
className
])
const containerClasses = classNames([
styles.container,
wrapperClassName
])
const subTextClasses = classNames([
styles.subtext,
subTextClassName
])
</script>

<footer class={classes}>
<div class={containerClasses}>
<ConditionalWrapper
condition={!!(logo?.url || logo?.html)}
class={styles.wrapper}
>
{#if logo?.url}
<a href="/">
<img
src={logo.url}
alt={logo.alt || 'Logo'}
width={logo.width}
height={logo.height}
loading={logo.eager ? undefined : 'lazy'}
/>
</a>
{/if}

{#if logo?.html}
<a href="/" aria-label={logo.alt || 'Logo'}>
{@html logo.html}
</a>
{/if}

{#if columns?.length}
<ConditionalWrapper
condition={columns.length > 1}
class={styles.columns}
>
{#each columns as column}
<ConditionalWrapper condition={!!column.title}>
{#if column.title}
<strong class={styles['column-title']}>{column.title}</strong>
{/if}
<ul class={styles.column}>
{#each column.items as item}
<li>
<a
href={item.href}
target={item.target}
class={item.active ? styles.active : undefined}
>
{item.name}
</a>
</li>
{/each}
</ul>
</ConditionalWrapper>
{/each}
</ConditionalWrapper>
{/if}
</ConditionalWrapper>
{#if subText || $$slots.default}
<div class={subTextClasses}>
{#if subText}
<span>{@html subText}</span>
{/if}
<slot />
</div>
{/if}
</div>
</footer>
107 changes: 107 additions & 0 deletions src/components/Footer/Footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import React from 'react'
import type { ReactFooterProps } from './footer'

import ConditionalWrapper from '../ConditionalWrapper/ConditionalWrapper.tsx'

import { classNames } from '../../utils/classNames'

import styles from './footer.module.scss'

const Footer = ({
logo,
columns,
subText,
className,
wrapperClassName,
subTextClassName,
children
}: ReactFooterProps) => {
const classes = classNames([
styles.footer,
className
])

const containerClasses = classNames([
styles.container,
wrapperClassName
])

const subTextClasses = classNames([
styles.subtext,
subTextClassName
])

return (
<footer className={classes}>
<div className={containerClasses}>
<ConditionalWrapper
condition={!!(logo?.url || logo?.html)}
wrapper={children => <div className={styles.wrapper}>{children}</div>}
>
{logo?.url && (
<a href="/">
<img
src={logo.url}
alt={logo.alt || 'Logo'}
width={logo.width}
height={logo.height}
loading={logo.eager ? undefined : 'lazy'}
/>
</a>
)}

{logo?.html && (
<a
href="/"
aria-label={logo.alt || 'Logo'}
dangerouslySetInnerHTML={{ __html: logo.html }}
/>
)}

{!!columns?.length && (
<ConditionalWrapper
condition={columns.length > 1}
wrapper={children => <div className={styles.columns}>{children}</div>}
>
{columns.map((column, columnIndex) => (
<ConditionalWrapper
condition={!!column.title}
wrapper={children => <div>{children}</div>}
key={columnIndex}
>
{column.title && (
<strong className={styles['column-title']}>
{column.title}
</strong>
)}
<ul className={styles.column}>
{column.items.map((item, itemKey) => (
<li key={itemKey}>
<a
href={item.href}
target={item.target}
className={item.active ? styles.active : undefined}
>
{item.name}
</a>
</li>
))}
</ul>
</ConditionalWrapper>
))}
</ConditionalWrapper>
)}
</ConditionalWrapper>
{(subText || children) && (
<div className={subTextClasses}>
{subText && <span dangerouslySetInnerHTML={{ __html: subText }} />}
{children}
</div>
)}
</div>
</footer>
)
}

export default Footer

61 changes: 61 additions & 0 deletions src/components/Footer/footer.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
@import '../../scss/config.scss';

.footer {
@include border(top, primary-50);

.column-title {
@include spacing(mb-default);

display: block;
}

.column {
@include spacing(0);

list-style-type: none;

a {
@include typography(primary-10, none);

&:hover,
&.active {
@include typography(primary, underline);
}
}
}
}

.container {
@include spacing(auto-default, px-default);

max-width: 1200px;
}

.wrapper {
@include layout(flex, column, default, h-between);
}

.columns {
@include layout(flex, column, default);
}

.subtext {
@include border(top, primary-60);
@include spacing(mt-default, py-default);
@include layout(flex, column, default, h-between);

span {
@include typography(md, primary-20);
}
}

@include media('sm') {
.wrapper,
.subtext {
@include layout(row, none);
}

.columns {
@include layout(row, '5xl');
}
}
27 changes: 27 additions & 0 deletions src/components/Footer/footer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
export type FooterProps = {
logo?: {
url?: string
alt?: string
width?: number
height?: number
eager?: boolean
html?: string
} | null
columns?: {
title?: string
items: {
href: string
name: string
target?: '_self' | '_blank' | '_parent' | '_top' | '_unfencedTop'
active?: boolean
}[]
}[]
subText?: string
className?: string
wrapperClassName?: string
subTextClassName?: string
}

export type ReactFooterProps = {
children?: React.ReactNode
} & FooterProps
Loading

0 comments on commit acf1121

Please sign in to comment.