mirror of
https://github.com/lucide-icons/lucide.git
synced 2026-11-10 13:18:25 +00:00
fix(site): Fix reset button and rename absolute stroke width to non-scaling stroke (#4956)
* Fix reset button and rename absolute stroke width * Adjust props * Adjust icon preview * Rename switch ID for non-scaling stroke Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
co-authored by
Copilot Autofix powered by AI
parent
851bc6deed
commit
ccb4b193d2
@@ -73,7 +73,7 @@ function hidePopup() {
|
||||
:iconNode="x"
|
||||
name="x"
|
||||
:size="20"
|
||||
absoluteStrokeWidth
|
||||
nonScalingStroke
|
||||
/>
|
||||
</Button>
|
||||
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
id: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
|
||||
@@ -23,6 +27,7 @@
|
||||
@update:model-value="emit('update:modelValue', $event)"
|
||||
class="switch"
|
||||
:class="{ enabled: isHydrated && modelValue }"
|
||||
:id="id"
|
||||
>
|
||||
<span class="thumb" />
|
||||
</Switch>
|
||||
|
||||
@@ -9,7 +9,7 @@ import ResetButton from '../base/ResetButton.vue';
|
||||
import HomeIconCustomizerIcons from './HomeIconCustomizerIcons.vue';
|
||||
import Switch from '../base/Switch.vue';
|
||||
|
||||
const { color, strokeWidth, size, absoluteStrokeWidth, isCustomized, resetStyle } = useIconStyle();
|
||||
const { color, strokeWidth, size, nonScalingStroke, isCustomized, resetStyle } = useIconStyle();
|
||||
|
||||
const iconStyle = computed(() => ({
|
||||
'--home-icon-color': color.value,
|
||||
@@ -85,14 +85,14 @@ const iconStyle = computed(() => ({
|
||||
</InputField>
|
||||
|
||||
<InputField
|
||||
id="absolute-stroke-width"
|
||||
label="Absolute Stroke width"
|
||||
id="non-scaling-stroke"
|
||||
label="Non-scaling stroke"
|
||||
>
|
||||
<template #display>
|
||||
<Switch
|
||||
id="absolute-stroke-width-switch"
|
||||
name="absolute-stroke-width"
|
||||
v-model="absoluteStrokeWidth"
|
||||
id="non-scaling-stroke-switch"
|
||||
name="non-scaling-stroke"
|
||||
v-model="nonScalingStroke"
|
||||
/>
|
||||
</template>
|
||||
</InputField>
|
||||
@@ -101,7 +101,7 @@ const iconStyle = computed(() => ({
|
||||
|
||||
<div class="icons-container card-column">
|
||||
<HomeIconCustomizerIcons
|
||||
:class="{ 'absolute-stroke-width': absoluteStrokeWidth }"
|
||||
:class="{ 'non-scaling-stroke': nonScalingStroke }"
|
||||
:style="iconStyle"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -79,7 +79,7 @@ const onIntersectionObserver: IntersectionObserverCallback = ([{ isIntersecting
|
||||
max-height: 3rem;
|
||||
}
|
||||
|
||||
.icon-grid.absolute-stroke-width .lucide-icon {
|
||||
.icon-grid.non-scaling-stroke .lucide-icon {
|
||||
stroke-width: calc(var(--home-icon-stroke-width, 2) * 24 / var(--home-icon-size, 24));
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -48,7 +48,7 @@ onMounted(() => {
|
||||
:iconNode="x"
|
||||
name="x"
|
||||
:size="20"
|
||||
absoluteStrokeWidth
|
||||
nonScalingStroke
|
||||
/>
|
||||
</Button>
|
||||
<VPDocAsideCarbonAds :carbon-ads="theme.carbonAds" overlay />
|
||||
|
||||
@@ -9,7 +9,7 @@ const props = defineProps<{
|
||||
name: string;
|
||||
popoverPosition?: 'top' | 'bottom';
|
||||
}>();
|
||||
const { size, color, strokeWidth, absoluteStrokeWidth } = useIconStyleContext();
|
||||
const { size, color, strokeWidth, nonScalingStroke } = useIconStyleContext();
|
||||
const { animate, confetti } = useConfetti();
|
||||
const componentName = computed(() => {
|
||||
return (toPascalCase(props.name) as string).replace(/\s/g, '');
|
||||
@@ -30,8 +30,8 @@ function copyJSX() {
|
||||
attrs.push(`strokeWidth={${strokeWidth.value}}`);
|
||||
}
|
||||
|
||||
if (absoluteStrokeWidth.value) {
|
||||
attrs.push(`absoluteStrokeWidth`);
|
||||
if (nonScalingStroke.value) {
|
||||
attrs.push(`nonScalingStroke`);
|
||||
}
|
||||
|
||||
const code = `<${componentName.value}${attrs.join(' ')} />`;
|
||||
@@ -60,8 +60,8 @@ function copyVue() {
|
||||
attrs.push(`:stroke-width="${strokeWidth.value}"`);
|
||||
}
|
||||
|
||||
if (absoluteStrokeWidth.value) {
|
||||
attrs.push(`absoluteStrokeWidth`);
|
||||
if (nonScalingStroke.value) {
|
||||
attrs.push(`nonScalingStroke`);
|
||||
}
|
||||
|
||||
const code = `<${componentName.value}${attrs.join(' ')} />`;
|
||||
@@ -86,8 +86,8 @@ function copyAngular() {
|
||||
attrs.push(`[strokeWidth]="${strokeWidth.value}"`);
|
||||
}
|
||||
|
||||
if (absoluteStrokeWidth.value) {
|
||||
attrs.push(`[absoluteStrokeWidth]="true"`);
|
||||
if (nonScalingStroke.value) {
|
||||
attrs.push(`[nonScalingStroke]="true"`);
|
||||
}
|
||||
|
||||
const code = `<lucide-icon${attrs.join(' ')}></lucide-icon>`;
|
||||
|
||||
@@ -204,7 +204,7 @@ const DiamondIcon = createLucideIcon('Diamond', diamond);
|
||||
max-height: 3rem;
|
||||
}
|
||||
|
||||
html.absolute-stroke-width .lucide-icon.customizable {
|
||||
html.non-scaling-stroke .lucide-icon.customizable {
|
||||
stroke-width: calc(var(--customize-strokeWidth, 2) * 24 / var(--customize-size, 24));
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import type { IconEntity } from '../../types';
|
||||
import { computed, ref } from 'vue';
|
||||
import createLucideIcon from '@lucide/vue/src/createLucideIcon';
|
||||
import Icon from '@lucide/vue/src/Icon';
|
||||
import { useIconStyleContext } from '../../composables/useIconStyle';
|
||||
|
||||
const props = defineProps<{
|
||||
@@ -12,25 +12,23 @@ const props = defineProps<{
|
||||
|
||||
const activeSize = ref('1000%');
|
||||
|
||||
const { size, color, strokeWidth, absoluteStrokeWidth } = useIconStyleContext();
|
||||
const { size, color, strokeWidth, nonScalingStroke } = useIconStyleContext();
|
||||
const previewIcon = ref();
|
||||
|
||||
const gridLines = computed(() => Array.from({ length: size.value - 1 }));
|
||||
|
||||
const iconComponent = computed(() => {
|
||||
if (!props.name || !props.iconNode) return null;
|
||||
return createLucideIcon(props.name, props.iconNode);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="icon-container">
|
||||
<component
|
||||
<Icon
|
||||
v-if="name && iconNode"
|
||||
:name="name"
|
||||
:iconNode="iconNode"
|
||||
ref="previewIcon"
|
||||
:is="iconComponent"
|
||||
:size="size"
|
||||
:color="color"
|
||||
:strokeWidth="absoluteStrokeWidth ? (Number(strokeWidth) * 24) / Number(size) : strokeWidth"
|
||||
:strokeWidth="strokeWidth"
|
||||
:nonScalingStroke="nonScalingStroke"
|
||||
class="preview-icon"
|
||||
:data-size="activeSize"
|
||||
/>
|
||||
|
||||
@@ -71,7 +71,7 @@ const Icon = createLucideIcon(props.name, props.iconNode);
|
||||
height: calc(var(--customize-size, 24) * 1px); */
|
||||
}
|
||||
|
||||
html.absolute-stroke-width .lucide-icon {
|
||||
html.non-scaling-stroke .lucide-icon {
|
||||
stroke-width: calc(var(--customize-strokeWidth, 2) * 24 / var(--customize-size, 24));
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { useMounted } from '@vueuse/core';
|
||||
import { useIconStyleContext } from '../../composables/useIconStyle';
|
||||
import RangeSlider from '../base/RangeSlider.vue';
|
||||
import InputField from '../base/InputField.vue';
|
||||
@@ -6,19 +8,24 @@ import ColorPicker from '../base/ColorPicker.vue';
|
||||
import ResetButton from '../base/ResetButton.vue';
|
||||
import Switch from '../base/Switch.vue';
|
||||
|
||||
const { color, strokeWidth, size, absoluteStrokeWidth, isCustomized, resetStyle } =
|
||||
const { color, strokeWidth, size, nonScalingStroke, isCustomized, resetStyle } =
|
||||
useIconStyleContext();
|
||||
|
||||
// The server always renders the default style. Keep the first client render identical,
|
||||
// otherwise the hydrated DOM keeps the stale `disabled` attribute on the reset button.
|
||||
const isMounted = useMounted();
|
||||
const showCustomized = computed(() => isMounted.value && isCustomized.value);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="customizer-card"
|
||||
:class="{ customized: isCustomized }"
|
||||
:class="{ customized: showCustomized }"
|
||||
>
|
||||
<div class="card-header">
|
||||
<h2 class="card-title">Customizer</h2>
|
||||
<ResetButton
|
||||
:disabled="!isCustomized"
|
||||
:disabled="!showCustomized"
|
||||
@click="resetStyle"
|
||||
/>
|
||||
</div>
|
||||
@@ -68,13 +75,13 @@ const { color, strokeWidth, size, absoluteStrokeWidth, isCustomized, resetStyle
|
||||
</InputField>
|
||||
|
||||
<InputField
|
||||
id="absolute-stroke-width"
|
||||
label="Absolute stroke width"
|
||||
id="non-scaling-stroke"
|
||||
label="Non-scaling stroke"
|
||||
>
|
||||
<Switch
|
||||
id="absolute-stroke-width-switch"
|
||||
name="absolute-stroke-width"
|
||||
v-model="absoluteStrokeWidth"
|
||||
id="non-scaling-stroke-switch"
|
||||
name="non-scaling-stroke"
|
||||
v-model="nonScalingStroke"
|
||||
/>
|
||||
</InputField>
|
||||
</div>
|
||||
|
||||
@@ -6,7 +6,7 @@ const storedValues = new Map<string, string>([
|
||||
['icon-size', '240'],
|
||||
['icon-stroke-width', '1.5'],
|
||||
['icon-color', '#ff0000'],
|
||||
['icon-absolute-stroke-width', 'true'],
|
||||
['icon-non-scaling-stroke', 'true'],
|
||||
]);
|
||||
const styleProperties = new Map<string, string>();
|
||||
const classes = new Set<string>();
|
||||
@@ -70,7 +70,7 @@ test('creates a non-persisted icon style from the defaults', () => {
|
||||
assert.equal(style.size.value, 24);
|
||||
assert.equal(style.strokeWidth.value, 2);
|
||||
assert.equal(style.color.value, 'currentColor');
|
||||
assert.equal(style.absoluteStrokeWidth.value, false);
|
||||
assert.equal(style.nonScalingStroke.value, false);
|
||||
|
||||
style.size.value = 48;
|
||||
|
||||
@@ -84,12 +84,12 @@ test('restores persisted settings and applies the shared CSS variables', () => {
|
||||
assert.equal(style.size.value, 240);
|
||||
assert.equal(style.strokeWidth.value, 1.5);
|
||||
assert.equal(style.color.value, '#ff0000');
|
||||
assert.equal(style.absoluteStrokeWidth.value, true);
|
||||
assert.equal(style.nonScalingStroke.value, true);
|
||||
assert.equal(style.isCustomized.value, true);
|
||||
assert.equal(styleProperties.get('--customize-size'), '240');
|
||||
assert.equal(styleProperties.get('--customize-strokeWidth'), '1.5');
|
||||
assert.equal(styleProperties.get('--customize-color'), '#ff0000');
|
||||
assert.ok(classes.has('absolute-stroke-width'));
|
||||
assert.ok(classes.has('non-scaling-stroke'));
|
||||
});
|
||||
|
||||
test('resetting updates refs, CSS variables, and persisted values', async () => {
|
||||
@@ -100,14 +100,14 @@ test('resetting updates refs, CSS variables, and persisted values', async () =>
|
||||
assert.equal(style.size.value, 24);
|
||||
assert.equal(style.strokeWidth.value, 2);
|
||||
assert.equal(style.color.value, 'currentColor');
|
||||
assert.equal(style.absoluteStrokeWidth.value, false);
|
||||
assert.equal(style.nonScalingStroke.value, false);
|
||||
assert.equal(style.isCustomized.value, false);
|
||||
assert.equal(styleProperties.get('--customize-size'), '24');
|
||||
assert.equal(styleProperties.get('--customize-strokeWidth'), '2');
|
||||
assert.equal(styleProperties.get('--customize-color'), 'currentColor');
|
||||
assert.equal(classes.has('absolute-stroke-width'), false);
|
||||
assert.equal(classes.has('non-scaling-stroke'), false);
|
||||
assert.equal(storedValues.get('icon-size'), '24');
|
||||
assert.equal(storedValues.get('icon-stroke-width'), '2');
|
||||
assert.equal(storedValues.get('icon-color'), 'currentColor');
|
||||
assert.equal(storedValues.get('icon-absolute-stroke-width'), 'false');
|
||||
assert.equal(storedValues.get('icon-non-scaling-stroke'), 'false');
|
||||
});
|
||||
|
||||
@@ -7,18 +7,18 @@ interface IconStyleContext {
|
||||
size: Ref<number>;
|
||||
strokeWidth: Ref<number>;
|
||||
color: Ref<string>;
|
||||
absoluteStrokeWidth: Ref<boolean>;
|
||||
nonScalingStroke: Ref<boolean>;
|
||||
isCustomized: ComputedRef<boolean>;
|
||||
resetStyle: () => void;
|
||||
}
|
||||
|
||||
type IconStyle = Pick<IconStyleContext, 'size' | 'strokeWidth' | 'color' | 'absoluteStrokeWidth'>;
|
||||
type IconStyle = Pick<IconStyleContext, 'size' | 'strokeWidth' | 'color' | 'nonScalingStroke'>;
|
||||
|
||||
export const STYLE_DEFAULTS = {
|
||||
size: 24,
|
||||
strokeWidth: 2,
|
||||
color: 'currentColor',
|
||||
absoluteStrokeWidth: false,
|
||||
nonScalingStroke: false,
|
||||
};
|
||||
|
||||
const persistedIconStyle = {
|
||||
@@ -27,11 +27,9 @@ const persistedIconStyle = {
|
||||
initOnMounted: false,
|
||||
}),
|
||||
color: useLocalStorage('icon-color', STYLE_DEFAULTS.color, { initOnMounted: false }),
|
||||
absoluteStrokeWidth: useLocalStorage(
|
||||
'icon-absolute-stroke-width',
|
||||
STYLE_DEFAULTS.absoluteStrokeWidth,
|
||||
{ initOnMounted: false },
|
||||
),
|
||||
nonScalingStroke: useLocalStorage('icon-non-scaling-stroke', STYLE_DEFAULTS.nonScalingStroke, {
|
||||
initOnMounted: false,
|
||||
}),
|
||||
};
|
||||
|
||||
function createIconStyleContext(style: IconStyle): IconStyleContext {
|
||||
@@ -40,7 +38,7 @@ function createIconStyleContext(style: IconStyle): IconStyleContext {
|
||||
style.color.value !== STYLE_DEFAULTS.color ||
|
||||
style.strokeWidth.value !== STYLE_DEFAULTS.strokeWidth ||
|
||||
style.size.value !== STYLE_DEFAULTS.size ||
|
||||
style.absoluteStrokeWidth.value !== STYLE_DEFAULTS.absoluteStrokeWidth
|
||||
style.nonScalingStroke.value !== STYLE_DEFAULTS.nonScalingStroke
|
||||
);
|
||||
});
|
||||
|
||||
@@ -48,7 +46,7 @@ function createIconStyleContext(style: IconStyle): IconStyleContext {
|
||||
style.color.value = STYLE_DEFAULTS.color;
|
||||
style.strokeWidth.value = STYLE_DEFAULTS.strokeWidth;
|
||||
style.size.value = STYLE_DEFAULTS.size;
|
||||
style.absoluteStrokeWidth.value = STYLE_DEFAULTS.absoluteStrokeWidth;
|
||||
style.nonScalingStroke.value = STYLE_DEFAULTS.nonScalingStroke;
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -65,7 +63,7 @@ export function useIconStyle() {
|
||||
size: ref(STYLE_DEFAULTS.size),
|
||||
strokeWidth: ref(STYLE_DEFAULTS.strokeWidth),
|
||||
color: ref(STYLE_DEFAULTS.color),
|
||||
absoluteStrokeWidth: ref(STYLE_DEFAULTS.absoluteStrokeWidth),
|
||||
nonScalingStroke: ref(STYLE_DEFAULTS.nonScalingStroke),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -79,9 +77,9 @@ if (typeof document !== 'undefined') {
|
||||
persistedIconStyle.size,
|
||||
persistedIconStyle.strokeWidth,
|
||||
persistedIconStyle.color,
|
||||
persistedIconStyle.absoluteStrokeWidth,
|
||||
persistedIconStyle.nonScalingStroke,
|
||||
],
|
||||
([size, strokeWidth, color, absoluteStrokeWidth]) => {
|
||||
([size, strokeWidth, color, nonScalingStroke]) => {
|
||||
const root = document.documentElement;
|
||||
root.style.setProperty('--customize-size', String(Math.min(256, Math.max(16, size))));
|
||||
root.style.setProperty(
|
||||
@@ -89,7 +87,7 @@ if (typeof document !== 'undefined') {
|
||||
String(Math.min(3, Math.max(0.5, strokeWidth))),
|
||||
);
|
||||
if (CSS.supports('color', color)) root.style.setProperty('--customize-color', color);
|
||||
root.classList.toggle('absolute-stroke-width', absoluteStrokeWidth);
|
||||
root.classList.toggle('non-scaling-stroke', nonScalingStroke);
|
||||
},
|
||||
{ immediate: true, flush: 'sync' },
|
||||
);
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
const size = globalThis.localStorage.getItem('icon-size');
|
||||
const stroke = globalThis.localStorage.getItem('icon-stroke-width');
|
||||
const color = globalThis.localStorage.getItem('icon-color');
|
||||
const absolute = globalThis.localStorage.getItem('icon-absolute-stroke-width');
|
||||
if ([size, stroke, color, absolute].every((value) => value === null)) return;
|
||||
const nonScaling = globalThis.localStorage.getItem('icon-non-scaling-stroke');
|
||||
if ([size, stroke, color, nonScaling].every((value) => value === null)) return;
|
||||
if (size !== null && Number.isFinite(Number(size))) {
|
||||
root.style.setProperty('--customize-size', String(Math.min(256, Math.max(16, Number(size)))));
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
);
|
||||
if (color !== null && globalThis.CSS.supports('color', color))
|
||||
root.style.setProperty('--customize-color', color);
|
||||
root.classList.toggle('absolute-stroke-width', absolute === 'true');
|
||||
root.classList.toggle('non-scaling-stroke', nonScaling === 'true');
|
||||
} catch {
|
||||
// Storage can be unavailable, for example in private browsing mode.
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user