mirror of
https://github.com/mue/mue.git
synced 2026-07-16 13:34:03 +02:00
* feat: add professional three-branch release workflow automation (#1129) - Add version-bump workflow for semantic versioning across all files - Add beta-release workflow for automated pre-release testing - Add production-release workflow with manual approval gates - Add hotfix-release workflow for emergency patches - Create comprehensive CONTRIBUTING.md with workflow guide - Create detailed RELEASE_PROCESS.md for maintainers - Add PR template with release checklists - Update CODEOWNERS to protect workflow files - Update README with contribution links - Remove /docs from .gitignore to allow documentation This implements a dev beta main branching strategy with: - Automated version management across 6 files - Changelog generation from conventional commits - GitHub Releases with build artifacts - Environment-based approvals for production - Back-merge support for hotfixes * feat: new default quotes experience, improve added page * Fix/beta workflow version check (#1131) * fix(workflows): prevent beta release for non-beta versions * fix(workflows): address copilot PR review feedback - Support iterative beta versions (7.6.0-beta.1 -> 7.6.0-beta.2) - Remove tag trigger from beta workflow to prevent premature releases - Fix tag format in docs/summaries to include 'v' prefix - Clarify deployment approval wording * feat: replace mui with new style * feat: improve time formatting in Clock component with padded digits * fix: change Checkbox component from label to div for better semantics * fix: change Switch component from label to div for better semantics * feat: add smooth animation to reset functionality in Slider component * feat: enhance accessibility and styling for form components including Checkbox, Dropdown, Radio, Slider, and Text * feat: enhance WeatherOptions component with improved layout and auto location reset functionality * feat: update Slider and Dropdown components with improved layout and z-index adjustments * feat: add reset functionality to Dropdown component with toast notification * feat: update Dropdown component styles for improved layout and structure * feat: update languageSettings component with increased padding for better spacing * feat: bump version to 7.6.0 across all manifests and documentation --------- Signed-off-by: Alex Sparkes <alexsparkes@gmail.com> Co-authored-by: David Ralph <me@davidcralph.co.uk>
150 lines
4.4 KiB
JavaScript
150 lines
4.4 KiB
JavaScript
import variables from 'config/variables';
|
|
import { memo, useState, useEffect } from 'react';
|
|
import { useT } from 'contexts';
|
|
|
|
import { MdContentCopy, MdAssignment, MdPushPin, MdDownload } from 'react-icons/md';
|
|
import { useFloating, shift } from '@floating-ui/react-dom';
|
|
import { toast } from 'react-toastify';
|
|
import { Tooltip } from 'components/Elements';
|
|
import { Textarea } from 'components/Form/Settings';
|
|
|
|
import { saveFile } from 'utils/saveFile';
|
|
import EventBus from 'utils/eventbus';
|
|
|
|
const Notes = ({ notesRef, floatRef, position, xPosition, yPosition }) => {
|
|
const t = useT();
|
|
const [notes, setNotes] = useState(localStorage.getItem('notes') || '');
|
|
const [showNotes, setShowNotes] = useState(localStorage.getItem('notesPinned') === 'true');
|
|
const [zoomFontSize, setZoomFontSize] = useState('1.2rem');
|
|
|
|
useEffect(() => {
|
|
const handleRefresh = (data) => {
|
|
if (data === 'navbar') {
|
|
setZoomFontSize(Number(((localStorage.getItem('zoomNavbar') || 100) / 100) * 1.2) + 'rem');
|
|
}
|
|
};
|
|
|
|
setZoomFontSize(Number(((localStorage.getItem('zoomNavbar') || 100) / 100) * 1.2) + 'rem');
|
|
|
|
EventBus.on('refresh', handleRefresh);
|
|
return () => {
|
|
EventBus.off('refresh');
|
|
};
|
|
}, []);
|
|
|
|
const handleSetNotes = (e) => {
|
|
localStorage.setItem('notes', e.target.value);
|
|
setNotes(e.target.value);
|
|
};
|
|
|
|
const handleShowNotes = () => {
|
|
setShowNotes(true);
|
|
};
|
|
|
|
const handleHideNotes = () => {
|
|
setShowNotes(localStorage.getItem('notesPinned') === 'true');
|
|
};
|
|
|
|
const handlePin = () => {
|
|
variables.stats.postEvent('feature', 'Notes pin');
|
|
const notesPinned = localStorage.getItem('notesPinned') === 'true';
|
|
localStorage.setItem('notesPinned', !notesPinned);
|
|
setShowNotes(!notesPinned);
|
|
};
|
|
|
|
const handleCopy = () => {
|
|
variables.stats.postEvent('feature', 'Notes copied');
|
|
navigator.clipboard.writeText(notes);
|
|
toast(t('toasts.notes'));
|
|
};
|
|
|
|
const handleDownload = () => {
|
|
if (!notes || notes === '') {
|
|
return;
|
|
}
|
|
|
|
variables.stats.postEvent('feature', 'Notes download');
|
|
saveFile(notes, 'mue-notes.txt', 'text/plain');
|
|
};
|
|
|
|
return (
|
|
<div className="notes" onMouseLeave={handleHideNotes} onFocus={handleShowNotes}>
|
|
<button
|
|
className="navbarButton"
|
|
onMouseEnter={handleShowNotes}
|
|
onFocus={handleShowNotes}
|
|
onBlur={handleHideNotes}
|
|
ref={notesRef}
|
|
style={{ fontSize: zoomFontSize }}
|
|
aria-label={t('widgets.navbar.notes.title')}
|
|
>
|
|
<MdAssignment className="topicons" />
|
|
</button>
|
|
{showNotes && (
|
|
<span
|
|
className="notesContainer"
|
|
ref={floatRef}
|
|
style={{
|
|
position: position,
|
|
top: yPosition ?? '44',
|
|
left: xPosition ?? '',
|
|
}}
|
|
>
|
|
<div className="flexNotes">
|
|
<div className="topBarNotes" style={{ display: 'flex' }}>
|
|
<MdAssignment />
|
|
<span>{t('widgets.navbar.notes.title')}</span>
|
|
</div>
|
|
<div className="notes-buttons">
|
|
<Tooltip title={t('widgets.navbar.todo.pin')}>
|
|
<button onClick={handlePin}>
|
|
<MdPushPin />
|
|
</button>
|
|
</Tooltip>
|
|
<Tooltip title={t('widgets.quote.copy')}>
|
|
<button onClick={handleCopy} disabled={notes === ''}>
|
|
<MdContentCopy />
|
|
</button>
|
|
</Tooltip>
|
|
<Tooltip title={t('widgets.background.download')}>
|
|
<button onClick={handleDownload} disabled={notes === ''}>
|
|
<MdDownload />
|
|
</button>
|
|
</Tooltip>
|
|
</div>
|
|
<Textarea
|
|
placeholder={t('widgets.navbar.notes.placeholder')}
|
|
value={notes}
|
|
onChange={handleSetNotes}
|
|
minRows={5}
|
|
/>
|
|
</div>
|
|
</span>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
function NotesWrapper() {
|
|
const [reference, setReference] = useState(null);
|
|
|
|
const { x, y, refs, strategy } = useFloating({
|
|
placement: 'bottom',
|
|
middleware: [shift()],
|
|
elements: { reference },
|
|
});
|
|
|
|
return (
|
|
<Notes
|
|
notesRef={setReference}
|
|
floatRef={refs.setFloating}
|
|
position={strategy}
|
|
xPosition={x}
|
|
yPosition={y}
|
|
/>
|
|
);
|
|
}
|
|
|
|
const MemoizedNotesWrapper = memo(NotesWrapper);
|
|
export { MemoizedNotesWrapper as default, MemoizedNotesWrapper as Notes };
|