代码上传

This commit is contained in:
KeiferJu 2020-03-21 17:35:30 +08:00
commit 5227d045e3
133 changed files with 30251 additions and 0 deletions

1
.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
*.svelte linguist-language=HTML

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
.DS_Store
node_modules
dist/*

0
.npmignore Normal file
View File

8
.prettierrc.js Normal file
View File

@ -0,0 +1,8 @@
module.exports = {
trailingComma: 'es5',
tabWidth: 2,
semi: false,
singleQuote: true,
printWidth: 120,
semi: false,
}

32
.travis.yml Normal file
View File

@ -0,0 +1,32 @@
language: node_js
node_js: lts/*
branches:
only:
- master
- dev
# Tags
- /^v\d+\.\d+(\.\d+)?(-\S*)?$/
- /^greenkeeper\//
addons:
apt:
packages:
- xvfb
install:
- export DISPLAY=':99.0'
- Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &
- npm ci || npm install
script: skip
jobs:
include:
- stage: release
node_js: lts/*
deploy:
provider: script
skip_cleanup: true
script:
- npx semantic-release

22
LICENSE Normal file
View File

@ -0,0 +1,22 @@
MIT License
Copyright (c) 2019 Brian Hann; Modified Copyright 2020 Keifer Ju
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

127
README.md Normal file
View File

@ -0,0 +1,127 @@
# svelma-pro
Based on [svelma](https://github.com/c0bra/svelma) project extension and modification, thanks to the original author components such as c0bra and bulma
Based on the original component library, some common components and bug fixes are extended, and the functions of some components are modified.
# Documentation
[See docs + demos site here](http://www.myllcn.com/svelma-pro/)
# Quick Start
### 1. Create a svelte app(or sapper app) from the template
[https://github.com/sveltejs/template](sveltejs/template) is a template repo for svelte. [degit](https://www.npmjs.com/package/degit) will scaffold the repo for you:
$ npx degit sveltejs/template my-svelma-project
$ cd my-svelma-project
$ npm install
### 2. Install svelma and dependencies
#### bulma and svelma-pro
$ npm install --save bulma svelma-pro
#### scss
$ npm install --save-dev svelte-preprocess autoprefixer node-sass sass
### 3. config
Add the scss plugin to your rollup(webpack) config:
```js
// rollup.config.js
import sveltePreprocess from 'svelte-preprocess';
// ...
const preprocess = sveltePreprocess({
scss: {
includePaths: ['src'],
},
postcss: {
plugins: [require('autoprefixer')],
},
});
export default {
// ...
plugins: [
svelte({
// ...
preprocess: preprocess,
})
]
}
```
```js
// webpack.config.js
import sveltePreprocess from 'svelte-preprocess';
// ...
const preprocess = sveltePreprocess({
scss: {
includePaths: ['src'],
},
postcss: {
plugins: [require('autoprefixer')],
},
});
module.export = {
// ...
module: {
rules: [
{
test: /.(svelte|html)$/,
use: {
loader: 'svelte-loader',
options: {
preprocess,
// ...
}
}
},
]
},
]
}
```
### 4. Import Bulma's CSS and Svelma components
```html
<!-- main.js or client.js(sapper) -->
<script>
import 'bulma/css/bulma.css'
</script>
```
### 5. Include [Font Awesome](https://fontawesome.com/) icons
From CDN in your HTML page:
```html
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.3.1/css/all.css"></link>
```
...or as an npm package imported into your root component:
$ npm install --save @fortawesome/fontawesome-free
```html
<!-- main.js or client.js(sapper) -->
<script>
import 'bulma/css/bulma.css'
import '@fortawesome/fontawesome-free/css/all.css'
</script>
```

9
deploy.js Normal file
View File

@ -0,0 +1,9 @@
var ghpages = require('gh-pages');
ghpages.publish('docs/__sapper__/export/svelma-pro', {
branch: 'gh-pages',
repo: 'https://github.com/KeiferJu/svelma-pro.git',
message: 'deploy',
}, function (err) {
console.log(err);
});

5
docs/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
.DS_Store
node_modules
yarn-error.log
/cypress/screenshots/
/__sapper__/

127
docs/README.md Normal file
View File

@ -0,0 +1,127 @@
# svelma-pro
Based on [svelma](https://github.com/c0bra/svelma) project extension and modification, thanks to the original author components such as c0bra and bulma
Based on the original component library, some common components and bug fixes are extended, and the functions of some components are modified.
# Documentation
[See docs + demos site here]()
# Quick Start
### 1. Create a svelte app(or sapper app) from the template
[https://github.com/sveltejs/template](sveltejs/template) is a template repo for svelte. [degit](https://www.npmjs.com/package/degit) will scaffold the repo for you:
$ npx degit sveltejs/template my-svelma-project
$ cd my-svelma-project
$ npm install
### 2. Install svelma and dependencies
#### bulma and svelma-pro
$ npm install --save bulma svelma-pro
#### scss
$ npm install --save-dev svelte-preprocess autoprefixer node-sass sass
### 3. config
Add the scss plugin to your rollup(webpack) config:
```js
// rollup.config.js
import sveltePreprocess from 'svelte-preprocess';
// ...
const preprocess = sveltePreprocess({
scss: {
includePaths: ['src'],
},
postcss: {
plugins: [require('autoprefixer')],
},
});
export default {
// ...
plugins: [
svelte({
// ...
preprocess: preprocess,
})
]
}
```
```js
// webpack.config.js
import sveltePreprocess from 'svelte-preprocess';
// ...
const preprocess = sveltePreprocess({
scss: {
includePaths: ['src'],
},
postcss: {
plugins: [require('autoprefixer')],
},
});
module.export = {
// ...
module: {
rules: [
{
test: /.(svelte|html)$/,
use: {
loader: 'svelte-loader',
options: {
preprocess,
// ...
}
}
},
]
},
]
}
```
### 4. Import Bulma's CSS and Svelma components
```html
<!-- main.js or client.js(sapper) -->
<script>
import 'bulma/css/bulma.css'
</script>
```
### 5. Include [Font Awesome](https://fontawesome.com/) icons
From CDN in your HTML page:
```html
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.3.1/css/all.css"></link>
```
...or as an npm package imported into your root component:
$ npm install --save @fortawesome/fontawesome-free
```html
<!-- main.js or client.js(sapper) -->
<script>
import 'bulma/css/bulma.css'
import '@fortawesome/fontawesome-free/css/all.css'
</script>
```

18
docs/appveyor.yml Normal file
View File

@ -0,0 +1,18 @@
version: "{build}"
shallow_clone: true
init:
- git config --global core.autocrlf false
build: off
environment:
matrix:
# node.js
- nodejs_version: stable
install:
- ps: Install-Product node $env:nodejs_version
- npm install cypress
- npm install

0
docs/bundle.css Normal file
View File

4
docs/cypress.json Normal file
View File

@ -0,0 +1,4 @@
{
"baseUrl": "http://localhost:3000",
"video": false
}

View File

@ -0,0 +1,5 @@
{
"name": "Using fixtures to represent data",
"email": "hello@cypress.io",
"body": "Fixtures are a great way to mock data for responses to routes"
}

View File

@ -0,0 +1,19 @@
describe('Sapper template app', () => {
beforeEach(() => {
cy.visit('/')
});
it('has the correct <h1>', () => {
cy.contains('h1', 'Great success!')
});
it('navigates to /about', () => {
cy.get('nav a').contains('about').click();
cy.url().should('include', '/about');
});
it('navigates to /blog', () => {
cy.get('nav a').contains('blog').click();
cy.url().should('include', '/blog');
});
});

View File

@ -0,0 +1,17 @@
// ***********************************************************
// This example plugins/index.js can be used to load plugins
//
// You can change the location of this file or turn off loading
// the plugins file with the 'pluginsFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/plugins-guide
// ***********************************************************
// This function is called when a project is opened or re-opened (e.g. due to
// the project's config changing)
module.exports = (on, config) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
}

View File

@ -0,0 +1,25 @@
// ***********************************************
// This example commands.js shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add("login", (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This is will overwrite an existing command --
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })

View File

@ -0,0 +1,20 @@
// ***********************************************************
// This example support/index.js is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************
// Import commands.js using ES2015 syntax:
import './commands'
// Alternatively you can use CommonJS syntax:
// require('./commands')

6501
docs/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

41
docs/package.json Normal file
View File

@ -0,0 +1,41 @@
{
"name": "svelma-site",
"description": "Docs and examples for Svelma",
"version": "0.0.1",
"scripts": {
"dev": "sapper dev",
"build": "sapper build --legacy",
"export": "sapper export --legacy",
"start": "node __sapper__/build"
},
"dependencies": {
"bulma": "^0.7.5",
"clipboard": "^2.0.4",
"compression": "^1.7.1",
"highlight.js": "^9.15.6",
"lodash": "^4.17.15",
"polka": "^0.5.0",
"sirv": "^0.4.0"
},
"devDependencies": {
"@babel/core": "^7.0.0",
"@babel/plugin-syntax-dynamic-import": "^7.0.0",
"@babel/plugin-transform-runtime": "^7.0.0",
"@babel/preset-env": "^7.0.0",
"@babel/runtime": "^7.0.0",
"chokidar": "^3.0.1",
"codesandbox": "^2.1.6",
"npm-run-all": "^4.1.5",
"rollup": "^1.0.0",
"rollup-plugin-babel": "^4.0.2",
"rollup-plugin-commonjs": "^9.1.6",
"rollup-plugin-includepaths": "^0.2.3",
"rollup-plugin-json": "^4.0.0",
"rollup-plugin-node-resolve": "^4.0.0",
"rollup-plugin-replace": "^2.0.0",
"rollup-plugin-scss": "^1.0.1",
"rollup-plugin-svelte": "^5.0.1",
"rollup-plugin-terser": "^4.0.4",
"sapper": "^0.27.4"
}
}

129
docs/rollup.config.js Normal file
View File

@ -0,0 +1,129 @@
import path from 'path'
import { promisify } from 'util'
import { exec as execRaw } from 'child_process'
import alias from 'rollup-plugin-alias'
import autoPreprocess from 'svelte-preprocess'
import babel from 'rollup-plugin-babel'
import commonjs from 'rollup-plugin-commonjs'
import json from 'rollup-plugin-json'
import resolve from 'rollup-plugin-node-resolve'
import replace from 'rollup-plugin-replace'
import svelte from 'rollup-plugin-svelte'
import { terser } from 'rollup-plugin-terser'
import config from 'sapper/config/rollup.js'
import pkg from './package.json'
const exec = promisify(execRaw)
const mode = process.env.NODE_ENV
const dev = mode === 'development'
const legacy = !!process.env.SAPPER_LEGACY_BUILD
export default {
client: {
watch: { chokidar: true },
input: config.client.input(),
output: config.client.output(),
plugins: [
replace({
'process.browser': true,
'process.env.NODE_ENV': JSON.stringify(mode),
}),
alias({
resolve: ['.js', '.mjs', '.html', '.svelte'],
'~': path.join(__dirname, '../src'),
'svelma-pro': '../src/index.js',
}),
// scss(),
svelte({
dev,
hydratable: true,
emitCss: true,
preprocess: autoPreprocess({
postcss: {
plugins: [require('autoprefixer')()],
},
})
}),
resolve(),
commonjs(),
json(),
legacy &&
babel({
extensions: ['.js', '.mjs', '.html', '.svelte'],
runtimeHelpers: true,
exclude: ['node_modules/@babel/**'],
presets: [
[
'@babel/preset-env',
{
targets: '> 0.25%, not dead',
},
],
],
plugins: [
'@babel/plugin-syntax-dynamic-import',
[
'@babel/plugin-transform-runtime',
{
useESModules: true,
},
],
],
}),
!dev &&
terser({
module: true,
})
],
},
server: {
watch: { chokidar: true },
input: config.server.input(),
output: config.server.output(),
plugins: [
replace({
'process.browser': false,
'process.env.NODE_ENV': JSON.stringify(mode),
}),
alias({
resolve: ['.js', '.mjs', '.html', '.svelte'],
'~': path.join(__dirname, '../src'),
'svelma-pro': '../src/index.js',
}),
// scss(),
svelte({
generate: 'ssr',
dev,
preprocess: autoPreprocess({
postcss: {
plugins: [require('autoprefixer')()],
},
})
}),
resolve(),
commonjs(),
json(),
],
external: Object.keys(pkg.dependencies).concat(
require('module').builtinModules || Object.keys(process.binding('natives'))
),
},
serviceworker: {
watch: { chokidar: true },
input: config.serviceworker.input(),
output: config.serviceworker.output(),
plugins: [
resolve(),
replace({
'process.browser': true,
'process.env.NODE_ENV': JSON.stringify(mode),
}),
commonjs(),
!dev && terser(),
],
},
}

13
docs/src/client.js Normal file
View File

@ -0,0 +1,13 @@
import * as sapper from '@sapper/app';
import hljs from 'highlight.js/lib/highlight';
import bash from 'highlight.js/lib/languages/bash';
import xml from 'highlight.js/lib/languages/xml';
import javascript from 'highlight.js/lib/languages/javascript';
hljs.registerLanguage('bash', bash);
hljs.registerLanguage('xml', xml);
hljs.registerLanguage('javascript', javascript);
sapper.start({
target: document.querySelector('#sapper')
});

View File

@ -0,0 +1,110 @@
<script>
import Clipboard from 'clipboard'
import hljs from 'highlight.js/lib/highlight'
import { beforeUpdate, tick, onMount, onDestroy } from 'svelte'
export let lang = 'js'
export let code = ''
export let showCopy = true
let _code = ''
let button
let codeElm
let clip
let show = false
let compiled
let observer
$: {
_code = code || (codeElm && codeElm.innerHTML) || _code
updateCode(code)
}
function updateCode(newCode) {
if (!newCode) return
code = newCode.trim()
compiled = hljs.highlightAuto(code, [lang]).value
}
onMount(async () => {
if (codeElm.innerHTML) code = codeElm.innerHTML
if (button) {
clip = new Clipboard(button, {
text: trigger => code,
})
}
const MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver
observer = new MutationObserver(() => {
if (codeElm && codeElm.innerHTML) updateCode(codeElm.innerHTML)
})
observer.observe(codeElm, {
subtree: true,
childList: true,
characterData: true,
})
await tick()
show = true
})
onDestroy(() => {
if (clip) clip.destroy()
if (observer) observer.disconnect()
})
</script>
<style>
.codeview {
padding: 0;
}
.codeview:not(:last-child) {
margin-bottom: 1.5rem;
}
figure.highlight {
position: relative;
}
.button-container {
position: absolute;
right: 0;
}
/* code {
padding: 1.25rem 1.5rem;
} */
pre.hidden {
visibility: hidden;
height: 0px;
padding: 0px;
}
pre.show {
/* display: block; */
visibility: visible;
}
</style>
<div class="codeview">
<figure class="highlight is-expanded">
{#if showCopy}
<div class="button-container">
<button class="button is-text is-small copy-code" bind:this={button}>Copy</button>
</div>
{/if}
<pre class="hidden">
<code class={lang} bind:this={codeElm}>
<slot />
</code>
</pre>
<pre class:hidden={!show} class:show>
<code>
{@html compiled}
</code>
</pre>
</figure>
</div>

View File

@ -0,0 +1,113 @@
<script>
import { getParameters } from 'codesandbox/lib/api/define'
export let title = 'Svelma Example'
export let code
let form
function extractTag(code, tag) {
let start = code.indexOf(`<${tag}>`)
if (start === -1) return
start = start + tag.length + 2
const end = code.lastIndexOf(`<\/${tag}>`)
const extracted = code.substring(start, end)
return extracted
}
function extractHTML(code) {
code = code.replace(/<script>[\s\S]*<\/script>/im, '')
code = code.replace(/<script>[\s\S]*<\/style>/im, '')
return code
}
$: value = getParameters({
files: {
'sandbox.config.json': {
content: {
template: 'svelte',
},
},
'index.html': {
content: `<html>
<body>
<link
id="external-css"
rel="stylesheet"
type="text/css"
href="https://unpkg.com/bulma/css/bulma.min.css"
media="all"
/>
<link
id="external-css2"
rel="stylesheet"
type="text/css"
href="https://use.fontawesome.com/releases/v5.3.1/css/all.css"
media="all"
/>
</body>
</html>`,
},
'index.js': {
content: `import App from "./App.svelte";
const app = new App({
target: document.body
});
export default app;`,
},
'App.svelte': { content: code },
'package.json': {
content: {
name: 'svelma-example',
version: '1.0.0',
devDependencies: {
'npm-run-all': '^4.1.5',
rollup: '^1.10.1',
'rollup-plugin-commonjs': '^9.3.4',
'rollup-plugin-node-resolve': '^4.2.3',
'rollup-plugin-svelte': '^5.0.3',
'rollup-plugin-terser': '^4.0.4',
'sirv-cli': '^0.3.1',
},
dependencies: {
svelte: 'latest',
svelma: 'latest',
'@fortawesome/fontawesome-free': 'latest',
bulma: 'latest',
},
scripts: {
build: 'rollup -c',
autobuild: 'rollup -c -w',
dev: 'run-p start:dev autobuild',
start: 'sirv public',
'start:dev': 'sirv public --dev',
},
},
},
},
})
function open() {
form.submit()
}
</script>
<style>
.slot-wrap {
cursor: pointer;
pointer-events: auto;
}
</style>
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" bind:this={form}>
<input type="hidden" name="parameters" {value} />
<div class="slot-wrap" on:click={open}>
<slot />
</div>
</form>

View File

@ -0,0 +1,18 @@
<script>
export let title
export let subtitle
$: newTitle = `${title} | Svelma`
</script>
<svelte:head>
<meta property="og:type" content="article" />
<meta property="og:title" content={newTitle} />
<meta property="og:description" content={subtitle} />
</svelte:head>
<!-- Doc for a Svelma Component -->
<header class="header">
<h1 class="title">{title}</h1>
<h2 class="subtitle">{subtitle}</h2>
</header>

View File

@ -0,0 +1,194 @@
<script>
import { onMount } from 'svelte'
import { Button } from 'svelma-pro'
import Code from './Code.svelte'
import CodepenButton from './CodepenButton.svelte'
export let lang = 'xml'
export let code
export let horizontal = false
let showCode = false
function show() {
showCode = true
}
function hide(e) {
e.stopPropagation()
showCode = false
}
</script>
<style lang="scss">
.snippet {
position: relative;
display: flex;
justify-content: center;
align-items: stretch;
border-radius: 6px;
border-top-left-radius: 0;
border: 2px solid #f5f5f5;
flex-direction: row;
margin-top: 3em;
&.horizontal {
flex-direction: column;
}
}
@media screen and (max-width: 1087px) {
.snippet {
flex-direction: column;
}
}
.preview {
min-width: 50%;
padding: 1.5rem;
}
.code {
min-width: 50%;
display: flex;
flex-direction: column;
align-items: stretch;
border-radius: 0 6px 6px 0;
border-left: 1px solid #f5f5f5;
overflow: hidden;
position: relative;
/* cursor: pointer;
pointer-events: auto; */
/*
&::before {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
opacity: 0.8;
background-color: white;
content: '<> Show Code';
display: flex;
justify-content: center;
align-items: center;
z-index: 1;
font-size: 0.75rem;
}*/
/*
&:hover::before {
background-color: #ffdd57;
}
& :global(pre),
& :global(pre code) {
overflow: hidden;
}
&.show-code {
cursor: auto;
&::before {
content: inherit;
}
& :global(figure) {
margin-bottom: 3em;
}
& :global(pre) {
overflow: auto;
}
}*/
}
.snippet::before {
background: #ffdd57;
border-radius: 2px 2px 0 0;
bottom: 100%;
color: rgba(0, 0, 0, 0.7);
content: 'Example';
display: inline-block;
font-size: 7px;
font-weight: 700;
left: -1px;
letter-spacing: 1px;
margin-left: -1px;
padding: 3px 5px;
position: absolute;
text-transform: uppercase;
vertical-align: top;
}
.snippet::before {
content: 'Snippet';
align-items: stretch;
display: flex;
}
.codepen-button {
position: absolute;
display: inline-flex;
background: #ffdd57;
border-radius: 4px 4px 0 0;
bottom: 100%;
font-size: 7px;
font-weight: 700;
right: -1px;
padding: 0 0 0 8px;
vertical-align: top;
letter-spacing: 1px;
text-transform: uppercase;
line-height: 17px;
}
/*.code {
:global(.codeview) {
height: 100%;
:global(figure) {
height: 100%;
:global(pre:not(.hidden)) {
height: 100%;
}
}
}
}*/
:global(.codeview) {
margin-bottom: 0 !important;
}
:global(.btn-show-code) {
align-self: center;
margin: 2em 0 0.5em;
position: absolute;
bottom: 0;
background: none;
}
</style>
<div class="snippet" class:horizontal>
<CodepenButton {code}>
<div class="codepen-button">
Codesandbox
<i class="icon is-small fas fa-external-link-alt" />
</div>
</CodepenButton>
<div class="preview">
<slot name="preview" />
</div>
<div class="code">
<!-- class:show-code={showCode} on:click={show} -->
<Code {lang} {code} />
<!-- {#if showCode}
<Button class="btn-show-code is-rounded is-outline has-text-grey-light" on:click|stopPropagation={hide}>
Hide Code
</Button>
{/if} -->
</div>
</div>

View File

@ -0,0 +1,93 @@
<script>
export let jsdoc
export let showEvent = false
export let showHeader = true
</script>
<style>
@media screen and (max-width: 1087px) {
.table-wrapper {
overflow-x: scroll;
}
}
</style>
{#if jsdoc}
{#if showHeader}<hr class="is-medium" />{/if}
<section>
{#if showHeader}<h2 class="title is-4">API</h2>{/if}
<div class="table-wrapper">
<table class="table is-fullwidth">
<thead>
<tr>
<th>Name</th>
<th>Description</th>
<th>Type</th>
<th>Values</th>
<th>Default</th>
</tr>
</thead>
<tbody>
{#each jsdoc as doc}
{#if !doc.isEvent}
<tr>
<td>
<code>{doc.name}</code>
</td>
<td>
{@html doc.description}{#if doc.optional}, optional{/if}
</td>
<td>{(doc.type || []).join(', ')}</td>
<td>
{@html doc.values || '&mdash;'}
</td>
<td>
{@html ('defaultvalue' in doc && `<code>${doc.defaultvalue}</code>`) || '&mdash;'}
</td>
</tr>
{/if}
{/each}
</tbody>
</table>
</div>
</section>
{/if}
{#if showEvent}
{#if showHeader}<hr class="is-medium" />{/if}
<section>
{#if showHeader}<h2 class="title is-4">EVENT</h2>{/if}
<div class="table-wrapper">
<table class="table is-fullwidth">
<thead>
<tr>
<th>Name</th>
<th>Parameters</th>
<th>Description</th>
</tr>
</thead>
<tbody>
{#each jsdoc as doc}
{#if doc.isEvent}
<tr>
<td>
<code>{doc.name}</code>
</td>
<td>
{@html doc.values || '&mdash;'}
</td>
<td>
{@html doc.description}{#if doc.optional}, optional{/if}
</td>
</tr>
{/if}
{/each}
</tbody>
</table>
</div>
</section>
{/if}

View File

@ -0,0 +1,60 @@
<script>
export let segment
</script>
<style>
img.logo {
padding: 0 10px;
vertical-align: top;
}
.brand {
text-transform: uppercase;
font-weight: bold;
}
</style>
{#if false}
<nav>
<ul>
<li>
<a class={segment === undefined ? 'selected' : ''} href=".">home</a>
</li>
<li>
<a class={segment === 'about' ? 'selected' : ''} href="about">about</a>
</li>
<!-- for the blog link, we're using rel=prefetch so that Sapper prefetches
the blog data when we hover over the link or tap it on a touchscreen -->
<li>
<a rel="prefetch" class={segment === 'blog' ? 'selected' : ''} href="blog">blog</a>
</li>
</ul>
</nav>
{/if}
<nav id="navbar" class="navbar has-shadow is-spaced">
<div class="container">
<div class="navbar-brand">
<a href="/" class="navbar-item brand">
<!-- <img src="svelma-pro-logo.svg" class="logo" alt="Svelma: Bulma components for Svelte" /> -->
svelma-pro
</a>
<!-- <a class="navbar-item is-hidden-desktop" href={github} target="_blank">
<span class="icon" style="color: #333;">
<i class="fab fa-github-alt" />
</span>
</a> -->
</div>
<!-- <div class="navbar-menu">
<div class="navbar-end">
<a class="navbar-item is-hidden-touch" href={github} target="_blank">
<span class="icon" style="color: #333;">
<i class="fab fa-lg fa-github-alt" />
</span>
</a>
</div>
</div> -->
</div>
</nav>

View File

@ -0,0 +1,111 @@
<script context="module">
export async function preload({ params, query }) {
// const res = await this.fetch('')
}
</script>
<script>
import difference from 'lodash/difference'
import { Svelma as Components } from 'svelma-pro'
const formComponents = ['Input', 'Field', 'Switch'].sort()
const omittedComponents = ['Tab']
let components = ['Form', ...Object.keys(Components)].sort()
components = difference(components, [...formComponents, ...omittedComponents])
const bulmaElements = ['Media', 'Table', 'Hero', 'Tiles'].sort()
</script>
<style lang="scss">
.sidebar {
display: flex;
flex-direction: column;
flex-shrink: 0;
width: 16rem;
padding: 3rem 1rem;
background: #f5f5f5;
}
.sidebar > ul {
margin-bottom: 1.5em;
margin-top: 0;
ul {
margin-left: 1.5em;
}
}
.sidebar li {
font-weight: 600;
}
.sidebar-label {
margin-bottom: 0.5em;
color: #7a7a7a;
font-size: 0.9em;
text-transform: uppercase;
letter-spacing: 0.1em;
}
.sidebar-bg {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 50%;
background: #f5f5f5;
min-height: calc(100vh - 4rem);
z-index: -1;
}
@media screen and (max-width: 1087px) {
.sidebar {
order: 2;
width: 100%;
}
}
</style>
<div class="sidebar-bg" />
<aside class="sidebar">
<p class="sidebar-label">Installation</p>
<ul>
<li>
<a href="install">Start</a>
</li>
</ul>
<p class="sidebar-label">Bulma Elements</p>
<ul>
<li><a href="bulma/intro">Intro</a></li>
{#each bulmaElements as c}
<li>
<a href="bulma/{c.toLowerCase()}">{c}</a>
</li>
{/each}
</ul>
<p class="sidebar-label">Svelma Components</p>
<ul>
{#each components as c}
<li>
{#if c === 'Form'}
<p>{c}</p>
<ul>
{#each formComponents as fc}
<li>
<a href="components/{fc.toLowerCase()}">{fc}</a>
</li>
{/each}
</ul>
{:else}
<a href="components/{c.toLowerCase()}">{c}</a>
{/if}
</li>
{/each}
<!-- <li>
<a href="/components/collapse">Collapse</a>
</li>
<li>
<a href="/components/icon">Icon</a>
</li> -->
</ul>
</aside>

View File

@ -0,0 +1,40 @@
<script>
export let status;
export let error;
const dev = process.env.NODE_ENV === 'development';
</script>
<style>
h1, p {
margin: 0 auto;
}
h1 {
font-size: 2.8em;
font-weight: 700;
margin: 0 0 0.5em 0;
}
p {
margin: 1em auto;
}
@media (min-width: 480px) {
h1 {
font-size: 4em;
}
}
</style>
<svelte:head>
<title>{status}</title>
</svelte:head>
<h1>{status}</h1>
<p>{error.message}</p>
{#if dev && error.stack}
<pre>{error.stack}</pre>
{/if}

View File

@ -0,0 +1,78 @@
<!-- <script context="module">
export async function preload({ path }) {
const url = 'https://c0bra.github.io' + `/svelma-pro/${path}`.replace(/\/\//g, '/').replace(/([^\/]$)/, '$1/')
return { url };
}
</script> -->
<script>
import 'bulma/css/bulma.css'
import 'highlight.js/styles/github.css'
import { afterUpdate } from 'svelte'
import { stores } from '@sapper/app';
import Nav from '../components/Nav.svelte'
import Sidebar from '../components/Sidebar.svelte'
const { page } = stores()
export let segment
let url
// page.subscribe(({ path }) => {
// url = 'https://c0bra.github.io' + `/svelma-pro/${path}`.replace(/\/\//g, '/').replace(/([^\/]$)/, '$1/')
// })
// afterUpdate(function() {
// console.log('I updated!', this)
// })
</script>
<style lang="scss">
.docs {
display: flex;
position: relative;
flex-direction: row;
}
.docs-main {
flex-grow: 1;
flex-shrink: 1;
padding: 3rem;
background-color: white;
min-height: calc(100vh - 4rem);
overflow: auto;
}
@media screen and (max-width: 1087px) {
.docs {
flex-direction: column;
}
.docs-main {
min-height: unset;
}
}
</style>
<svelte:head>
<title>svelma-pro</title>
<meta property="og:site_name" content="Svelma" />
<meta property="og:image" content="https://c0bra.github.io/svelma-pro/svelma-pro-logo.png" />
<meta property="og:image:width" content="200" />
<meta property="og:image:height" content="200" />
<meta property="og:url" content={url}>
</svelte:head>
<Nav {segment} />
<main>
<section class="docs">
<Sidebar />
<div class="docs-main">
<slot />
</div>
</section>
</main>

View File

@ -0,0 +1,7 @@
<svelte:head>
<title>关于</title>
</svelte:head>
<h1>关于页面</h1>
<p>本文档基于MIT开源项目svelma-pro扩展修改,由Sm@rtMapX团队维护升级</p>

View File

@ -0,0 +1,28 @@
import posts from './_posts.js';
const lookup = new Map();
posts.forEach(post => {
lookup.set(post.slug, JSON.stringify(post));
});
export function get(req, res, next) {
// the `slug` parameter is available because
// this file is called [slug].json.js
const { slug } = req.params;
if (lookup.has(slug)) {
res.writeHead(200, {
'Content-Type': 'application/json'
});
res.end(lookup.get(slug));
} else {
res.writeHead(404, {
'Content-Type': 'application/json'
});
res.end(JSON.stringify({
message: `Not found`
}));
}
}

View File

@ -0,0 +1,64 @@
<script context="module">
export async function preload({ params, query }) {
// the `slug` parameter is available because
// this file is called [slug].html
const res = await this.fetch(`blog/${params.slug}.json`);
const data = await res.json();
if (res.status === 200) {
return { post: data };
} else {
this.error(res.status, data.message);
}
}
</script>
<script>
export let post;
</script>
<style>
/*
By default, CSS is locally scoped to the component,
and any unused styles are dead-code-eliminated.
In this page, Svelte can't know which elements are
going to appear inside the {{{post.html}}} block,
so we have to use the :global(...) modifier to target
all elements inside .content
*/
.content :global(h2) {
font-size: 1.4em;
font-weight: 500;
}
.content :global(pre) {
background-color: #f9f9f9;
box-shadow: inset 1px 1px 5px rgba(0,0,0,0.05);
padding: 0.5em;
border-radius: 2px;
overflow-x: auto;
}
.content :global(pre) :global(code) {
background-color: transparent;
padding: 0;
}
.content :global(ul) {
line-height: 1.5;
}
.content :global(li) {
margin: 0 0 0.5em 0;
}
</style>
<svelte:head>
<title>{post.title}</title>
</svelte:head>
<h1>{post.title}</h1>
<div class='content'>
{@html post.html}
</div>

View File

@ -0,0 +1,92 @@
// Ordinarily, you'd generate this data from markdown files in your
// repo, or fetch them from a database of some kind. But in order to
// avoid unnecessary dependencies in the starter template, and in the
// service of obviousness, we're just going to leave it here.
// This file is called `_posts.js` rather than `posts.js`, because
// we don't want to create an `/blog/posts` route — the leading
// underscore tells Sapper not to do that.
const posts = [
{
title: 'What is Sapper?',
slug: 'what-is-sapper',
html: `
<p>First, you have to know what <a href='https://svelte.dev'>Svelte</a> is. Svelte is a UI framework with a bold new idea: rather than providing a library that you write code with (like React or Vue, for example), it's a compiler that turns your components into highly optimized vanilla JavaScript. If you haven't already read the <a href='https://svelte.dev/blog/frameworks-without-the-framework'>introductory blog post</a>, you should!</p>
<p>Sapper is a Next.js-style framework (<a href='blog/how-is-sapper-different-from-next'>more on that here</a>) built around Svelte. It makes it embarrassingly easy to create extremely high performance web apps. Out of the box, you get:</p>
<ul>
<li>Code-splitting, dynamic imports and hot module replacement, powered by webpack</li>
<li>Server-side rendering (SSR) with client-side hydration</li>
<li>Service worker for offline support, and all the PWA bells and whistles</li>
<li>The nicest development experience you've ever had, or your money back</li>
</ul>
<p>It's implemented as Express middleware. Everything is set up and waiting for you to get started, but you keep complete control over the server, service worker, webpack config and everything else, so it's as flexible as you need it to be.</p>
`
},
{
title: 'How to use Sapper',
slug: 'how-to-use-sapper',
html: `
<h2>Step one</h2>
<p>Create a new project, using <a href='https://github.com/Rich-Harris/degit'>degit</a>:</p>
<pre><code>npx degit sveltejs/sapper-template#rollup my-app
cd my-app
npm install # or yarn!
npm run dev
</code></pre>
<h2>Step two</h2>
<p>Go to <a href='http://localhost:3000'>localhost:3000</a>. Open <code>my-app</code> in your editor. Edit the files in the <code>src/routes</code> directory or add new ones.</p>
<h2>Step three</h2>
<p>...</p>
<h2>Step four</h2>
<p>Resist overdone joke formats.</p>
`
},
{
title: 'Why the name?',
slug: 'why-the-name',
html: `
<p>In war, the soldiers who build bridges, repair roads, clear minefields and conduct demolitions all under combat conditions are known as <em>sappers</em>.</p>
<p>For web developers, the stakes are generally lower than those for combat engineers. But we face our own hostile environment: underpowered devices, poor network connections, and the complexity inherent in front-end engineering. Sapper, which is short for <strong>S</strong>velte <strong>app</strong> mak<strong>er</strong>, is your courageous and dutiful ally.</p>
`
},
{
title: 'How is Sapper different from Next.js?',
slug: 'how-is-sapper-different-from-next',
html: `
<p><a href='https://github.com/zeit/next.js'>Next.js</a> is a React framework from <a href='https://zeit.co'>Zeit</a>, and is the inspiration for Sapper. There are a few notable differences, however:</p>
<ul>
<li>It's powered by <a href='https://svelte.dev'>Svelte</a> instead of React, so it's faster and your apps are smaller</li>
<li>Instead of route masking, we encode route parameters in filenames. For example, the page you're looking at right now is <code>src/routes/blog/[slug].html</code></li>
<li>As well as pages (Svelte components, which render on server or client), you can create <em>server routes</em> in your <code>routes</code> directory. These are just <code>.js</code> files that export functions corresponding to HTTP methods, and receive Express <code>request</code> and <code>response</code> objects as arguments. This makes it very easy to, for example, add a JSON API such as the one <a href='blog/how-is-sapper-different-from-next.json'>powering this very page</a></li>
<li>Links are just <code>&lt;a&gt;</code> elements, rather than framework-specific <code>&lt;Link&gt;</code> components. That means, for example, that <a href='blog/how-can-i-get-involved'>this link right here</a>, despite being inside a blob of HTML, works with the router as you'd expect.</li>
</ul>
`
},
{
title: 'How can I get involved?',
slug: 'how-can-i-get-involved',
html: `
<p>We're so glad you asked! Come on over to the <a href='https://github.com/sveltejs/svelte'>Svelte</a> and <a href='https://github.com/sveltejs/sapper'>Sapper</a> repos, and join us in the <a href='https://svelte.dev/chat'>Discord chatroom</a>. Everyone is welcome, especially you!</p>
`
}
];
posts.forEach(post => {
post.html = post.html.replace(/^\t{3}/gm, '');
});
export default posts;

View File

@ -0,0 +1,16 @@
import posts from './_posts.js';
const contents = JSON.stringify(posts.map(post => {
return {
title: post.title,
slug: post.slug
};
}));
export function get(req, res) {
res.writeHead(200, {
'Content-Type': 'application/json'
});
res.end(contents);
}

View File

@ -0,0 +1,34 @@
<script context="module">
export function preload({ params, query }) {
return this.fetch(`blog.json`).then(r => r.json()).then(posts => {
return { posts };
});
}
</script>
<script>
export let posts;
</script>
<style>
ul {
margin: 0 0 1em 0;
line-height: 1.5;
}
</style>
<svelte:head>
<title>Blog</title>
</svelte:head>
<h1>Recent posts</h1>
<ul>
{#each posts as post}
<!-- we're using the non-standard `rel=prefetch` attribute to
tell Sapper to load the data for the page as soon as
the user hovers over the link or taps it, instead of
waiting for the 'click' event -->
<li><a rel='prefetch' href='blog/{post.slug}'>{post.title}</a></li>
{/each}
</ul>

View File

@ -0,0 +1,77 @@
<script>
import { onDestroy, onMount } from 'svelte'
import { slide } from 'svelte/transition'
import Codepreview from '../../components/Code.svelte'
import DocHeader from '../../components/DocHeader.svelte'
import Example from '../../components/Example.svelte'
const types = ['is-primary', 'is-success', 'is-danger', 'is-warning', 'is-info', 'is-link']
let type = 'is-primary'
async function update() {
type = ''
setTimeout(() => {
type = types[Math.floor(Math.random() * types.length)];
}, 1000)
}
</script>
<DocHeader title="Hero" subtitle="Hero headers" />
<Example horizontal={true} code={`<script>
import { slide } from 'svelte/transition'
const types = ['is-primary', 'is-success', 'is-danger', 'is-warning', 'is-info', 'is-link']
let type = 'is-primary'
async function update() {
type = ''
setTimeout(() => {
type = types[Math.floor(Math.random() * types.length)];
}, 1000)
}
</script>
<button class="button is-primary" on:click={update}>Update Hero</button>
<br />
<br />
{#if type}
<section class="hero {type}" transition:slide>
<div class="hero-body">
<div class="container">
<h1 class="title">
Title
</h1>
<h2 class="subtitle">
Subtitle
</h2>
</div>
</div>
</section>
{/if}`}>
<div slot="preview">
<button class="button is-primary" on:click={update}>Update Hero</button>
<br />
<br />
{#if type}
<section class="hero {type}" transition:slide>
<div class="hero-body">
<div class="container">
<h1 class="title">
Title
</h1>
<h2 class="subtitle">
Subtitle
</h2>
</div>
</div>
</section>
{/if}
</div>
</Example>

View File

@ -0,0 +1,9 @@
<script>
import DocHeader from '../../components/DocHeader.svelte'
</script>
<DocHeader title="Bulma Elements" subtitle="在Svelte中使用常规Bulma元素" />
<p class="content">
许多Bulma组件很容易与常规的Svelte代码一起使用而不需要额外的Svelma组件层。本节的文档将讨论如何在Svelte中使用这些元素。
</p>

View File

@ -0,0 +1,141 @@
<script>
import { onDestroy, onMount } from 'svelte'
import { fade, slide } from 'svelte/transition'
import Codepreview from '../../components/Code.svelte'
import DocHeader from '../../components/DocHeader.svelte'
import Example from '../../components/Example.svelte'
let timer
let user
const titleize = s => s.replace(/^([a-z])/, (_, r) => r.toUpperCase())
async function updateUser() {
user = null
user = (await (await fetch('https://randomuser.me/api/')).json()).results[0]
}
onMount(() => updateUser())
</script>
<DocHeader title="Media" subtitle="Social media UI element" />
<Example horizontal={true} code={`<script>
import { onDestroy, onMount } from 'svelte'
import { fade } from 'svelte/transition'
let user
const titleize = s => s.replace(/^([a-z])/, (_, r) => r.toUpperCase())
async function updateUser() {
user = null
user = (await (await fetch('https://randomuser.me/api/')).json()).results[0]
}
</script>
<button class="button is-primary" on:click={updateUser}>Fetch New User</button>
<br />
<br />
<div class="box">
<article class="media">
<div class="media-left">
<figure class="image is-64x64">
{#if user}
<img transition:fade class="is-rounded" src={user.picture.medium} alt="Profile picture" />
{/if}
</figure>
</div>
<div class="media-content">
<div class="content">
{#if user}
<p transition:fade>
<strong>{titleize(user.name.first)} {titleize(user.name.last)}</strong>
<small>@{user.login.username}</small>
<small />
<br />
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean efficitur sit amet massa fringilla
egestas. Nullam condimentum luctus turpis.
</p>
{/if}
</div>
{#if user}
<nav class="level is-mobile" transition:fade>
<div class="level-left">
<a href class="level-item" aria-label="reply">
<span class="icon is-small">
<i class="fas fa-reply" aria-hidden="true" />
</span>
</a>
<a href class="level-item" aria-label="retweet">
<span class="icon is-small">
<i class="fas fa-retweet" aria-hidden="true" />
</span>
</a>
<a href class="level-item" aria-label="like">
<span class="icon is-small">
<i class="fas fa-heart" aria-hidden="true" />
</span>
</a>
</div>
</nav>
{/if}
</div>
</article>
</div>`}>
<div slot="preview">
<button class="button is-primary" on:click={updateUser}>Fetch New User</button>
<br />
<br />
<div class="box">
<article class="media">
<div class="media-left">
<figure class="image is-64x64">
{#if user}
<img transition:fade class="is-rounded" src={user.picture.medium} alt="Profile picture" />
{/if}
</figure>
</div>
<div class="media-content">
<div class="content">
{#if user}
<p transition:fade>
<strong>{titleize(user.name.first)} {titleize(user.name.last)}</strong>
<small>@{user.login.username}</small>
<small />
<br />
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean efficitur sit amet massa fringilla
egestas. Nullam condimentum luctus turpis.
</p>
{/if}
</div>
{#if user}
<nav class="level is-mobile" transition:fade>
<div class="level-left">
<a href class="level-item" aria-label="reply">
<span class="icon is-small">
<i class="fas fa-reply" aria-hidden="true" />
</span>
</a>
<a href class="level-item" aria-label="retweet">
<span class="icon is-small">
<i class="fas fa-retweet" aria-hidden="true" />
</span>
</a>
<a href class="level-item" aria-label="like">
<span class="icon is-small">
<i class="fas fa-heart" aria-hidden="true" />
</span>
</a>
</div>
</nav>
{/if}
</div>
</article>
</div>
</div>
</Example>

View File

@ -0,0 +1,128 @@
<script>
import { onMount } from 'svelte'
import Codepreview from '../../components/Code.svelte'
import DocHeader from '../../components/DocHeader.svelte'
import Example from '../../components/Example.svelte'
let loading = false
let users = []
const titleize = s => s.replace(/^([a-z])/, (_, r) => r.toUpperCase())
async function update() {
loading = true
users = []
users = (await (await fetch('https://randomuser.me/api/?results=10')).json()).results
loading = false
}
onMount(() => update())
</script>
<DocHeader title="Tables" subtitle="Pretty HTML tables" />
<Example code={`<script>
let loading = false
let users = []
const titleize = s => s.replace(/^([a-z])/, (_, r) => r.toUpperCase())
async function update() {
loading = true
users = []
users = (await (await fetch('https://randomuser.me/api/?results=10')).json()).results
loading = false
}
onMount(() => update())
</script>
<button class="button is-primary" on:click={update}>Update</button>
<button class="button is-primary" on:click={() => users = []}>No Data</button>
<br>
<br>
<table class="table is-fullwidth">
<thead>
<tr>
<th></th>
<th>First Name</th>
<th>Last Name</th>
<th>City</th>
<th>State</th>
</tr>
</thead>
<tbody>
{#each users as user}
<tr>
<td><figure class="image"><img class="is-rounded" src="{user.picture.thumbnail}" alt=""></figure></td>
<td>{titleize(user.name.first)}</td>
<td>{titleize(user.name.last)}</td>
<td>{titleize(user.location.city)}</td>
<td>{titleize(user.location.state)}</td>
</tr>
{:else}
{#if !loading}
<tr>
<td colspan="5">
<section class="section">
<div class="content has-text-grey has-text-centered">
<p><i class="far fa-3x fa-frown"></i></p>
<p>No data</p>
</div>
</section>
</td>
</tr>
{/if}
{/each}
</tbody>
</table>`}>
<div slot="preview">
<button class="button is-primary" on:click={update}>Update</button>
<button class="button is-primary" on:click={() => users = []}>No Data</button>
<br>
<br>
<table class="table is-fullwidth">
<thead>
<tr>
<th></th>
<th>First Name</th>
<th>Last Name</th>
<th>City</th>
<th>State</th>
</tr>
</thead>
<tbody>
{#each users as user}
<tr>
<td><figure class="image"><img class="is-rounded" src="{user.picture.thumbnail}" alt=""></figure></td>
<td>{titleize(user.name.first)}</td>
<td>{titleize(user.name.last)}</td>
<td>{titleize(user.location.city)}</td>
<td>{titleize(user.location.state)}</td>
</tr>
{:else}
{#if !loading}
<tr>
<td colspan="5">
<section class="section">
<div class="content has-text-grey has-text-centered">
<p><i class="far fa-3x fa-frown"></i></p>
<p>No data</p>
</div>
</section>
</td>
</tr>
{/if}
{/each}
</tbody>
</table>
</div>
</Example>

View File

@ -0,0 +1,179 @@
<script>
import { onDestroy, onMount } from 'svelte'
import DocHeader from '../../components/DocHeader.svelte'
import Example from '../../components/Example.svelte'
async function waitForDraggabilly() {
return new Promise((resolve, reject) => {
const interval = setInterval(() => {
if (Draggabilly) {
clearInterval(interval);
resolve();
}
}, 250);
});
}
onMount(async () => {
const draggables = document.querySelectorAll('.tile.is-child');
await waitForDraggabilly();
for (const elm of draggables) {
let drag = new Draggabilly(elm, { // .tile:not(.is-ancestor)
containment: '.tile.is-ancestor',
});
}
})
</script>
<style>
.tile:not(.is-ancestor) {
user-select: none;
}
:global(.is-dragging) {
transform: rotate(25deg);
cursor: move;
}
</style>
<DocHeader title="Tiles" subtitle="2D grids with flexbox" />
<Example code={`<script>
import { onMount } from 'svelte'
waitForDraggabilly() {
return new Promise((resolve, reject) => {
const interval = setInterval({
if (Draggabilly) {
clearInterval(interval);
resolve();
}
}, 100);
});
}
onMount(async () => {
const draggables = document.querySelectorAll('.tile.is-child');
await waitForDraggabilly();
for (const elm of draggables) {
let drag = new Draggabilly(elm, {
containment: '.tile.is-ancestor',
});
}
})
</script>
<style>
.tile:not(.is-ancestor) {
user-select: none;
}
:global(.is-dragging) {
transform: rotate(25deg);
cursor: move;
}
</style>
<script src="https://unpkg.com/draggabilly@2/dist/draggabilly.pkgd.min.js"></script>
<div class="tile is-ancestor">
<div class="tile is-vertical is-8">
<div class="tile">
<div class="tile is-parent is-vertical">
<article class="tile is-child notification is-primary">
<p class="title">Vertical...</p>
<p class="subtitle">Top tile</p>
</article>
<article class="tile is-child notification is-warning">
<p class="title">...tiles</p>
<p class="subtitle">Bottom tile</p>
</article>
</div>
<div class="tile is-parent">
<article class="tile is-child notification is-info">
<p class="title">Middle tile</p>
<p class="subtitle">With an image</p>
<figure class="image is-4by3">
<img src="https://bulma.io/images/placeholders/640x480.png" />
</figure>
</article>
</div>
</div>
<div class="tile is-parent">
<article class="tile is-child notification is-danger">
<p class="title">Wide tile</p>
<p class="subtitle">Aligned with the right tile</p>
<div class="content">
<!-- Content -->
</div>
</article>
</div>
</div>
<div class="tile is-parent">
<article class="tile is-child notification is-success">
<div class="content">
<p class="title">Tall tile</p>
<p class="subtitle">With even more content</p>
<div class="content">
<!-- Content -->
</div>
</div>
</article>
</div>
</div>`}>
<div slot="preview">
<script src="https://unpkg.com/draggabilly@2/dist/draggabilly.pkgd.min.js"></script>
<h5 class="title">Click to drag tiles</h5>
<div class="tile is-ancestor">
<div class="tile is-vertical is-8">
<div class="tile">
<div class="tile is-parent is-vertical">
<article class="tile is-child notification is-primary">
<p class="title">Vertical...</p>
<p class="subtitle">Top tile</p>
</article>
<article class="tile is-child notification is-warning">
<p class="title">...tiles</p>
<p class="subtitle">Bottom tile</p>
</article>
</div>
<div class="tile is-parent">
<article class="tile is-child notification is-info">
<p class="title">Middle tile</p>
<p class="subtitle">With an image</p>
<figure class="image is-4by3">
<img src="https://bulma.io/images/placeholders/640x480.png" alt="profile" />
</figure>
</article>
</div>
</div>
<div class="tile is-parent">
<article class="tile is-child notification is-danger">
<p class="title">Wide tile</p>
<p class="subtitle">Aligned with the right tile</p>
<div class="content">
<!-- Content -->
</div>
</article>
</div>
</div>
<div class="tile is-parent">
<article class="tile is-child notification is-success">
<div class="content">
<p class="title">Tall tile</p>
<p class="subtitle">With even more content</p>
<div class="content">
<!-- Content -->
</div>
</div>
</article>
</div>
</div>
</div>
</Example>

View File

@ -0,0 +1,14 @@
import jsdocs from './jsdocs.json'
const titleize = s => s.replace(/^([a-z])/, (_, r) => r.toUpperCase())
export async function get(req, res, next) {
const { slug } = req.params;
res.setHeader('Content-Type', 'application/json');
res.end(
JSON.stringify(
jsdocs[titleize(slug)]
)
);
}

View File

@ -0,0 +1,180 @@
<script context="module">
export async function preload(page, session) {
const res = await this.fetch(`components/button.json`)
const jsdoc = await res.json()
return { jsdoc }
}
</script>
<script>
import { onMount } from 'svelte'
import { Button, Icon } from 'svelma-pro'
import DocHeader from '../../components/DocHeader.svelte'
import Example from '../../components/Example.svelte'
import JSDoc from '../../components/JSDoc.svelte'
export let jsdoc
let counter = 0
</script>
<style>
.buttons {
display: flex;
justify-content: flex-start;
flex-wrap: wrap;
}
</style>
<DocHeader title="Buttons" subtitle="可点击按钮" />
<Example
code={`<Button type="is-primary" on:click={() => counter++}>
Click!: {counter}
</Button>`}>
<div slot="preview">
<Button type="is-primary" on:click={() => counter++}>Click!: {counter}</Button>
</div>
</Example>
<hr class="is-medium" />
<p class="title is-4">状态,样式和类型</p>
<Example
code={`<div class="buttons">
<Button type="is-primary">Primary</Button>
<Button type="is-success">Success</Button>
<Button type="is-danger">Danger</Button>
<Button type="is-warning">Warning</Button>
<Button type="is-info">Info</Button>
<Button type="is-link">Link</Button>
<Button type="is-light">Light</Button>
<Button type="is-dark">Dark</Button>
<Button type="is-text">Text</Button>
</div>
<div class="buttons">
<Button disabled>Disabled</Button>
<Button type="is-primary" loading>Loading</Button>
<Button type="is-success" rounded>Rounded</Button>
<Button type="is-info" outline>Outlined</Button>
</div>
<div class="buttons">
<div class="notification is-primary">
<Button type="is-primary" inverted>Inverted</Button>
<Button type="is-primary" inverted outlined>Invert Outlined</Button>
</div>
</div>
<div class="buttons">
<Button type="is-primary" nativeType="submit">Submit</Button>
<Button type="is-primary" nativeType="reset">Reset</Button>
</div>`}>
<div slot="preview">
<div class="buttons">
<Button type="is-primary">Primary</Button>
<Button type="is-success">Success</Button>
<Button type="is-danger">Danger</Button>
<Button type="is-warning">Warning</Button>
<Button type="is-info">Info</Button>
<Button type="is-link">Link</Button>
<Button type="is-light">Light</Button>
<Button type="is-dark">Dark</Button>
<Button type="is-text">Text</Button>
</div>
<div class="buttons">
<Button disabled>Disabled</Button>
<Button type="is-primary" loading>Loading</Button>
<Button type="is-success" rounded>Rounded</Button>
<Button type="is-info" outline>Outlined</Button>
</div>
<div class="buttons">
<div class="notification is-primary">
<Button type="is-primary" inverted>Inverted</Button>
<Button type="is-primary" inverted outlined>Invert Outlined</Button>
</div>
</div>
<div class="buttons">
<Button type="is-primary" nativeType="submit">Submit</Button>
<Button type="is-primary" nativeType="reset">Reset</Button>
</div>
</div>
</Example>
<hr class="is-medium" />
<p class="title is-4">Sizes</p>
<Example
code={`<div class="buttons">
<Button size="is-small">Small</Button>
<Button>Default</Button>
<Button size="is-medium">Medium</Button>
<Button size="is-large">Large</Button>
</div>`}>
<div slot="preview">
<div class="buttons">
<Button size="is-small">Small</Button>
<Button>Default</Button>
<Button size="is-medium">Medium</Button>
<Button size="is-large">Large</Button>
</div>
</div>
</Example>
<hr class="is-medium" />
<p class="title is-4">Icons</p>
<Example
code={`<div class="buttons">
<Button>
<Icon icon="bold" />
</Button>
<Button>
<Icon icon="underline" />
</Button>
<Button>
<Icon icon="italic" />
</Button>
</div>
<div class="buttons">
<Button iconPack="fab" iconLeft="github">GitHub</Button>
<Button type="is-primary" iconPack="fab" iconLeft="twitter">Twitter</Button>
<Button type="is-success" iconPack="fa" iconLeft="check">Save</Button>
<Button type="is-danger" outline iconPack="fa" iconRight="times">Delete</Button>
</div>
<div class="buttons">
<Button size="is-small" iconPack="fab" iconLeft="github">GitHub</Button>
<Button iconLeft="github" iconPack="fab">GitHub</Button>
<Button size="is-medium" iconPack="fab" iconLeft="github">GitHub</Button>
<Button size="is-large" iconPack="fab" iconLeft="github">GitHub</Button>
</div>`}>
<div slot="preview">
<div class="buttons">
<Button>
<Icon icon="bold" />
</Button>
<Button>
<Icon icon="underline" />
</Button>
<Button>
<Icon icon="italic" />
</Button>
</div>
<div class="buttons">
<Button iconPack="fab" iconLeft="github">GitHub</Button>
<Button type="is-primary" iconPack="fab" iconLeft="twitter">Twitter</Button>
<Button type="is-success" iconPack="fa" iconLeft="check">Save</Button>
<Button type="is-danger" outline iconPack="fa" iconRight="times">Delete</Button>
</div>
<div class="buttons">
<Button size="is-small" iconPack="fab" iconLeft="github">GitHub</Button>
<Button iconLeft="github" iconPack="fab">GitHub</Button>
<Button size="is-medium" iconPack="fab" iconLeft="github">GitHub</Button>
<Button size="is-large" iconPack="fab" iconLeft="github">GitHub</Button>
</div>
</div>
</Example>
<JSDoc {jsdoc} />

View File

@ -0,0 +1,49 @@
<script context="module">
export async function preload() {
const res = await this.fetch(`components/collapse.json`);
const jsdoc = await res.json();
return { jsdoc };
}
</script>
<script>
import { Collapse } from 'svelma-pro'
import DocHeader from '../../components/DocHeader.svelte'
import Example from '../../components/Example.svelte'
import JSDoc from '../../components/JSDoc.svelte'
export let jsdoc
</script>
<DocHeader title="Collapse" subtitle="可折叠元素" />
<Example code={`<script>
import { Collapse } from 'svelma-pro'
</script>
<Collapse>
<button class="button is-primary" slot="trigger">
Click Me!
</button>
<div class="notification">
<div class="content">
<h3>Subtitle</h3>
<p>Lorem ipsum dolor...</p>
</div>
</div>
</Collapse>`}>
<div slot="preview">
<Collapse>
<button class="button is-primary" slot="trigger">Click Me!</button>
<div class="notification">
<div class="content">
<h3>Subtitle</h3>
<p>Lorem ipsum dolor...</p>
</div>
</div>
</Collapse>
</div>
</Example>
<JSDoc {jsdoc}></JSDoc>

View File

@ -0,0 +1,77 @@
<script context="module">
export async function preload(page, session) {
const res = await this.fetch(`components/datepicker.json`)
const jsdoc = await res.json()
return { jsdoc }
}
</script>
<script>
import { Datepicker } from 'svelma-pro'
import DocHeader from '../../components/DocHeader.svelte'
import Example from '../../components/Example.svelte'
import JSDoc from '../../components/JSDoc.svelte'
export let jsdoc
let result = 1584517629215;
function click(e){
alert(e.detail.time)
}
</script>
<DocHeader title="Datepicker" subtitle="日期选择器" />
<p class="title is-4">默认与暗黑主题</p>
<Example code={`<script>
import {Datepicker} from 'svelma-pro'
</script>
<Datepicker/>
<Datepicker theme="dark"/>
`}>
<div slot="preview">
<Datepicker/>
<Datepicker theme="dark"/>
</div>
</Example>
<hr class="is-medium" />
<p class="title is-4">范围选择与自由选择</p>
<Example code={`<script>
import {Datepicker} from 'svelma-pro'
</script>
<Datepicker pickerRule="freeChoice"/>
<Datepicker pickerRule="rangeChoice"/>
`}>
<div slot="preview">
<Datepicker pickerRule="freeChoice"/>
<Datepicker pickerRule="rangeChoice"/>
</div>
</Example>
<hr class="is-medium" />
<p class="title is-4">获取结果</p>
<Example code={`<script>
import Datepicker from 'svelma-pro'
function click(e){
alert(e.detail.timeStamp)
}
</script>
<Datepicker on:dateChecked={click}/>
`}>
<div slot="preview">
<Datepicker on:dateChecked={click}/>
</div>
</Example>
<JSDoc {jsdoc} showEvent="true"/>

View File

@ -0,0 +1,129 @@
<script context="module">
export async function preload() {
const res = await this.fetch(`components/dialog.json`);
const jsdoc = await res.json();
return { jsdoc };
}
</script>
<script>
import { Button, Dialog, Toast } from 'svelma-pro'
import Codepreview from '../../components/Code.svelte'
import DocHeader from '../../components/DocHeader.svelte'
import Example from '../../components/Example.svelte'
import JSDoc from '../../components/JSDoc.svelte'
export let jsdoc
function alert() {
Dialog.alert('Alles ist gut')
}
const thenHandler = result => Toast.create(`You ${result ? 'confirmed' : 'canceled'}`)
function confirm(type) {
switch(type) {
case 'custom':
return Dialog.confirm({
message: 'This is a custom confirmation message',
title: "I'm a title!",
type: 'is-danger',
icon: 'times-circle'
})
.then(thenHandler)
default:
Dialog.confirm('Shall we dance?')
.then(thenHandler)
}
}
function prompt(opts) {
Dialog.prompt({
message: "What is your quest?",
...opts
})
.then(prompt => Toast.create(`Your answer was: '${prompt}'`))
}
</script>
<DocHeader title="Dialog" subtitle="用户警报,提示和确认对话框" />
<p class="title is-4">Alert and Dialog</p>
<p class="content">Use <code>Dialog.alert()</code> and <code>Dialog.confirm()</code> to create these kinds of dialogs.
The methods return a promise that is resolved when the user cancels or confirms the alert. If the use closes/cancels the
value will be <code>false</code>. If the user clicks the confirm button the value will be <code>true</code>.
The first argument can either be an object of options or a string to use as the message.</p>
<Example code={`<script>
import { Button, Dialog, Toast } from 'svelma-pro'
function alert() {
Dialog.alert('Alles ist gut')
}
const thenHandler = result => Toast.create(\`You \${result ? 'confirmed' : 'canceled'}\`)
function confirm(type) {
switch(type) {
case 'custom':
return Dialog.confirm({
message: 'This is a custom confirmation message',
title: "I'm a title!",
type: 'is-danger',
icon: 'times-circle'
})
.then(thenHandler)
default:
Dialog.confirm('Shall we dance?')
.then(thenHandler)
}
}
</script>
<Button type="is-primary" on:click={() => alert()}>Dialog</Button>
<Button type="is-info" on:click={() => confirm()}>Confirm</Button>
<Button type="is-danger" on:click={() => confirm('custom')}>Confirm (custom)</Button>
`}>
<div slot="preview">
<Button type="is-primary" on:click={() => alert()}>Dialog</Button>
<Button type="is-info" on:click={() => confirm()}>Confirm</Button>
<Button type="is-danger" on:click={() => confirm('custom')}>Confirm (custom)</Button>
</div>
</Example>
<hr class="is-medium">
<p class="title is-4">Prompt</p>
<p class="content">Use <code>Dialog.prompt()</code> to programmatically create prompts for user input. By default the
dialog will be created with a required text input. You can control the props (attributes) on the prompt with the
<code>inputProps</code> prop.
<code>prompt()</code> returns a promise that will be resolved with the prompt input value if the user confirms, or null
if they cancel/close.</p>
<Example code={`<script>
import { Button, Dialog, Toast } from 'svelma-pro'
function prompt(opts) {
Dialog.prompt({
message: "What is your quest?",
...opts
})
.then(prompt => Toast.create(\`Your answer was: '\${prompt}'\`))
}
</script>
<Button type="is-primary" on:click={() => prompt()}>Prompt</Button>
<Button type="is-link" on:click={() => prompt({ message: 'Which date?', inputProps: { type: 'date' }})}>Date Prompt</Button>`
}>
<div slot="preview">
<Button type="is-primary" on:click={() => prompt()}>Prompt</Button>
<Button type="is-link" on:click={() => prompt({ message: 'Which date?', inputProps: { type: 'date' }})}>Date Prompt</Button>
</div>
</Example>
<JSDoc {jsdoc} />

View File

@ -0,0 +1,269 @@
<script context="module">
export async function preload(page, session) {
const res = await this.fetch(`components/field.json`);
const jsdoc = await res.json();
return { jsdoc };
}
</script>
<script>
import { Button, Field, Icon, Input } from 'svelma-pro'
import DocHeader from '../../components/DocHeader.svelte'
import Example from '../../components/Example.svelte'
import JSDoc from '../../components/JSDoc.svelte'
let name = 'Moby Dick'
export let jsdoc
</script>
<DocHeader title="Field" subtitle="添加功能和样式表单元素/输入" />
<Example code={`<script>
import { Field, Input } from 'svelma-pro'
</script>
<Field label="Name">
<Input value="Rich Harris" />
</Field>
<Field label="Email" type="is-danger" message="Email is invalid">
<Input value="john@" />
</Field>
<Field label="Username" type="is-success" message="Username is available">
<Input value="joey55" />
</Field>`}>
<div slot="preview">
<Field label="Name">
<Input value="Rich Harris" />
</Field>
<Field label="Email" type="is-danger" message="Email is invalid">
<Input value="john@" />
</Field>
<Field label="Username" type="is-success" message="Username is available">
<Input value="joey55" />
</Field>
</div>
</Example>
<hr class="is-medium">
<p class="title is-4">Addons</p>
Multiple controls in a field get attached. Use <code>expanded</code> property on the control to fill up space on the line.
<Example code={`<script>
import { Button, Field, Icon, Input } from 'svelma-pro'
</script>
<Field>
<Input type="search" placeholder="Search" icon="search" />
<p class="control">
<Button type="is-primary">Search</Button>
</p>
</Field>
<Field>
<Input type="search" placeholder="This is expanded" expanded />
<p class="control">
<Button type="is-static">@gmail.com</Button>
</p>
</Field>
<hr>
<Field>
<div class="control"><Button><Icon icon="bold"></Icon></Button></div>
<div class="control"><Button><Icon icon="italic"></Icon></Button></div>
<div class="control"><Button><Icon icon="underline"></Icon></Button></div>
<div class="control"><Button><Icon icon="align-left"></Icon></Button></div>
<div class="control"><Button><Icon icon="align-center"></Icon></Button></div>
<div class="control"><Button><Icon icon="align-right"></Icon></Button></div>
<Input expanded icon="comment" placeholder="Text here" />
</Field>
<Field>
<div class="control"><Button type="is-primary">Button</Button></div>
<div class="control"><Button type="is-primary"><Icon icon="search" /></Button></div>
</Field>`}>
<div slot="preview">
<Field>
<Input type="search" placeholder="Search" icon="search" />
<p class="control">
<Button type="is-primary">Search</Button>
</p>
</Field>
<Field>
<Input type="search" placeholder="This is expanded" expanded />
<p class="control">
<Button type="is-static">@gmail.com</Button>
</p>
</Field>
<hr>
<Field>
<div class="control"><Button><Icon icon="bold"></Icon></Button></div>
<div class="control"><Button><Icon icon="italic"></Icon></Button></div>
<div class="control"><Button><Icon icon="underline"></Icon></Button></div>
<div class="control"><Button><Icon icon="align-left"></Icon></Button></div>
<div class="control"><Button><Icon icon="align-center"></Icon></Button></div>
<div class="control"><Button><Icon icon="align-right"></Icon></Button></div>
<Input expanded icon="comment" placeholder="Text here" />
</Field>
<Field>
<div class="control"><Button type="is-primary">Button</Button></div>
<div class="control"><Button type="is-primary"><Icon icon="search" /></Button></div>
</Field>
</div>
</Example>
<hr class="is-medium">
<p class="title is-4">Groups</p>
Use the <code>grouped</code> property to group controls together. Use the <code>expanded</code> property to make a control take up remaining space.
<Example code={`<script>
import { Button, Field, Input } from 'svelma-pro'
</script>
<Field grouped>
<Input type="search" placeholder="Search" icon="search" />
<p class="control">
<Button type="is-primary">Search</Button>
</p>
</Field>
<Field grouped>
<Input type="search" placeholder="Search" icon="search" expanded />
<p class="control">
<Button type="is-primary">Search</Button>
</p>
</Field>`}>
<div slot="preview">
<Field grouped>
<Input type="search" placeholder="Search" icon="search" />
<p class="control">
<Button type="is-primary">Search</Button>
</p>
</Field>
<Field grouped>
<Input type="search" placeholder="Search" icon="search" expanded />
<p class="control">
<Button type="is-primary">Search</Button>
</p>
</Field>
</div>
</Example>
<hr class="is-medium">
<p class="title is-4">Nested Groups</p>
You can nest fields inside fields. You have to use the <code>expanded</code> property on the <strong>Field</strong> to fill up the remaining space.
<Example code={`<script>
import { Button, Field, Input } from 'svelma-pro'
</script>
<Field grouped>
<Field label="Button">
<Button type="is-primary">Button</Button>
</Field>
<Field label="Name" expanded>
<Input />
</Field>
<Field label="Email" expanded>
<Input />
</Field>
</Field>`}>
<div slot="preview">
<Field grouped>
<Field label="Button">
<Button type="is-primary">Button</Button>
</Field>
<Field label="Name" expanded>
<Input />
</Field>
<Field label="Email" expanded>
<Input />
</Field>
</Field>
</div>
</Example>
<hr class="is-medium">
<p class="title is-4">Responsive Groups</p>
Add <code>groupMultiline</code> property to allow controls to fill up multiple lines.
<Example code={`<script>
import { Button, Field, Input } from 'svelma-pro'
</script>
<Field grouped groupMultiline>
<Input />
{#each Array(30).fill().map((x, i) => i+1) as num}
<div class="control">
<Button>{num}</Button>
</div>
{/each}
</Field>`}>
<div slot="preview">
<Field grouped groupMultiline>
<Input />
{#each Array(30).fill().map((x, i) => i+1) as num}
<div class="control">
<Button>{num}</Button>
</div>
{/each}
</Field>
</div>
</Example>
<hr class="is-medium">
<p class="title is-4">Positions</p>
Use <code>position</code> property to align Field horizontally.
<Example code={`<script>
import { Button, Field, Input } from 'svelma-pro'
</script>
<Field position="is-centered">
<Input />
<div class="control"><Button type="is-primary">Button</Button></div>
</Field>
<Field grouped position="is-right">
<Input />
<div class="control"><Button type="is-primary">Button</Button></div>
</Field>`}>
<div slot="preview">
<Field position="is-centered">
<Input />
<div class="control"><Button type="is-primary">Button</Button></div>
</Field>
<Field grouped position="is-right">
<Input />
<div class="control"><Button type="is-primary">Button</Button></div>
</Field>
</div>
</Example>
<JSDoc {jsdoc}></JSDoc>

View File

@ -0,0 +1,33 @@
<script>
import { Icon } from 'svelma-pro'
import DocHeader from '../../components/DocHeader.svelte'
import Example from '../../components/Example.svelte'
</script>
<DocHeader title="Icon" subtitle="浮标" />
<Example code={`<script>
import { Icon } from 'svelma-pro'
</script>
<Icon pack="fab" size="is-large" icon="github" />
`}>
<div slot="preview">
<Icon pack="fab" size="is-large" icon="github"/>
</div>
</Example>
<hr class="is-medium" />
<p class="title is-4">添加角标</p>
<Example code={`<script>
import { Icon } from 'svelma-pro'
</script>
<Icon pack="fab" size="is-large" icon="github" num="99"/>
`}>
<div slot="preview">
<Icon pack="fab" size="is-large" icon="github" num="99"/>
</div>
</Example>

View File

@ -0,0 +1,213 @@
<script context="module">
export async function preload() {
const res = await this.fetch(`components/input.json`);
const jsdoc = await res.json();
return { jsdoc };
}
</script>
<script>
import { Field, Input } from 'svelma-pro'
import Codeview from '../../components/Code.svelte'
import DocHeader from '../../components/DocHeader.svelte'
import Example from '../../components/Example.svelte'
import JSDoc from '../../components/JSDoc.svelte'
export let jsdoc
let bound = {
name: 'Rich Harris',
email: 'rich@',
username: 'richie55',
password: 'secret123',
}
</script>
<DocHeader title="Input" subtitle="用户输入控件" />
<p class="content">
Mostly just wraps <code>{`<input>`}</code> and <code>{`<textarea>`}</code> so additional Bulma features can be bound easily.
</p>
<br>
<Example code={`<script>
import { Input } from 'svelma-pro'
</script>
<Input type="text" placeholder="Text input" />
`}>
<div slot="preview">
<Input type="text" placeholder="Text input" />
</div>
</Example>
<br>
<p class="title is-4">Types and colors</p>
<p class="content">Wrap with <a href="components/field"><strong>Field</strong></a> for additional features</p>
<Example code={`<script>
import { Field, Input } from 'svelma-pro'
let bound = {
name: 'Rich Harris',
email: 'rich@',
username: 'richie55',
password: 'secret123',
}
</script>
<Field label="Name">
<Input type="text" bind:value={bound.name} placeholder="Text input" />
</Field>
<Field label="Email" type="is-danger" message="Invalid email">
<Input type="email" bind:value={bound.email} maxlength="30" />
</Field>
<Field label="Username" type="is-success" message="Username available">
<Input type="email" bind:value={bound.username} />
</Field>
<Field label="Password">
<Input type="password" bind:value={bound.password} passwordReveal={true} />
</Field>
<Field label="Textarea">
<Input type="textarea" maxlength="200" />
</Field>
`}>
<div slot="preview">
<Codeview lang="js" showCopy={false}>
// Bound values
{JSON.stringify(bound, null, 2)}
</Codeview>
<br>
<Field label="Name">
<Input type="text" bind:value={bound.name} placeholder="Text input" />
</Field>
<Field label="Email" type="is-danger" message="Invalid email">
<Input type="email" bind:value={bound.email} maxlength="30" />
</Field>
<Field label="Username" type="is-success" message="Username available">
<Input type="email" bind:value={bound.username} />
</Field>
<Field label="Password">
<Input type="password" bind:value={bound.password} passwordReveal={true} />
</Field>
<Field label="Textarea">
<Input type="textarea" maxlength="200" />
</Field>
</div>
</Example>
<hr class="is-medium">
<p class="title is-4">States, plus more styles</p>
<Example code={`<script>
import { Field, Input } from 'svelma-pro'
</script>
<Field>
<Input placeholder="No label" />
</Field>
<Field label="Rounded">
<Input class="is-rounded" placeholder="Rounded" />
</Field>
<Field label="Info" type="is-info">
<Input placeholder="Info" />
</Field>
<Field label="Warning" type="is-warning">
<Input placeholder="Warning" />
</Field>
<Field label="Disabled">
<Input placeholder="Disabled" disabled />
</Field>
<Field label="Loading">
<Input placeholder="Loading" loading />
</Field>`}>
<div slot="preview">
<Field>
<Input placeholder="No label" />
</Field>
<Field label="Rounded">
<Input class="is-rounded" placeholder="Rounded" />
</Field>
<Field label="Info" type="is-info">
<Input placeholder="Info" />
</Field>
<Field label="Warning" type="is-warning">
<Input placeholder="Warning" />
</Field>
<Field label="Disabled">
<Input placeholder="Disabled" disabled />
</Field>
<Field label="Loading">
<Input placeholder="Loading" loading />
</Field>
</div>
</Example>
<hr class="is-medium">
<p class="title is-4">Sizes</p>
<Example code={`<script>
import { Field, Input } from 'svelma-pro'
</script>
<Field>
<Input placeholder="Small" size="is-small" />
</Field>
<Field>
<Input placeholder="Default" />
</Field>
<Field>
<Input placeholder="Medium" size="is-medium" />
</Field>
<Field>
<Input placeholder="Large" size="is-large" />
</Field>`}>
<div slot="preview">
<Field>
<Input placeholder="Small" size="is-small" />
</Field>
<Field>
<Input placeholder="Default" />
</Field>
<Field>
<Input placeholder="Medium" size="is-medium" />
</Field>
<Field>
<Input placeholder="Large" size="is-large" />
</Field>
</div>
</Example>
<JSDoc {jsdoc}></JSDoc>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,55 @@
<script context="module">
export async function preload(page, session) {
const res = await this.fetch(`components/layout.json`)
const jsdoc = await res.json()
return { jsdoc }
}
</script>
<script>
import { Layout, Children } from 'svelma-pro'
import DocHeader from '../../components/DocHeader.svelte'
import Example from '../../components/Example.svelte'
import JSDoc from '../../components/JSDoc.svelte'
export let jsdoc
</script>
<DocHeader title="Layout" subtitle="布局" />
<Example
code={`<script>
import { Layout, Children } from 'svelma-pro';
</script>
<Layout>
<Children.Sider width="100px">
侧边栏
</Children.Sider>
<Layout>
<Children.Header>
头部
</Children.Header>
<Children.Content height="300px">
内容
</Children.Content>
<Children.Footer>
脚部
</Children.Footer>
</Layout>
</Layout>
`}>
<div slot="preview">
<Layout>
<Children.Sider width="100px">侧边栏</Children.Sider>
<Layout>
<Children.Header>头部</Children.Header>
<Children.Content height="300px">内容</Children.Content>
<Children.Footer>脚部</Children.Footer>
</Layout>
</Layout>
</div>
</Example>
<JSDoc {jsdoc} />

View File

@ -0,0 +1,34 @@
<script>
import { Button, Message } from 'svelma-pro'
import DocHeader from '../../components/DocHeader.svelte'
import Example from '../../components/Example.svelte'
let open
</script>
<DocHeader title="Message" subtitle="传递信息的消息块" />
<Example code={`<script>
import { Button, Message } from 'svelma-pro'
let open
</script>
<Button class="block" on:click={() => open = !open}>Toggle</Button>
<Message active={!open} title="Default"
on:close={active => open = active}>
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Fusce id fermentum quam. Proin sagittis, nibh id
hendrerit imperdiet, elit sapien laoreet elit
</Message>`}>
<div slot="preview">
<Button class="block" on:click={() => open = !open}>Toggle</Button>
<Message active={!open} title="Default"
on:close={active => open = active}
>
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Fusce id fermentum quam. Proin sagittis, nibh id
hendrerit imperdiet, elit sapien laoreet elit
</Message>
</div>
</Example>

View File

@ -0,0 +1,45 @@
<script context="module">
export async function preload() {
const res = await this.fetch(`components/modal.json`);
const jsdoc = await res.json();
return { jsdoc };
}
</script>
<script>
import { Button, Modal } from 'svelma-pro'
import DocHeader from '../../components/DocHeader.svelte'
import Example from '../../components/Example.svelte'
import JSDoc from '../../components/JSDoc.svelte'
export let jsdoc
let active = false
</script>
<DocHeader title="Modal" subtitle="模态框" />
<Example code={`<script>
import { Button, Modal } from 'svelma-pro'
let active = false
</script>
<Button class="block" on:click={() => active = !active}>Toggle</Button>
<Modal bind:active={active}>
<p class="image is-4by3">
<img alt="Test image" src="https://via.placeholder.com/1280x920"/>
</p>
</Modal>`}>
<div slot="preview">
<Button class="block" on:click={() => active = !active}>Toggle</Button>
<Modal bind:active={active}>
<p class="image is-4by3">
<img alt="Test image" src="https://via.placeholder.com/1280x920"/>
</p>
</Modal>
</div>
</Example>
<JSDoc {jsdoc}/>

View File

@ -0,0 +1,236 @@
<script context="module">
export async function preload() {
const res = await this.fetch(`components/notification.json`)
const jsdoc = await res.json()
return { jsdoc }
}
</script>
<script>
import { Button, Notification } from 'svelma-pro'
import DocHeader from '../../components/DocHeader.svelte'
import Example from '../../components/Example.svelte'
import JSDoc from '../../components/JSDoc.svelte'
export let jsdoc
let isOpen = true
let autoIsOpen = false
function open(props) {
Notification.create({ message: 'I am a notification message', ...props })
}
function showNotification(props) {
Notification.create({
message: 'You opened this programmatically!',
...props
})
}
</script>
<style>
</style>
<DocHeader title="Notification" subtitle="提醒用户的通知" />
<Example
code={`<script>
import { Button, Notification } from 'svelma-pro';
let isOpen = true
</script>
<Button class="block" on:click={() => (isOpen = !isOpen)}>Toggle</Button>
<Notification bind:active={isOpen}>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce id fermentum quam. Proin sagittis, nibh id
hendrerit imperdiet, elit sapien laoreet elit
</Notification>`}>
<div slot="preview">
<Button class="block" on:click={() => (isOpen = !isOpen)}>Toggle</Button>
<Notification bind:active={isOpen}>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce id fermentum quam. Proin sagittis, nibh id
hendrerit imperdiet, elit sapien laoreet elit
</Notification>
</div>
</Example>
<hr class="is-medium" />
<p class="title is-4">Types</p>
<Example
code={`<script>
import { Notification } from 'svelma-pro';
</script>
<Notification>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce id fermentum quam. Proin sagittis, nibh id
hendrerit imperdiet, elit sapien laoreet elit
</Notification>
<Notification type="is-info">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce id fermentum quam. Proin sagittis, nibh id
hendrerit imperdiet, elit sapien laoreet elit
</Notification>
<Notification type="is-success">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce id fermentum quam. Proin sagittis, nibh id
hendrerit imperdiet, elit sapien laoreet elit
</Notification>
<Notification type="is-warning">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce id fermentum quam. Proin sagittis, nibh id
hendrerit imperdiet, elit sapien laoreet elit
</Notification>
<Notification type="is-danger">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce id fermentum quam. Proin sagittis, nibh id
hendrerit imperdiet, elit sapien laoreet elit
</Notification>`}>
<div slot="preview">
<Notification>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce id fermentum quam. Proin sagittis, nibh id
hendrerit imperdiet, elit sapien laoreet elit
</Notification>
<Notification type="is-info">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce id fermentum quam. Proin sagittis, nibh id
hendrerit imperdiet, elit sapien laoreet elit
</Notification>
<Notification type="is-success">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce id fermentum quam. Proin sagittis, nibh id
hendrerit imperdiet, elit sapien laoreet elit
</Notification>
<Notification type="is-warning">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce id fermentum quam. Proin sagittis, nibh id
hendrerit imperdiet, elit sapien laoreet elit
</Notification>
<Notification type="is-danger">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce id fermentum quam. Proin sagittis, nibh id
hendrerit imperdiet, elit sapien laoreet elit
</Notification>
</div>
</Example>
<hr class="is-medium" />
<p class="title is-4">Icons</p>
<Example
code={`<script>
import { Notification } from 'svelma-pro';
</script>
<Notification icon="question-circle">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce id fermentum quam. Proin sagittis, nibh id
hendrerit imperdiet, elit sapien laoreet elit
</Notification>
<Notification type="is-info" icon={true}>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce id fermentum quam. Proin sagittis, nibh id
hendrerit imperdiet, elit sapien laoreet elit
</Notification>
<Notification type="is-success" icon={true}>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce id fermentum quam. Proin sagittis, nibh id
hendrerit imperdiet, elit sapien laoreet elit
</Notification>
<Notification type="is-warning" icon={true}>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce id fermentum quam. Proin sagittis, nibh id
hendrerit imperdiet, elit sapien laoreet elit
</Notification>
<Notification type="is-danger" icon={true}>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce id fermentum quam. Proin sagittis, nibh id
hendrerit imperdiet, elit sapien laoreet elit
</Notification>`}>
<div slot="preview">
<Notification icon="question-circle">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce id fermentum quam. Proin sagittis, nibh id
hendrerit imperdiet, elit sapien laoreet elit
</Notification>
<Notification type="is-info" icon={true}>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce id fermentum quam. Proin sagittis, nibh id
hendrerit imperdiet, elit sapien laoreet elit
</Notification>
<Notification type="is-success" icon={true}>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce id fermentum quam. Proin sagittis, nibh id
hendrerit imperdiet, elit sapien laoreet elit
</Notification>
<Notification type="is-warning" icon={true}>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce id fermentum quam. Proin sagittis, nibh id
hendrerit imperdiet, elit sapien laoreet elit
</Notification>
<Notification type="is-danger" icon={true}>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce id fermentum quam. Proin sagittis, nibh id
hendrerit imperdiet, elit sapien laoreet elit
</Notification>
</div>
</Example>
<hr class="is-medium" />
<p class="title is-4">Auto-close</p>
<p>
Notification will close automatically after
<code>duration</code>
.
</p>
<Example code={`<script>
import { Button, Notification } from 'svelma-pro';
let autoIsOpen = false
</script>
<Button class="block" on:click={() => (autoIsOpen = true)}>Show</Button>
<Notification bind:active={autoIsOpen} autoClose={true}>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce id fermentum quam. Proin sagittis, nibh id
hendrerit imperdiet, elit sapien laoreet elit
</Notification>`}>
<div slot="preview">
<Button class="block" on:click={() => (autoIsOpen = true)}>Show</Button>
<Notification bind:active={autoIsOpen} autoClose={true}>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce id fermentum quam. Proin sagittis, nibh id
hendrerit imperdiet, elit sapien laoreet elit
</Notification>
</div>
</Example>
<hr class="is-medium" />
<p class="title is-4">Opening with code</p>
<Example code={`<script>
import { Button, Notification } from 'svelma-pro';
function showNotification(props) {
Notification.create({
message: 'You opened this programmatically!',
...props
})
}
</script>
<Button class="block" on:click={() => showNotification()}>Show Notification</Button>
<Button class="block" type="is-success" on:click={() => showNotification({ type: 'is-success' })}>Show Notification (success)</Button>
<Button class="block" type="is-danger" on:click={() => showNotification({ type: 'is-danger', position: 'is-bottom-right', icon: true })}>Show Notification (danger)</Button>`}>
<div slot="preview">
<Button class="block" on:click={() => showNotification()}>Show Notification</Button>
<Button class="block" type="is-success" on:click={() => showNotification({ type: 'is-success' })}>Show Notification (success)</Button>
<Button class="block" type="is-danger" on:click={() => showNotification({ type: 'is-danger', position: 'is-bottom-right', icon: true })}>Show Notification (danger)</Button>
</div>
</Example>
<JSDoc {jsdoc} />

View File

@ -0,0 +1,19 @@
<script>
import {Pagination} from 'svelma-pro'
import DocHeader from '../../components/DocHeader.svelte'
import Example from '../../components/Example.svelte'
</script>
<DocHeader title="Pagination" subtitle="分页" />
<Example
code={`<script>
import {Pagination} from 'svelma-pro'
</script>
<Pagination current="1" total="10" show="5" align="centered" />
`}>
<div slot="preview">
<Pagination current="1" total="10" show="5" align="centered" />
</div>
</Example>

View File

@ -0,0 +1,72 @@
<script>
import { onDestroy, onMount } from 'svelte'
import Codepreview from '../../components/Code.svelte'
import DocHeader from '../../components/DocHeader.svelte'
import Example from '../../components/Example.svelte'
import { Progress } from 'svelma-pro'
const types = ['is-primary', 'is-success', 'is-danger', 'is-warning', 'is-info', 'is-link']
const progresses = Array(6).fill(0)
function update() {
types.forEach((type, i) => {
progresses[i] = Math.floor(Math.random() * 100)
})
}
onMount(() => {
update()
})
</script>
<DocHeader title="Progress" subtitle="进度条" />
<Example code={`<script>
import { onDestroy, onMount } from 'svelte'
import { Progress } from 'svelma-pro'
const types = ['is-primary', 'is-success', 'is-danger', 'is-warning', 'is-info', 'is-link']
const progresses = Array(6).fill(0)
function update() {
types.forEach((type, i) => {
progresses[i] = Math.floor(Math.random() * 100)
})
}
onMount(() => {
update()
})
</script>
<button class="button is-primary" on:click={update}>Update</button>
<br />
<br />
{#each types as type, i}
<Progress {type} value={progresses[i]} duration={i * 200} max="100"></Progress>
{/each}
<br>
<br>
<p class="title is-5">Indeterminate (no value)</p>
<Progress max="100"></Progress>`}>
<div slot="preview">
<button class="button is-primary" on:click={update}>Update</button>
<br />
<br />
{#each types as type, i}
<Progress {type} value={progresses[i]} duration={i * 200} max="100"></Progress>
{/each}
<br>
<br>
<p class="title is-5">Indeterminate (no value)</p>
<Progress max="100"></Progress>
</div>
</Example>

View File

@ -0,0 +1,58 @@
<script context="module">
export async function preload() {
const res = await this.fetch(`components/snackbar.json`);
const jsdoc = await res.json();
return { jsdoc };
}
</script>
<script>
import { Button, Snackbar } from 'svelma-pro'
import DocHeader from '../../components/DocHeader.svelte'
import Example from '../../components/Example.svelte'
import JSDoc from '../../components/JSDoc.svelte'
export let jsdoc
function open(props) {
Snackbar.create({ message: 'I am a snackbar message', ...props })
}
</script>
<style>
.buttons {
display: flex;
justify-content: flex-start;
flex-wrap: wrap;
}
</style>
<DocHeader title="Snackbar" subtitle="比提示轻量,比吐司重要的提醒框" />
<Example code={`<script>
import { Button, Snackbar } from 'svelma-pro'
function open(props) {
Snackbar.create({ message: 'I am a snackbar message', ...props })
}
</script>
<div class="buttons">
<Button on:click={() => open()}>Default Snackbar</Button>
<Button type="is-success" on:click={() => open({ type: 'is-success' })}>Success</Button>
<Button type="is-danger" on:click={() => open({ type: 'is-danger', actionText: 'retry', position: 'is-top-right' })}>Top Right</Button>
<Button type="is-primary" on:click={() => open({ background: 'has-background-grey-lighter' })}>Custom Background</Button>
</div>`}>
<div slot="preview">
<div class="buttons">
<Button on:click={() => open()}>Default Snackbar</Button>
<Button type="is-success" on:click={() => open({ type: 'is-success' })}>Success</Button>
<Button type="is-danger" on:click={() => open({ type: 'is-danger', actionText: 'retry', position: 'is-top-right' })}>Top Right</Button>
<Button type="is-primary" on:click={() => open({ background: 'has-background-grey-lighter' })}>Custom Background</Button>
</div>
</div>
</Example>
<JSDoc {jsdoc} />

View File

@ -0,0 +1,134 @@
<script context="module">
export async function preload() {
const res = await this.fetch(`components/switch.json`);
const jsdoc = await res.json();
return { jsdoc };
}
</script>
<script>
import { Switch } from 'svelma-pro'
import DocHeader from '../../components/DocHeader.svelte'
import Example from '../../components/Example.svelte'
import JSDoc from '../../components/JSDoc.svelte'
export let jsdoc
let val
</script>
<DocHeader title="Switch" subtitle="开关" />
<Example code={`<script>
import { Switch } from 'svelma-pro'
let val
</script>
<div class="field">
<Switch bind:checked={val}>Foo</Switch>
<br>
<code>value = {JSON.stringify(val)}</code>
</div>
<div class="field">
<Switch disabled>Disabled</Switch>
</div>
`}>
<div slot="preview">
<div class="field">
<Switch bind:checked={val}>Foo</Switch>
<br>
<code>value = {JSON.stringify(val)}</code>
</div>
<div class="field">
<Switch disabled>Disabled</Switch>
</div>
</div>
</Example>
<hr class="is-medium">
<p class="title is-4">Types</p>
<Example code={`<script>
import { Switch } from 'svelma-pro'
</script>
<div class="field">
<Switch checked="true" type="is-primary">Primary</Switch>
</div>
<div class="field">
<Switch checked="true" type="is-danger">Danger</Switch>
</div>
<div class="field">
<Switch checked="true" type="is-warning">Warning</Switch>
</div>
<div class="field">
<Switch checked="true" type="is-info">Info</Switch>
</div>
<div class="field">
<Switch checked="true" type="is-link">Link</Switch>
</div>
<div class="field">
<Switch checked="true" type="is-dark">Dark</Switch>
</div>
`}>
<div slot="preview">
<div class="field">
<Switch checked="true" type="is-primary">Primary</Switch>
</div>
<div class="field">
<Switch checked="true" type="is-danger">Danger</Switch>
</div>
<div class="field">
<Switch checked="true" type="is-warning">Warning</Switch>
</div>
<div class="field">
<Switch checked="true" type="is-info">Info</Switch>
</div>
<div class="field">
<Switch checked="true" type="is-link">Link</Switch>
</div>
<div class="field">
<Switch checked="true" type="is-dark">Dark</Switch>
</div>
</div>
</Example>
<hr class="is-medium">
<p class="title is-4">Sizes</p>
<Example code={`<script>
import { Switch } from 'svelma-pro'
</script>
<div class="field">
<Switch size="is-small">Small</Switch>
</div>
<div class="field">
<Switch>Default</Switch>
</div>
<div class="field">
<Switch size="is-medium">Medium</Switch>
</div>
<div class="field">
<Switch size="is-large">Large</Switch>
</div>
</div>
`}>
<div slot="preview">
<div class="field">
<Switch size="is-small">Small</Switch>
</div>
<div class="field">
<Switch>Default</Switch>
</div>
<div class="field">
<Switch size="is-medium">Medium</Switch>
</div>
<div class="field">
<Switch size="is-large">Large</Switch>
</div>
</div>
</Example>
<JSDoc {jsdoc}></JSDoc>

View File

@ -0,0 +1,210 @@
<script context="module">
export async function preload() {
const tabsRes = await this.fetch(`components/tabs.json`);
const tabRes = await this.fetch(`components/tab.json`);
const jsdocTabs = await tabsRes.json();
const jsdocTab = await tabRes.json();
return { jsdocTabs, jsdocTab };
}
</script>
<script>
import { Tabs, Tab } from 'svelma-pro'
import DocHeader from '../../components/DocHeader.svelte'
import Example from '../../components/Example.svelte'
import JSDoc from '../../components/JSDoc.svelte'
export let jsdocTabs
export let jsdocTab
</script>
<DocHeader title="Tabs" subtitle="横向导航选项卡" />
<Example code={`<script>
import { Tabs, Tab } from 'svelma-pro'
</script>
<Tabs>
<Tab label="Svelte">
Is cool
</Tab>
<Tab label="Vue">
Is good
</Tab>
<Tab label="Angular">
lol no
</Tab>
</Tabs>`}>
<div slot="preview">
<Tabs>
<Tab label="Svelte">
Is cool
</Tab>
<Tab label="Vue">
Is good
</Tab>
<Tab label="Angular">
lol no
</Tab>
</Tabs>
</div>
</Example>
<hr class="is-medium">
<p class="title is-4">Icons and Sizes</p>
<Example code={`<script>
import { Tabs, Tab } from 'svelma-pro'
</script>
<Tabs>
<Tab label="People" icon="users"></Tab>
<Tab label="Places" icon="map-marker-alt"></Tab>
<Tab label="Things" icon="ellipsis-h"></Tab>
</Tabs>
<Tabs size="is-medium">
<Tab label="People" icon="users"></Tab>
<Tab label="Places" icon="map-marker-alt"></Tab>
<Tab label="Things" icon="ellipsis-h"></Tab>
</Tabs>
<Tabs size="is-large">
<Tab label="People" icon="users"></Tab>
<Tab label="Places" icon="map-marker-alt"></Tab>
<Tab label="Things" icon="ellipsis-h"></Tab>
</Tabs>`}>
<div slot="preview">
<Tabs>
<Tab label="People" icon="users"></Tab>
<Tab label="Places" icon="map-marker-alt"></Tab>
<Tab label="Things" icon="ellipsis-h"></Tab>
</Tabs>
<Tabs size="is-medium">
<Tab label="People" icon="users"></Tab>
<Tab label="Places" icon="map-marker-alt"></Tab>
<Tab label="Things" icon="ellipsis-h"></Tab>
</Tabs>
<Tabs size="is-large">
<Tab label="People" icon="users"></Tab>
<Tab label="Places" icon="map-marker-alt"></Tab>
<Tab label="Things" icon="ellipsis-h"></Tab>
</Tabs>
</div>
</Example>
<hr class="is-medium">
<p class="title is-4">Position</p>
<Example code={`<script>
import { Tabs, Tab } from 'svelma-pro'
</script>
<Tabs position="is-centered">
<Tab label="People" icon="users"></Tab>
<Tab label="Places" icon="map-marker-alt"></Tab>
<Tab label="Things" icon="ellipsis-h"></Tab>
</Tabs>
<Tabs position="is-right">
<Tab label="People" icon="users"></Tab>
<Tab label="Places" icon="map-marker-alt"></Tab>
<Tab label="Things" icon="ellipsis-h"></Tab>
</Tabs>`}>
<div slot="preview">
<Tabs position="is-centered">
<Tab label="People" icon="users"></Tab>
<Tab label="Places" icon="map-marker-alt"></Tab>
<Tab label="Things" icon="ellipsis-h"></Tab>
</Tabs>
<Tabs position="is-right">
<Tab label="People" icon="users"></Tab>
<Tab label="Places" icon="map-marker-alt"></Tab>
<Tab label="Things" icon="ellipsis-h"></Tab>
</Tabs>
</div>
</Example>
<hr class="is-medium">
<p class="title is-4">Style</p>
<p class="content">
Use <code>is-boxed</code>, <code>is-toggle</code>, <code>is-toggle</code> and <code>is-toggle-rounded</code>, or
<code>is-fullwidth</code> to alter to style of your tabs.
</p>
<Example code={`<script>
import { Tabs, Tab } from 'svelma-pro'
</script>
<Tabs style="is-boxed">
<Tab label="People" icon="users"></Tab>
<Tab label="Places" icon="map-marker-alt"></Tab>
<Tab label="Things" icon="ellipsis-h"></Tab>
</Tabs>
<Tabs style="is-toggle">
<Tab label="People" icon="users"></Tab>
<Tab label="Places" icon="map-marker-alt"></Tab>
<Tab label="Things" icon="ellipsis-h"></Tab>
</Tabs>
<Tabs style="is-toggle is-toggle-rounded">
<Tab label="People" icon="users"></Tab>
<Tab label="Places" icon="map-marker-alt"></Tab>
<Tab label="Things" icon="ellipsis-h"></Tab>
</Tabs>
<Tabs style="is-fullwidth">
<Tab label="People" icon="users"></Tab>
<Tab label="Places" icon="map-marker-alt"></Tab>
<Tab label="Things" icon="ellipsis-h"></Tab>
</Tabs>`}>
<div slot="preview">
<Tabs style="is-boxed">
<Tab label="People" icon="users"></Tab>
<Tab label="Places" icon="map-marker-alt"></Tab>
<Tab label="Things" icon="ellipsis-h"></Tab>
</Tabs>
<Tabs style="is-toggle">
<Tab label="People" icon="users"></Tab>
<Tab label="Places" icon="map-marker-alt"></Tab>
<Tab label="Things" icon="ellipsis-h"></Tab>
</Tabs>
<Tabs style="is-toggle is-toggle-rounded">
<Tab label="People" icon="users"></Tab>
<Tab label="Places" icon="map-marker-alt"></Tab>
<Tab label="Things" icon="ellipsis-h"></Tab>
</Tabs>
<Tabs style="is-fullwidth">
<Tab label="People" icon="users"></Tab>
<Tab label="Places" icon="map-marker-alt"></Tab>
<Tab label="Things" icon="ellipsis-h"></Tab>
</Tabs>
</div>
</Example>
<hr class="is-medium" />
<h2 class="title is-4 is-spaced">API</h2>
<h3 class="subtitle">Tabs</h3>
<JSDoc jsdoc={jsdocTabs} showHeader={false}></JSDoc>
<br>
<br>
<h3 class="subtitle is-spaced">Tab</h3>
<JSDoc jsdoc={jsdocTab} showHeader={false}></JSDoc>

View File

@ -0,0 +1,39 @@
<script context="module">
export async function preload(page, session) {
const res = await this.fetch(`components/timepicker.json`)
const jsdoc = await res.json()
return { jsdoc }
}
</script>
<script>
import {Timepicker} from 'svelma-pro'
import DocHeader from '../../components/DocHeader.svelte'
import Example from '../../components/Example.svelte'
import JSDoc from '../../components/JSDoc.svelte'
export let jsdoc
let time = new Date();
function test(e){
// debugger;
console.log(e)
}
</script>
<DocHeader title="Timepicker" subtitle="时间选择器" />
<Example
code={`<script>
import {Timepicker} from 'svelma-pro'
</script>
<Timepicker bind:time />
`}>
<div slot="preview">
<Timepicker bind:time on:change={test}/>
</div>
</Example>
<JSDoc {jsdoc} showEvent="true"/>

View File

@ -0,0 +1,55 @@
<script context="module">
export async function preload() {
const res = await this.fetch(`components/toast.json`);
const jsdoc = await res.json();
return { jsdoc };
}
</script>
<script>
import { Button, Toast } from 'svelma-pro'
import DocHeader from '../../components/DocHeader.svelte'
import Example from '../../components/Example.svelte'
import JSDoc from '../../components/JSDoc.svelte'
export let jsdoc
function open(type, position, background) {
Toast.create({ message: 'I am a toast', type, position, background })
}
</script>
<style>
.buttons {
display: flex;
justify-content: flex-start;
flex-wrap: wrap;
}
</style>
<DocHeader title="Toast" subtitle="吐司" />
<Example code={`<script>
import { Button, Toast } from 'svelma-pro'
function open(type, position) {
Toast.create({ message: 'I am a toast', type, position })
}
</script>
<Button on:click={() => open()}>Toast</Button>
<Button type="is-success" on:click={() => open('is-success')}>Success</Button>
<Button type="is-danger" on:click={() => open('is-danger', 'is-bottom-right')}>Bottom Right</Button>
<Button type="is-primary" on:click={() => open('is-primary', 'is-top', 'has-background-grey-lighter')}>Custom Background</Button>`}>
<div slot="preview">
<div class="buttons">
<Button on:click={() => open()}>Toast</Button>
<Button type="is-success" on:click={() => open('is-success')}>Success</Button>
<Button type="is-danger" on:click={() => open('is-danger', 'is-bottom-right')}>Bottom Right</Button>
<Button type="is-primary" on:click={() => open('is-primary', 'is-top', 'has-background-grey-lighter')}>Custom Background</Button>
</div>
</div>
</Example>
<JSDoc {jsdoc} />

View File

@ -0,0 +1,72 @@
<script>
import { Message } from 'svelma-pro'
</script>
<style>
h1,
/* figure, */
p {
text-align: center;
margin: 0 auto;
}
h1 {
font-size: 2.8em;
text-transform: uppercase;
font-weight: 700;
margin: 0 0 0.5em 0;
}
/* figure {
margin: 0 0 1em 0;
}
img {
width: 100%;
max-width: 400px;
margin: 0 0 1em 0;
} */
p {
margin: 1em auto;
}
@media (min-width: 480px) {
h1 {
font-size: 4em;
}
}
pre {
display: inline-flex;
}
</style>
<svelte:head>
<title>svelma-pro</title>
<meta property="og:type" content="website" />
<meta property="og:title" content="Svelma" />
<meta property="og:description" content="Bulma components for Svelte" />
</svelte:head>
<div class="hero is-full-height">
<div class="hero-body">
<div class="container has-text-centered">
<h1 class="title">svelma-pro</h1>
<h2 class="subtitle">基于开源svelma-pro项目扩展而来的组件库,扩展原有功能,新增一些常用组件.</h2>
<pre>
<code>$ npm install svelma-pro</code>
</pre>
<br />
<br />
<p>
<Message title="Note!" type="is-primary" showClose={false}>
为了针对svelte市面成熟组件库缺少及组件分散的情况,团队在svelma-pro开源库的基础上定制及扩展团队私有组件库,可以避免大量的引入分散组件导致的模块管理混乱及市面组件无法自定义扩展,升级等问题.
</Message>
</p>
</div>
</div>
</div>

View File

@ -0,0 +1,154 @@
<script>
import { Message } from 'svelma-pro'
import DocHeader from '../../components/DocHeader.svelte'
import Codeview from '../../components/Code.svelte'
</script>
<DocHeader title="Start" subtitle="如何使用" />
<div class="media">
<div class="media-left">
<p class="title">1</p>
</div>
<div class="media-content">
<p class="title">NPM</p>
<p class="subtitle is-spaced">此组件库适用于基于rollup或者webpack搭建的svelte及sapper项目</p>
<p class="title is-4">下载安装</p>
<div class="content">下载bluma与组件库.</div>
<Codeview lang="bash">npm install --save bulma svelma-pro</Codeview>
<div class="content">集成scss模板语法支持(因为组件库采用了类似vue的scss模板写法,所以需要也集成进去).</div>
<Codeview lang="bash">npm install --save-dev svelte-preprocess autoprefixer node-sass sass</Codeview>
<div class="content">
添加
<code>scss编译</code>
到你的
<code>rollup.config.js</code>
配置文件中(或者webpack.config.js).
</div>
<Codeview
lang="js"
code={`import sveltePreprocess from 'svelte-preprocess';
const preprocess = sveltePreprocess({
scss: {
includePaths: ['src'],
},
postcss: {
plugins: [require('autoprefixer')],
},
});
// ...
export default {
// ...
plugins: [
svelte({
// ...
preprocess: preprocess,
})
]
}`} />
<div class="content">
如果使用webpack,在
<code>webpack.config.js</code>
配置文件中.
</div>
<Codeview
lang="js"
code={`import sveltePreprocess from 'svelte-preprocess';
const preprocess = sveltePreprocess({
scss: {
includePaths: ['src'],
},
postcss: {
plugins: [require('autoprefixer')],
},
});
// ...
module.export = {
// ...
module: {
rules: [
{
test: /\.(svelte|html)$/,
use: {
loader: 'svelte-loader',
options: {
preprocess,
// ...
}
}
},
]
},
]
}`} />
<p class="title is-4">使用</p>
<div class="content">引入bluma样式到您的项目</div>
<Codeview lang="html" code={`
<!-- main.js或者client.js全局引入 -->
<script>
import 'bulma/css/bulma.css'
</script>
`}>
</Codeview>
<div class="content">
svelma-pro组件可以一次导入一个就像这样
</div>
<Codeview lang="html" code={`
<script>
import { Button } from 'svelma-pro'
</script>
<Button>I am a Button</Button>
`}>
</Codeview>
<div class="content">
或导入完整的Svelma软件包。
</div>
<Codeview lang="html" code={`
<script>
import { Svelma } from 'svelma-pro'
</script>
<Svelma.Button>I am a Button</Svelma.Button>
`}>
</Codeview>
</div>
</div>
<hr class="is-medium">
<div class="media">
<div class="media-left">
<p class="title">2</p>
</div>
<div class="media-content">
<p class="title is-spaced">使用 [Font Awesome] 图标</p>
添加 CDN 在你的 HTML 页面:
<Codeview lang="bash" code={`
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.3.1/css/all.css"></link>
`}/>
...或者使用npm包:
<Codeview lang="bash" code={`npm install --save @fortawesome/fontawesome-free`}/>
<Codeview lang="bash" code={`<!-- main.js or client.js(sapper) -->
<script>
import '@fortawesome/fontawesome-free/css/all.css'
</script>`}/>
</div>
</div>

18
docs/src/server.js Normal file
View File

@ -0,0 +1,18 @@
import sirv from 'sirv';
import polka from 'polka';
import compression from 'compression';
import * as sapper from '@sapper/server';
const { PORT, NODE_ENV } = process.env;
const dev = NODE_ENV === 'development';
polka() // You can also use Express
.use(...[
process.env.SAPPER_EXPORT && '/svelma-pro' || undefined,
compression({ threshold: 0 }),
sirv('static', { dev }),
sapper.middleware()
].filter(x => !!x))
.listen(PORT, err => {
if (err) console.log('error', err);
});

View File

@ -0,0 +1,82 @@
import { timestamp, files, shell, routes } from '@sapper/service-worker';
const ASSETS = `cache${timestamp}`;
// `shell` is an array of all the files generated by the bundler,
// `files` is an array of everything in the `static` directory
const to_cache = shell.concat(files);
const cached = new Set(to_cache);
self.addEventListener('install', event => {
event.waitUntil(
caches
.open(ASSETS)
.then(cache => cache.addAll(to_cache))
.then(() => {
self.skipWaiting();
})
);
});
self.addEventListener('activate', event => {
event.waitUntil(
caches.keys().then(async keys => {
// delete old caches
for (const key of keys) {
if (key !== ASSETS) await caches.delete(key);
}
self.clients.claim();
})
);
});
self.addEventListener('fetch', event => {
if (event.request.method !== 'GET' || event.request.headers.has('range')) return;
const url = new URL(event.request.url);
// don't try to handle e.g. data: URIs
if (!url.protocol.startsWith('http')) return;
// ignore dev server requests
if (url.hostname === self.location.hostname && url.port !== self.location.port) return;
// always serve static files and bundler-generated assets from cache
if (url.host === self.location.host && cached.has(url.pathname)) {
event.respondWith(caches.match(event.request));
return;
}
// for pages, you might want to serve a shell `service-worker-index.html` file,
// which Sapper has generated for you. It's not right for every
// app, but if it's right for yours then uncomment this section
/*
if (url.origin === self.origin && routes.find(route => route.pattern.test(url.pathname))) {
event.respondWith(caches.match('/service-worker-index.html'));
return;
}
*/
if (event.request.cache === 'only-if-cached') return;
// for everything else, try the network first, falling back to
// cache if the user is offline. (If the pages never change, you
// might prefer a cache-first approach to a network-first one.)
event.respondWith(
caches
.open(`offline${timestamp}`)
.then(async cache => {
try {
const response = await fetch(event.request);
cache.put(event.request, response.clone());
return response;
} catch(err) {
const response = await cache.match(event.request);
if (response) return response;
throw err;
}
})
);
});

37
docs/src/template.html Normal file
View File

@ -0,0 +1,37 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<meta name="theme-color" content="#333333" />
%sapper.base%
<link rel="stylesheet" href="global.css" />
<link rel="manifest" href="manifest.json" />
<link rel="icon" type="image/png" href="favicon.ico" />
<!-- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.5/css/bulma.min.css" /> -->
<!-- <script defer src="https://use.fontawesome.com/releases/v5.3.1/js/all.js"></script> -->
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.3.1/css/all.css"></link>
<!-- Sapper generates a <style> tag containing critical CSS
for the current page. CSS for the rest of the app is
lazily loaded when it precaches secondary pages -->
%sapper.styles%
<!-- This contains the contents of the <svelte:head> component, if
the current page has one -->
%sapper.head%
</head>
<body>
<!-- The application will be rendered inside this element,
because `app/client.js` references it -->
<div id="sapper">%sapper.html%</div>
<!-- Sapper creates a <script> tag containing `app/client.js`
and anything else it needs to hydrate the app and
initialise the router -->
%sapper.scripts%
</body>
</html>

BIN
docs/static/favicon.ico vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
docs/static/favicon.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

61
docs/static/global.css vendored Normal file
View File

@ -0,0 +1,61 @@
/* body {
margin: 0;
font-family: Roboto, -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans,
Helvetica Neue, sans-serif;
font-size: 14px;
line-height: 1.5;
color: #333;
}
h1,
h2,
h3,
h4,
h5,
h6 {
margin: 0 0 0.5em 0;
font-weight: 400;
line-height: 1.2;
}
h1 {
font-size: 2em;
}
a {
color: inherit;
}
code {
font-family: menlo, inconsolata, monospace;
font-size: calc(1em - 2px);
color: #555;
background-color: #f0f0f0;
padding: 0.2em 0.4em;
border-radius: 2px;
}
@media (min-width: 400px) {
body {
font-size: 16px;
}
} */
header.header {
border-bottom: 2px solid #f5f5f5;
margin-bottom: 3rem;
padding-bottom: 3rem;
}
header.header .subtitle {
color: #7a7a7a;
}
hr.is-medium {
margin: 3rem 0
}
.control .icon.is-clickable, .control.has-icons-left .icon.is-clickable, .control.has-icons-right .icon.is-clickable {
pointer-events: auto;
cursor: pointer;
}

BIN
docs/static/great-success.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

BIN
docs/static/logo-192.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
docs/static/logo-512.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

20
docs/static/manifest.json vendored Normal file
View File

@ -0,0 +1,20 @@
{
"background_color": "#ffffff",
"theme_color": "#333333",
"name": "Svelma",
"short_name": "Svelma",
"display": "minimal-ui",
"start_url": "/",
"icons": [
{
"src": "logo-192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "logo-512.png",
"sizes": "512x512",
"type": "image/png"
}
]
}

BIN
docs/static/svelma-logo-ico.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

BIN
docs/static/svelma-logo.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

86
docs/static/svelma-logo.svg vendored Normal file
View File

@ -0,0 +1,86 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Gravit.io -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
style="isolation:isolate"
viewBox="0 0 93.19593 126.78137"
width="93.19593"
height="126.78137"
version="1.1"
id="svg13"
sodipodi:docname="svelte-logo(1).svg"
inkscape:version="0.92.2 5c3e80d, 2017-08-06">
<metadata
id="metadata17">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1107"
inkscape:window-height="721"
id="namedview15"
showgrid="false"
inkscape:zoom="1.0300053"
inkscape:cx="254.27558"
inkscape:cy="73.807952"
inkscape:window-x="189"
inkscape:window-y="87"
inkscape:window-maximized="0"
inkscape:current-layer="svg13"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0" />
<defs
id="defs5">
<clipPath
id="_clipPath_tx9IWIff9jpFhn3EvaPjyIq3XXdSNcS0">
<rect
width="519"
height="139"
id="rect2"
x="0"
y="0" />
</clipPath>
</defs>
<g
clip-path="url(#_clipPath_tx9IWIff9jpFhn3EvaPjyIq3XXdSNcS0)"
id="g11"
inkscape:export-xdpi="95.919998"
inkscape:export-ydpi="95.919998"
transform="translate(-22.975806,-7.0562131)">
<path
d="M 110.23,28.39 C 99.83,13.51 97.139206,0.86190476 82.289206,10.321905 L 38.36,35.18 c -7.117,4.47 -12.025,11.729 -13.52,20 -1.247,6.904 -0.156,14.026 3.1,20.24 -2.232,3.386 -3.752,7.189 -4.47,11.18 -1.505,8.446 0.46,17.142 5.45,24.12 10.4,14.88 13.090794,29.58762 27.940794,20.12762 L 100.79,104 c 7.109,-4.479 12.013,-11.734 13.52,-20 1.243,-6.902 0.148,-14.02 -3.11,-20.23 2.231,-3.387 3.754,-7.19 4.48,-11.18 1.5,-8.446 -0.464,-17.14 -5.45,-24.12"
id="path7"
inkscape:connector-curvature="0"
style="fill:#00c4a7"
sodipodi:nodetypes="ccccccccccccc" />
<path
d="m 61.89,112.135 c -8.41,2.183 -17.288,-1.111 -22.24,-8.25 -2.999,-4.195 -4.178,-9.423 -3.27,-14.5 0.147,-0.817 0.355,-1.623 0.62,-2.41 l 0.49,-1.5 1.34,1 c 3.08,2.249 6.519,3.96 10.17,5.06 l 1,0.29 -0.09,1 c -0.096,1.371 0.289,2.733 1.09,3.85 1.494,2.148 4.168,3.137 6.7,2.48 0.565,-0.152 1.105,-0.388 1.6,-0.7 l 26.04,-16.62 c 1.293,-0.813 2.183,-2.135 2.45,-3.64 0.269,-1.532 -0.091,-3.107 -1,-4.37 -1.494,-2.147 -4.168,-3.137 -6.7,-2.48 -0.566,0.15 -1.106,0.386 -1.6,0.7 l -10,6.35 c -1.636,1.037 -3.419,1.82 -5.29,2.32 -8.395,2.169 -17.253,-1.118 -22.2,-8.24 -2.99,-4.199 -4.162,-9.426 -3.25,-14.5 0.893,-4.984 3.844,-9.362 8.13,-12.06 L 72,29.295 c 1.626,-1.035 3.399,-1.817 5.26,-2.32 8.407,-2.183 17.283,1.111 22.23,8.25 3.002,4.194 4.185,9.422 3.28,14.5 -0.156,0.822 -0.363,1.634 -0.62,2.43 l -0.5,1.5 -1.33,-1 c -3.087,-2.265 -6.536,-3.99 -10.2,-5.1 l -1,-0.29 0.09,-1 c 0.115,-1.378 -0.26,-2.752 -1.06,-3.88 -1.503,-2.11 -4.155,-3.069 -6.66,-2.41 -0.566,0.15 -1.106,0.386 -1.6,0.7 L 53.8,57.265 c -1.288,0.815 -2.177,2.131 -2.45,3.63 -0.264,1.535 0.096,3.112 1,4.38 1.487,2.127 4.133,3.115 6.65,2.48 0.564,-0.154 1.103,-0.39 1.6,-0.7 l 10,-6.34 c 1.634,-1.048 3.422,-1.834 5.3,-2.33 8.405,-2.189 17.282,1.102 22.23,8.24 3,4.195 4.183,9.423 3.28,14.5 -0.893,4.985 -3.844,9.363 -8.13,12.06 l -26.09,16.62 c -1.639,1.041 -3.426,1.826 -5.3,2.33"
id="path9"
inkscape:connector-curvature="0"
style="fill:#ffffff" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

11307
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

72
package.json Normal file
View File

@ -0,0 +1,72 @@
{
"name": "svelma-pro",
"svelte": "src/index.js",
"description": "Based on svelma project extension and modification",
"version": "1.0.0",
"author": "KeiferJu",
"license": "MIT",
"keywords": [
"svelte",
"svelte.js",
"svelma",
"bulma",
"component",
"components"
],
"repository": {
"type": "git",
"url": "https://github.com/KeiferJu/svelma-pro"
},
"bugs": {
"url": "https://github.com/KeiferJu/svelma-pro/issues"
},
"module": "dist/module.js",
"main": "dist/index.js",
"files": [
"dist",
"src"
],
"peerDependencies": {
"bulma": "^0.8.0"
},
"devDependencies": {
"autoprefixer": "^9.6.0",
"bulma": "^0.8.0",
"conventional-changelog-cli": "^2.0.21",
"get-port-cli": "^2.0.0",
"gh-pages": "^2.2.0",
"node-sass": "^4.12.0",
"npm-run-all": "^4.1.5",
"postcss": "^7.0.17",
"prettier": "^1.17.1",
"prettier-plugin-svelte": "^0.5.1",
"rollup": "^1.2.2",
"rollup-plugin-alias": "^1.5.1",
"rollup-plugin-analyzer": "^3.0.1",
"rollup-plugin-bundle-size": "^1.0.3",
"rollup-plugin-commonjs": "^9.2.0",
"rollup-plugin-copy": "^2.0.1",
"rollup-plugin-livereload": "^1.0.4",
"rollup-plugin-node-resolve": "^4.0.1",
"rollup-plugin-scss": "^1.0.1",
"rollup-plugin-svelte": "^5.0.3",
"rollup-plugin-terser": "^4.0.4",
"semantic-release": "^15.13.24",
"sirv-cli": "^0.3.1",
"standard-version": "^6.0.1",
"svelte": "^3.9.2",
"svelte-preprocess": "^2.12.0",
"wait-for-localhost-cli": "^1.1.0"
},
"scripts": {
"build": "rollup -c",
"autobuild": "rollup -c -w",
"autodocs": "(cd docs; npx sapper dev --basepath svelma-pro)",
"dev": "run-p autobuild autodocs",
"docs": "(cd docs; npx sapper export --basepath svelma-pro)",
"clean": "rm -rf node_modules/gh-pages/.cache",
"deploy": "npm run clean && npm run docs && node ./deploy.js",
"pkg": "npm run build && npm publish"
},
"browserslist": "last 2 versions"
}

BIN
public/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

65
public/global.css Normal file
View File

@ -0,0 +1,65 @@
html, body {
position: relative;
width: 100%;
height: 100%;
}
body {
color: #333;
margin: 0;
padding: 8px;
box-sizing: border-box;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
}
a {
color: rgb(0,100,200);
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
a:visited {
color: rgb(0,80,160);
}
label {
display: block;
}
input, button, select, textarea {
font-family: inherit;
font-size: inherit;
padding: 0.4em;
margin: 0 0 0.5em 0;
box-sizing: border-box;
border: 1px solid #ccc;
border-radius: 2px;
}
input:disabled {
color: #ccc;
}
input[type="range"] {
height: 0;
}
button {
background-color: #f4f4f4;
outline: none;
}
button:active {
background-color: #ddd;
}
button:focus {
border-color: #666;
}
hr.is-medium {
margin: 3rem 0
}

15
public/index.html Normal file
View File

@ -0,0 +1,15 @@
<!doctype html>
<html>
<head>
<meta charset='utf8'>
<meta name='viewport' content='width=device-width'>
<title>Svelte app</title>
<link rel='stylesheet' href='global.css'>
</head>
<body>
<script src='index.js'></script>
</body>
</html>

55
rollup.config.js Normal file
View File

@ -0,0 +1,55 @@
import analyze from 'rollup-plugin-analyzer'
import autoPreprocess from 'svelte-preprocess'
import bundleSize from 'rollup-plugin-bundle-size'
import commonjs from 'rollup-plugin-commonjs'
import resolve from 'rollup-plugin-node-resolve'
import svelte from 'rollup-plugin-svelte'
import { terser } from 'rollup-plugin-terser'
import pkg from './package.json'
const production = !process.env.ROLLUP_WATCH
const { name } = pkg
export default {
input: 'src/index.js',
output: [
{
file: pkg.module,
format: 'es',
sourcemap: true,
name,
},
{
file: pkg.main,
format: 'umd',
sourcemap: true,
name,
},
],
plugins: [
svelte({
// enable run-time checks when not in production
dev: !production,
// generate: production ? 'dom' : 'ssr',
hydratable: true,
preprocess: autoPreprocess({
postcss: {
plugins: [require('autoprefixer')()],
},
})
}),
resolve(),
commonjs(),
production && terser(),
// production && analyze(),
production && bundleSize(),
],
watch: {
clearScreen: false,
},
}

View File

@ -0,0 +1,104 @@
<script>
import { onMount } from 'svelte'
import Icon from './Icon.svelte'
import { omit } from '../utils'
/** HTML tag to use for button (either 'a' or 'button')
* @svelte-prop {String} tag=button
* @values <code>button</code>, <code>a</code>
* */
export let tag = 'button'
/** Type (color of control)
* @svelte-prop {String} [type] - Type (color of control)
* @values $$colors$$
* */
export let type = ''
/** Size of button
* @svelte-prop {String} [size]
* @values $$sizes$$
* */
export let size = ''
/** Href to use when <code>tag</code> is 'a'
* @svelte-prop {String} [href]
* */
export let href = ''
/** Native button type
* @svelte-prop {String} [nativeType]=button
* @values Any native button type (button, submit, reset)
* */
export let nativeType = 'button'
export let loading = false
export let inverted = false
export let outlined = false
export let rounded = false
export let iconLeft = null
export let iconRight = null
export let iconPack = null
let iconSize = ''
onMount(() => {
if (!['button', 'a'].includes(tag)) throw new Error(`'${tag}' cannot be used as a tag for a Bulma button`)
})
$: props = {
...omit($$props, 'loading', 'inverted', 'nativeType', 'outlined', 'rounded', 'type'),
class: `button ${type} ${size} ${$$props.class || ''}`,
}
$: {
if (!size || size === 'is-medium') {
iconSize = 'is-small'
} else if (size === 'is-large') {
iconSize = 'is-medium'
} else {
iconSize = size
}
}
</script>
{#if tag === 'button'}
<button
{...props}
type={nativeType}
class:is-inverted={inverted}
class:is-loading={loading}
class:is-outlined={outlined}
class:is-rounded={rounded}
on:click>
{#if iconLeft}
<Icon pack={iconPack} icon={iconLeft} size={iconSize} />
{/if}
<span>
<slot />
</span>
{#if iconRight}
<Icon pack={iconPack} icon={iconRight} size={iconSize} />
{/if}
</button>
{:else if tag === 'a'}
<a
{href}
{...props}
class:is-inverted={inverted}
class:is-loading={loading}
class:is-outlined={outlined}
class:is-rounded={rounded}
on:click>
{#if iconLeft}
<Icon pack={iconPack} icon={iconLeft} size={iconSize} />
{/if}
<span>
<slot />
</span>
{#if iconRight}
<Icon pack={iconPack} icon={iconRight} size={iconSize} />
{/if}
</a>
{/if}

View File

@ -0,0 +1,32 @@
<script>
import * as transitions from 'svelte/transition'
/** Whether the Collapse is open or not
* @svelte-prop {boolean} open=true
* */
export let open = true
/** Animation to use when opening/closing
* @svelte-prop {String} animation=slide
* @values Any animation that ships with Svelte
* */
export let animation = 'slide'
let _animation = transitions[animation]
$: _animation = typeof animation === 'function' ? animation : transitions[animation]
function toggle() {
open = !open
}
</script>
<div class="collapse">
<div class="collapse-trigger" on:click={toggle}>
<slot name="trigger" />
</div>
{#if open}
<div class="collapse-content" transition:_animation|local>
<slot />
</div>
{/if}
</div>

View File

@ -0,0 +1,242 @@
<script>
import { setContext, getContext } from 'svelte'
import { writable } from 'svelte/store'
import MonthView from './View/MonthView.svelte'
import YearView from './View/YearView.svelte'
import DecadeYearView from './View/DecadeYearView.svelte'
import Selector from './Selector/Selector.svelte'
import { obtainWeeks } from './main.js'
import { createEventDispatcher } from 'svelte'
const dispatch = createEventDispatcher()
export let width = '100%'
export let nowDate = new Date()
export let i18n = 'ZH'
export let markDate = []
export let disableDate = []
export let disableDateRule = 'piecemeal'
export let date = nowDate.getTime()
export let pickerRule = 'singleChoice'
export let align = "left";
let left;
$: {
if(align === 'center'){
left = 'calc(50% - 150px)';
}else if(align === 'right'){
left = 'calc(100% - 300px)'
}else{
left = 0;
}
}
let pickerResult = []
if (pickerRule === 'singleChoice') {
const dt = new Date(Number(date))
pickerResult = dt.getFullYear() + '-' + (dt.getMonth() + 1) + '-' + dt.getDate()
}
if (pickerRule === 'freeChoice') {
const dts = []
if (typeof date === 'number' || typeof date === 'string') {
date = [date]
}
for (let v of date) {
const dt = new Date(Number(v))
const pr = dt.getFullYear() + '-' + (dt.getMonth() + 1) + '-' + dt.getDate()
dts.push(pr)
}
pickerResult = dts
}
if (pickerRule === 'rangeChoice') {
if (typeof date === 'number' || typeof date === 'string') {
date = [{ start: date }, { end: date }]
}
const sdt = new Date(Number(date[0].start))
const edt = new Date(Number(date[1].end))
const spr = sdt.getFullYear() + '-' + (sdt.getMonth() + 1) + '-' + sdt.getDate()
const epr = edt.getFullYear() + '-' + (edt.getMonth() + 1) + '-' + edt.getDate()
pickerResult = [{ start: spr }, { end: epr }]
}
//主题
export let theme = 'light'
export let calendar = false
let visible = calendar ? true : false
if (theme !== 'light' && theme !== 'dark') {
throw new RangeError(`Unexpected value.[ErrorPlace]:Datepicker.porps.theme.`)
}
if (i18n !== 'EN' && i18n !== 'ZH') {
throw new RangeError(`Unexpected value.[ErrorPlace]:Datepicker.porps.i18n.`)
}
if (disableDateRule !== 'piecemeal' && disableDateRule !== 'range') {
throw new RangeError(`Unexpected value.[ErrorPlace]:Datepicker.porps.disableDateRule.`)
}
if (pickerRule !== 'singleChoice' && pickerRule !== 'freeChoice' && pickerRule !== 'rangeChoice') {
throw new RangeError(`Unexpected value.[ErrorPlace]:Datepicker.porps.pickerRule.`)
}
//Initialize to the store
const viewDate = writable(1)
const viewMonth = writable(1)
const viewYear = writable(1920)
const thisView = writable('m') //This month:'m' this year:'y',ten years:'d'
//Bind to context
setContext('theme', theme)
setContext('nowDate', nowDate)
setContext('i18n', i18n)
setContext('viewMonth', nowDate.getMonth() + 1)
setContext('thisView', thisView)
setContext('viewYear', viewYear)
setContext('viewMonth', viewMonth)
setContext('viewDate', viewDate)
setContext('markDate', markDate)
setContext('disableDate', disableDate)
setContext('disableDateRule', disableDateRule)
setContext('pickerRule', pickerRule)
//Reacquire
let view = getContext('thisView')
let _year = getContext('viewYear')
let _month = getContext('viewMonth')
let _date = getContext('viewDate')
//Reassign
$_year = nowDate.getFullYear()
$_month = nowDate.getMonth() + 1
$_date = nowDate.getDate()
//Obtain weeks
$: theFirstWeek = obtainWeeks($_year, $_month, $_date).theFirstWeek
$: theSecondWeek = obtainWeeks($_year, $_month, $_date).theSecondWeek
$: theThirdWeek = obtainWeeks($_year, $_month, $_date).theThirdWeek
$: theFourthWeek = obtainWeeks($_year, $_month, $_date).theFourthWeek
$: fifthWeek = obtainWeeks($_year, $_month, $_date).fifthWeek
$: sixthWeek = obtainWeeks($_year, $_month, $_date).sixthWeek
function checked(e) {
date = e.detail.timeStamp
dispatch('dateChecked', e.detail)
}
</script>
<style>
.calendar_light,
.calendar_dark {
background-color: #ffffff;
/* width: 100%; */
height: 245px;
/* padding: 8px 6px 8px 6px; */
/* margin: 5px; */
border: 1px solid #ededf0;
border-radius: 2px;
box-shadow: 0px 1px #ededf0;
position: absolute;
z-index: 9;
}
.calendar_dark {
background-color: #141416;
border: 1px solid #0f1126;
box-shadow: 0px 1px #0f1126;
}
.dp-input {
margin: 5px 0 0 0;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
display: inline-block;
padding-left: 30px;
}
.date-icon {
height: 40px;
display: inline-block;
width: 40px;
position: absolute;
bottom: 0;
left: 10px;
line-height: 40px;
}
.range-input {
width: 50%;
}
.range-input.left,
.range-input.left:focus,
.range-input.left:active {
border-right: 0;
box-shadow: none !important;
/* float: left; */
}
.range-input.right,
.range-input.right:focus,
.range-input.right:active {
border-left: 0;
box-shadow: none !important;
float: right;
}
</style>
<div style="width: {width};position: relative">
{#if !calendar}
{#if pickerRule === 'rangeChoice'}
<div
style="position: relative;"
on:click={() => {
visible = !visible
}}>
<input class="dp-input input is-primary range-input left" type="text" value={pickerResult[0].start} readonly />
<span class="fa fa-calendar date-icon" />
<input class="dp-input input is-primary range-input right" type="text" value={pickerResult[1].end} readonly />
<span class="fa fa-chevron-right date-icon" style="left: calc(50% - 5px);" />
</div>
{:else}
<div style="position: relative;">
<input
class="dp-input input is-primary"
type="text"
value={pickerResult}
readonly
on:click={() => {
visible = !visible
}} />
<span class="fa fa-calendar date-icon" />
</div>
{/if}
{/if}
{#if visible || calendar}
<div class={'calendar_' + theme} style="left: {left}">
<Selector />
{#if $view === 'y'}
<YearView />
{:else if $view === 'm'}
<MonthView
{theFirstWeek}
{theSecondWeek}
{theThirdWeek}
{theFourthWeek}
{fifthWeek}
{sixthWeek}
on:checked={checked}
bind:result={pickerResult} />
{:else if $view === 'd'}
<DecadeYearView />
{/if}
</div>
{/if}
</div>

View File

@ -0,0 +1,232 @@
<script>
import { getContext, beforeUpdate } from "svelte";
export let date;
export let result;
export let isChosen;
let chosen;
let getDate = getContext("nowDate");
let pickerRule = getContext("pickerRule");
let theme = getContext("theme");
$: nowMonth = getDate.getMonth() + 1;
$: nowYear = getDate.getFullYear();
$: nowDay = getDate.getDate();
function hasChosen(date) {
let _date = date.year + "-" + date.month + "-" + date.day;
if (pickerRule === "singleChoice") {
return result == _date ? (chosen = "isChosen_" + theme) : (chosen = "");
} else if (pickerRule === "freeChoice") {
let r = new Set(result);
return r.has(_date) ? (chosen = "isFreeChosen_" + theme) : (chosen = "");
} else if (pickerRule === "rangeChoice") {
isStartOrEnd(_date);
}
}
let start = "";
let end = "";
function isStartOrEnd(arr) {
if (result.length === 0) {
return;
}
switch (+parseDate(arr)) {
case result[0].start:
start = "startChosen_" + theme;
break;
case result[1].end:
end = "endChosen_" + theme;
break;
default:
start = "";
end = "";
break;
}
}
function parseDate(str) {
var mdy = str.split("-");
return new Date(mdy[0], mdy[1] - 1, mdy[2]);
}
function datediff(first, second) {
return Math.round((second - first) / (1000 * 60 * 60 * 24));
}
beforeUpdate(() => {
hasChosen(date);
});
</script>
<div
class="{date.day == nowDay && date.month == nowMonth && date.year == nowYear ? 'today' : ''}
{chosen}
{isChosen}
{start}
{end}
">
{date.day}
</div>
<style>
td, .endChosen_dark, .endChosen_light,.startChosen_dark, .startChosen_light, .selected_dark, .selected_light, .isFreeChosen_dark,.isFreeChosen_light, .isChosen_dark, .isChosen_light,.th_dark, .th_light {
display: inline-flex;
padding: 0;
height: 30px;
width: 42.8px;
line-height: 30px;
justify-content: center;
color: #b1b1b3;
cursor: pointer;
user-select: none;
}
.endChosen_dark:hover, .endChosen_light:hover, .startChosen_dark:hover, .startChosen_light:hover, .selected_dark:hover, .selected_light:hover, .isFreeChosen_dark:hover, .isFreeChosen_light:hover, .isChosen_dark:hover, .isChosen_light:hover, .th_dark:hover, .th_light:hover {
background-color: rgba(10, 132, 255, 0.1);
color: #0c0c0d;
border-radius: 3px;
}
.dark{
color: #737373;
}
.dark:hover{
background-color: #003eaa;
color: #f9f9fa;
border-radius: 3px;
}
.today {
text-align: center;
height: 30px;
width: 42.8px;
position: relative;
}
.today::before {
content: "";
position: absolute;
bottom: 0px;
left: 0;
width: 39px;
border: 1.6px solid #0060df;
border-radius: 0.8px;
}
.markDate_light, .markDate_dark {
position: relative;
}
.markDate_light::before, .markDate_dark::before {
content: "";
position: absolute;
top: 3.2px;
left: 47%;
width: 3px;
height: 3px;
border-radius: 1.5px;
background-color: #0060df;
}
.markDate_dark::before {
background-color: #45a1ff;
}
.isChosen_light {
background-color: #002275;
color: #f9f9fa;
border-radius: 3px;
}
.isChosen_light:hover {
background-color: #003eaa;
color: #f9f9fa;
}
.isChosen_dark {
background-color: #0060df;
color: #f9f9fa;
border-radius: 3px;
}
.isChosen_dark:hover {
background-color: #003eaa;
color: #f9f9fa;
}
.isFreeChosen_light {
background-color: rgba(10, 132, 255, 0.3);
color: #0c0c0d;
}
.isFreeChosen_light:hover {
background-color: #45a1ff;
color: #f9f9fa;
}
.isFreeChosen_dark {
background-color: #0a84ff;
color: #f9f9fa;
}
.isFreeChosen_dark:hover {
background-color: #0060df;
color: #f9f9fa;
}
.selected_light {
background-color: rgba(10, 132, 255, 0.1);
color: #0c0c0d;
}
.selected_light:hover {
background-color: rgba(10, 132, 255, 0.3);
color: #0c0c0d;
}
.selected_dark {
background-color: rgba(10, 132, 255, 0.1);
color: #f9f9fa;
}
.selected_dark:hover {
background-color: rgba(10, 132, 255, 0.3);
color: #f9f9fa;
}
.startChosen_light {
background-color: #003eaa;
color: #f9f9fa;
border-top-left-radius: 3px;
border-bottom-left-radius: 3px;
}
.startChosen_light:hover {
background-color: #0060df;
color: #f9f9fa;
}
.startChosen_dark {
background-color: #0a84ff;
color: #f9f9fa;
border-top-left-radius: 3px;
border-bottom-left-radius: 3px;
}
.startChosen_dark:hover {
background-color: #0060df;
color: #f9f9fa;
}
.endChosen_light {
background-color: #003eaa;
color: #f9f9fa;
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
}
.endChosen_light:hover {
background-color: #0060df;
color: #f9f9fa;
}
.endChosen_dark {
background-color: #0a84ff;
color: #f9f9fa;
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
}
.endChosen_dark:hover {
background-color: #0060df;
color: #f9f9fa;
}
</style>

View File

@ -0,0 +1,76 @@
<script>
import { getContext } from "svelte";
//i18N
let i18n = getContext("i18n");
let theme = getContext("theme");
const WEEK_NAME = {
EN: [
{ id: 1, name: "MON" },
{ id: 2, name: "TUE" },
{ id: 3, name: "WED" },
{ id: 4, name: "THU" },
{ id: 5, name: "FRI" },
{ id: 6, name: "SAT" },
{ id: 7, name: "SUN" }
],
ZH: [
{ id: 1, name: "一" },
{ id: 2, name: "二" },
{ id: 3, name: "三" },
{ id: 4, name: "四" },
{ id: 5, name: "五" },
{ id: 6, name: "六" },
{ id: 7, name: "日" }
]
};
</script>
<style>
thead {
padding: 0;
width: 301px;
}
tr {
padding: 0;
}
.th_dark,
.th_light {
display: inline-flex;
padding: 0;
height: 30px;
width: 42.8px;
line-height: 30px;
justify-content: center;
color: #1d8ef1;
cursor: pointer;
user-select: none;
font-size: 12px;
}
th {
font-weight: 500;
}
.th_light:hover {
background: none;
color: #0c0c0d;
}
.th_dark {
color: #4a4a4f;
}
.th_dark:hover {
background: none;
color: rgb(207, 207, 207);
border-radius: 3px;
}
</style>
<thead>
<tr>
{#each WEEK_NAME[i18n] as item}
<th class={'th_' + theme}>{item.name}</th>
{/each}
</tr>
</thead>

View File

@ -0,0 +1,94 @@
<script>
import {getContext} from 'svelte';
import { fly } from 'svelte/transition';
import { quintOut } from 'svelte/easing';
const MONTH_NAME = {
EN:[{id:1,name:"January"},{id:2,name:"February"},{id:3,name:"March"},
{id:4,name:"April"},{id:5,name:"May"},{id:6,name:"June"},
{id:7,name:"July"},{id:8,name:"August"},{id:9,name:"September"},
{id:10,name:"October"},{id:11,name:"November"},{id:12,name:"December"}],
ZH:[{id:1,name:"一月"},{id:2,name:"二月"},{id:3,name:"三月"},
{id:4,name:"四月"},{id:5,name:"五月"},{id:6,name:"六月"},
{id:7,name:"七月"},{id:8,name:"八月"},{id:9,name:"九月"},
{id:10,name:"十月"},{id:11,name:"十一月"},{id:12,name:"十二月"}]
}
let i18n = getContext('i18n');
let viewMonth = getContext('viewMonth')
let viewYear = getContext('viewYear')
let thisView = getContext('thisView')
let theme = getContext('theme')
$:monthName=i18n==='ZH'? $viewYear+"年 "+MONTH_NAME[i18n][$viewMonth-1].name: MONTH_NAME[i18n][$viewMonth-1].name+" "+$viewYear;
//切换视图
function switchView (){
if($thisView==='m'){
$thisView='y'
}else if($thisView==='y'){
$thisView='d'
}else if($thisView==='d'){
$thisView='m'
}
}
</script>
<div class="{'monthTitle_'+theme}" on:click={switchView} >
<div class="titleBox">
{#if $thisView==='m'}
<div class="monthTitle" transition:fly="{{ y: -20, opacity: 0.2,duration: 200 ,easing: quintOut }}">
{monthName}
</div>
{:else if $thisView==='y'}
<div class="monthTitle" transition:fly="{{ y: 20, opacity: 0.2,duration: 200 ,easing: quintOut}}">
{$viewYear}
</div>
{:else if $thisView==='d'}
<div class="monthTitle" transition:fly="{{ y: -20, opacity: 0.2,duration: 200 ,easing: quintOut}}">
{$viewYear}-{$viewYear+11}
</div>
{/if}
</div>
</div>
<style>
.monthTitle_light, .monthTitle_dark {
width: 60%;
line-height: 30px;
text-align: center;
color: #0c0c0d;
user-select: none;
cursor: pointer;
font-weight: 600;
}
.monthTitle_light:hover, .monthTitle_dark:hover {
background-color: rgba(10, 132, 255, 0.1);
color: #0c0c0d;
border-radius: 3px;
}
.monthTitle_dark {
color: #d7d7db;
}
.monthTitle_dark:hover {
background-color: #003eaa;
color: #f9f9fa;
border-radius: 3px;
}
.titleBox {
display: block;
width: 100%;
height: 100%;
text-align: center;
position: relative;
}
.monthTitle {
width: 100%;
position: absolute;
}
</style>

View File

@ -0,0 +1,56 @@
<script>
import { getContext } from "svelte";
let view = getContext("thisView");
let viewYear = getContext("viewYear");
let viewMonth = getContext("viewMonth");
let theme = getContext("theme");
function nextClick() {
switch ($view) {
case "m":
if ($viewMonth === 12) {
$viewMonth = 1;
$viewYear = $viewYear + 1;
} else {
$viewMonth = $viewMonth + 1;
}
break;
case "y":
$viewYear = $viewYear + 1;
break;
case "d":
$viewYear = $viewYear + 11;
break;
default:
break;
}
}
</script>
<style>
.next_light, .next_dark {
width: 20%;
line-height: 30px;
text-align: center;
stroke: #b1b1b3;
cursor: pointer;
}
.next_light:hover{
background-color: rgba(10, 132, 255, 0.1);
stroke: #0c0c0d;
border-radius: 3px;
}
.next_dark {
stroke: #4a4a4f;
}
.next_dark:hover {
background-color: #003eaa;
stroke: #f9f9fa;
border-radius: 3px;
}
</style>
<div class={'next_' + theme} on:click={nextClick}>
<svg xmlns='http://www.w3.org/2000/svg' width='20' height='30' viewBox='0 0 512 512' style="display: inline-block;"><polyline points='184 112 328 256 184 400' style='fill:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:48px'/></svg>
</div>

View File

@ -0,0 +1,53 @@
<script>
import {getContext} from 'svelte'
let viewYear = getContext('viewYear')
let viewMonth = getContext('viewMonth')
let view = getContext('thisView')
let theme = getContext('theme')
function prevClick(){
if($view==='m'){
if($viewMonth===1){
$viewMonth=12
$viewYear=$viewYear-1
}else{
$viewMonth= $viewMonth-1
}
}else if($view === 'y'){
$viewYear = $viewYear-1
}else if($view === 'd'){
$viewYear = $viewYear-11
}
}
</script>
<div
class="{'prev_'+theme}"
on:click={prevClick}>
<svg xmlns='http://www.w3.org/2000/svg' width='20' height='30' viewBox='0 0 512 512' style="display: inline-block;"><polyline points='328 112 184 256 328 400' style='fill:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:48px'/></svg>
</div>
<style >
.prev_light, .prev_dark{
width: 20%;
line-height: 30px;
text-align: center;
stroke: #b1b1b3;
cursor: pointer;
}
.prev_light:hover, .prev_dark:hover {
background-color: rgba(10, 132, 255, 0.1);
stroke: #0c0c0d;
border-radius: 3px;
}
.prev_dark{
stroke: #4a4a4f;
}
.prev_dark:hover {
background-color: #003eaa;
stroke: #f9f9fa;
}
</style>

View File

@ -0,0 +1,21 @@
<script>
import MonthTitle from './MonthTitle.svelte';
import Prev from './Prev.svelte';
import Next from './Next.svelte';
</script>
<div class="header">
<Prev />
<MonthTitle />
<Next/>
</div>
<style >
.header {
display: flex;
width: 301px;
height: 30px;
padding-bottom: 4px;
}
</style>

View File

@ -0,0 +1,104 @@
<script>
import { getContext } from "svelte";
import { scale } from "svelte/transition";
import { quintOut } from "svelte/easing";
let viewYear = getContext("viewYear");
let thisView = getContext("thisView");
let theme = getContext("theme");
function updateYear(e) {
$viewYear = +e.target.innerText;
$thisView = "y";
}
</script>
<table
transition:scale={{ duration: 100, delay: 100, opacity: 0.1, start: 0.5, easing: quintOut }}>
<tbody>
<tr class={'YearView_' + theme}>
<td on:click={updateYear}>{$viewYear}</td>
<td on:click={updateYear}>{$viewYear + 1}</td>
<td on:click={updateYear}>{$viewYear + 2}</td>
</tr>
<tr class={'YearView_' + theme}>
<td on:click={updateYear}>{$viewYear + 3}</td>
<td on:click={updateYear}>{$viewYear + 4}</td>
<td on:click={updateYear}>{$viewYear + 5}</td>
</tr>
<tr class={'YearView_' + theme}>
<td on:click={updateYear}>{$viewYear + 6}</td>
<td on:click={updateYear}>{$viewYear + 7}</td>
<td on:click={updateYear}>{$viewYear + 8}</td>
</tr>
<tr class={'YearView_' + theme}>
<td on:click={updateYear}>{$viewYear + 9}</td>
<td on:click={updateYear}>{$viewYear + 10}</td>
<td on:click={updateYear}>{$viewYear + 11}</td>
</tr>
</tbody>
</table>
<style >
table {
padding: 0;
border-collapse: collapse;
position: absolute;
width: 301px;
}
tbody {
padding: 0;
width: 301px;
}
tr {
padding: 0;
}
td, .YearView_light td, .YearView_dark td, .YearView_light .th_light, .YearView_light .th_dark, .th_dark, .th_light {
display: inline-flex;
padding: 0;
height: 30px;
width: 42.8px;
line-height: 30px;
justify-content: center;
color: #b1b1b3;
cursor: pointer;
user-select: none;
}
td:hover{
background-color: rgba(10, 132, 255, 0.1);
color: #0c0c0d;
border-radius: 3px;
}
.dark{
color: #737373;
}
.dark:hover{
background-color: #003eaa;
color: #f9f9fa;
border-radius: 3px;
}
.YearView_light, .YearView_dark {
width: 100%;
padding: 0;
text-align: center;
}
.YearView_light td, .YearView_dark td, .YearView_dark .endChosen_dark, .YearView_dark .endChosen_light, .YearView_dark .startChosen_dark, .YearView_dark .startChosen_light, .YearView_dark .selected_dark, .YearView_dark .selected_light, .YearView_dark .isFreeChosen_dark, .YearView_dark .isFreeChosen_light, .YearView_dark .isChosen_dark, .YearView_dark .isChosen_light, .YearView_light .th_light, .YearView_dark .th_light, .YearView_light .th_dark, .YearView_dark .th_dark {
color: #0c0c0d;
width: 32%;
height: 52.5px;
line-height: 52.5px;
}
.YearView_dark td, .YearView_dark .endChosen_dark, .YearView_dark .endChosen_light, .YearView_dark .startChosen_dark, .YearView_dark .startChosen_light, .YearView_dark .selected_dark, .YearView_dark .selected_light, .YearView_dark .isFreeChosen_dark, .YearView_dark .isFreeChosen_light, .YearView_dark .isChosen_dark, .YearView_dark .isChosen_light, .YearView_dark .th_light, .YearView_dark .th_dark {
color: #ededf0;
}
.YearView_dark td:hover, .YearView_dark .endChosen_dark:hover, .YearView_dark .endChosen_light:hover, .YearView_dark .startChosen_dark:hover, .YearView_dark .startChosen_light:hover, .YearView_dark .selected_dark:hover, .YearView_dark .selected_light:hover, .YearView_dark .isFreeChosen_dark:hover, .YearView_dark .isFreeChosen_light:hover, .YearView_dark .isChosen_dark:hover, .YearView_dark .isChosen_light:hover, .YearView_dark .th_light:hover, .YearView_dark .th_dark:hover {
background-color: #003eaa;
}
</style>

View File

@ -0,0 +1,420 @@
<script>
import { getContext } from 'svelte'
import { scale } from 'svelte/transition'
import { quintOut } from 'svelte/easing'
import { createEventDispatcher } from 'svelte'
const dispatch = createEventDispatcher()
import WeekTitle from '../Month/WeekTitle.svelte'
import Day from '../Month/Day.svelte'
export let theFirstWeek
export let theSecondWeek
export let theThirdWeek
export let theFourthWeek
export let fifthWeek
export let sixthWeek
export let result
let array = []
$: {
array[0] = theFirstWeek
array[1] = theSecondWeek
array[2] = theThirdWeek
array[3] = theFourthWeek
array[4] = fifthWeek
array[5] = sixthWeek
}
const TODAY_NAME = {
EN: 'today',
ZH: '今天',
}
//判断周末
function isSatOrSun(arr) {
let _date = arr.year + '-' + arr.month + '-' + arr.day
let d = new Date(Date.parse(_date.replace(/\-/g, '/'))).getDay()
return d === 6 || d === 0 ? true : false
}
//是否被标记
function isMark(arr) {
let _date = arr.year + '-' + arr.month + '-' + arr.day
let markDate = new Set(primaevalMarkDate)
return markDate.has(_date)
}
//是否被禁用
function isDisableDate(arr) {
if (disableDateRule === 'piecemeal') {
let _date = arr.year + '-' + arr.month + '-' + arr.day
let _disableDate = new Set(disableDate)
return _disableDate.has(_date)
} else if (disableDateRule === 'range') {
let _date = arr.year + '-' + arr.month + '-' + arr.day
let dateNum = datediff(parseDate(disableDate[0].start), parseDate(disableDate[1].end))
let startDateNum = datediff(parseDate(_date), parseDate(disableDate[0].start))
let endDateNum = datediff(parseDate(_date), parseDate(disableDate[1].end))
if (startDateNum > 0 || endDateNum < 0) {
return false
} else {
return true
}
}
}
function parseDate(str) {
var mdy = str.split('-')
return new Date(mdy[0], mdy[1] - 1, mdy[2])
}
function datediff(first, second) {
return Math.round((second - first) / (1000 * 60 * 60 * 24))
}
let i18n = getContext('i18n')
let theme = getContext('theme')
let pickerRule = getContext('pickerRule')
let viewMonth = getContext('viewMonth')
let primaevalMarkDate = getContext('markDate')
let disableDate = getContext('disableDate')
let disableDateRule = getContext('disableDateRule')
let getDate = getContext('nowDate')
let thisView = getContext('thisView')
$: nowMonth = getDate.getMonth() + 1
$: nowYear = getDate.getFullYear()
$: nowDay = getDate.getDate()
function handleClick(date) {
let _date = date.year + '-' + date.month + '-' + date.day
let times = []
switch (pickerRule) {
case 'freeChoice':
let r = new Set(result)
if (r.has(_date)) {
r.delete(_date)
result = [...new Set(r)]
} else {
result = [...result, _date]
}
for (let v of result) {
times.push(+parseDate(v))
}
// dispatch('dateChecked', {
// time: result,
// timeStamp: times
// })
break
case 'rangeChoice':
if (result.length === 0) {
result = [{ start: 0 }, { end: 0 }]
result[0].start = _date
result[1].end = _date
} else if (+parseDate(_date) > +parseDate(result[1].end)) {
result[1].end = _date
} else if (+parseDate(_date) === +parseDate(result[0].start)) {
result[1].end = _date
} else if (+parseDate(_date) < +parseDate(result[1].end)) {
result[0].start = _date
}
times.push({ start: +parseDate(result[0].start) })
times.push({ end: +parseDate(result[1].end) })
// dispatch('dateChecked', {
// time: result,
// timeStamp: times
// })
break
default:
if (result !== _date) {
result = _date
times = +parseDate(_date)
} else if (result === _date) {
result = []
}
}
if ((result.length !== 0)) {
dispatch('checked', { time: result, timeStamp: times })
} else {
dispatch('checked', '')
}
array = array
}
function isChosen(arr) {
let _date = arr.year + '-' + arr.month + '-' + arr.day
if (pickerRule === 'rangeChoice') {
if (result.length === 0) {
return
}
let dateNum = datediff(new Date(result[0].start), new Date(result[1].end))
let startDateNum = datediff(parseDate(_date), new Date(result[0].start))
let endDateNum = datediff(parseDate(_date), new Date(result[1].end))
if (startDateNum > 0 || endDateNum < 0 || result[0].start === 0) {
return false
} else {
return true
}
}
}
</script>
<style>
table {
padding: 0;
border-collapse: collapse;
/* position: absolute; */
width: 300px;
left: -1px;
}
tbody {
padding: 0;
width: 300px;
}
tr {
padding: 0;
}
td,
.endChosen_dark,
.YearView_light .endChosen_dark,
.endChosen_light,
.YearView_light .endChosen_light,
.startChosen_dark,
.YearView_light .startChosen_dark,
.startChosen_light,
.YearView_light .startChosen_light,
.selected_dark,
.YearView_light .selected_dark,
.selected_light,
.YearView_light .selected_light,
.isFreeChosen_dark,
.YearView_light .isFreeChosen_dark,
.isFreeChosen_light,
.YearView_light .isFreeChosen_light,
.isChosen_dark,
.YearView_light .isChosen_dark,
.isChosen_light,
.YearView_light .isChosen_light,
.YearView_light td,
.YearView_dark td,
.YearView_light .th_light,
.YearView_light .th_dark,
.th_dark,
.th_light {
display: inline-flex;
padding: 0;
height: 30px;
width: 42.8px;
line-height: 30px;
justify-content: center;
color: #b1b1b3;
cursor: pointer;
user-select: none;
}
td:hover,
.endChosen_dark:hover,
.endChosen_light:hover,
.startChosen_dark:hover,
.startChosen_light:hover,
.selected_dark:hover,
.selected_light:hover,
.isFreeChosen_dark:hover,
.isFreeChosen_light:hover,
.isChosen_dark:hover,
.isChosen_light:hover,
.th_dark:hover,
.th_light:hover {
background-color: rgba(10, 132, 255, 0.1);
color: #0c0c0d;
border-radius: 3px;
}
.dark,
.th_dark {
color: #737373;
}
.dark:hover,
.th_dark:hover {
background-color: #003eaa;
color: #f9f9fa;
border-radius: 3px;
}
.isSatOrSun_light {
background-color: #f9f9fa;
}
.isSatOrSun_dark {
background-color: #0c0c0d;
}
.thisMonth_light {
color: #0c0c0d;
}
.thisMonth_dark {
color: #d7d7db;
}
.disableDate_light {
color: #d7d7db;
pointer-events: none;
}
.disableDate_dark {
color: #38383d;
pointer-events: none;
}
.markDate_light,
.markDate_dark {
position: relative;
}
.markDate_light::before,
.markDate_dark::before {
content: '';
position: absolute;
top: 3.2px;
left: 47%;
width: 3px;
height: 3px;
border-radius: 1.5px;
background-color: #0060df;
}
.markDate_dark::before {
background-color: #45a1ff;
}
.isChosen_light {
background-color: #002275;
color: #f9f9fa;
border-radius: 3px;
}
.isChosen_light:hover {
background-color: #003eaa;
color: #f9f9fa;
}
.isChosen_dark {
background-color: #0060df;
color: #f9f9fa;
border-radius: 3px;
}
.isChosen_dark:hover {
background-color: #003eaa;
color: #f9f9fa;
}
.isFreeChosen_light {
background-color: rgba(10, 132, 255, 0.3);
color: #0c0c0d;
}
.isFreeChosen_light:hover {
background-color: #45a1ff;
color: #f9f9fa;
}
.isFreeChosen_dark {
background-color: #0a84ff;
color: #f9f9fa;
}
.isFreeChosen_dark:hover {
background-color: #0060df;
color: #f9f9fa;
}
.selected_light {
background-color: rgba(10, 132, 255, 0.1);
color: #0c0c0d;
}
.selected_light:hover {
background-color: rgba(10, 132, 255, 0.3);
color: #0c0c0d;
}
.selected_dark {
background-color: rgba(10, 132, 255, 0.1);
color: #f9f9fa;
}
.selected_dark:hover {
background-color: rgba(10, 132, 255, 0.3);
color: #f9f9fa;
}
.startChosen_light {
background-color: #003eaa;
color: #f9f9fa;
border-top-left-radius: 3px;
border-bottom-left-radius: 3px;
}
.startChosen_light:hover {
background-color: #0060df;
color: #f9f9fa;
}
.startChosen_dark {
background-color: #0a84ff;
color: #f9f9fa;
border-top-left-radius: 3px;
border-bottom-left-radius: 3px;
}
.startChosen_dark:hover {
background-color: #0060df;
color: #f9f9fa;
}
.endChosen_light {
background-color: #003eaa;
color: #f9f9fa;
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
}
.endChosen_light:hover {
background-color: #0060df;
color: #f9f9fa;
}
.endChosen_dark {
background-color: #0a84ff;
color: #f9f9fa;
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
}
.endChosen_dark:hover {
background-color: #0060df;
color: #f9f9fa;
}
</style>
<table transition:scale={{ duration: 100, delay: 100, opacity: 0.1, start: 0.5, easing: quintOut }}>
<WeekTitle />
<tbody>
{#each array as Weeks}
<tr>
{#each Weeks as item, i}
<td
title={item.day == nowDay && item.month == nowMonth && item.year == nowYear ? TODAY_NAME[i18n] : ''}
class="{theme}
{(item.month === $viewMonth ? 'thisMonth_' : '') + theme}
{(isSatOrSun(item) ? 'isSatOrSun_' : '') + theme}
{(isMark(item) ? 'markDate_' : '') + theme}
{(isDisableDate(item) ? 'disableDate_' : '') + theme}
{isChosen(item) ? 'selected_' + theme : ''}
"
on:click={()=> handleClick(item)}>
<Day date={item} {result} isChosen={isChosen(item) ? 'selected_' + theme : ''} />
</td>
{/each}
</tr>
{/each}
</tbody>
</table>

View File

@ -0,0 +1,158 @@
<script>
import { getContext } from "svelte";
import { scale } from "svelte/transition";
import { quintOut } from "svelte/easing";
const MONTH_NAME = {
EN: [
{ id: 1, name: "January" },
{ id: 2, name: "February" },
{ id: 3, name: "March" },
{ id: 4, name: "April" },
{ id: 5, name: "May" },
{ id: 6, name: "June" },
{ id: 7, name: "July" },
{ id: 8, name: "August" },
{ id: 9, name: "September" },
{ id: 10, name: "October" },
{ id: 11, name: "November" },
{ id: 12, name: "December" }
],
ZH: [
{ id: 1, name: "一月" },
{ id: 2, name: "二月" },
{ id: 3, name: "三月" },
{ id: 4, name: "四月" },
{ id: 5, name: "五月" },
{ id: 6, name: "六月" },
{ id: 7, name: "七月" },
{ id: 8, name: "八月" },
{ id: 9, name: "九月" },
{ id: 10, name: "十月" },
{ id: 11, name: "十一月" },
{ id: 12, name: "十二月" }
]
};
let i18n = getContext("i18n");
let viewMonth = getContext("viewMonth");
let thisView = getContext("thisView");
let theme = getContext("theme");
function changeMonth(e) {
$viewMonth = +e.target.id;
$thisView = "m";
}
</script>
<table
transition:scale={{ duration: 100, delay: 100, opacity: 0.1, start: 0.5, easing: quintOut }}>
<tbody>
<tr class={'YearView_' + theme}>
<td id={MONTH_NAME[i18n][0].id} on:click={changeMonth}>
{MONTH_NAME[i18n][0].name}
</td>
<td id={MONTH_NAME[i18n][1].id} on:click={changeMonth}>
{MONTH_NAME[i18n][1].name}
</td>
<td id={MONTH_NAME[i18n][2].id} on:click={changeMonth}>
{MONTH_NAME[i18n][2].name}
</td>
</tr>
<tr class={'YearView_' + theme}>
<td id={MONTH_NAME[i18n][3].id} on:click={changeMonth}>
{MONTH_NAME[i18n][3].name}
</td>
<td id={MONTH_NAME[i18n][4].id} on:click={changeMonth}>
{MONTH_NAME[i18n][4].name}
</td>
<td id={MONTH_NAME[i18n][5].id} on:click={changeMonth}>
{MONTH_NAME[i18n][5].name}
</td>
</tr>
<tr class={'YearView_' + theme}>
<td id={MONTH_NAME[i18n][6].id} on:click={changeMonth}>
{MONTH_NAME[i18n][6].name}
</td>
<td id={MONTH_NAME[i18n][7].id} on:click={changeMonth}>
{MONTH_NAME[i18n][7].name}
</td>
<td id={MONTH_NAME[i18n][8].id} on:click={changeMonth}>
{MONTH_NAME[i18n][8].name}
</td>
</tr>
<tr class={'YearView_' + theme}>
<td id={MONTH_NAME[i18n][9].id} on:click={changeMonth}>
{MONTH_NAME[i18n][9].name}
</td>
<td id={MONTH_NAME[i18n][10].id} on:click={changeMonth}>
{MONTH_NAME[i18n][10].name}
</td>
<td id={MONTH_NAME[i18n][11].id} on:click={changeMonth}>
{MONTH_NAME[i18n][11].name}
</td>
</tr>
</tbody>
</table>
<style >
table {
padding: 0;
border-collapse: collapse;
position: absolute;
width: 301px;
}
tbody {
padding: 0;
width: 301px;
}
tr {
padding: 0;
}
td, .YearView_light td, .YearView_dark td, .YearView_light .th_light, .YearView_light .th_dark, .th_dark, .th_light {
display: inline-flex;
padding: 0;
height: 30px;
width: 42.8px;
line-height: 30px;
justify-content: center;
color: #b1b1b3;
cursor: pointer;
user-select: none;
}
td:hover{
background-color: rgba(10, 132, 255, 0.1);
color: #0c0c0d;
border-radius: 3px;
}
.dark{
color: #737373;
}
.dark:hover{
background-color: #003eaa;
color: #f9f9fa;
border-radius: 3px;
}
.YearView_light, .YearView_dark {
width: 100%;
padding: 0;
text-align: center;
}
.YearView_light td, .YearView_dark td, .YearView_dark .endChosen_dark, .YearView_dark .endChosen_light, .YearView_dark .startChosen_dark, .YearView_dark .startChosen_light, .YearView_dark .selected_dark, .YearView_dark .selected_light, .YearView_dark .isFreeChosen_dark, .YearView_dark .isFreeChosen_light, .YearView_dark .isChosen_dark, .YearView_dark .isChosen_light, .YearView_light .th_light, .YearView_dark .th_light, .YearView_light .th_dark, .YearView_dark .th_dark {
color: #0c0c0d;
width: 32%;
height: 52.5px;
line-height: 52.5px;
}
.YearView_dark td, .YearView_dark .endChosen_dark, .YearView_dark .endChosen_light, .YearView_dark .startChosen_dark, .YearView_dark .startChosen_light, .YearView_dark .selected_dark, .YearView_dark .selected_light, .YearView_dark .isFreeChosen_dark, .YearView_dark .isFreeChosen_light, .YearView_dark .isChosen_dark, .YearView_dark .isChosen_light, .YearView_dark .th_light, .YearView_dark .th_dark {
color: #ededf0;
}
.YearView_dark td:hover, .YearView_dark .endChosen_dark:hover, .YearView_dark .endChosen_light:hover, .YearView_dark .startChosen_dark:hover, .YearView_dark .startChosen_light:hover, .YearView_dark .selected_dark:hover, .YearView_dark .selected_light:hover, .YearView_dark .isFreeChosen_dark:hover, .YearView_dark .isFreeChosen_light:hover, .YearView_dark .isChosen_dark:hover, .YearView_dark .isChosen_light:hover, .YearView_dark .th_light:hover, .YearView_dark .th_dark:hover {
background-color: #003eaa;
}
</style>

View File

@ -0,0 +1,206 @@
//Is there a sixth week of the month
let thisMonthHasSixthWeek = false;
//Solar month
const SOLAR_MONTH = [1, 3, 5, 7, 8, 10, 12];
let thisDate;
let thisMonthDays;
let lastMonthOfYear;
let lastMonth;
let lastMonthDays;
let monthFirstDayDay;
let monthLastDayDay;
let nextMonthOfYear;
let nextMonth;
let theFirstWeek;
let theSecondWeek;
let theThirdWeek;
let theFourthWeek;
let fifthWeek;
let sixthWeek;
let thisYear;
let thisDay;
let thisMonth;
export const obtainWeeks = function (y, m, d) {
thisDay = d;
thisYear = y;
thisMonth = m;
//当前日期
thisDate = dayIsIt(thisDay);
//当前月天数
thisMonthDays = computeMonthDays(thisYear, thisMonth);
//上月所在年份
lastMonthOfYear = computeLastMonth(thisYear, thisMonth)[0];
//上月所在月份
lastMonth = computeLastMonth(thisYear, thisMonth)[1]
//下个月所在年份
nextMonthOfYear = computeNextMonth(thisYear, thisMonth)[0];
//下个所在月份
nextMonth = computeNextMonth(thisYear, thisMonth)[1]
//上月有几天
lastMonthDays = computeMonthDays(lastMonthOfYear, lastMonth);
//当月第一天是周几
monthFirstDayDay = dayIsIt(1);
//当月最后一天是周几
monthLastDayDay = dayIsIt(thisMonthDays);
//第一周
theFirstWeek = computeFirstWeek();
//第二周
theSecondWeek = computeMidWeek(theFirstWeek[6].day + 1);
//第三周
theThirdWeek = computeMidWeek(theSecondWeek[6].day + 1);
//第四周
theFourthWeek = computeMidWeek(theThirdWeek[6].day + 1);
//第五周
switch (true) {
case (thisMonthDays - theFourthWeek[6].day) === 7:
fifthWeek = computeLastWeek(theFourthWeek[6].day + 1);
thisMonthHasSixthWeek = true;
break;
case (thisMonthDays - theFourthWeek[6].day) > 7:
fifthWeek = computeMidWeek(theFourthWeek[6].day + 1);
thisMonthHasSixthWeek = true;
break;
default:
fifthWeek = computeLastWeek(theFourthWeek[6].day + 1)
thisMonthHasSixthWeek = false;
break;
}
//第六周
sixthWeek = thisMonthHasSixthWeek
? computeLastWeek(fifthWeek[6].day + 1)
: computeMidWeek(fifthWeek[6].day + 1, true);
return {
theFirstWeek,
theSecondWeek,
theThirdWeek,
theFourthWeek,
fifthWeek,
sixthWeek
}
}
//判断大月
const isSolarMonth = function (m) { return !!~SOLAR_MONTH.indexOf(m) }
//判断闰年
const isLeapYear = function (y) { return (y % 4 == 0 && y % 100 != 0) || y % 400 == 0 }
//计算是周几
const dayIsIt = function (n) {
let _date = thisYear + '-' + thisMonth + '-' + n;
let d = new Date(Date.parse(_date.replace(/\-/g, "/"))).getDay();
return d === 0 ? 7 : d;
}
//判断某个月有几天
const computeMonthDays = function(y, m) {
let d = NaN;
if (isLeapYear(y) && m === 2) { d = 29; }
else if (m === 2) { d = 28; }
else if (isSolarMonth(m)) { d = 31; }
else { d = 30; }
return d;
}
//计算上个月和上个月所在的年份
const computeLastMonth = function(y, m) {
let ly = NaN;
let lm = NaN;
if (m !== 1) { lm = m - 1; ly = y }
else { lm = 12; ly = y - 1 }
return [ly, lm]
}
//计算下个月和下个月所在的年份
const computeNextMonth = function(y, m) {
let ny = NaN;
let nm = NaN;
if (m !== 12) { nm = m + 1; ny = y }
else { nm = 1; ny = y + 1 }
return [ny, nm]
}
//计算当月首周
const computeFirstWeek = function() {
let array = [];
array.length = 7;
let i = 8 - monthFirstDayDay
let times = monthFirstDayDay - 2
for (let index = 0; index < array.length; index++) {
array[index] = {
"year": lastMonthOfYear == thisYear ? thisYear : thisYear - 1,
"month": thisMonth == 1 ? 12 : thisMonth - 1,
"day": lastMonthDays - times
};
times--
}
for (let index = 0; index < i; index++) {
array[(7 - i) + index] = {
"year": thisYear,
"month": thisMonth,
"day": index + 1
};
}
return array
}
//计算其他周
const computeMidWeek = function(d, s) {
let array = [];
array.length = 7;
if(s && thisMonth==12){
for (let index = 0; index < array.length; index++) {
array[index] = {
"year": thisYear+1,
"month": 1,
"day": d + index
};
}
}else{
for (let index = 0; index < array.length; index++) {
array[index] = {
"year": thisYear,
"month": thisMonthHasSixthWeek === false && s ? thisMonth + 1 : thisMonth,
"day": d + index
};
}
}
return array
}
//计算当月最后一周
const computeLastWeek = function(d) {
let array = [];
let times = thisMonthDays - d + 1
for (let index = 0; index < times; index++) {
array[index] = {
"year": thisYear,
"month": thisMonth,
"day": d + index
}
}
for (let index = 0; index < 7 - times; index++) {
array[times + index] = {
"year": nextMonthOfYear == thisYear ? thisYear : thisYear + 1,
"month": nextMonth == 1 ? 1 : thisMonth + 1,
"day": index + 1
};
}
array.length = 7;
return array
}

View File

@ -0,0 +1,277 @@
<script>
import { createEventDispatcher, onDestroy, onMount, tick } from 'svelte'
import Icon from '../Icon.svelte'
import { chooseAnimation, isEnterKey, isEscKey } from '../../utils'
/** Show a header on the dialog with this text
* @svelte-prop {String} [message]
* */
export let title = ''
/** Text or html message for this dialog
* @svelte-prop {String} message
* */
export let message
/** Text to show on the confirmation button
* @svelte-prop {String} [confirmText=OK]
* */
export let confirmText = 'OK'
/** Text to show on the cancel button
* @svelte-prop {String} [cancelText=Cancel]
* */
export let cancelText = 'Cancel'
/** Focus on confirm or cancel button when dialog opens
* @svelte-prop {String} [focusOn=confirm]
* @values <code>confirm</code>, <code>cancel</code>
* */
export let focusOn = 'confirm'
/** Show this icon on left-side of dialog. It will use the color from <code>type</code>
* @svelte-prop {String} [icon]
* */
export let icon = ''
/** Fontawesome icon pack to use. By default the <code>Icon</code> component uses <code>fas</code>
* @svelte-prop {String} [iconPack]
* @values <code>fas</code>, <code>fab</code>, etc...
* */
export let iconPack = ''
/** Show an input field
* @svelte-prop {Boolean} [hasInput=false]
* */
export let hasInput = false
export let prompt = null
/** Show the cancel button. True for <code>confirm()</code>
* @svelte-prop {Boolean} [showCancel=false]
* */
export let showCancel = false
/** Dialog's size
* @svelte-prop {String} [size]
* @values $$sizes$$
* */
export let size = ''
/** Type (color) to use on confirm button and icon
* @svelte-prop {String} [type=is-primary]
* @values $$colors$$
* */
export let type = 'is-primary'
export let active = true
/** Animation to use when showing dialog
* @svelte-prop {String|Function} [animation=scale]
* @values Any transition name that ships with Svelte, or a custom function
* */
export let animation = 'scale'
/** Props to pass to animation function
* @svelte-prop {Object} [animProps={ start: 1.2 }]
* */
export let animProps = { start: 1.2 }
/** Props (attributes) to use to on prompt input element
* @svelte-prop {Object} [inputProps]
* */
export let inputProps = {}
// export let showClose = true
let resolve
export const promise = new Promise((fulfil) => (resolve = fulfil))
// TODO: programmatic subcomponents
export const subComponent = null
export let appendToBody = true
let modal
let cancelButton
let confirmButton
let input
let validationMessage = ''
const dispatch = createEventDispatcher()
$: _animation = chooseAnimation(animation)
$: {
if (modal && active && appendToBody) {
modal.parentNode.removeChild(modal)
document.body.appendChild(modal)
}
}
$: newInputProps = { required: true, ...inputProps }
onMount(async () => {
await tick()
if (hasInput) {
input.focus()
} else if (focusOn === 'cancel' && showCancel) {
cancelButton.focus()
} else {
confirmButton.focus()
}
})
function cancel() {
resolve(hasInput ? null : false)
close()
}
function close() {
resolve(hasInput ? null : false)
active = false
dispatch('destroyed')
}
async function confirm() {
if (input && !input.checkValidity()) {
validationMessage = input.validationMessage
await tick()
input.select()
return
}
validationMessage = ''
resolve(hasInput ? prompt: true)
close()
}
function keydown(e) {
if (active && isEscKey(e)) {
close()
}
}
</script>
<style lang="scss">
@import 'node_modules/bulma/sass/utilities/all';
.dialog {
.modal-card {
max-width: 460px;
width: auto;
.modal-card-head {
font-size: $size-5;
font-weight: $weight-semibold;
}
.modal-card-body {
.field {
margin-top: 16px;
}
&.is-titleless {
border-top-left-radius: $radius-large;
border-top-right-radius: $radius-large;
}
}
.modal-card-foot {
justify-content: flex-end;
.button {
display: inline; // Fix Safari centering
min-width: 5em;
font-weight: $weight-semibold;
}
}
@include tablet {
min-width: 320px;
}
}
&.is-small {
.modal-card,
.input,
.button {
@include control-small;
}
}
&.is-medium {
.modal-card,
.input,
.button {
@include control-medium;
}
}
&.is-large {
.modal-card,
.input,
.button {
@include control-large;
}
}
}
</style>
<svelte:window on:keydown={keydown}></svelte:window>
<svelte:options accessors/>
{#if active}
<div class="modal dialog {size} is-active" bind:this={modal}>
<div class="modal-background" on:click={close}></div>
<div class="modal-card" transition:_animation={animProps}>
{#if title}
<header class="modal-card-head">
<p class="modal-card-title">{title}</p>
<!-- NOTE: don't think we need this... -->
<!-- {#if showClose}
<button class="delete" aria-label="close" on:click={close}></button>
{/if} -->
</header>
{/if}
<section class="modal-card-body" class:is-titleless={!title} class:is-flex={icon}>
<div class="media">
{#if icon}
<div class="media-left">
<Icon pack={iconPack} {icon} {type} size="is-large"></Icon>
</div>
{/if}
<div class="media-content">
<p>{@html message}</p>
{#if hasInput}
<div class="field">
<div class="control">
<input
bind:value={prompt}
class="input"
bind:this={input}
{...newInputProps}
on:keyup={e => isEnterKey(e) && confirm()}>
<p class="help is-danger">{validationMessage}</p>
</div>
</div>
{/if}
</div>
</div>
</section>
<footer class="modal-card-foot">
{#if showCancel}
<button
class="button"
bind:this={cancelButton}
on:click={cancel}>
{cancelText}
</button>
{/if}
<button
class="button {type}"
bind:this={confirmButton}
on:click={confirm}>
{confirmText}
</button>
</footer>
</div>
</div>
{/if}

View File

@ -0,0 +1,39 @@
import Dialog from './Dialog.svelte'
function createDialog(props) {
if (typeof props === 'string') props = { message: props }
const dialog = new Dialog({
target: document.body,
props,
intro: true,
});
dialog.$on('destroy', () => {
dialog.$destroy
})
return dialog.promise
}
export function alert(props) {
return createDialog(props);
}
export function confirm(props) {
if (typeof props === 'string') props = { message: props }
return createDialog({ showCancel: true, ...props });
}
export function prompt(props) {
if (typeof props === 'string') props = { message: props }
return createDialog({ hasInput: true, confirmText: 'Done', ...props });
}
Dialog.alert = alert
Dialog.confirm = confirm
Dialog.prompt = prompt
export default Dialog

View File

@ -0,0 +1,24 @@
<script>
import * as transitions from 'svelte/transition'
export let open = true
export let animation = 'slide'
let _animation = transitions[animation]
$: _animation = typeof animation === 'function' ? animation : transitions[animation]
function toggle() {
open = !open
}
</script>
<div class="collapse">
<div class="collapse-trigger" on:click={toggle}>
<slot name="trigger" />
</div>
{#if open}
<div class="collapse-content" transition:_animation|local>
<slot />
</div>
{/if}
</div>

122
src/components/Field.svelte Normal file
View File

@ -0,0 +1,122 @@
<script>
import { onMount, setContext } from 'svelte'
import { omit } from '../utils'
/** Type (color) of the field and help message. Also adds a matching icon.
* @svelte-prop {String} [type]
* @values $$colors$$
* */
export let type = ''
/** Label for input
* @svelte-prop {String} [label]
* */
export let label = null
/** Same as native <code>for</code> on label
* @svelte-prop {String} [labelFor]
* */
export let labelFor = ''
/** Message to show beneath input
* @svelte-prop {String} [message]
* */
export let message = ''
/** Direct child components/elements of Field will be grouped horizontally
* @svelte-prop {Boolean} grouped=false
* */
export let grouped = false
/** Allow grouped controls to cover multiple lines
* @svelte-prop {Boolean} groupMultiline=false
* */
export let groupMultiline = false
/** Alter the alignment of the field
* @svelte-prop {String} [position]
* @values is-centered, is-right
* */
export let position = ''
/** Automatically attach child controls together
* @svelte-prop {Boolean} addons=true
* */
export let addons = true
export let expanded = false
setContext('type', () => type)
let el
let labelEl
let messageEl
let fieldType = ''
let hasIcons = false
let iconType = ''
let mounted = false
let newPosition = ''
// Determine the icon type
$: {
if (['is-danger', 'is-success'].includes(type)) {
iconType = type
}
}
$: {
if (grouped) fieldType = 'is-grouped'
else if (mounted) {
const childNodes = Array.prototype.filter.call(el.children, c => !([labelEl, messageEl].includes(c)))
if (childNodes.length > 1 && addons) {
fieldType = 'has-addons'
}
}
}
// Update has-addons-* or is-grouped-* classes based on position prop
$: {
if (position) {
const pos = position.split('-')
if (pos.length >= 1) {
const prefix = grouped ? 'is-grouped-' : 'has-addons-'
newPosition = prefix + pos[1]
}
}
}
$: props = { ...omit($$props, 'addons', 'class', 'expanded', 'grouped', 'label', 'labelFor', 'position', 'type') }
onMount(() => {
mounted = true
})
</script>
<style lang="scss">
.field {
&.is-grouped {
.field {
flex-shrink: 0;
&:not(:last-child) {
margin-right: 0.75rem;
}
&.is-expanded {
flex-grow: 1;
flex-shrink: 1;
}
}
}
}
</style>
<div {...props} class="field {type} {fieldType} {newPosition} {$$props.class || ''}" class:is-expanded={expanded} class:is-grouped-multiline={groupMultiline} bind:this={el}>
{#if label}
<label for={labelFor} class="label" bind:this={labelEl}>{label}</label>
{/if}
<slot statusType={type} />
{#if message}
<p class="help {type}" bind:this={messageEl}>{message}</p>
{/if}
</div>

Some files were not shown because too many files have changed in this diff Show More