fu-kit 0.0.1-beta.2 → 0.0.1-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +47 -19
- package/dist/favicon.ico +0 -0
- package/dist/img/splash-screen.8bd73950.jpg +0 -0
- package/dist/index.html +1 -0
- package/dist/js/app.53980592.js +2 -0
- package/dist/js/app.53980592.js.map +1 -0
- package/dist/js/chunk-vendors.fe8aa7a9.js +8 -0
- package/dist/js/chunk-vendors.fe8aa7a9.js.map +1 -0
- package/package.json +36 -36
- package/reset.scss +60 -0
- package/root.scss +130 -0
- package/scss.scss +5 -3
- package/src/App.vue +122 -30
- package/src/Home.vue +112 -0
- package/src/assets/splash-screen.jpg +0 -0
- package/src/components/FuButton.vue +104 -27
- package/src/components/FuButtonLink.vue +79 -0
- package/src/components/FuCodeView.vue +58 -0
- package/src/components/FuCopy.vue +103 -0
- package/src/components/FuProgressRadial.vue +117 -0
- package/src/components/FuSelect.vue +84 -55
- package/src/components/FuSelectX.vue +317 -0
- package/src/components/FuSidebar.vue +90 -0
- package/src/components/FuText.vue +98 -60
- package/src/components/FuTextarea.vue +118 -0
- package/src/docs/DocButton.vue +67 -0
- package/src/docs/DocSandbox.vue +71 -0
- package/src/docs/DocSelect.vue +55 -0
- package/src/docs/DocSidebar.vue +93 -0
- package/src/docs/DocText.vue +59 -0
- package/src/docs/DocTextarea.vue +64 -0
- package/src/docs/DocTypo.vue +98 -0
- package/src/main.js +9 -5
- package/src/router.js +29 -17
- package/src/scss/colors.scss +16 -6
- package/src/scss/typo.scss +5 -14
- package/src/scss/ui.scss +22 -38
- package/src/scss/utils.scss +36 -0
- package/src/styles.scss +15 -0
- package/src/utils/media.js +1 -0
- package/src/utils/woosh.js +2 -0
- package/vue.config.js +1 -4
- package/src/views/Home.vue +0 -24
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<button
|
|
3
|
+
v-bind="{
|
|
4
|
+
...$attrs,
|
|
5
|
+
type: $attrs.type || 'button',
|
|
6
|
+
class: 'fu-button-link',
|
|
7
|
+
}"
|
|
8
|
+
@mouseup="mUp"
|
|
9
|
+
>
|
|
10
|
+
<slot />
|
|
11
|
+
</button>
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<script>
|
|
15
|
+
export default {
|
|
16
|
+
name: 'fu-button-link',
|
|
17
|
+
props: {
|
|
18
|
+
hollow: { type: Boolean, default: false },
|
|
19
|
+
},
|
|
20
|
+
setup (props) {
|
|
21
|
+
const mUp = (e) => e.target.blur()
|
|
22
|
+
return { hollow: props.hollow, mUp }
|
|
23
|
+
},
|
|
24
|
+
}
|
|
25
|
+
</script>
|
|
26
|
+
|
|
27
|
+
<style lang="scss">
|
|
28
|
+
:root {
|
|
29
|
+
--button-link-pal: var(--pal-link);
|
|
30
|
+
--button-link-pal-active: var(--pal-link-active);
|
|
31
|
+
--button-link-disabled-pal: var(--ui-pal-disabled);
|
|
32
|
+
}
|
|
33
|
+
</style>
|
|
34
|
+
|
|
35
|
+
<style lang="scss" scoped>
|
|
36
|
+
.fu-button-link {
|
|
37
|
+
@include typo(200);
|
|
38
|
+
@include spacing-padding(0, 0);
|
|
39
|
+
|
|
40
|
+
display: inline-block;
|
|
41
|
+
font-weight: normal;
|
|
42
|
+
box-sizing: border-box;
|
|
43
|
+
cursor: pointer;
|
|
44
|
+
font-family: var(--typo-font-text);
|
|
45
|
+
border: 0 none;
|
|
46
|
+
transition: var(--ui-transition);
|
|
47
|
+
background: transparent;
|
|
48
|
+
color: var(--button-link-pal);
|
|
49
|
+
line-height: 1;
|
|
50
|
+
will-change: box-shadow, transform;
|
|
51
|
+
outline: none;
|
|
52
|
+
user-select: none;
|
|
53
|
+
-webkit-tap-highlight-color: transparent;
|
|
54
|
+
text-decoration: underline;
|
|
55
|
+
|
|
56
|
+
& > * {
|
|
57
|
+
pointer-events: none;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
&:hover {
|
|
61
|
+
text-decoration: none;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
&:focus {
|
|
65
|
+
color: var(--button-link-pal-active);
|
|
66
|
+
text-decoration: underline dashed;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
&:active {
|
|
70
|
+
color: var(--button-link-pal-active);
|
|
71
|
+
text-decoration: underline dashed;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
&:disabled {
|
|
75
|
+
cursor: not-allowed;
|
|
76
|
+
color: var(--pal-link-active);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
</style>
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="fu-code-view">
|
|
3
|
+
<fu-button-link
|
|
4
|
+
v-if="collapse"
|
|
5
|
+
class="fu-code-view_toggle"
|
|
6
|
+
@click="isShown = !isShown"
|
|
7
|
+
>
|
|
8
|
+
{{ isShown ? 'Hide' : 'Show' }} {{ label }}
|
|
9
|
+
</fu-button-link>
|
|
10
|
+
<p class="fu-code-view_title" v-else-if="label">{{ label }}</p>
|
|
11
|
+
<pre v-if="collapse ? isShown : true" class="fu-code-view_pre"><slot /></pre>
|
|
12
|
+
</div>
|
|
13
|
+
</template>
|
|
14
|
+
|
|
15
|
+
<script>
|
|
16
|
+
import { ref, toRaw } from 'vue'
|
|
17
|
+
|
|
18
|
+
import FuButtonLink from './FuButtonLink.vue'
|
|
19
|
+
|
|
20
|
+
export default {
|
|
21
|
+
name: 'fu-code-view',
|
|
22
|
+
components: { FuButtonLink },
|
|
23
|
+
props: {
|
|
24
|
+
label: { type: String, default: '' },
|
|
25
|
+
collapse: { type: Boolean, default: null },
|
|
26
|
+
},
|
|
27
|
+
setup (props) {
|
|
28
|
+
const collapse = ref(toRaw(props.collapse))
|
|
29
|
+
const isShown = ref(false)
|
|
30
|
+
const label = props.label
|
|
31
|
+
return { isShown, label, collapse }
|
|
32
|
+
},
|
|
33
|
+
}
|
|
34
|
+
</script>
|
|
35
|
+
|
|
36
|
+
<style scoped lang="scss">
|
|
37
|
+
.fu-code-view {
|
|
38
|
+
@include spacing-margin(200, 0);
|
|
39
|
+
|
|
40
|
+
&_title {
|
|
41
|
+
@include typo(100);
|
|
42
|
+
|
|
43
|
+
font-weight: bold;
|
|
44
|
+
margin-bottom: spacing(200);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
&_pre {
|
|
48
|
+
@include scrollbar-awesome();
|
|
49
|
+
@include spacing-padding(300, 200);
|
|
50
|
+
|
|
51
|
+
overflow: auto;
|
|
52
|
+
max-width: 100%;
|
|
53
|
+
background: pal(block-light);
|
|
54
|
+
border: 1px solid pal(block);
|
|
55
|
+
border-radius: var(--lt-border-radius-inner);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
</style>
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<fu-button
|
|
3
|
+
v-bind="$attrs"
|
|
4
|
+
hollow
|
|
5
|
+
class="fu-copy"
|
|
6
|
+
@click="handleCopyToClipboard"
|
|
7
|
+
:class="{'_hot': isCopied}"
|
|
8
|
+
>
|
|
9
|
+
<slot />
|
|
10
|
+
</fu-button>
|
|
11
|
+
</template>
|
|
12
|
+
|
|
13
|
+
<script>
|
|
14
|
+
import { onBeforeUnmount, ref } from 'vue'
|
|
15
|
+
import FuButton from '@/components/FuButton.vue'
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
export default {
|
|
19
|
+
name: 'fu-copy',
|
|
20
|
+
components: { FuButton },
|
|
21
|
+
props: {
|
|
22
|
+
value: { type: String, required: true },
|
|
23
|
+
},
|
|
24
|
+
setup (props) {
|
|
25
|
+
const isCopied = ref(false)
|
|
26
|
+
let timeout
|
|
27
|
+
|
|
28
|
+
onBeforeUnmount(() => {
|
|
29
|
+
if (timeout) clearTimeout(timeout)
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
const handleCopyToClipboard = (event) => {
|
|
33
|
+
if (navigator.clipboard) {
|
|
34
|
+
navigator.clipboard.writeText(props.value)
|
|
35
|
+
} else {
|
|
36
|
+
execCopy()
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
isCopied.value = false
|
|
40
|
+
requestAnimationFrame(() => (isCopied.value = true))
|
|
41
|
+
|
|
42
|
+
if (timeout) clearTimeout(timeout)
|
|
43
|
+
timeout = setTimeout(() => isCopied.value = false, 1000)
|
|
44
|
+
|
|
45
|
+
event.target.blur()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// fallback
|
|
49
|
+
const execCopy = () => {
|
|
50
|
+
const textArea = document.createElement('textarea')
|
|
51
|
+
textArea.value = props.value
|
|
52
|
+
textArea.setAttribute('readonly', '')
|
|
53
|
+
textArea.style.position = 'absolute'
|
|
54
|
+
textArea.style.left = '-9999px'
|
|
55
|
+
document.body.appendChild(textArea)
|
|
56
|
+
textArea.select()
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
document.execCommand('copy')
|
|
60
|
+
} catch (err) {
|
|
61
|
+
console.error(err)
|
|
62
|
+
} finally {
|
|
63
|
+
document.body.removeChild(textArea)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
handleCopyToClipboard,
|
|
69
|
+
isCopied,
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
}
|
|
75
|
+
</script>
|
|
76
|
+
|
|
77
|
+
<style lang="scss" scoped>
|
|
78
|
+
.fu-copy {
|
|
79
|
+
@include spacing-padding(0, 200);
|
|
80
|
+
|
|
81
|
+
&._hollow {
|
|
82
|
+
font-weight: normal;
|
|
83
|
+
|
|
84
|
+
&:active {
|
|
85
|
+
box-shadow: none;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
&:hover {
|
|
89
|
+
box-shadow: none;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
&:focus {
|
|
93
|
+
box-shadow: none;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
&._hot {
|
|
97
|
+
transition: none;
|
|
98
|
+
border-color: var(--pal-positive);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
}
|
|
103
|
+
</style>
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="fu-progress-radial">
|
|
3
|
+
<div class="fu-progress-radial__svg-wrap">
|
|
4
|
+
<svg
|
|
5
|
+
class="fu-progress-radial__svg"
|
|
6
|
+
:viewBox="`0 0 ${r2} ${r2}`"
|
|
7
|
+
:width="r2"
|
|
8
|
+
:height="r2"
|
|
9
|
+
>
|
|
10
|
+
<circle
|
|
11
|
+
class="fu-progress-radial__svg-bg"
|
|
12
|
+
:cx="r"
|
|
13
|
+
:cy="r"
|
|
14
|
+
:r="r"
|
|
15
|
+
/>
|
|
16
|
+
<circle
|
|
17
|
+
class="fu-progress-radial__svg-value"
|
|
18
|
+
:cx="r"
|
|
19
|
+
:cy="r"
|
|
20
|
+
:r="r"
|
|
21
|
+
:style="valueStyle"
|
|
22
|
+
/>
|
|
23
|
+
</svg>
|
|
24
|
+
</div>
|
|
25
|
+
<span
|
|
26
|
+
class="fu-progress-radial__slot"
|
|
27
|
+
v-if="hasSlot('default')">
|
|
28
|
+
<slot />
|
|
29
|
+
</span>
|
|
30
|
+
</div>
|
|
31
|
+
</template>
|
|
32
|
+
|
|
33
|
+
<script>
|
|
34
|
+
export default {
|
|
35
|
+
name: 'fu-progress-radial',
|
|
36
|
+
props: {
|
|
37
|
+
/**
|
|
38
|
+
* Value must be between 0 and 1 (otherwise will be normalized automatically)
|
|
39
|
+
*/
|
|
40
|
+
value: { type: Number, default: 0 },
|
|
41
|
+
},
|
|
42
|
+
data () {
|
|
43
|
+
return {
|
|
44
|
+
r: 50, r2: 100,
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
computed: {
|
|
48
|
+
normalizeValue () {
|
|
49
|
+
if (this.value > 1) return 1
|
|
50
|
+
if (this.value < 0) return 0
|
|
51
|
+
return this.value
|
|
52
|
+
},
|
|
53
|
+
dasharray () {
|
|
54
|
+
return Math.PI * this.r2
|
|
55
|
+
},
|
|
56
|
+
valueStyle () {
|
|
57
|
+
return {
|
|
58
|
+
'stroke-dasharray': this.dasharray,
|
|
59
|
+
'stroke-dashoffset': this.dasharray * (1 - this.normalizeValue),
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
methods: {
|
|
64
|
+
hasSlot (slot) {
|
|
65
|
+
return !!this.$slots[slot]
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
}
|
|
69
|
+
</script>
|
|
70
|
+
|
|
71
|
+
<style lang="scss" scoped>
|
|
72
|
+
|
|
73
|
+
.fu-progress-radial {
|
|
74
|
+
display: flex;
|
|
75
|
+
position: relative;
|
|
76
|
+
white-space: nowrap;
|
|
77
|
+
align-items: center;
|
|
78
|
+
justify-content: center;
|
|
79
|
+
height: calc(var(--progress-radial-size, 64px));
|
|
80
|
+
width: calc(var(--progress-radial-size, 64px));
|
|
81
|
+
|
|
82
|
+
&__svg-wrap {
|
|
83
|
+
position: absolute;
|
|
84
|
+
display: block;
|
|
85
|
+
left: 0;
|
|
86
|
+
top: 0;
|
|
87
|
+
right: 0;
|
|
88
|
+
bottom: 0;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
&__svg {
|
|
92
|
+
overflow: visible;
|
|
93
|
+
vertical-align: middle;
|
|
94
|
+
transform: rotate(90deg);
|
|
95
|
+
height: var(--progress-radial-size, 64px);
|
|
96
|
+
width: var(--progress-radial-size, 64px);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
&__svg-bg {
|
|
100
|
+
stroke: var(--progress-radial-bg-stroke, #{pal(primary,0.2)});
|
|
101
|
+
fill: var(--progress-radial-bg-fill, transparent);
|
|
102
|
+
stroke-width: var(--progress-radial-stroke-width, 10);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
&__svg-value {
|
|
106
|
+
fill: none;
|
|
107
|
+
stroke-dasharray: 0;
|
|
108
|
+
stroke-dashoffset: 0;
|
|
109
|
+
transition-duration: var(--progress-radial-t-duration, 500ms);
|
|
110
|
+
transition-property: var(--progress-radial-t-property, all);
|
|
111
|
+
transition-timing-function: var(--progress-radial-t-function, linear);
|
|
112
|
+
stroke: var(--progress-radial-color, #{pal(primary)});
|
|
113
|
+
stroke-linecap: var(--progress-radial-stroke-linecap, round);
|
|
114
|
+
stroke-width: var(--progress-radial-stroke-width, 10);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
</style>
|
|
@@ -1,55 +1,84 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<label class="fu-select">
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
v-bind="
|
|
6
|
-
:value="modelValue"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
1
|
+
<template>
|
|
2
|
+
<label class="fu-select" v-bind="{ class: $attrs.class }">
|
|
3
|
+
<select
|
|
4
|
+
class="fu-select_select"
|
|
5
|
+
v-bind="{ ...$attrs, class: undefined }"
|
|
6
|
+
:value="modelValue"
|
|
7
|
+
@input="$emit('update:modelValue', $event.target.value)"
|
|
8
|
+
>
|
|
9
|
+
<slot />
|
|
10
|
+
</select>
|
|
11
|
+
</label>
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<script>
|
|
15
|
+
export default {
|
|
16
|
+
name: 'fu-select',
|
|
17
|
+
props: {
|
|
18
|
+
modelValue: {
|
|
19
|
+
type: [ String, Number ],
|
|
20
|
+
default: '',
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
emits: [ 'update:modelValue' ],
|
|
24
|
+
}
|
|
25
|
+
</script>
|
|
26
|
+
|
|
27
|
+
<style lang="scss" scoped>
|
|
28
|
+
.fu-select {
|
|
29
|
+
@include typo(200);
|
|
30
|
+
|
|
31
|
+
padding: 0;
|
|
32
|
+
display: flex;
|
|
33
|
+
box-sizing: border-box;
|
|
34
|
+
align-items: center;
|
|
35
|
+
justify-content: stretch;
|
|
36
|
+
border-style: var(--ui-lt-border-style);
|
|
37
|
+
border-width: var(--ui-lt-border-width);
|
|
38
|
+
border-color: var(--ui-pal-lateral);
|
|
39
|
+
border-radius: var(--ui-lt-border-radius);
|
|
40
|
+
transition-duration: 240ms;
|
|
41
|
+
transition-timing-function: ease-in-out;
|
|
42
|
+
transition-property: border-color, box-shadow;
|
|
43
|
+
height: var(--ui-lt-h);
|
|
44
|
+
|
|
45
|
+
&_select {
|
|
46
|
+
@include typo(200);
|
|
47
|
+
@include spacing-padding(100, 200);
|
|
48
|
+
|
|
49
|
+
color: var(--ui-pal-text);
|
|
50
|
+
caret-color: var(--ui-pal);
|
|
51
|
+
min-height: min(100%);
|
|
52
|
+
border: none;
|
|
53
|
+
outline: none;
|
|
54
|
+
background: transparent;
|
|
55
|
+
box-sizing: border-box;
|
|
56
|
+
flex: 1;
|
|
57
|
+
display: block;
|
|
58
|
+
min-width: 0;
|
|
59
|
+
margin: 0;
|
|
60
|
+
|
|
61
|
+
&[disabled] {
|
|
62
|
+
cursor: not-allowed;
|
|
63
|
+
color: var(--ui-pal-disabled-border);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
&:hover {
|
|
68
|
+
outline: none;
|
|
69
|
+
box-shadow: 0 5px 12px -4px rgb(var(--rgb-dark), 0.2);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
&:focus-within {
|
|
73
|
+
outline: none;
|
|
74
|
+
box-shadow: 0 0 0 0 var(--ui-pal);
|
|
75
|
+
border-color: var(--ui-pal);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
&._disabled {
|
|
79
|
+
border: var(--ui-lt-border-width) var(--ui-lt-disabled-border-style) var(--ui-pal-disabled-border);
|
|
80
|
+
background: transparent;
|
|
81
|
+
box-shadow: none;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
</style>
|