Skip to content

Dev - #1134

Merged
davidcralph merged 19 commits into
betafrom
dev
Jan 25, 2026
Merged

Dev#1134
davidcralph merged 19 commits into
betafrom
dev

Conversation

@alexsparkes

Copy link
Copy Markdown
Member

removes MUI UI
fixed issue with 0 padding on clock

alexsparkes and others added 18 commits January 25, 2026 17:27
- 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
* 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
… Checkbox, Dropdown, Radio, Slider, and Text
Copilot AI review requested due to automatic review settings January 25, 2026 20:52
davidcralph
davidcralph previously approved these changes Jan 25, 2026

@davidcralph davidcralph left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pretty nice update

Signed-off-by: Alex Sparkes <alexsparkes@gmail.com>
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jan 25, 2026

Copy link
Copy Markdown

Deploying mue with  Cloudflare Pages  Cloudflare Pages

Latest commit: ce6b05f
Status: ✅  Deploy successful!
Preview URL: https://95219183.mue.pages.dev
Branch Preview URL: https://dev.mue.pages.dev

View logs

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request removes Material-UI (MUI) dependencies and replaces them with custom-built form components, fixes a clock padding issue with zero digits in localized numerals, migrates from the deprecated 'api' quote type to 'quote_pack', and bumps the version to 7.6.0. The PR also adds comprehensive release process documentation and GitHub Actions workflows for version management.

Changes:

  • Removed all MUI dependencies (@mui/material, @emotion/react, @emotion/styled, embla-carousel packages) and replaced with custom-built components (Checkbox, Radio, Switch, Dropdown, Slider, Textarea, SearchInput, ChipSelect)
  • Fixed clock display issue where padded zeros weren't being formatted correctly for locales with custom numeral systems
  • Deprecated 'api' quote type in favor of 'quote_pack' with automatic migration logic and default pack installation
  • Added release process documentation (CONTRIBUTING.md, RELEASE_PROCESS.md) and GitHub Actions workflows for version bumping, beta releases, production releases, and hotfixes

Reviewed changes

Copilot reviewed 49 out of 50 changed files in this pull request and generated 13 comments.

Show a summary per file
File Description
package.json, bun.lock Removed MUI and related dependencies, bumped version to 7.6.0
src/components/Form/Settings/* New custom form components replacing MUI components with full styling
src/features/time/Clock.jsx Fixed padding issue with formatPaddedDigits helper for locale-specific numerals
src/features/quote/* Migrated from 'api' to 'quote_pack' type with backward compatibility
src/features/misc/modals/Modals.jsx Added default pack auto-installation logic
src/utils/marketplace/uninstall.js Added tracking of uninstalled packs to prevent auto-reinstall
src/features/marketplace/* Updated marketplace UI with uninstall buttons, sideload badges, and improved sorting
src/scss/_toast.scss Complete redesign with glassmorphism effects
docs/, .github/workflows/ Added comprehensive release documentation and automation workflows
manifest/, safari/ Version bumped to 7.6.0 across all platforms

Comment on lines +11 to +16
// Helper function to format padded time values while preserving padding
const formatPaddedDigits = (value) => {
const str = String(value);
// Format each digit individually to preserve padding with locale numerals
return str.split('').map(digit => formatDigits(digit)).join('');
};

Copilot AI Jan 25, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description mentions "fixed issue with 0 padding on clock" but the change from formatDigits to formatPaddedDigits affects all padded values (hours, minutes, seconds) when they contain '0' digits. The formatPaddedDigits function formats each digit individually, which is correct for preserving locale-specific numerals for '0'. However, ensure this works correctly with all locales and doesn't break RTL languages or locales with different numeral systems.

Copilot uses AI. Check for mistakes.
Comment on lines +25 to +33
const [quoteType, setQuoteType] = useState(() => {
let type = localStorage.getItem('quoteType') || 'quote_pack';
// Migrate deprecated 'api' type to 'quote_pack'
if (type === 'api') {
type = 'quote_pack';
localStorage.setItem('quoteType', 'quote_pack');
}
return type;
});

Copilot AI Jan 25, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default value fallback logic has changed from 'api' to 'quote_pack', but the migration only happens in the useState initialization and in getQuote. If quoteType is accessed or set elsewhere in the codebase without going through these code paths, the old 'api' value could persist. Consider adding a migration check in localStorage directly on application initialization to ensure all users are migrated.

Copilot uses AI. Check for mistakes.
Comment on lines +212 to +217
<div
className={'todo-checkbox' + (todoItem.done ? ' checked' : '')}
onClick={() => updateTodo('done', index)}
/>
<TextareaAutosize
>
{todoItem.done && <MdCheck />}
</div>

Copilot AI Jan 25, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The todo-checkbox class is used in the JSX but there are no corresponding styles defined in the codebase for this class. This will result in an unstyled checkbox element. The styles for .todo-checkbox and .todo-checkbox.checked need to be added to properly display the checkbox.

Copilot uses AI. Check for mistakes.
.items {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
grid-template-columns: repeat(auto-fill, minmax(250px, 280px));

Copilot AI Jan 25, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The grid layout has changed from 'repeat(auto-fit, minmax(250px, 1fr))' to 'repeat(auto-fill, minmax(250px, 280px))'. This changes the behavior significantly: auto-fill creates as many columns as can fit (leaving empty space), while auto-fit stretches items to fill available space. Also, the max width is now fixed at 280px instead of 1fr (flexible). This could result in awkward gaps on larger screens. Consider whether auto-fit with 1fr was the intended behavior.

Suggested change
grid-template-columns: repeat(auto-fill, minmax(250px, 280px));
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));

Copilot uses AI. Check for mistakes.
Comment on lines 35 to +49
return (
<FormControlLabel
control={
<SwitchUI
name={props.name}
color="primary"
checked={checked}
onChange={handleChange}
/>
}
label={props.header ? '' : props.text}
labelPlacement="start"
/>
<div className="switch-wrapper">
{!props.header && <span className="switch-label">{props.text}</span>}
<div className={`switch-track ${checked ? 'checked' : ''}`} onClick={handleChange}>
<div className="switch-thumb" />
</div>
<input
type="checkbox"
name={props.name}
checked={checked}
onChange={handleChange}
className="switch-input"
aria-hidden="true"
/>
</div>

Copilot AI Jan 25, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Switch component has aria-hidden="true" on the input element, which hides it from screen readers. However, the switch-track div that handles the click has no ARIA attributes and is not keyboard accessible. This makes the switch completely inaccessible to keyboard and screen reader users. Consider: 1) Removing aria-hidden from the input, 2) Adding proper ARIA role and labels to the wrapper, 3) Making the switch keyboard accessible with proper focus management and keyboard event handlers.

Copilot uses AI. Check for mistakes.
Comment on lines +13 to +73
const handleChange = useCallback(
async (newValue) => {
if (newValue === 'loading') {
return;
}

if (newValue === 'loading') {
return;
}
if (props.name === 'language') {
changeLanguage(newValue);
setValue(newValue);

if (props.name === 'language') {
// Use context to change language directly - no EventBus needed
changeLanguage(newValue);
setValue(newValue);
variables.stats.postEvent('setting', `${props.name} from ${value} to ${newValue}`);

variables.stats.postEvent('setting', `${props.name} from ${value} to ${newValue}`);
if (props.onChange) {
props.onChange(newValue);
}

if (props.onChange) {
props.onChange(newValue);
EventBus.emit('refresh', props.category);
return;
}

EventBus.emit('refresh', props.category);
return;
}

localStorage.setItem(props.name, newValue);
setValue(newValue);
localStorage.setItem(props.name, newValue);
setValue(newValue);

if (props.onChange) {
props.onChange(newValue);
}
if (props.onChange) {
props.onChange(newValue);
}

variables.stats.postEvent('setting', `${props.name} from ${value} to ${newValue}`);
variables.stats.postEvent('setting', `${props.name} from ${value} to ${newValue}`);

if (props.element) {
if (!document.querySelector(props.element)) {
document.querySelector('.reminder-info').style.display = 'flex';
return localStorage.setItem('showReminder', true);
if (props.element) {
if (!document.querySelector(props.element)) {
document.querySelector('.reminder-info').style.display = 'flex';
return localStorage.setItem('showReminder', true);
}
}
}

EventBus.emit('refresh', props.category);
}, [value, props, changeLanguage]);
EventBus.emit('refresh', props.category);
},
[value, props, changeLanguage],
);

return (
<FormControl component="fieldset">
<FormLabel
className={props.smallTitle ? 'radio-title-small' : 'radio-title'}
component="legend"
>
{props.title}
</FormLabel>
<RadioGroup
aria-label={props.name}
name={props.name}
onChange={handleChange}
value={value}
>
<div className="radio-group">
{props.title && (
<legend className={props.smallTitle ? 'radio-title-small' : 'radio-title'}>
{props.title}
</legend>
)}
<div className="radio-options" role="radiogroup" aria-label={props.name}>
{props.options.map((option) => (
<FormControlLabel
value={option.value}
control={<RadioUI />}
label={option.name}
<label
key={option.value}
/>
className={`radio-option ${value === option.value ? 'selected' : ''} ${option.disabled || props.disabled ? 'disabled' : ''}`}
>
<span className="radio-label">{option.name}</span>
<input
type="radio"
name={props.name}
value={option.value}
checked={value === option.value}
onChange={() => handleChange(option.value)}

Copilot AI Jan 25, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The handleChange function is called with newValue directly instead of event.target.value. This is inconsistent with the previous implementation and could cause issues if there are any onChange handlers expecting an event object. Consider maintaining backward compatibility by checking if the parameter is an event object before extracting the value.

Copilot uses AI. Check for mistakes.
Comment on lines +115 to 120
<Textarea
placeholder={t('widgets.navbar.notes.placeholder')}
value={notes}
onChange={handleSetNotes}
minRows={5}
maxLength={10000}
/>

Copilot AI Jan 25, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The maxLength prop has been removed from the Textarea component. If this was intentional to allow unlimited input, this is fine. However, if there was a specific reason for the 10000 character limit (e.g., storage constraints, performance), this should be re-added to the custom Textarea component or handled differently.

Copilot uses AI. Check for mistakes.
Comment on lines +42 to +51
<textarea
ref={textareaRef}
className={`textarea-autosize${className ? ` ${className}` : ''}`}
value={value}
onChange={onChange}
placeholder={placeholder}
style={style}
readOnly={readOnly}
rows={minRows}
/>

Copilot AI Jan 25, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Textarea component is missing support for the maxLength property that was previously available in MUI's TextareaAutosize. This property is used in Notes.jsx (removed on line 119). If character limits are needed for any textarea usage, the component should accept and pass through the maxLength prop to the native textarea element.

Copilot uses AI. Check for mistakes.
Comment on lines +52 to +72
const animate = (currentTime) => {
const elapsed = currentTime - startTime;
const progress = Math.min(elapsed / duration, 1);

// Easing function for smooth animation
const easeOutCubic = 1 - Math.pow(1 - progress, 3);

const currentValue = startValue + (endValue - startValue) * easeOutCubic;
const roundedValue = Math.round(currentValue / (Number(props.step) || 1)) * (Number(props.step) || 1);

localStorage.setItem(props.name, roundedValue);
setValue(roundedValue);

if (progress < 1) {
animationRef.current = requestAnimationFrame(animate);
} else {
// Ensure we end exactly at the target value
localStorage.setItem(props.name, endValue);
setValue(endValue);
EventBus.emit('refresh', props.category);
}

Copilot AI Jan 25, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reset animation emits the 'refresh' event only at the end of the animation (line 71), but also updates localStorage during each animation frame (line 62). This could cause a performance issue if the refresh event triggers expensive operations. The previous implementation called refresh immediately. If components are listening to localStorage changes separately, they might update during the animation causing janky UI. Consider debouncing the refresh event or only updating localStorage at the end of the animation.

Copilot uses AI. Check for mistakes.
Comment on lines 42 to +77
const resetItem = useCallback(() => {
handleChange({
target: {
value: props.default || '',
},
});
if (animationRef.current) {
cancelAnimationFrame(animationRef.current);
}

const startValue = Number(value);
const endValue = Number(props.default || 0);
const duration = 300; // milliseconds
const startTime = performance.now();

const animate = (currentTime) => {
const elapsed = currentTime - startTime;
const progress = Math.min(elapsed / duration, 1);

// Easing function for smooth animation
const easeOutCubic = 1 - Math.pow(1 - progress, 3);

const currentValue = startValue + (endValue - startValue) * easeOutCubic;
const roundedValue = Math.round(currentValue / (Number(props.step) || 1)) * (Number(props.step) || 1);

localStorage.setItem(props.name, roundedValue);
setValue(roundedValue);

if (progress < 1) {
animationRef.current = requestAnimationFrame(animate);
} else {
// Ensure we end exactly at the target value
localStorage.setItem(props.name, endValue);
setValue(endValue);
EventBus.emit('refresh', props.category);
}
};

animationRef.current = requestAnimationFrame(animate);
toast(variables.getMessage('toasts.reset'));
}, [handleChange, props.default]);
}, [value, props]);

Copilot AI Jan 25, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The component is missing a cleanup for the animation when the component unmounts. If the user navigates away while the reset animation is running, the animationRef.current will still be scheduled and could cause a memory leak or errors when trying to update state on an unmounted component. Add a useEffect cleanup that cancels the animation frame on unmount.

Copilot uses AI. Check for mistakes.
@davidcralph
davidcralph self-requested a review January 25, 2026 20:58
@davidcralph
davidcralph merged commit 4cf5269 into beta Jan 25, 2026
10 of 11 checks passed
davidcralph added a commit that referenced this pull request Jan 27, 2026
* feat: add professional three-branch release workflow automation (#1129) (#1130)

- 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

* Sync/workflow fixes to beta (#1132)

* 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

* fix(workflows): prevent beta release for non-beta versions

* 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

---------

Signed-off-by: Alex Sparkes <alexsparkes@gmail.com>

* 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

* Dev (#1134)

* 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>

* font: replace montserrat with inter

* cleanup: remove unused code from addons and marketplace

* fix(greeting/events): event text box styling

* fix(quote/buttons): improve state management and event handling

* feat(background): implement custom background loading and improve state management

* feat: enhance image management features

- Added new localization strings for image management, including upload and storage information.
- Refactored custom background database functions to support metadata and backward compatibility.
- Introduced a new FolderTaggingModal component for organizing images into folders.
- Created utility functions for image metadata extraction, including dimensions, blur hash generation, and file size calculation.
- Implemented functions to delete multiple backgrounds and update background metadata.

* Add new localization strings and improve image metadata utility functions

- Updated localization files for multiple languages (Hungarian, Indonesian, Japanese, Lithuanian, Latvian, Dutch, Norwegian, Persian, Portuguese, Brazilian Portuguese, Russian, Slovenian, Swedish, Tamil, Turkish, Ukrainian, Vietnamese, Simplified Chinese, Traditional Chinese) to include new strings for image management features such as "Delete Selected", "Uploading", "Tag Images", and storage information.
- Enhanced the `getDataUrlSize` and `formatBytes` functions in `imageMetadata.js` for better readability and maintainability by adding braces for conditional statements.

* fix(background/custom): prevent flashing during uploads

* feat(storage): implement dynamic storage quota estimation and request persistence

* feat(modal): enhance close button styling and theming support

* fix(Custom): remove unnecessary characters from loading state

* feat(Dropdown): implement dropdown closing animation and portal rendering

* fix(QuoteOptions): ensure authorDetails is set to true for all users during migration

* refactor(Items): remove unused imports and hex color conversion logic

* fix: add blurhash dependency for image metadata encoding

---------

Signed-off-by: Alex Sparkes <alexsparkes@gmail.com>
Co-authored-by: David Ralph <me@davidcralph.co.uk>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants