mirror of
https://github.com/mue/mue.git
synced 2026-07-09 21:45:26 +02:00
feat: enhance click handling for color inputs and update event bus cleanup
This commit is contained in:
@@ -22,7 +22,7 @@ const useAppSetup = () => {
|
||||
loadSettings();
|
||||
|
||||
const refreshHandler = (data) => {
|
||||
if (data === 'other') {
|
||||
if (data === 'other' || data === 'greeting' || data === 'clock' || data === 'quote') {
|
||||
loadSettings(true);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -29,6 +29,26 @@ function ChipSelect({ label, options, onChange, name }) {
|
||||
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event) => {
|
||||
// Ignore clicks on color inputs to prevent closing when native color picker opens
|
||||
if (event.target.type === 'color') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Also ignore clicks on color input labels and wrappers
|
||||
const target = event.target;
|
||||
if (target.tagName === 'LABEL' && target.htmlFor) {
|
||||
const associatedInput = document.getElementById(target.htmlFor) || document.querySelector(`input[name="${target.htmlFor}"]`);
|
||||
if (associatedInput && associatedInput.type === 'color') {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if clicking within a color input wrapper
|
||||
const colorInputWrapper = target.closest('.colourInput');
|
||||
if (colorInputWrapper && colorInputWrapper.querySelector('input[type="color"]')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
containerRef.current &&
|
||||
!containerRef.current.contains(event.target) &&
|
||||
|
||||
@@ -23,6 +23,26 @@ const DatePicker = memo((props) => {
|
||||
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event) => {
|
||||
// Ignore clicks on color inputs to prevent closing when native color picker opens
|
||||
if (event.target.type === 'color') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Also ignore clicks on color input labels and wrappers
|
||||
const target = event.target;
|
||||
if (target.tagName === 'LABEL' && target.htmlFor) {
|
||||
const associatedInput = document.getElementById(target.htmlFor) || document.querySelector(`input[name="${target.htmlFor}"]`);
|
||||
if (associatedInput && associatedInput.type === 'color') {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if clicking within a color input wrapper
|
||||
const colorInputWrapper = target.closest('.colourInput');
|
||||
if (colorInputWrapper && colorInputWrapper.querySelector('input[type="color"]')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
containerRef.current &&
|
||||
!containerRef.current.contains(event.target) &&
|
||||
|
||||
@@ -35,6 +35,26 @@ const Dropdown = memo((props) => {
|
||||
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event) => {
|
||||
// Ignore clicks on color inputs to prevent closing when native color picker opens
|
||||
if (event.target.type === 'color') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Also ignore clicks on color input labels and wrappers
|
||||
const target = event.target;
|
||||
if (target.tagName === 'LABEL' && target.htmlFor) {
|
||||
const associatedInput = document.getElementById(target.htmlFor) || document.querySelector(`input[name="${target.htmlFor}"]`);
|
||||
if (associatedInput && associatedInput.type === 'color') {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if clicking within a color input wrapper
|
||||
const colorInputWrapper = target.closest('.colourInput');
|
||||
if (colorInputWrapper && colorInputWrapper.querySelector('input[type="color"]')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
containerRef.current &&
|
||||
!containerRef.current.contains(event.target) &&
|
||||
|
||||
@@ -52,6 +52,26 @@ const LocationSearch = memo((props) => {
|
||||
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event) => {
|
||||
// Ignore clicks on color inputs to prevent closing when native color picker opens
|
||||
if (event.target.type === 'color') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Also ignore clicks on color input labels and wrappers
|
||||
const target = event.target;
|
||||
if (target.tagName === 'LABEL' && target.htmlFor) {
|
||||
const associatedInput = document.getElementById(target.htmlFor) || document.querySelector(`input[name="${target.htmlFor}"]`);
|
||||
if (associatedInput && associatedInput.type === 'color') {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if clicking within a color input wrapper
|
||||
const colorInputWrapper = target.closest('.colourInput');
|
||||
if (colorInputWrapper && colorInputWrapper.querySelector('input[type="color"]')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const t = useT();
|
||||
if (
|
||||
containerRef.current &&
|
||||
|
||||
@@ -141,7 +141,7 @@ const Greeting = () => {
|
||||
|
||||
EventBus.on('refresh', handleRefresh);
|
||||
return () => {
|
||||
EventBus.off('refresh');
|
||||
EventBus.off('refresh', handleRefresh);
|
||||
if (timerRef.current) {
|
||||
clearTimeout(timerRef.current);
|
||||
}
|
||||
|
||||
@@ -273,12 +273,12 @@ const GreetingOptions = ({ currentSubSection, onSubSectionChange, sectionName })
|
||||
name="greetingFontWeight"
|
||||
category="greeting"
|
||||
items={[
|
||||
{ value: '400', text: t(fontWeight + '.normal') },
|
||||
{ value: '600', text: t(fontWeight + '.semi_bold') },
|
||||
{ value: '100', text: t(fontWeight + '.thin') },
|
||||
{ value: '200', text: t(fontWeight + '.extra_light') },
|
||||
{ value: '300', text: t(fontWeight + '.light') },
|
||||
{ value: '400', text: t(fontWeight + '.normal') },
|
||||
{ value: '500', text: t(fontWeight + '.medium') },
|
||||
{ value: '600', text: t(fontWeight + '.semi_bold') },
|
||||
{ value: '700', text: t(fontWeight + '.bold') },
|
||||
{ value: '800', text: t(fontWeight + '.extra_bold') },
|
||||
]}
|
||||
|
||||
@@ -26,7 +26,7 @@ const Message = () => {
|
||||
|
||||
EventBus.on('refresh', handleRefresh);
|
||||
return () => {
|
||||
EventBus.off('refresh');
|
||||
EventBus.off('refresh', handleRefresh);
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ const Widgets = () => {
|
||||
|
||||
EventBus.on('refresh', handleRefresh);
|
||||
return () => {
|
||||
EventBus.off('refresh');
|
||||
EventBus.off('refresh', handleRefresh);
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ const Navbar = ({ openModal }) => {
|
||||
|
||||
EventBus.on('refresh', handleRefresh);
|
||||
return () => {
|
||||
EventBus.off('refresh');
|
||||
EventBus.off('refresh', handleRefresh);
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ const Notes = ({ notesRef, floatRef, position, xPosition, yPosition }) => {
|
||||
|
||||
EventBus.on('refresh', handleRefresh);
|
||||
return () => {
|
||||
EventBus.off('refresh');
|
||||
EventBus.off('refresh', handleRefresh);
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
||||
@@ -232,12 +232,12 @@ const QuoteOptions = ({ currentSubSection, onSubSectionChange, sectionName }) =>
|
||||
name="quoteFontWeight"
|
||||
category="quote"
|
||||
items={[
|
||||
{ value: '400', text: t(fontWeight + '.normal') },
|
||||
{ value: '600', text: t(fontWeight + '.semi_bold') },
|
||||
{ value: '100', text: t(fontWeight + '.thin') },
|
||||
{ value: '200', text: t(fontWeight + '.extra_light') },
|
||||
{ value: '300', text: t(fontWeight + '.light') },
|
||||
{ value: '400', text: t(fontWeight + '.normal') },
|
||||
{ value: '500', text: t(fontWeight + '.medium') },
|
||||
{ value: '600', text: t(fontWeight + '.semi_bold') },
|
||||
{ value: '700', text: t(fontWeight + '.bold') },
|
||||
{ value: '800', text: t(fontWeight + '.extra_bold') },
|
||||
]}
|
||||
|
||||
@@ -81,11 +81,16 @@ function Search() {
|
||||
}
|
||||
}
|
||||
|
||||
EventBus.on('refresh', (data) => {
|
||||
const handleRefresh = (data) => {
|
||||
if (data === 'search') {
|
||||
init();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
EventBus.on('refresh', handleRefresh);
|
||||
return () => {
|
||||
EventBus.off('refresh', handleRefresh);
|
||||
};
|
||||
}, [init]);
|
||||
|
||||
function searchButton(e) {
|
||||
|
||||
@@ -54,7 +54,7 @@ const Autocomplete = ({
|
||||
|
||||
EventBus.on('refresh', handleRefresh);
|
||||
return () => {
|
||||
EventBus.off('refresh');
|
||||
EventBus.off('refresh', handleRefresh);
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ const Clock = () => {
|
||||
|
||||
EventBus.on('refresh', handleRefresh);
|
||||
return () => {
|
||||
EventBus.off('refresh');
|
||||
EventBus.off('refresh', handleRefresh);
|
||||
if (timerRef.current) {
|
||||
clearTimeout(timerRef.current);
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ const DateWidget = () => {
|
||||
|
||||
EventBus.on('refresh', handleRefresh);
|
||||
return () => {
|
||||
EventBus.off('refresh');
|
||||
EventBus.off('refresh', handleRefresh);
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
||||
@@ -253,12 +253,12 @@ const TimeOptions = ({ currentSubSection, onSubSectionChange, sectionName }) =>
|
||||
name="clockFontWeight"
|
||||
category="clock"
|
||||
items={[
|
||||
{ value: '400', text: t(fontWeight + '.normal') },
|
||||
{ value: '600', text: t(fontWeight + '.semi_bold') },
|
||||
{ value: '100', text: t(fontWeight + '.thin') },
|
||||
{ value: '200', text: t(fontWeight + '.extra_light') },
|
||||
{ value: '300', text: t(fontWeight + '.light') },
|
||||
{ value: '400', text: t(fontWeight + '.normal') },
|
||||
{ value: '500', text: t(fontWeight + '.medium') },
|
||||
{ value: '600', text: t(fontWeight + '.semi_bold') },
|
||||
{ value: '700', text: t(fontWeight + '.bold') },
|
||||
{ value: '800', text: t(fontWeight + '.extra_bold') },
|
||||
]}
|
||||
|
||||
@@ -143,113 +143,104 @@ export function loadSettings(hotreload) {
|
||||
|
||||
// Per-widget fonts (override global widget font)
|
||||
const greetingFont = localStorage.getItem('greetingFont');
|
||||
if (greetingFont) {
|
||||
const greetingFontWeight = localStorage.getItem('greetingFontWeight') || '400';
|
||||
const greetingFontStyle = localStorage.getItem('greetingFontStyle') || 'normal';
|
||||
const greetingColor = localStorage.getItem('greetingColor') || '#ffffff';
|
||||
const greetingFontWeight = localStorage.getItem('greetingFontWeight');
|
||||
const greetingFontStyle = localStorage.getItem('greetingFontStyle');
|
||||
const greetingColor = localStorage.getItem('greetingColor');
|
||||
|
||||
const fontFamily = greetingFont.replace(/ /g, '+');
|
||||
const googleFontUrl = `@import url('https://fonts.googleapis.com/css2?family=${fontFamily}:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800&display=swap');`;
|
||||
if (greetingFont || greetingFontWeight || greetingFontStyle || greetingColor) {
|
||||
let styleContent = '';
|
||||
|
||||
if (greetingFont) {
|
||||
const fontFamily = greetingFont.replace(/ /g, '+');
|
||||
styleContent += `@import url('https://fonts.googleapis.com/css2?family=${fontFamily}:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800&display=swap');\n`;
|
||||
}
|
||||
|
||||
styleContent += '.greeting {';
|
||||
if (greetingFont) {
|
||||
styleContent += `font-family: '${greetingFont}', 'Lexend Deca', 'Inter', sans-serif !important;`;
|
||||
}
|
||||
if (greetingFontWeight) {
|
||||
styleContent += `font-weight: ${greetingFontWeight} !important;`;
|
||||
}
|
||||
if (greetingFontStyle) {
|
||||
styleContent += `font-style: ${greetingFontStyle} !important;`;
|
||||
}
|
||||
if (greetingColor) {
|
||||
styleContent += `color: ${greetingColor} !important;`;
|
||||
}
|
||||
styleContent += '}';
|
||||
|
||||
document.head.insertAdjacentHTML(
|
||||
'beforeend',
|
||||
`
|
||||
<style id='customgreetingfont'>
|
||||
${googleFontUrl}
|
||||
.greeting {
|
||||
font-family: '${greetingFont}', 'Lexend Deca', 'Inter', sans-serif !important;
|
||||
font-weight: ${greetingFontWeight};
|
||||
font-style: ${greetingFontStyle};
|
||||
color: ${greetingColor} !important;
|
||||
}
|
||||
</style>
|
||||
`,
|
||||
);
|
||||
} else if (localStorage.getItem('greetingColor')) {
|
||||
const greetingColor = localStorage.getItem('greetingColor');
|
||||
document.head.insertAdjacentHTML(
|
||||
'beforeend',
|
||||
`
|
||||
<style id='customgreetingfont'>
|
||||
.greeting {
|
||||
color: ${greetingColor} !important;
|
||||
}
|
||||
</style>
|
||||
`,
|
||||
`<style id='customgreetingfont'>${styleContent}</style>`,
|
||||
);
|
||||
}
|
||||
|
||||
const clockFont = localStorage.getItem('clockFont');
|
||||
if (clockFont) {
|
||||
const clockFontWeight = localStorage.getItem('clockFontWeight') || '400';
|
||||
const clockFontStyle = localStorage.getItem('clockFontStyle') || 'normal';
|
||||
const clockColor = localStorage.getItem('clockColor') || '#ffffff';
|
||||
const clockFontWeight = localStorage.getItem('clockFontWeight');
|
||||
const clockFontStyle = localStorage.getItem('clockFontStyle');
|
||||
const clockColor = localStorage.getItem('clockColor');
|
||||
|
||||
const fontFamily = clockFont.replace(/ /g, '+');
|
||||
const googleFontUrl = `@import url('https://fonts.googleapis.com/css2?family=${fontFamily}:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800&display=swap');`;
|
||||
if (clockFont || clockFontWeight || clockFontStyle || clockColor) {
|
||||
let styleContent = '';
|
||||
|
||||
if (clockFont) {
|
||||
const fontFamily = clockFont.replace(/ /g, '+');
|
||||
styleContent += `@import url('https://fonts.googleapis.com/css2?family=${fontFamily}:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800&display=swap');\n`;
|
||||
}
|
||||
|
||||
styleContent += '.clock, .date {';
|
||||
if (clockFont) {
|
||||
styleContent += `font-family: '${clockFont}', 'Lexend Deca', 'Inter', sans-serif !important;`;
|
||||
}
|
||||
if (clockFontWeight) {
|
||||
styleContent += `font-weight: ${clockFontWeight} !important;`;
|
||||
}
|
||||
if (clockFontStyle) {
|
||||
styleContent += `font-style: ${clockFontStyle} !important;`;
|
||||
}
|
||||
if (clockColor) {
|
||||
styleContent += `color: ${clockColor} !important;`;
|
||||
}
|
||||
styleContent += '}';
|
||||
|
||||
document.head.insertAdjacentHTML(
|
||||
'beforeend',
|
||||
`
|
||||
<style id='customclockfont'>
|
||||
${googleFontUrl}
|
||||
.clock, .date {
|
||||
font-family: '${clockFont}', 'Lexend Deca', 'Inter', sans-serif !important;
|
||||
font-weight: ${clockFontWeight};
|
||||
font-style: ${clockFontStyle};
|
||||
color: ${clockColor} !important;
|
||||
}
|
||||
</style>
|
||||
`,
|
||||
);
|
||||
} else if (localStorage.getItem('clockColor')) {
|
||||
const clockColor = localStorage.getItem('clockColor');
|
||||
document.head.insertAdjacentHTML(
|
||||
'beforeend',
|
||||
`
|
||||
<style id='customclockfont'>
|
||||
.clock, .date {
|
||||
color: ${clockColor} !important;
|
||||
}
|
||||
</style>
|
||||
`,
|
||||
`<style id='customclockfont'>${styleContent}</style>`,
|
||||
);
|
||||
}
|
||||
|
||||
const quoteFont = localStorage.getItem('quoteFont');
|
||||
if (quoteFont) {
|
||||
const quoteFontWeight = localStorage.getItem('quoteFontWeight') || '400';
|
||||
const quoteFontStyle = localStorage.getItem('quoteFontStyle') || 'normal';
|
||||
const quoteColor = localStorage.getItem('quoteColor') || '#ffffff';
|
||||
const quoteFontWeight = localStorage.getItem('quoteFontWeight');
|
||||
const quoteFontStyle = localStorage.getItem('quoteFontStyle');
|
||||
const quoteColor = localStorage.getItem('quoteColor');
|
||||
|
||||
const fontFamily = quoteFont.replace(/ /g, '+');
|
||||
const googleFontUrl = `@import url('https://fonts.googleapis.com/css2?family=${fontFamily}:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800&display=swap');`;
|
||||
if (quoteFont || quoteFontWeight || quoteFontStyle || quoteColor) {
|
||||
let styleContent = '';
|
||||
|
||||
if (quoteFont) {
|
||||
const fontFamily = quoteFont.replace(/ /g, '+');
|
||||
styleContent += `@import url('https://fonts.googleapis.com/css2?family=${fontFamily}:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800&display=swap');\n`;
|
||||
}
|
||||
|
||||
styleContent += '.quote, .quoteauthor {';
|
||||
if (quoteFont) {
|
||||
styleContent += `font-family: '${quoteFont}', 'Lexend Deca', 'Inter', sans-serif !important;`;
|
||||
}
|
||||
if (quoteFontWeight) {
|
||||
styleContent += `font-weight: ${quoteFontWeight} !important;`;
|
||||
}
|
||||
if (quoteFontStyle) {
|
||||
styleContent += `font-style: ${quoteFontStyle} !important;`;
|
||||
}
|
||||
if (quoteColor) {
|
||||
styleContent += `color: ${quoteColor} !important;`;
|
||||
}
|
||||
styleContent += '}';
|
||||
|
||||
document.head.insertAdjacentHTML(
|
||||
'beforeend',
|
||||
`
|
||||
<style id='customquotefont'>
|
||||
${googleFontUrl}
|
||||
.quote, .quoteauthor {
|
||||
font-family: '${quoteFont}', 'Lexend Deca', 'Inter', sans-serif !important;
|
||||
font-weight: ${quoteFontWeight};
|
||||
font-style: ${quoteFontStyle};
|
||||
color: ${quoteColor} !important;
|
||||
}
|
||||
</style>
|
||||
`,
|
||||
);
|
||||
} else if (localStorage.getItem('quoteColor')) {
|
||||
const quoteColor = localStorage.getItem('quoteColor');
|
||||
document.head.insertAdjacentHTML(
|
||||
'beforeend',
|
||||
`
|
||||
<style id='customquotefont'>
|
||||
.quote, .quoteauthor {
|
||||
color: ${quoteColor} !important;
|
||||
}
|
||||
</style>
|
||||
`,
|
||||
`<style id='customquotefont'>${styleContent}</style>`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -272,15 +263,15 @@ export function loadSettings(hotreload) {
|
||||
|
||||
// easter egg
|
||||
console.log(`
|
||||
█████████████████████████████████████████████████████████████
|
||||
█████████████████████████████████████████████████████████████
|
||||
██ ██
|
||||
██ ███ ███ ██ ██ ███████ ██
|
||||
██ ████ ████ ██ ██ ██ ██
|
||||
██ ██ ████ ██ ██ ██ █████ ██
|
||||
██ ██ ██ ██ ██ ██ ██ ██
|
||||
██ ██ ██ ██████ ███████ ██
|
||||
██ ██
|
||||
██ ██
|
||||
██ ███ ███ ██ ██ ███████ ██
|
||||
██ ████ ████ ██ ██ ██ ██
|
||||
██ ██ ████ ██ ██ ██ █████ ██
|
||||
██ ██ ██ ██ ██ ██ ██ ██
|
||||
██ ██ ██ ██████ ███████ ██
|
||||
██ ██
|
||||
██ ██
|
||||
██ Copyright 2018-${new Date().getFullYear()} The Mue Authors ██
|
||||
██ GitHub: https://github.com/mue/mue ██
|
||||
██ ██
|
||||
|
||||
Reference in New Issue
Block a user