Skip to content

Commit

Permalink
add blog template
Browse files Browse the repository at this point in the history
  • Loading branch information
xuelink committed Oct 24, 2023
1 parent 2c10ed2 commit 714b971
Show file tree
Hide file tree
Showing 91 changed files with 4,260 additions and 0 deletions.
410 changes: 410 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,19 @@
"@types/cookie": "^0.5.1",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
"dateformat": "^5.0.3",
"eslint": "^8.28.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-svelte": "^2.30.0",
"mdsvex": "^0.11.0",
"prettier": "^2.8.0",
"prettier-plugin-svelte": "^2.10.1",
"reading-time": "^1.5.0",
"rehype-autolink-headings": "^7.0.0",
"rehype-external-links": "^3.0.0",
"rehype-slug": "^6.0.0",
"sass": "^1.69.4",
"striptags": "^3.2.0",
"svelte": "^4.0.5",
"svelte-check": "^3.4.3",
"tslib": "^2.4.1",
Expand Down
51 changes: 51 additions & 0 deletions src/lib/components/atoms/Button.story.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<script lang="ts">
import '$lib/scss/global.scss';
import type { ComponentProps } from 'svelte';
import type { Hst } from '@histoire/plugin-svelte';
import Button from './Button.svelte';
import type { NoUndefinedField } from '$lib/utils/types';
import Icon from '$lib/icons/chat.svelte';
export let Hst: Hst;
let props: NoUndefinedField<ComponentProps<Button>> = {
color: 'primary',
style: 'solid',
size: 'medium',
href: '',
target: '_blank',
rel: 'noopener noreferrer'
};
let text = 'This is a Button';
</script>

<Hst.Story title="Atoms/Button" layout={{ type: 'grid', width: 400 }}>
<svelte:fragment slot="controls">
<Hst.Text bind:value={text} title="Text" />
<Hst.Select bind:value={props.color} title="color" options={['primary', 'secondary']} />
<Hst.Select
bind:value={props.style}
title="Style"
options={['solid', 'understated', 'clear']}
/>
<Hst.Select bind:value={props.size} title="Size" options={['small', 'medium', 'large']} />
<Hst.Text bind:value={props.href} title="Href" />
<Hst.Select bind:value={props.target} title="Target" options={['_self', '_blank']} />
<Hst.Text bind:value={props.rel} title="Rel" />
</svelte:fragment>

<div style="padding: 12px;">
<Hst.Variant title="No Icon">
<Button {...props}>
{text}
</Button>
</Hst.Variant>
<Hst.Variant title="With Icon">
<Button {...props}>
<Icon slot="icon" />
{text}
</Button>
</Hst.Variant>
</div>
</Hst.Story>
132 changes: 132 additions & 0 deletions src/lib/components/atoms/Button.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
<script lang="ts">
import { HttpRegex } from '$lib/utils/regex';
export let color: 'primary' | 'secondary' = 'primary';
export let style: 'solid' | 'understated' | 'clear' = 'solid';
export let size: 'small' | 'medium' | 'large' = 'medium';
export let href: string | undefined = undefined;
export let additionalClass: string | undefined = undefined;
const isExternalLink = !!href && HttpRegex.test(href);
export let target: '_self' | '_blank' = isExternalLink ? '_blank' : '_self';
export let rel = isExternalLink ? 'noopener noreferrer' : undefined;
$: tag = href ? 'a' : 'button';
$: linkProps = {
href,
target,
rel
};
</script>

<svelte:element
this={tag}
{...linkProps}
class={['button', `style--${style}`, `size--${size}`, `color--${color}`, additionalClass].join(
' '
)}
data-sveltekit-preload-data
on:click
{...$$restProps}
>
{#if $$slots['icon']}
<div class="icon">
<slot name="icon" />
</div>
{/if}
<slot />
</svelte:element>

<style lang="scss">
.button {
--main-color: red;
--light-color: blue;
--contrast-color: green;
-webkit-appearance: none;
appearance: none;
cursor: pointer;
text-decoration: none;
transition: all 0.2s ease-in-out;
display: flex;
align-items: center;
justify-content: center;
gap: 5px;
border: none;
border-radius: 20px;
font-weight: 700;
.icon {
width: 24px;
height: 24px;
}
&.color {
&--primary {
--main-color: var(--color--primary-rgb);
--light-color: var(--color--primary-tint-rgb);
--contrast-color: var(--color--primary-contrast);
}
&--secondary {
--main-color: var(--color--secondary-rgb);
--light-color: var(--color--secondary-tint-rgb);
--contrast-color: var(--color--secondary-contrast);
}
}
&.style {
&--solid {
background-color: rgb(var(--main-color));
color: var(--contrast-color);
&:hover {
box-shadow: 0px 0px 1px 7px rgba(var(--main-color), 0.3);
}
}
&--understated {
background-color: rgb(var(--light-color));
color: rgb(var(--main-color));
&:hover {
box-shadow: 0px 0px 1px 7px rgba(var(--main-color), 0.3);
}
}
&--clear {
background-color: transparent;
color: rgb(var(--main-color));
&:hover {
background-color: rgb(var(--light-color));
}
}
}
&.size {
&--small {
padding: 5px 10px;
font-size: 0.75rem;
.icon {
width: 20px;
height: 20px;
}
}
&--medium {
padding: 10px 20px;
font-size: 1rem;
}
&--large {
padding: 15px 30px;
font-size: 1.15rem;
.icon {
width: 28px;
height: 28px;
}
}
}
}
</style>
36 changes: 36 additions & 0 deletions src/lib/components/atoms/Card.story.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<script lang="ts">
import '$lib/scss/global.scss';
import type { Hst } from '@histoire/plugin-svelte';
import Card from './Card.svelte';
export let Hst: Hst;
</script>

<Hst.Story title="Atoms/Card" layout={{ type: 'grid', width: 400 }}>
<div style="padding: 10px;">
<Hst.Variant title="Default">
<Card>
<div slot="content">Card Content</div>
<div slot="footer">Footer</div>
</Card>
</Hst.Variant>

<Hst.Variant title="With Image">
<Card>
<img slot="image" src="https://placedog.net/500" alt="A cute dog" />
<div slot="content">
Cards with images will automatically adapt between showing the image on top or bottom
depending on how wide it is.
</div>
</Card>
</Hst.Variant>

<Hst.Variant title="With Link">
<Card href="#">
<img slot="image" src="https://placedog.net/500" alt="A cute dog" />
<div slot="content">Card Content</div>
<div slot="footer">Footer</div>
</Card>
</Hst.Variant>
</div>
</Hst.Story>
99 changes: 99 additions & 0 deletions src/lib/components/atoms/Card.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<script lang="ts">
import { HttpRegex } from '$lib/utils/regex';
export let additionalClass: string | undefined = undefined;
export let href: string | undefined = undefined;
const isExternalLink = !!href && HttpRegex.test(href);
export let target: '_self' | '_blank' = isExternalLink ? '_blank' : '_self';
export let rel = isExternalLink ? 'noopener noreferrer' : undefined;
$: tag = href ? 'a' : 'article';
$: linkProps = {
href,
target,
rel
};
</script>

<svelte:element
this={tag}
class="card {additionalClass}"
{...linkProps}
data-sveltekit-preload-data
{...$$restProps}
>
{#if $$slots.image}
<div class="image">
<slot name="image" />
</div>
{/if}
<div class="body">
<div class="content">
<slot name="content" />
</div>
{#if $$slots.footer}
<div class="footer">
<slot name="footer" />
</div>
{/if}
</div>
</svelte:element>

<style lang="scss">
.card {
background: var(--color--card-background);
box-shadow: var(--card-shadow);
color: var(--color--text);
border-radius: 10px;
transition: all 0.4s ease;
position: relative;
overflow: hidden;
width: 100%;
display: flex;
flex-direction: row;
flex-wrap: wrap;
text-decoration: none;
&[href],
&[onclick] {
cursor: pointer;
&:hover {
box-shadow: var(--card-shadow-hover);
transform: scale(1.01);
}
}
}
.body {
display: flex;
flex-direction: column;
justify-content: space-between;
gap: 10px;
padding: 20px 20px;
flex: 1 0 50%;
.content {
display: flex;
flex-direction: column;
flex: 1;
}
}
.image {
position: relative;
flex: 1 0 max(50%, 330px);
// height: min(100%, 300px);
min-height: 280px;
max-height: 350px;
}
:global(.card [slot='image']) {
width: 100%;
height: 100%;
object-fit: cover;
position: absolute;
}
</style>
48 changes: 48 additions & 0 deletions src/lib/components/atoms/Image.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<script lang="ts">
import { dev } from '$app/environment';
export let src: string;
export let alt: string;
export let fullBleed: boolean | undefined = undefined;
export let formats: string[] = ['avif', 'webp', 'png'];
export let widths: string[] | undefined = undefined;
$: fileName = src.split('.')[0];
function buildSrcset() {
if (dev) return;
let srcset = '';
if (widths) {
for (let i = 0; i < widths.length; i++) {
srcset += `${fileName}-${widths[i]}.${formats[0]} ${widths[i]}w`;
if (i < widths.length - 1) {
srcset += ', ';
}
}
} else {
for (let i = 0; i < formats.length; i++) {
srcset += `${fileName}.${formats[i]}`;
if (i < formats.length - 1) {
srcset += ', ';
}
}
}
return srcset;
}
</script>

<img srcset={buildSrcset()} {src} {alt} loading="lazy" decoding="async" class:full-bleed={fullBleed} />

<style lang="scss">
img {
width: 100%;
height: 100%;
object-fit: contain;
}
</style>
Loading

0 comments on commit 714b971

Please sign in to comment.