This commit is contained in:
2021-12-07 15:59:29 +01:00
parent 58ba312e90
commit 6faa389feb
67 changed files with 950 additions and 893 deletions
@@ -0,0 +1,11 @@
import uiRte from './ui-rte/ui-rte.vue';
import uiCheckList from './ui-check-list.vue';
import uiSearch from './ui-search.vue';
import uiToggle from './ui-toggle.vue';
export {
uiRte,
uiCheckList,
uiSearch,
uiToggle
};
@@ -0,0 +1,13 @@
import { App } from 'vue';
import * as components from './index';
export default function (app: App)
{
for (var key in components)
{
let component = components[key];
app.component(key, component.default || component);
}
};
@@ -0,0 +1,133 @@
<template>
<div class="ui-input-list" :class="{'is-disabled': disabled }">
<div v-for="item in items" class="ui-input-list-item">
<input v-model="item.value" type="text" class="ui-input" :maxlength="maxLength" :readonly="disabled" @input="onChange" size="5" />
<ui-icon-button type="light" icon="fth-x" @click="removeItem(item)" v-if="!disabled" />
</div>
<ui-button v-if="!disabled && !plusButton" type="light" :label="addLabel" @click="addItem" />
<ui-select-button v-if="!disabled && plusButton" icon="fth-plus" :label="items.length > 0 ? null : addLabel" @click="addItem" />
</div>
</template>
<script>
export default {
name: 'uiInputList',
props: {
addLabel: {
type: String,
default: '@ui.add'
},
modelValue: {
type: Array,
default: () => []
},
disabled: {
type: Boolean,
default: false
},
maxItems: {
type: Number,
default: 100
},
maxLength: {
type: Number,
default: 200
},
plusButton: {
type: Boolean,
default: false
},
},
data: () => ({
items: []
}),
watch: {
modelValue(value)
{
this.reload();
}
},
mounted()
{
this.reload();
},
methods: {
reload()
{
this.items = this.modelValue.map(item => ({ value: item }));
},
onChange()
{
this.$emit('update:modelValue', this.items.map(item => item.value));
},
addItem()
{
this.items.push({
value: null
});
this.onChange();
this.$nextTick(() =>
{
this.$el.querySelector('.ui-input-list-item:last-of-type input').focus();
});
},
removeItem(item)
{
const index = this.items.indexOf(item);
this.items.splice(index, 1);
this.onChange();
}
}
}
</script>
<style lang="scss">
.ui-input-list
{
}
.ui-input-list-item
{
display: grid;
grid-template-columns: 1fr auto auto;
background: var(--color-input);
border-radius: var(--radius);
margin-bottom: 6px;
.ui-input-list.is-disabled &
{
background: transparent;
}
.ui-input
{
border-radius: var(--radius) 0 0 var(--radius);
}
.ui-icon-button
{
border-radius: 0 var(--radius) var(--radius) 0;
height: 48px;
width: 48px;
border-left: none;
background: transparent !important;
box-shadow: none;
}
.ui-icon-button + .ui-icon-button
{
margin-left: 0;
}
}
</style>
@@ -0,0 +1,174 @@
import Document from '@tiptap/extension-document'
import Paragraph from '@tiptap/extension-paragraph'
import Text from '@tiptap/extension-text'
import Bold from '@tiptap/extension-bold';
import Code from '@tiptap/extension-code';
import Italic from '@tiptap/extension-italic';
//import Link from '@tiptap/extension-link';
import Strike from '@tiptap/extension-strike';
//import Underline from '@tiptap/ex';
import History from '@tiptap/extension-history';
//import Placeholder from '@tiptap/extension-placeholder';
import HorizontalRule from '@tiptap/extension-horizontal-rule';
import ListItem from '@tiptap/extension-list-item';
import BulletList from '@tiptap/extension-bullet-list';
import OrderedList from '@tiptap/extension-ordered-list';
import Heading from '@tiptap/extension-heading';
import HardBreak from '@tiptap/extension-hard-break';
export default function ()
{
return {
removeExtension(name)
{
var ext = this.extensions.find(x => x.name === name);
ext && this.extensions.splice(this.extensions.indexOf(ext), 1);
},
removeCommand(alias)
{
var cmd = this.commands.find(x => x.alias === alias);
cmd && this.commands.splice(this.commands.indexOf(cmd), 1);
},
extensions: [
Document,
Paragraph,
Text,
History,
HardBreak,
//new Link({
// target: '_blank'
//}), // TODO
Bold,
Code,
Italic,
Strike,
//Underline,
ListItem,
BulletList,
OrderedList,
HorizontalRule,
Heading.configure({ // TODO
levels: [2, 3, 4],
})
],
commands: [
//{
// alias: 'undo',
// title: '@rte.undo',
// symbol: 'fth-chevron-left',
// disabled: cmd => cmd.undoDepth() > 1,
// onClick: (ev, cmd) => cmd.undo(ev),
//},
//{
// alias: 'redo',
// title: '@rte.redo',
// symbol: 'fth-chevron-right',
// disabled: cmd => cmd.redoDepth() > 1,
// onClick: (ev, cmd) => cmd.redo(ev)
//},
{
alias: 'bold',
title: '@rte.bold',
symbol: 'fth-bold',
symbolSize: 14,
isActive: editor => editor.isActive('bold'),
onClick: editor => editor.chain().focus().toggleBold().run(),
bubble: true
},
{
alias: 'italic',
title: '@rte.italic',
symbol: 'fth-italic',
symbolSize: 14,
isActive: editor => editor.isActive('italic'),
onClick: editor => editor.chain().focus().toggleItalic().run(),
bubble: true
},
{
alias: 'underline',
title: '@rte.underline',
symbol: 'fth-underline',
symbolSize: 14,
isActive: editor => editor.isActive('underline'),
onClick: editor => editor.chain().focus().toggleUnderline().run(),
bubble: true
},
//{
// alias: 'strikethrough',
// title: '@rte.strike',
// symbol: 'fth-zap-off',
// symbolSize: 14,
// isActive: active => active.strike(),
// onClick: (ev, cmd) => cmd.strike(ev)
//},
{
alias: 'code',
title: '@rte.code',
symbol: 'fth-code',
symbolSize: 14,
isActive: editor => editor.isActive('code'),
onClick: editor => editor.chain().focus().toggleCode().run(),
bubble: true
},
{
alias: 'line',
title: '@rte.line',
symbol: 'fth-minus',
symbolSize: 15,
onClick: editor => editor.chain().focus().setHorizontalRule().run()
},
{
alias: 'list',
title: '@rte.list',
symbol: 'fth-list',
symbolSize: 14,
children: [
{
alias: 'ulist',
title: '@rte.ulist',
isActive: editor => editor.isActive('bullet_list'),
onClick: editor => editor.chain().focus().toggleBulletList().run()
},
{
alias: 'olist',
title: '@rte.olist',
isActive: editor => editor.isActive('ordered_list'),
onClick: editor => editor.chain().focus().toggleOrderedList().run()
}
]
},
{
alias: 'heading',
title: '@rte.heading',
symbol: 'fth-type',
symbolSize: 14,
children: [
{
alias: 'h2',
title: '@rte.heading2',
isActive: editor => editor.isActive('heading', { level: 2}),
onClick: editor => editor.chain().focus().toggleHeading({ level: 2 }).run()
},
{
alias: 'h3',
title: '@rte.heading3',
isActive: editor => editor.isActive('heading', { level: 3 }),
onClick: editor => editor.chain().focus().toggleHeading({ level: 3 }).run()
},
{
alias: 'h4',
title: '@rte.heading4',
isActive: editor => editor.isActive('heading', { level: 4 }),
onClick: editor => editor.chain().focus().toggleHeading({ level: 4 }).run()
}
]
}
]
};
};
@@ -0,0 +1,73 @@
//import { Node, Extension, Plugin } from '@tiptap/vue-3';
//import { chainCommands, exitCode } from 'prosemirror-commands';
//export class HardBreak extends Node
//{
// get name()
// {
// return 'br'
// }
// get schema()
// {
// return {
// inline: true,
// group: 'inline',
// selectable: false,
// parseDOM: [
// { tag: 'br' },
// ],
// toDOM: () => ['br'],
// }
// }
// keys({ type })
// {
// const command = chainCommands(exitCode, (state, dispatch) =>
// {
// dispatch(state.tr.replaceSelectionWith(type.create()).scrollIntoView())
// return true
// })
// return {
// 'Enter': command
// }
// }
//}
//export class MaxSize extends Extension
//{
// get name()
// {
// return 'maxSize'
// }
// get defaultOptions()
// {
// return {
// maxSize: null
// }
// }
// get plugins()
// {
// return [
// new Plugin({
// appendTransaction: (transactions, oldState, newState) =>
// {
// const max = this.options.maxSize;
// const oldLength = oldState.doc.content.size;
// const newLength = newState.doc.content.size;
// if (max && newLength > max && newLength > oldLength)
// {
// let newTr = newState.tr;
// newTr.insertText('', max + 1, newLength);
// return newTr;
// }
// }
// })
// ]
// }
//}
@@ -0,0 +1,113 @@
import { Plugin, PluginKey } from 'prosemirror-state'
class Menu
{
constructor({ options })
{
this.options = options
this.preventHide = false
// the mousedown event is fired before blur so we can prevent it
this.mousedownHandler = this.handleClick.bind(this)
this.options.element.addEventListener('mousedown', this.mousedownHandler, { capture: true })
this.blurHandler = () =>
{
if (this.preventHide)
{
this.preventHide = false
return
}
this.options.editor.emit('menubar:focusUpdate', false)
}
this.options.editor.on('blur', this.blurHandler)
}
handleClick()
{
this.preventHide = true
}
destroy()
{
this.options.element.removeEventListener('mousedown', this.mousedownHandler)
this.options.editor.off('blur', this.blurHandler)
}
}
const MenuBar = function (options)
{
return new Plugin({
key: new PluginKey('menu_bar'),
view(editorView)
{
return new Menu({ editorView, options })
},
})
};
export default {
props: {
editor: {
default: null,
type: Object,
},
},
data() {
return {
focused: false,
}
},
watch: {
editor: {
immediate: true,
handler(editor) {
if (editor) {
this.$nextTick(() =>
{
var menubar = MenuBar({
editor,
element: this.$el,
});
editor.registerPlugin(menubar);
this.focused = editor.focused
editor.on('focus', () => {
this.focused = true
})
editor.on('menubar:focusUpdate', focused => {
this.focused = focused
})
})
}
},
},
},
render() {
if (!this.editor) {
return null
}
return this.$slots.default({
focused: this.focused,
focus: this.editor.focus,
commands: this.editor.commands,
isActive: this.editor.isActive,
getMarkAttrs: this.editor.getMarkAttrs.bind(this.editor),
getNodeAttrs: this.editor.getNodeAttrs.bind(this.editor),
})
},
}
@@ -0,0 +1,435 @@
<template>
<div class="ui-rte" :id="id" :disabled="disabled">
<!--<bubble-menu :editor="editor" :tippy-options="{ duration: 100 }" v-if="editor && hasBubble">
<div class="ui-rte-overlay-controls theme-dark is-active">
<div class="ui-rte-overlay-control-outer" v-for="cmd in editor.cmds" v-if="cmd && cmd.bubble && !cmd.isParent" :key="cmd.id">
<button type="button" :data-alias="cmd.alias" v-localize:title="cmd.title" class="ui-rte-overlay-control" :class="{ 'is-active': cmd.isActive(editor) }" @click="cmd.onClick(editor)">
<ui-icon :symbol="cmd.symbol" :size="cmd.symbolSize" />
</button>
</div>
</div>
</bubble-menu>-->
<div class="ui-rte-controls" v-if="editor">
<div class="ui-rte-control-outer" v-for="cmd in cmds" :key="cmd.id">
<button type="button" v-if="!cmd.isParent" :data-alias="cmd.alias" v-localize:title="cmd.title" class="ui-rte-control" :class="{ 'is-active': cmd.isActive(editor) }" @click="cmd.onClick(editor)">
<ui-icon :symbol="cmd.symbol" :size="cmd.symbolSize" />
</button>
<!--<ui-dropdown v-if="cmd.isParent" align="right">
<template v-slot:button>
<button :data-alias="cmd.alias" type="button" v-localize:title="cmd.title" class="ui-rte-control" :class="{ 'is-active': cmd.isActive(editor) }">
<ui-icon :symbol="cmd.symbol" :size="cmd.symbolSize" />
</button>
</template>
<ui-dropdown-button v-for="child in cmd.children" :key="child.id" :label="child.title" @click="child.onClick(editor)" />
</ui-dropdown>-->
</div>
</div>
<editor-content class="ui-rte-input" :editor="editor" />
</div>
</template>
<script lang="ts">
import { generateId } from '../../../utils/numbers';
import { debounce } from '../../../utils/timing';
import { Editor, EditorContent, BubbleMenu } from '@tiptap/vue-3';
// import { Placeholder } from '@tiptap/vue-3';
import EditorMenuBar from './rte.menubar';
//import { MaxSize } from './rte.extensions';
import createConfig from './rte.config';
export default {
name: 'uiRte',
components: { EditorContent, BubbleMenu, EditorMenuBar },
props: {
modelValue: {
type: String,
default: ''
},
disabled: {
type: Boolean,
default: false
},
maxLength: {
type: Number,
default: null
},
placeholder: {
type: String,
default: null
},
setup: {
type: Function,
default: () => { }
}
},
data: () => ({
id: 'rte-' + generateId(),
blocked: false,
onDebouncedChange: null,
editor: null,
extensions: [],
cmds: []
}),
watch: {
modelValue()
{
if (!this.blocked)
{
this.init();
}
},
disabled(value)
{
this.editor.setOptions({
editable: !value
})
},
},
computed: {
hasBubble()
{
return this.cmds.find(x => x.bubble) != null;
}
},
created()
{
this.onDebouncedChange = debounce(this.onChange, 350);
},
mounted()
{
var config = createConfig();
if (typeof this.setup === 'function')
{
this.setup(config);
}
this.extensions = config.extensions;
this.cmds = config.commands.map(cmd =>
{
let params = this.mapCommand(cmd);
if (cmd.children && cmd.children.length)
{
params.isParent = true;
params.children = cmd.children.map(child => this.mapCommand(child));
}
return params;
});
//if (this.placeholder)
//{
// this.extensions.push(new Placeholder({
// emptyEditorClass: 'is-editor-empty',
// emptyNodeClass: 'is-empty',
// emptyNodeText: this.placeholder,
// showOnlyWhenEditable: true,
// showOnlyCurrent: true
// }));
//}
//if (this.maxLength > 0)
//{
// this.extensions.push(new MaxSize({ maxSize: this.maxLength }));
//}
this.editor = new Editor({
editable: !this.disabled,
extensions: this.extensions,
onUpdate: ({ editor }) =>
{
this.onDebouncedChange(editor.getHTML());
}
});
this.editor.cmds = this.cmds;
this.init();
},
methods: {
init()
{
this.editor.commands.setContent(this.modelValue, false);
},
onChange(content)
{
this.blocked = true;
this.$emit('update:modelValue', content);
this.$nextTick(() => this.blocked = false);
},
mapCommand(cmd)
{
return {
id: generateId(),
alias: cmd.alias,
title: cmd.title,
symbol: cmd.symbol,
symbolSize: cmd.symbolSize || 17,
isActive: typeof cmd.isActive === 'function' ? cmd.isActive : () => false,
disabled: typeof cmd.disabled === 'function' ? cmd.disabled : () => false,
onClick: typeof cmd.onClick === 'function' ? cmd.onClick : () => { },
bubble: cmd.bubble || false
};
}
},
beforeDestroy()
{
this.editor.destroy();
}
}
</script>
<style lang="scss">
.ui-rte
{
background: var(--color-input);
border-radius: var(--radius);
border: var(--color-input-border);
}
.ui-rte:focus-within
{
background-color: var(--color-input-focus-bg);
border: var(--color-input-focus-border);
box-shadow: var(--color-input-focus-shadow);
outline: none;
}
.ui-rte-input
{
height: auto;
min-height: 48px;
padding-top: 9px;
max-height: 420px;
overflow-y: auto;
border: none !important;
.ProseMirror:focus
{
outline: none;
}
p
{
margin: 0;
}
p + p
{
margin-top: 1em;
}
p.is-editor-empty:first-child:before
{
content: attr(data-empty-text);
float: left;
color: var(--color-input-placeholder);
opacity: .7;
pointer-events: none;
height: 0;
}
a
{
color: var(--color-primary);
text-decoration: underline;
cursor: pointer;
}
}
.ui-rte-overlay-controls
{
position: absolute;
display: flex;
z-index: 20;
background: var(--color-bg);
border-radius: var(--radius);
padding: 5px;
margin-bottom: 8px;
transform: translateX(-50%);
visibility: hidden;
opacity: 0;
transition: opacity 0.2s, visibility 0.2s;
pointer-events: none;
&:after
{
content: '';
position: absolute;
left: 50%;
top: 100%;
width: 0;
height: 0;
border: 8px solid transparent;
margin-left: -7px;
border-top-color: var(--color-bg);
}
}
.ui-rte-overlay-controls.is-active
{
opacity: 1;
visibility: visible;
pointer-events: auto;
}
.ui-rte-overlay-control
{
display: inline-flex;
align-items: center;
justify-content: center;
background: transparent;
border: 0;
color: var(--color-text);
height: 32px;
width: 32px;
border-radius: var(--radius);
cursor: pointer;
}
.ui-rte-overlay-control + .ui-rte-overlay-control
{
margin-left: 4px;
}
.ui-rte-overlay-control:hover
{
background-color: var(--color-bg-shade-1);
}
.ui-rte-overlay-control.is-active
{
background-color: var(--color-bg-shade-1);
color: var(--color-text-dim);
}
.ui-rte-controls
{
background: none;
padding: 5px 5px 0;
display: flex;
align-items: center;
justify-content: flex-start;
border-bottom: var(--color-input-border);
}
.ui-rte-controls-label
{
color: var(--color-text-dim);
margin: 0 14px 0 8px;
font-size: 10px;
text-transform: uppercase;
pointer-events: none;
user-select: none;
}
.ui-rte-control
{
background-color: transparent;
cursor: pointer;
height: 30px;
width: 30px;
text-align: center;
border-radius: 5px;
font-size: 14px;
vertical-align: bottom;
}
.ui-rte-control[disabled]
{
opacity: .5;
}
.ui-rte-control-outer + .ui-rte-control-outer
{
margin-left: 5px;
}
.ui-rte-control:hover, .ui-rte-control.is-active
{
background: var(--color-box-nested);
color: var(--color-text);
}
.ui-rte-input
{
background: none !important;
border-radius: 0;
}
.ui-rte-input .ProseMirror
{
> *
{
margin: 1rem 0;
}
> :first-child
{
margin-top: 0;
}
> :last-child
{
margin-bottom: 0;
}
h1, h2, h3, h4, h5, h6
{
margin-bottom: .5rem;
font-weight: bold;
}
h1
{
font-size: 1.4em;
}
h2
{
font-size: 1.2em;
}
h3
{
font-size: 1.1em;
}
h4, h5, h6
{
font-size: 1em;
}
hr
{
display: block;
border-bottom-style: dashed;
border-bottom-color: var(--color-line-dashed);
}
li p
{
display: block;
line-height: 1.5;
}
}
</style>
@@ -0,0 +1,98 @@
<template>
<div class="ui-searchinput">
<input ref="input" type="search" :value="modelValue" @input="onChange" @keyup.enter="onSubmit" class="ui-input" v-localize:placeholder="placeholder" />
<slot name="button" v-bind="{ onSubmit: onSubmit }">
<button type="button" class="ui-searchinput-button" v-localize:title="'@ui.search.button'" @click="onSubmit">
<ui-icon symbol="fth-search" />
</button>
</slot>
</div>
</template>
<script>
export default {
name: 'uiSearch',
props: {
modelValue: {
type: String,
default: ''
},
placeholder: {
type: String,
default: '@ui.search.placeholder'
}
},
computed: {
},
methods: {
onChange(ev)
{
this.$emit('change', ev.target.value);
this.$emit('input', ev.target.value);
this.$emit('update:modelValue', ev.target.value);
},
onSubmit(ev)
{
this.$emit('submit', this.$refs.input.value);
},
focus()
{
this.$refs.input.focus();
}
}
}
</script>
<style lang="scss">
.ui-searchinput
{
position: relative;
.ui-input
{
display: block;
min-width: 320px;
padding-right: 40px;
border: var(--color-input-border);
background: var(--color-input);
}
&.onbg .ui-input:not(:focus)
{
/*box-shadow: var(--shadow-short);
background: var(--color-button-light-onbg);*/
background: transparent;
border: 1px dashed var(--color-line-dashed-onbg);
}
.ui-searchinput-button
{
position: absolute;
right: 0;
top: 0;
height: 100%;
width: 45px;
text-align: center;
font-size: var(--font-size);
padding-top: 1px;
border: 1px solid transparent;
border-radius: var(--radius);
}
.ui-input:focus
{
background-color: var(--color-input-focus-bg);
border: var(--color-input-focus-border);
box-shadow: var(--color-input-focus-shadow);
outline: none;
}
}
</style>
@@ -0,0 +1,77 @@
<template>
<div class="ui-native-select" :disabled="disabled">
<select :value="modelValue" @input="onChange" :disabled="disabled">
<option v-if="emptyOption"></option>
<option v-for="option in options" :value="option.key" v-localize="option.value"></option>
</select>
</div>
</template>
<script>
export default {
name: 'uiSelect',
props: {
modelValue: [String, Number, Object],
items: [Array, Function],
entity: Object,
disabled: Boolean,
emptyOption: {
type: Boolean,
default: false
}
},
data: () => ({
options: []
}),
created()
{
this.rebuild();
},
watch: {
items: {
deep: true,
handler()
{
this.rebuild();
this.onChange({ target: { value: this.modelValue } });
}
},
entity: {
deep: true,
handler()
{
this.rebuild();
this.onChange({ target: { value: this.modelValue } });
}
}
},
methods: {
rebuild()
{
if (this.entity && typeof this.items === 'function')
{
this.options = this.items(this.entity);
}
else if (typeof this.items !== 'function' && this.items)
{
this.options = [...this.items];
}
else
{
this.options = [];
}
},
onChange(ev)
{
this.$emit('update:modelValue', ev.target.value ? ev.target.value : null);
}
}
}
</script>
@@ -0,0 +1,192 @@
<template>
<div class="ui-toggle" :class="{'is-disabled': disabled, 'is-negative': negative, 'is-active': modelValue, 'is-content-left': contentLeft }">
<input type="checkbox" :value="modelValue" @input="onChange" :disabled="disabled" />
<span class="ui-toggle-switch" :class="{ 'is-active': modelValue }"><i></i></span>
<i class="fth-minus-circle ui-toggle-off-warning" v-if="offContent && !modelValue && offWarning"></i>
<span class="ui-toggle-text" v-if="onContent && modelValue" v-localize="onContent"></span>
<span class="ui-toggle-text" v-if="offContent && !modelValue" v-localize="offContent"></span>
</div>
</template>
<script>
export default {
name: 'uiToggle',
props: {
modelValue: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
},
negative: {
type: Boolean,
default: false
},
onContent: {
type: String,
default: null
},
offContent: {
type: String,
default: null
},
offWarning: {
type: Boolean,
default: false
},
contentLeft: {
type: Boolean,
default: false
}
},
methods: {
onChange(ev)
{
this.$emit('update:modelValue', !this.modelValue);
}
}
}
</script>
<style lang="scss">
.ui-toggle
{
display: inline-flex;
align-items: center;
position: relative;
height: 22px;
input
{
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
margin: 0;
z-index: 2;
opacity: 0;
cursor: pointer;
}
&.is-disabled input
{
cursor: default;
}
&.is-content-left
{
flex-direction: row-reverse;
.ui-toggle-text
{
margin-left: 0;
margin-right: 12px;
}
}
}
.ui-toggle-text
{
margin-top: 1px;
margin-left: 12px;
.ui-toggle.is-active &
{
font-weight: 600;
}
}
.ui-toggle-switch
{
display: inline-block;
height: 22px;
width: 36px;
background: var(--color-toggle);
border-radius: 20px;
border: 1px solid transparent;
transition: all 0.2s ease;
z-index: 1;
pointer-events: none;
i
{
display: inline-block;
height: 16px;
width: 16px;
border-radius: 20px;
margin: 2px;
background: var(--color-toggle-fg);
transition: all 0.2s ease;
}
&.is-active
{
background: var(--color-toggled);
}
&.is-active i
{
background: var(--color-toggled-fg);
transform: translateX(14px);
}
input:focus + &
{
border: var(--color-input-focus-border);
box-shadow: var(--color-input-focus-shadow);
outline: none;
&.is-active
{
background-color: var(--color-toggled);
}
}
.ui-toggle.is-disabled &
{
opacity: 0.7;
pointer-events: none;
}
}
.ui-toggle.onbg .ui-toggle-switch:not(.is-active)
{
background: var(--color-bg);
}
.ui-toggle.is-negative .ui-toggle-switch.is-active
{
background: var(--color-negative);
border-color: transparent !important;
i
{
background: white;
}
}
.ui-toggle.is-accent .ui-toggle-switch.is-active
{
background: var(--color-accent);
border-color: transparent !important;
i
{
background: var(--color-accent-fg);
}
}
.ui-toggle-off-warning
{
margin: 0 10px 0 -5px;
}
</style>