-
-
Notifications
You must be signed in to change notification settings - Fork 174
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This commits fixes an issue where the `REVERT` label on revert toggle might render as `REVER` or in a similarly clipped manner due to its fixed width. The problem is visible when certain fonts fail to load or browser engines render content non-standardly. Changes: - Refactor UI component to have its own separate Vue component with unit tests. - Rework component design to utilize flexbox, enhancing its adaptability and simplifying the structure. - Remove obselete `webkit` directives. - Refactor SCSS for clearer structure and better SCSS best-practices. - Use `em` when possible instead of `px` for improved responsiveness.
- Loading branch information
1 parent
bc91237
commit 39e650c
Showing
4 changed files
with
509 additions
and
130 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
188 changes: 188 additions & 0 deletions
188
src/presentation/components/Scripts/View/ScriptsTree/SelectableTree/Node/ToggleSwitch.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,188 @@ | ||
<template> | ||
<div | ||
class="toggle-switch" | ||
@click="handleClickPropagation" | ||
> | ||
<input | ||
type="checkbox" | ||
class="toggle-input" | ||
v-model="isChecked" | ||
> | ||
<div class="toggle-animation"> | ||
<span class="label-off">{{ label }}</span> | ||
<span class="label-on">{{ label }}</span> | ||
</div> | ||
</div> | ||
</template> | ||
|
||
<script lang="ts"> | ||
import { defineComponent, computed } from 'vue'; | ||
export default defineComponent({ | ||
props: { | ||
value: Boolean, | ||
label: { | ||
type: String, | ||
required: true, | ||
}, | ||
stopClickPropagation: { | ||
type: Boolean, | ||
default: false, | ||
}, | ||
}, | ||
emits: { | ||
/* eslint-disable @typescript-eslint/no-unused-vars */ | ||
input: (isChecked: boolean) => true, | ||
/* eslint-enable @typescript-eslint/no-unused-vars */ | ||
}, | ||
setup(props, { emit }) { | ||
const isChecked = computed({ | ||
get() { | ||
return props.value; | ||
}, | ||
set(value: boolean) { | ||
if (value === props.value) { | ||
return; | ||
} | ||
emit('input', value); | ||
}, | ||
}); | ||
function handleClickPropagation(event: Event): void { | ||
if (props.stopClickPropagation) { | ||
event.stopPropagation(); | ||
} | ||
} | ||
return { | ||
isChecked, | ||
handleClickPropagation, | ||
}; | ||
}, | ||
}); | ||
</script> | ||
|
||
<style scoped lang="scss"> | ||
@use 'sass:math'; | ||
@use "@/presentation/assets/styles/main" as *; | ||
$color-toggle-unchecked : $color-primary-darker; | ||
$color-toggle-checked : $color-on-secondary; | ||
$color-text-unchecked : $color-on-primary; | ||
$color-text-checked : $color-on-secondary; | ||
$color-bg-unchecked : $color-primary; | ||
$color-bg-checked : $color-secondary; | ||
$size-height : 30px; | ||
$size-circle : math.div($size-height * 2, 3); | ||
$padding-horizontal : 0.40em; | ||
$gap : 0.25em; | ||
@mixin locateNearCircle($direction: 'left') { | ||
$circle-width: calc(#{$size-circle} + #{$padding-horizontal}); | ||
$circle-space: calc(#{$circle-width} + #{$gap}); | ||
@if $direction == 'left' { | ||
margin-left: $circle-space; | ||
} @else { | ||
margin-right: $circle-space; | ||
} | ||
} | ||
@mixin setVisibility($isVisible: true) { | ||
@if $isVisible { | ||
display: block; | ||
opacity: 1; | ||
} @else { | ||
display: none; | ||
opacity: 0; | ||
} | ||
} | ||
.toggle-switch { | ||
display: flex; | ||
overflow: hidden; | ||
position: relative; | ||
width: auto; | ||
height: $size-height; | ||
border-radius: $size-height; | ||
line-height: $size-height; | ||
font-size: math.div($size-height, 2); | ||
input.toggle-input { | ||
position: absolute; | ||
left: 0; | ||
top: 0; | ||
width: 100%; | ||
height: 100%; | ||
opacity: 0; | ||
z-index: 2; | ||
@include clickable; | ||
} | ||
.toggle-animation { | ||
display: flex; | ||
align-items: center; | ||
gap: $gap; | ||
width: 100%; | ||
height: 100%; | ||
background-color: $color-bg-unchecked; | ||
transition: background-color 0.25s ease-out; | ||
&:before { | ||
content: ""; | ||
display: block; | ||
position: absolute; | ||
left: $padding-horizontal; | ||
$initial-top: 50%; | ||
$centered-top-offset: math.div($size-circle, 2); | ||
$centered-top: calc(#{$initial-top} - #{$centered-top-offset}); | ||
top: $centered-top; | ||
width: $size-circle; | ||
height: $size-circle; | ||
border-radius: 50%; | ||
background-color: $color-toggle-unchecked; | ||
transition: left 0.3s ease-out; | ||
z-index: 10; | ||
} | ||
} | ||
input.toggle-input:checked + .toggle-animation { | ||
background-color: $color-bg-checked; | ||
flex-direction: row-reverse; | ||
&:before { | ||
$left-offset: calc(100% - #{$size-circle}); | ||
$padded-left-offset: calc(#{$left-offset} - #{$padding-horizontal}); | ||
left: $padded-left-offset; | ||
background-color: $color-toggle-checked; | ||
} | ||
.label-off { | ||
@include setVisibility(false); | ||
} | ||
.label-on { | ||
@include setVisibility(true); | ||
} | ||
} | ||
.label-off, .label-on { | ||
text-transform: uppercase; | ||
font-weight: 700; | ||
transition: all 0.3s ease-out; | ||
} | ||
.label-off { | ||
@include setVisibility(true); | ||
@include locateNearCircle('left'); | ||
padding-right: $padding-horizontal; | ||
} | ||
.label-on { | ||
@include setVisibility(false); | ||
color: $color-text-checked; | ||
@include locateNearCircle('right'); | ||
padding-left: $padding-horizontal; | ||
} | ||
} | ||
</style> |
Oops, something went wrong.