jedmund-svelte/src/lib/components/admin/BrandingToggle.svelte
Justin Edmund 6ca6727eda refactor: modernize ProjectBrandingForm with reusable components
Extract BrandingToggle and BrandingSection components. Consolidate $effect blocks, add $derived state, and apply BEM naming. Reduces component size by 47% while improving maintainability.
2025-11-03 23:03:20 -08:00

79 lines
1.4 KiB
Svelte

<script lang="ts">
interface Props {
checked: boolean
disabled?: boolean
onchange?: (checked: boolean) => void
}
let { checked = $bindable(), disabled = false, onchange }: Props = $props()
function handleChange(e: Event) {
const target = e.target as HTMLInputElement
checked = target.checked
if (onchange) {
onchange(checked)
}
}
</script>
<label class="branding-toggle">
<input
type="checkbox"
bind:checked
{disabled}
onchange={handleChange}
class="branding-toggle__input"
/>
<span class="branding-toggle__slider"></span>
</label>
<style lang="scss">
.branding-toggle {
display: flex;
align-items: center;
cursor: pointer;
user-select: none;
}
.branding-toggle__input {
position: absolute;
opacity: 0;
pointer-events: none;
&:checked + .branding-toggle__slider {
background-color: $blue-60;
&::before {
transform: translateX(20px);
}
}
&:disabled + .branding-toggle__slider {
opacity: 0.5;
cursor: not-allowed;
}
}
.branding-toggle__slider {
position: relative;
width: 44px;
height: 24px;
background-color: $gray-80;
border-radius: 12px;
transition: background-color 0.2s ease;
flex-shrink: 0;
&::before {
content: '';
position: absolute;
top: 2px;
left: 2px;
width: 20px;
height: 20px;
background-color: white;
border-radius: 50%;
transition: transform 0.2s ease;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
}
</style>