add common components
This commit is contained in:
parent
d86a69c9a7
commit
f0ca5baf15
|
@ -1,10 +0,0 @@
|
|||
import FileDrop from './components/FileDrop.svelte'
|
||||
import Input from './components/Input.svelte'
|
||||
import Sortable from './components/Sortable.svelte'
|
||||
import BlockQuote from './components/BlockQuote.svelte'
|
||||
import MarkdownEditor from './components/MarkdownEditor.svelte'
|
||||
import MarkdownRenderer from './components/MarkdownRenderer.svelte'
|
||||
|
||||
import { Radio, Checkbox, Fileupload as FileUpload, Range, Select, Textarea, Toggle, Hr as HorizontalRule, Button, ButtonGroup } from 'flowbite-svelte'
|
||||
|
||||
export { FileDrop, Input, Radio, Checkbox, FileUpload, Range, Select, Textarea, Toggle, Sortable, BlockQuote, HorizontalRule, MarkdownEditor, MarkdownRenderer, Button, ButtonGroup }
|
|
@ -1,9 +0,0 @@
|
|||
<script>
|
||||
import { Blockquote, P } from 'flowbite-svelte'
|
||||
</script>
|
||||
|
||||
<Blockquote border bg class="p-4 my-4">
|
||||
<P height="relaxed">
|
||||
<slot />
|
||||
</P>
|
||||
</Blockquote>
|
|
@ -1,13 +0,0 @@
|
|||
<script lang="ts">
|
||||
import { Dropzone } from 'flowbite-svelte'
|
||||
|
||||
export let rules = []
|
||||
</script>
|
||||
|
||||
<Dropzone on:blur on:change on:click on:focus on:mouseenter on:mouseleave on:mouseover>
|
||||
<svg aria-hidden="true" class="mb-3 w-10 h-10 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" />
|
||||
</svg>
|
||||
<p class="mb-2 text-sm text-gray-500 dark:text-gray-400"><span class="font-semibold">Click to upload</span> or drag and drop</p>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">{rules.join(', ')}</p>
|
||||
</Dropzone>
|
|
@ -1,45 +0,0 @@
|
|||
<script lang="ts">
|
||||
import { Input, Label, Helper } from 'flowbite-svelte'
|
||||
import id from './idGenerator'
|
||||
|
||||
const elementId = id('input-')
|
||||
|
||||
export let label = ''
|
||||
export let value = ''
|
||||
export let error: string = null
|
||||
|
||||
export let type:
|
||||
| 'color'
|
||||
| 'date'
|
||||
| 'datetime-local'
|
||||
| 'email'
|
||||
| 'file'
|
||||
| 'hidden'
|
||||
| 'image'
|
||||
| 'month'
|
||||
| 'number'
|
||||
| 'password'
|
||||
| 'reset'
|
||||
| 'submit'
|
||||
| 'tel'
|
||||
| 'text'
|
||||
| 'time'
|
||||
| 'url'
|
||||
| 'week'
|
||||
| 'search' = 'text'
|
||||
</script>
|
||||
|
||||
<div class="mb-6">
|
||||
<Label for={elementId} color={error ? 'red' : null} class="mb-2">{label}</Label>
|
||||
|
||||
<Input bind:value {type} color={error ? 'red' : null} id={elementId} {...$$props}>
|
||||
<slot />
|
||||
</Input>
|
||||
|
||||
{#if error}
|
||||
<Helper class="mt-2" color="red">
|
||||
<span class="font-medium">Error!</span>
|
||||
{error}
|
||||
</Helper>
|
||||
{/if}
|
||||
</div>
|
|
@ -1,5 +0,0 @@
|
|||
<div class="h-full w-full top-0 left-0 flex justify-center items-center">
|
||||
<div class="animate-spin inline-block w-6 h-6 border-[3px] border-current border-t-transparent text-current rounded-full" role="status" aria-label="loading">
|
||||
<span class="sr-only">Loading...</span>
|
||||
</div>
|
||||
</div>
|
|
@ -1,15 +0,0 @@
|
|||
<script>
|
||||
import 'bytemd/dist/index.css'
|
||||
import { Editor } from 'bytemd'
|
||||
import gfm from '@bytemd/plugin-gfm'
|
||||
|
||||
const plugins = [gfm()]
|
||||
|
||||
export let value = ''
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<template>
|
||||
<Editor {value} {plugins} on:change={(e) => (value = e.detail.value)} />
|
||||
</template>
|
||||
</div>
|
|
@ -1,15 +0,0 @@
|
|||
<script>
|
||||
import 'bytemd/dist/index.css'
|
||||
import { Viewer } from 'bytemd'
|
||||
import gfm from '@bytemd/plugin-gfm'
|
||||
|
||||
const plugins = [gfm()]
|
||||
|
||||
export let value = ''
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<template>
|
||||
<Viewer {value} {plugins} />
|
||||
</template>
|
||||
</div>
|
|
@ -1,6 +0,0 @@
|
|||
const gen = (function* () {
|
||||
let index = -1
|
||||
while (true) yield index++
|
||||
})()
|
||||
|
||||
export default (pre: string = '') => `${pre}${gen.next().value}`
|
|
@ -0,0 +1,15 @@
|
|||
import Button from './Common/Button.svelte';
|
||||
import Input from './Common/Input.svelte';
|
||||
import InputWrappper from './Common/InputWrappper.svelte';
|
||||
import Loading from './Common/Loading.svelte';
|
||||
import SOffline from './Common/SOffline.svelte';
|
||||
import Link from './Common/Link.svelte';
|
||||
import Sortable from './Common/Sortable.svelte';
|
||||
import Radio from './Common/Radio.svelte';
|
||||
import Checkbox from './Common/Checkbox.svelte';
|
||||
import Switch from './Common/Switch.svelte';
|
||||
import Select from './Common/Select.svelte';
|
||||
|
||||
import { Body, Html, PwaInstaller } from './Common/Meta';
|
||||
|
||||
export { Button, Input, InputWrappper, Loading, SOffline, Body, Html, PwaInstaller, Link, Sortable, Switch, Radio, Checkbox, Select };
|
|
@ -0,0 +1,15 @@
|
|||
<script lang="ts">
|
||||
export let href: string = null
|
||||
let className = ''
|
||||
export { className as class }
|
||||
</script>
|
||||
|
||||
{#if href !== null}
|
||||
<a {href} class={className}>
|
||||
<slot />
|
||||
</a>
|
||||
{:else}
|
||||
<button class={className} on:click>
|
||||
<slot />
|
||||
</button>
|
||||
{/if}
|
|
@ -0,0 +1,13 @@
|
|||
<script>
|
||||
export let checked = false
|
||||
|
||||
let className = ''
|
||||
export { className as class }
|
||||
</script>
|
||||
|
||||
<input
|
||||
type="checkbox"
|
||||
class="{className} shrink-0 mt-0.5 border-gray-200 rounded text-blue-600 pointer-events-none focus:ring-blue-500 dark:bg-gray-800 dark:border-gray-700 dark:checked:bg-blue-500 dark:checked:border-blue-500 dark:focus:ring-offset-gray-800"
|
||||
{checked}
|
||||
{...$$restProps}
|
||||
/>
|
|
@ -0,0 +1,41 @@
|
|||
<script lang="ts">
|
||||
export let type:
|
||||
| 'color'
|
||||
| 'date'
|
||||
| 'datetime-local'
|
||||
| 'email'
|
||||
| 'file'
|
||||
| 'hidden'
|
||||
| 'image'
|
||||
| 'month'
|
||||
| 'number'
|
||||
| 'password'
|
||||
| 'reset'
|
||||
| 'submit'
|
||||
| 'tel'
|
||||
| 'text'
|
||||
| 'time'
|
||||
| 'url'
|
||||
| 'week'
|
||||
| 'search'
|
||||
| 'textarea' = 'text'
|
||||
|
||||
export let value: any = null
|
||||
let className = ''
|
||||
export { className as class }
|
||||
export let focus = false
|
||||
|
||||
const setType = (node: HTMLInputElement) => {
|
||||
node.type = type
|
||||
}
|
||||
|
||||
const setFocus = (node: HTMLInputElement | HTMLTextAreaElement) => {
|
||||
focus && node.focus()
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if type === 'textarea'}
|
||||
<textarea use:setFocus bind:value class={className} {...$$restProps} />
|
||||
{:else}
|
||||
<input use:setType use:setFocus bind:value class={className} {...$$restProps} />
|
||||
{/if}
|
|
@ -0,0 +1,9 @@
|
|||
<script lang="ts">
|
||||
import generateElementId from '$lib/utils/elementIdGenerator'
|
||||
let className = ''
|
||||
export { className as class }
|
||||
</script>
|
||||
|
||||
<div class={className}>
|
||||
<slot id={generateElementId()} />
|
||||
</div>
|
|
@ -0,0 +1,8 @@
|
|||
<script lang="ts">
|
||||
let className = 'text-blue-600'
|
||||
export { className as class }
|
||||
</script>
|
||||
|
||||
<div class="{className} animate-spin inline-block w-6 h-6 border-[3px] border-current border-t-transparent rounded-full" role="status" aria-label="loading">
|
||||
<span class="sr-only">Loading...</span>
|
||||
</div>
|
|
@ -0,0 +1,5 @@
|
|||
import Body from './meta/Body.svelte';
|
||||
import Html from './meta/Html.svelte';
|
||||
import PwaInstaller from './meta/PwaInstaller.svelte';
|
||||
|
||||
export { Body, Html, PwaInstaller }
|
|
@ -0,0 +1,5 @@
|
|||
<input
|
||||
type="radio"
|
||||
class="shrink-0 mt-0.5 border-gray-200 rounded-full text-blue-600 pointer-events-none focus:ring-blue-500 dark:bg-gray-800 dark:border-gray-700 dark:checked:bg-blue-500 dark:checked:border-blue-500 dark:focus:ring-offset-gray-800"
|
||||
{...$$restProps}
|
||||
/>
|
|
@ -0,0 +1,20 @@
|
|||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
$: isOnline = navigator.onLine || false
|
||||
|
||||
const updateOnlineStatus = () => {
|
||||
isOnline = navigator.onLine
|
||||
dispatch('detectedCondition', { online: isOnline })
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window on:online={updateOnlineStatus} on:offline={updateOnlineStatus} />
|
||||
|
||||
{#if isOnline}
|
||||
<slot name="online" />
|
||||
{:else}
|
||||
<slot name="offline" />
|
||||
{/if}
|
|
@ -0,0 +1,8 @@
|
|||
<select
|
||||
on:change
|
||||
on:select
|
||||
class="py-3 px-4 pr-9 block w-full border-gray-200 rounded-md text-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400"
|
||||
{...$$restProps}
|
||||
>
|
||||
<slot />
|
||||
</select>
|
|
@ -0,0 +1,13 @@
|
|||
<script>
|
||||
export let checked = false
|
||||
|
||||
let className = ''
|
||||
export { className as class }
|
||||
</script>
|
||||
|
||||
<input
|
||||
type="checkbox"
|
||||
class="{className} first-letter:relative w-[3.25rem] h-7 bg-gray-100 checked:bg-none checked:bg-blue-600 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 ring-1 ring-transparent focus:border-blue-600 focus:ring-blue-600 ring-offset-white focus:outline-none appearance-none dark:bg-gray-700 dark:checked:bg-blue-600 dark:focus:ring-offset-gray-800 before:inline-block before:w-6 before:h-6 before:bg-white checked:before:bg-blue-200 before:translate-x-0 checked:before:translate-x-full before:shadow before:rounded-full before:transform before:ring-0 before:transition before:ease-in-out before:duration-200 dark:before:bg-gray-400 dark:checked:before:bg-blue-200"
|
||||
{checked}
|
||||
{...$$restProps}
|
||||
/>
|
|
@ -0,0 +1,16 @@
|
|||
<script>
|
||||
import { onMount } from 'svelte'
|
||||
|
||||
let className = null
|
||||
export { className as class }
|
||||
export let style = null
|
||||
|
||||
let bodyElement
|
||||
|
||||
onMount(() => {
|
||||
bodyElement = document.body
|
||||
})
|
||||
|
||||
$: className !== null && bodyElement && (bodyElement.className = className)
|
||||
$: style !== null && bodyElement && (bodyElement.style.cssText = style)
|
||||
</script>
|
|
@ -0,0 +1,20 @@
|
|||
<script>
|
||||
import { onMount } from 'svelte'
|
||||
|
||||
export let lang = null
|
||||
let className = null
|
||||
export { className as class }
|
||||
export let style = null
|
||||
export let xmlns = null
|
||||
|
||||
let htmlElement
|
||||
|
||||
onMount(() => {
|
||||
htmlElement = document.documentElement
|
||||
})
|
||||
|
||||
$: className !== null && htmlElement && (htmlElement.className = className)
|
||||
$: lang !== null && htmlElement && (htmlElement.lang = lang)
|
||||
$: style !== null && htmlElement && (htmlElement.style.cssText = style)
|
||||
$: xmlns !== null && htmlElement && (htmlElement.xmlns = xmlns)
|
||||
</script>
|
|
@ -0,0 +1,22 @@
|
|||
<script>
|
||||
import { installPrompt } from '../../stores/pwaInstall'
|
||||
|
||||
const install = async () => {
|
||||
if ($installPrompt !== null) {
|
||||
$installPrompt.prompt()
|
||||
const { outcome } = await $installPrompt.userChoice
|
||||
|
||||
if (outcome === 'accepted') $installPrompt = null
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window
|
||||
on:beforeinstallprompt|preventDefault={(e) => {
|
||||
$installPrompt = e
|
||||
}}
|
||||
/>
|
||||
|
||||
{#if $installPrompt}
|
||||
<slot {install} />
|
||||
{/if}
|
|
@ -1,15 +0,0 @@
|
|||
<div>
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
div {
|
||||
background-color: rgba(0, 0, 0, 0.1);
|
||||
border-radius: 0.25rem;
|
||||
color: rgba(0, 0, 0, 0.7);
|
||||
|
||||
box-shadow: #d1d5db 0px -4px 0px inset, rgba(0, 0, 0, 0.4) 0px 1px 1px;
|
||||
|
||||
padding: 0.25rem 0.5rem;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,6 @@
|
|||
import Stack from './Layout/Stack.svelte';
|
||||
import Row from './Layout/Row.svelte';
|
||||
import Container from './Layout/Container.svelte';
|
||||
import AspectRatio from './Layout/AspectRatio.svelte';
|
||||
|
||||
export { Stack, Row, Container, AspectRatio };
|
|
@ -0,0 +1,13 @@
|
|||
<script lang="ts">
|
||||
export let ratio: string
|
||||
</script>
|
||||
|
||||
<div style="--ratio: {ratio};">
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
div {
|
||||
aspect-ratio: var(--ratio);
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,3 @@
|
|||
<div class="container">
|
||||
<slot />
|
||||
</div>
|
|
@ -0,0 +1,3 @@
|
|||
<div class="flex flex-wrap">
|
||||
<slot />
|
||||
</div>
|
|
@ -0,0 +1,8 @@
|
|||
<script lang="ts">
|
||||
let className = ''
|
||||
export { className as class }
|
||||
</script>
|
||||
|
||||
<div class="{className} flex flex-col justify-start">
|
||||
<slot />
|
||||
</div>
|
|
@ -1,5 +0,0 @@
|
|||
<div class="h-full w-full top-0 left-0 flex justify-center items-center">
|
||||
<div class="animate-spin inline-block w-6 h-6 border-[3px] border-current border-t-transparent text-current rounded-full" role="status" aria-label="loading">
|
||||
<span class="sr-only">Loading...</span>
|
||||
</div>
|
||||
</div>
|
|
@ -1,14 +0,0 @@
|
|||
<script lang="ts">
|
||||
export let columns = 3
|
||||
export let gap = 4
|
||||
</script>
|
||||
|
||||
<div class="masonry-grid columns-{columns} gap-x-{gap}">
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
:global(div.masonry-grid *) {
|
||||
break-inside: avoid;
|
||||
}
|
||||
</style>
|
|
@ -1,9 +0,0 @@
|
|||
<div class="flex">
|
||||
<aside class="sidebar__sidebar w-[30%]">
|
||||
<slot name="aside" />
|
||||
</aside>
|
||||
|
||||
<main class="overflow-auto flex-1">
|
||||
<slot />
|
||||
</main>
|
||||
</div>
|
|
@ -1,23 +0,0 @@
|
|||
<script lang="ts">
|
||||
export let space = '3rem'
|
||||
</script>
|
||||
|
||||
<div class="layout-stack" style="--space: {space};">
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
:global(.layout-stack) {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
|
||||
& > * {
|
||||
margin-block: 0;
|
||||
}
|
||||
|
||||
& > * + * {
|
||||
margin-block-start: var(--space, 1.5rem);
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,17 @@
|
|||
export default (node) => {
|
||||
const handleClick = event => {
|
||||
if (node && !node.contains(event.target) && !event.defaultPrevented) {
|
||||
node.dispatchEvent(
|
||||
new CustomEvent('outclick', node)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('click', handleClick, true)
|
||||
|
||||
return {
|
||||
destroy() {
|
||||
document.removeEventListener('click', handleClick, true)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
const generator = (function* () {
|
||||
let index = -1
|
||||
while (true) yield index++
|
||||
})()
|
||||
|
||||
export default (pre: string = 'input') => `${pre.split(' ').join('-')}-${generator.next().value}`
|
|
@ -0,0 +1,9 @@
|
|||
export default async (data) => {
|
||||
try {
|
||||
await navigator.share(data)
|
||||
} catch (e) {
|
||||
navigator.clipboard.writeText(data.url || window.location.href)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
<script lang="ts">
|
||||
import Link from '$lib/components/Link.svelte'
|
||||
import { Link } from '$lib/components/Common'
|
||||
import { _ } from 'svelte-i18n'
|
||||
</script>
|
||||
|
||||
|
|
|
@ -17,9 +17,6 @@
|
|||
"$src/*": [
|
||||
"./src/*"
|
||||
],
|
||||
"$cms/*": [
|
||||
"./cms/*"
|
||||
],
|
||||
"$routes/*": [
|
||||
"./src/routes/*"
|
||||
],
|
||||
|
|
|
@ -10,7 +10,6 @@ export default defineConfig({
|
|||
'$lib': path.resolve(__dirname, 'src', 'lib'),
|
||||
'$root': path.resolve(__dirname),
|
||||
'$src': path.resolve(__dirname, 'src'),
|
||||
'$cms': path.resolve(__dirname, 'src', 'cms'),
|
||||
'$routes': path.resolve(__dirname, 'src', 'routes')
|
||||
}
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue