Release 2.35.0 (#4072)

## Release Notes
Thanks to: @angeldeejay, @in-voker, @JHWelch, @khassel,
@KristjanESPERANTO, @rejas, @sdetweil
> ⚠️ This release needs nodejs version >=22.21.1 <23 || >=24 (no change
to previous release)

[Compare to previous Release
v2.34.0](https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.34.0...v2.25.0)

> ⚠️ We introduced some internal changes with this release, please read
[this forum
post](https://forum.magicmirror.builders/topic/20138/upcoming-release-april-1-2026-breaking-changes-some-operational-changes)
before upgrading!

### [core]
- Prepare Release 2.35.0 (#4071)
- docs: add security policy and vulnerability reporting guidelines
(#4069)
- refactor: simplify internal `require()` calls (#4056)
- allow environment variables in cors urls (#4033)
- fix cors proxy getting binary data (e.g. png, webp) (#4030)
- fix: correct secret redaction and optimize loadConfig (#4031)
- change loading config.js, allow variables in config.js and try to
protect sensitive data (#4029)
- remove kioskmode (#4027)
- Add dark theme logo (#4026)
- move custom.css from css to config (#4020)
- move default modules from /modules/default to /defaultmodules (#4019)
- update node versions in workflows (#4018)
- [core] refactor: extract and centralize HTTP fetcher (#4016)
- fix systeminformation not displaying electron version (#4012)
- Update node-ical and support it's rrule-temporal changes (#4010)
- Change default start scripts from X11 to Wayland (#4011)
- refactor: unify favicon for index.html and Electron (#4006)
- [core] run systeminformation in subprocess so the info is always
displayed (#4002)
- set next release dev number (#4000)

### [dependencies]
- update dependencies (#4068)
- update dependencies incl. electron to v41 (#4058)
- chore: upgrade ESLint to v10 and fix newly surfaced issues (#4057)
- chore: update ESLint and plugins, simplify config, apply new rules
(#4052)
- chore: update dependencies + add exports, files, and sideEffects
fields to package.json (#4040)
- [core] refactor: enable ESLint rule require-await and handle detected
issues (#4038)
- Update node-ical and other deps (#4025)
- chore: update dependencies (#4021)
- chore(eslint): migrate from eslint-plugin-vitest to
@vitest/eslint-plugin and run rules only on test files (#4014)
- Update deps as requested by dependabot (#4008)
- update Collaboration.md and dependencies (#4001)

### [logging]
- refactor: further logger clean-up (#4050)
- Fix Node.js v25 logging prefix and modernize logger (#4049)

### [modules/calendar]
- fix(calendar): make showEnd behavior more consistent across time
formats (#4059)
- test(calendar): fix hardcoded date in event shape test (#4055)
- [calendar] refactor: delegate event expansion to node-ical's
expandRecurringEvent (#4047)
- calendar.js: remove useless hasCalendarURL function (#4028)
- fix(calendar): update to node-ical 0.23.1 and fix full-day recurrence
lookup (#4013)
- fix(calendar): correct day-of-week for full-day recurring events
across all timezones (#4004)

### [modules/newsfeed]
- fix(newsfeed): fix full article view and add framing check (#4039)
- [newsfeed] refactor: migrate to centralized HTTPFetcher (#4023)

### [modules/weather]
- fix(weather): fix openmeteo forecast stuck in the past (#4064)
- fix(weather): fix weathergov forecast day labels off by one (#4065)
- weather: fixes for templates (#4054)
- weather: add possibility to override njk's and css (#4051)
- Use getDateString in openmeteo (#4046)
- [weather] refactor: migrate to server-side providers with centralized
HTTPFetcher (#4032)
- [weather] feat: add Weather API Provider  (#4036)

### [testing]
- chore: remove obsolete Jest config and unit test global setup (#4044)
- replace template_spec test with config_variables test (#4034)
- refactor(clientonly): modernize code structure and add comprehensive
tests (#4022)
- Switch to undici Agent for HTTPS requests (#4015)
- chore: migrate CI workflows to ubuntu-slim for faster startup times
(#4007)

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com>
Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: sam detweiler <sdetweil@gmail.com>
Co-authored-by: Veeck <github@veeck.de>
Co-authored-by: veeck <gitkraken@veeck.de>
Co-authored-by: Magnus <34011212+MagMar94@users.noreply.github.com>
Co-authored-by: Ikko Eltociear Ashimine <eltociear@gmail.com>
Co-authored-by: DevIncomin <56730075+Developer-Incoming@users.noreply.github.com>
Co-authored-by: Nathan <n8nyoung@gmail.com>
Co-authored-by: mixasgr <mixasgr@users.noreply.github.com>
Co-authored-by: Savvas Adamtziloglou <savvas-gr@greeklug.gr>
Co-authored-by: Konstantinos <geraki@gmail.com>
Co-authored-by: OWL4C <124401812+OWL4C@users.noreply.github.com>
Co-authored-by: BugHaver <43462320+bughaver@users.noreply.github.com>
Co-authored-by: BugHaver <43462320+lsaadeh@users.noreply.github.com>
Co-authored-by: Koen Konst <koenspero@gmail.com>
Co-authored-by: Koen Konst <c.h.konst@avisi.nl>
Co-authored-by: dathbe <github@beffa.us>
Co-authored-by: Marcel <m-idler@users.noreply.github.com>
Co-authored-by: Kevin G. <crazylegstoo@gmail.com>
Co-authored-by: Jboucly <33218155+jboucly@users.noreply.github.com>
Co-authored-by: Jboucly <contact@jboucly.fr>
Co-authored-by: Jarno <54169345+jarnoml@users.noreply.github.com>
Co-authored-by: Jordan Welch <JordanHWelch@gmail.com>
Co-authored-by: Blackspirits <blackspirits@gmail.com>
Co-authored-by: Samed Ozdemir <samed@xsor.io>
Co-authored-by: in-voker <58696565+in-voker@users.noreply.github.com>
Co-authored-by: Andrés Vanegas Jiménez <142350+angeldeejay@users.noreply.github.com>
This commit is contained in:
Karsten Hassel
2026-04-01 12:35:16 +02:00
committed by GitHub
parent b742e839be
commit d05ea751d9
294 changed files with 35941 additions and 10259 deletions
+6
View File
@@ -0,0 +1,6 @@
# Module: Clock
The `clock` module is one of the default modules of the MagicMirror².
This module displays the current date and time. The information will be updated realtime.
For configuration options, please check the [MagicMirror² documentation](https://docs.magicmirror.builders/modules/clock.html).
+318
View File
@@ -0,0 +1,318 @@
/* global SunCalc, formatTime */
Module.register("clock", {
// Module config defaults.
defaults: {
displayType: "digital", // options: digital, analog, both
timeFormat: config.timeFormat,
timezone: null,
displaySeconds: true,
showPeriod: true,
showPeriodUpper: false,
clockBold: false,
showDate: true,
showTime: true,
showWeek: false, // options: true, false, 'short'
dateFormat: "dddd, LL",
sendNotifications: false,
/* specific to the analog clock */
analogSize: "200px",
analogFace: "simple", // options: 'none', 'simple', 'face-###' (where ### is 001 to 012 inclusive)
analogPlacement: "bottom", // options: 'top', 'bottom', 'left', 'right'
analogShowDate: "top", // OBSOLETE, can be replaced with analogPlacement and showTime, options: false, 'top', or 'bottom'
secondsColor: "#888888", // DEPRECATED, use CSS instead. Class "clock-second-digital" for digital clock, "clock-second" for analog clock.
showSunTimes: false, // options: true, false, 'disableNextEvent'
showMoonTimes: false, // options: false, 'times' (rise/set), 'percent' (lit percent), 'phase' (current phase), or 'both' (percent & phase)
lat: 47.630539,
lon: -122.344147
},
// Define required scripts.
getScripts () {
return ["moment.js", "moment-timezone.js", "suncalc.js"];
},
// Define styles.
getStyles () {
return ["clock_styles.css", "font-awesome.css"];
},
// Define start sequence.
start () {
Log.info(`Starting module: ${this.name}`);
// Schedule update interval.
this.second = moment().second();
this.minute = moment().minute();
// Calculate how many ms should pass until next update depending on if seconds is displayed or not
const delayCalculator = (reducedSeconds) => {
const EXTRA_DELAY = 50; // Deliberate imperceptible delay to prevent off-by-one timekeeping errors
if (this.config.displaySeconds) {
return 1000 - moment().milliseconds() + EXTRA_DELAY;
} else {
return (60 - reducedSeconds) * 1000 - moment().milliseconds() + EXTRA_DELAY;
}
};
// A recursive timeout function instead of interval to avoid drifting
const notificationTimer = () => {
this.updateDom();
if (this.config.sendNotifications) {
// If seconds is displayed CLOCK_SECOND-notification should be sent (but not when CLOCK_MINUTE-notification is sent)
if (this.config.displaySeconds) {
this.second = moment().second();
if (this.second !== 0) {
this.sendNotification("CLOCK_SECOND", this.second);
setTimeout(notificationTimer, delayCalculator(0));
return;
}
}
// If minute changed or seconds isn't displayed send CLOCK_MINUTE-notification
this.minute = moment().minute();
this.sendNotification("CLOCK_MINUTE", this.minute);
}
setTimeout(notificationTimer, delayCalculator(0));
};
// Set the initial timeout with the amount of seconds elapsed as
// reducedSeconds, so it will trigger when the minute changes
setTimeout(notificationTimer, delayCalculator(this.second));
// Set locale.
moment.locale(config.language);
},
// Override dom generator.
getDom () {
const wrapper = document.createElement("div");
wrapper.classList.add("clock-grid");
/************************************
* Create wrappers for analog and digital clock
*/
const analogWrapper = document.createElement("div");
analogWrapper.className = "clock-circle";
const digitalWrapper = document.createElement("div");
digitalWrapper.className = "digital";
/************************************
* Create wrappers for DIGITAL clock
*/
const dateWrapper = document.createElement("div");
const timeWrapper = document.createElement("div");
const hoursWrapper = document.createElement("span");
const minutesWrapper = document.createElement("span");
const secondsWrapper = document.createElement("sup");
const periodWrapper = document.createElement("span");
const sunWrapper = document.createElement("div");
const moonWrapper = document.createElement("div");
const weekWrapper = document.createElement("div");
// Style Wrappers
dateWrapper.className = "date normal medium";
timeWrapper.className = "time bright large light";
hoursWrapper.className = "clock-hour-digital";
minutesWrapper.className = "clock-minute-digital";
secondsWrapper.className = "clock-second-digital dimmed";
sunWrapper.className = "sun dimmed small";
moonWrapper.className = "moon dimmed small";
weekWrapper.className = "week dimmed medium";
// Set content of wrappers.
const now = moment();
if (this.config.timezone) {
now.tz(this.config.timezone);
}
if (this.config.showDate) {
dateWrapper.innerHTML = now.format(this.config.dateFormat);
digitalWrapper.appendChild(dateWrapper);
}
if (this.config.displayType !== "analog" && this.config.showTime) {
let hourSymbol = "HH";
if (this.config.timeFormat !== 24) {
hourSymbol = "h";
}
hoursWrapper.innerHTML = now.format(hourSymbol);
minutesWrapper.innerHTML = now.format("mm");
timeWrapper.appendChild(hoursWrapper);
if (this.config.clockBold) {
minutesWrapper.classList.add("bold");
} else {
timeWrapper.innerHTML += ":";
}
timeWrapper.appendChild(minutesWrapper);
secondsWrapper.innerHTML = now.format("ss");
if (this.config.showPeriodUpper) {
periodWrapper.innerHTML = now.format("A");
} else {
periodWrapper.innerHTML = now.format("a");
}
if (this.config.displaySeconds) {
timeWrapper.appendChild(secondsWrapper);
}
if (this.config.showPeriod && this.config.timeFormat !== 24) {
timeWrapper.appendChild(periodWrapper);
}
digitalWrapper.appendChild(timeWrapper);
}
/****************************************************************
* Create wrappers for Sun Times, only if specified in config
*/
if (this.config.showSunTimes) {
const sunTimes = SunCalc.getTimes(now, this.config.lat, this.config.lon);
const isVisible = now.isBetween(sunTimes.sunrise, sunTimes.sunset);
let sunWrapperInnerHTML = "";
if (this.config.showSunTimes !== "disableNextEvent") {
let nextEvent;
if (now.isBefore(sunTimes.sunrise)) {
nextEvent = sunTimes.sunrise;
} else if (now.isBefore(sunTimes.sunset)) {
nextEvent = sunTimes.sunset;
} else {
const tomorrowSunTimes = SunCalc.getTimes(now.clone().add(1, "day"), this.config.lat, this.config.lon);
nextEvent = tomorrowSunTimes.sunrise;
}
const untilNextEvent = moment.duration(moment(nextEvent).diff(now));
const untilNextEventString = `${untilNextEvent.hours()}h ${untilNextEvent.minutes()}m`;
sunWrapperInnerHTML = `<span class="${isVisible ? "bright" : ""}"><i class="fas fa-sun" aria-hidden="true"></i> ${untilNextEventString}</span>`;
}
sunWrapperInnerHTML += `<span><i class="fas fa-arrow-up" aria-hidden="true"></i> ${formatTime(this.config, sunTimes.sunrise)}</span>`
+ `<span><i class="fas fa-arrow-down" aria-hidden="true"></i> ${formatTime(this.config, sunTimes.sunset)}</span>`;
sunWrapper.innerHTML = sunWrapperInnerHTML;
digitalWrapper.appendChild(sunWrapper);
}
/****************************************************************
* Create wrappers for Moon Times, only if specified in config
*/
if (this.config.showMoonTimes) {
const moonIllumination = SunCalc.getMoonIllumination(now.toDate());
const moonTimes = SunCalc.getMoonTimes(now, this.config.lat, this.config.lon);
const moonRise = moonTimes.rise;
let moonSet;
if (moment(moonTimes.set).isAfter(moonTimes.rise)) {
moonSet = moonTimes.set;
} else {
const nextMoonTimes = SunCalc.getMoonTimes(now.clone().add(1, "day"), this.config.lat, this.config.lon);
moonSet = nextMoonTimes.set;
}
const isVisible = now.isBetween(moonRise, moonSet) || moonTimes.alwaysUp === true;
const showFraction = ["both", "percent"].includes(this.config.showMoonTimes);
const showUnicode = ["both", "phase"].includes(this.config.showMoonTimes);
const illuminatedFractionString = `${Math.round(moonIllumination.fraction * 100)}%`;
const image = showUnicode ? [..."🌑🌒🌓🌔🌕🌖🌗🌘"][Math.floor(moonIllumination.phase * 8)] : "<i class=\"fas fa-moon\" aria-hidden=\"true\"></i>";
moonWrapper.innerHTML
= `<span class="${isVisible ? "bright" : ""}">${image} ${showFraction ? illuminatedFractionString : ""}</span>`
+ `<span><i class="fas fa-arrow-up" aria-hidden="true"></i> ${moonRise ? formatTime(this.config, moonRise) : "..."}</span>`
+ `<span><i class="fas fa-arrow-down" aria-hidden="true"></i> ${moonSet ? formatTime(this.config, moonSet) : "..."}</span>`;
digitalWrapper.appendChild(moonWrapper);
}
if (this.config.showWeek) {
if (this.config.showWeek === "short") {
weekWrapper.innerHTML = this.translate("WEEK_SHORT", { weekNumber: now.week() });
} else {
weekWrapper.innerHTML = this.translate("WEEK", { weekNumber: now.week() });
}
digitalWrapper.appendChild(weekWrapper);
}
/****************************************************************
* Create wrappers for ANALOG clock, only if specified in config
*/
if (this.config.displayType !== "digital") {
// If it isn't 'digital', then an 'analog' clock was also requested
// Calculate the degree offset for each hand of the clock
if (this.config.timezone) {
now.tz(this.config.timezone);
}
const second = now.seconds() * 6,
minute = now.minute() * 6 + second / 60,
hour = ((now.hours() % 12) / 12) * 360 + 90 + minute / 12;
// Create wrappers
analogWrapper.style.width = this.config.analogSize;
analogWrapper.style.height = this.config.analogSize;
if (this.config.analogFace !== "" && this.config.analogFace !== "simple" && this.config.analogFace !== "none") {
analogWrapper.style.background = `url(${this.data.path}faces/${this.config.analogFace}.svg)`;
analogWrapper.style.backgroundSize = "100%";
// The following line solves issue: https://github.com/MagicMirrorOrg/MagicMirror/issues/611
// analogWrapper.style.border = "1px solid black";
analogWrapper.style.border = "rgba(0, 0, 0, 0.1)"; //Updated fix for Issue 611 where non-black backgrounds are used
} else if (this.config.analogFace !== "none") {
analogWrapper.style.border = "2px solid white";
}
const clockFace = document.createElement("div");
clockFace.className = "clock-face";
const clockHour = document.createElement("div");
clockHour.id = "clock-hour";
clockHour.style.transform = `rotate(${hour}deg)`;
clockHour.className = "clock-hour";
const clockMinute = document.createElement("div");
clockMinute.id = "clock-minute";
clockMinute.style.transform = `rotate(${minute}deg)`;
clockMinute.className = "clock-minute";
// Combine analog wrappers
clockFace.appendChild(clockHour);
clockFace.appendChild(clockMinute);
if (this.config.displaySeconds) {
const clockSecond = document.createElement("div");
clockSecond.id = "clock-second";
clockSecond.style.transform = `rotate(${second}deg)`;
clockSecond.className = "clock-second";
clockSecond.style.backgroundColor = this.config.secondsColor; /* DEPRECATED, to be removed in a future version , use CSS instead */
clockFace.appendChild(clockSecond);
}
analogWrapper.appendChild(clockFace);
}
/*******************************************
* Update placement, respect old analogShowDate even if it's not needed anymore
*/
if (this.config.displayType === "analog") {
// Display only an analog clock
if (this.config.showDate) {
// Add date to the analog clock
dateWrapper.innerHTML = now.format(this.config.dateFormat);
wrapper.appendChild(dateWrapper);
}
if (this.config.analogShowDate === "bottom") {
wrapper.classList.add("clock-grid-bottom");
} else if (this.config.analogShowDate === "top") {
wrapper.classList.add("clock-grid-top");
}
wrapper.appendChild(analogWrapper);
} else if (this.config.displayType === "digital") {
wrapper.appendChild(digitalWrapper);
} else if (this.config.displayType === "both") {
wrapper.classList.add(`clock-grid-${this.config.analogPlacement}`);
wrapper.appendChild(analogWrapper);
wrapper.appendChild(digitalWrapper);
}
// Return the wrapper to the dom.
return wrapper;
}
});
+118
View File
@@ -0,0 +1,118 @@
.clock-grid {
display: inline-flex;
gap: 15px;
}
.clock-grid-left {
flex-direction: row;
}
.clock-grid-right {
flex-direction: row-reverse;
}
.clock-grid-top {
flex-direction: column;
}
.clock-grid-bottom {
flex-direction: column-reverse;
}
.clock-circle {
place-self: center;
position: relative;
border-radius: 50%;
background-size: 100%;
}
.clock-face {
width: 100%;
height: 100%;
}
.clock-face::after {
position: absolute;
top: 50%;
left: 50%;
width: 6px;
height: 6px;
margin: -3px 0 0 -3px;
background: var(--color-text-bright);
border-radius: 3px;
content: "";
display: block;
}
.clock-hour {
width: 0;
height: 0;
position: absolute;
top: 50%;
left: 50%;
margin: -2px 0 -2px -25%; /* numbers must match negative length & thickness */
padding: 2px 0 2px 25%; /* indicator length & thickness */
background: var(--color-text-bright);
transform-origin: 100% 50%;
border-radius: 3px 0 0 3px;
}
.clock-minute {
width: 0;
height: 0;
position: absolute;
top: 50%;
left: 50%;
margin: -35% -2px 0; /* numbers must match negative length & thickness */
padding: 35% 2px 0; /* indicator length & thickness */
background: var(--color-text-bright);
transform-origin: 50% 100%;
border-radius: 3px 0 0 3px;
}
.clock-second {
width: 0;
height: 0;
position: absolute;
top: 50%;
left: 50%;
margin: -38% -1px 0 0; /* numbers must match negative length & thickness */
padding: 38% 1px 0 0; /* indicator length & thickness */
/* background: #888888 !important; */
/* use this instead of secondsColor */
/* have to use !important, because the code explicitly sets the color currently */
transform-origin: 50% 100%;
}
.module.clock .digital {
display: flex;
flex-direction: column;
gap: 3px;
}
.module.clock .sun,
.module.clock .moon {
display: flex;
white-space: nowrap;
gap: 10px;
}
.module.clock .sun > *,
.module.clock .moon > * {
flex: 1;
}
.module.clock .clock-hour-digital {
color: var(--color-text-bright);
}
.module.clock .clock-minute-digital {
color: var(--color-text-bright);
}
.module.clock .clock-second-digital {
color: var(--color-text-dimmed);
}
+1
View File
@@ -0,0 +1 @@
<svg id="Hour_Markers_-_Singlets" data-name="Hour Markers - Singlets" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 250 250"><defs><style>.cls-1,.cls-2{fill:none;stroke:#fff;stroke-linecap:round;stroke-miterlimit:10;}.cls-2{stroke-width:0.5px;}</style></defs><title>face-001</title><line class="cls-1" x1="125" y1="1.25" x2="125" y2="16.23"/><line class="cls-1" x1="186.87" y1="17.83" x2="179.39" y2="30.8"/><line class="cls-1" x1="232.17" y1="63.12" x2="219.2" y2="70.61"/><line class="cls-1" x1="248.75" y1="125" x2="233.77" y2="125"/><line class="cls-1" x1="232.17" y1="186.87" x2="219.2" y2="179.39"/><line class="cls-1" x1="186.88" y1="232.17" x2="179.39" y2="219.2"/><line class="cls-1" x1="125" y1="248.75" x2="125" y2="233.77"/><line class="cls-1" x1="63.13" y1="232.17" x2="70.61" y2="219.2"/><line class="cls-1" x1="17.83" y1="186.88" x2="30.8" y2="179.39"/><line class="cls-1" x1="1.25" y1="125" x2="16.23" y2="125"/><line class="cls-1" x1="17.83" y1="63.13" x2="30.8" y2="70.61"/><line class="cls-1" x1="63.12" y1="17.83" x2="70.61" y2="30.8"/><line class="cls-2" x1="138.01" y1="1.25" x2="136.96" y2="11.23"/><line class="cls-2" x1="150.87" y1="3.29" x2="148.78" y2="13.11"/><line class="cls-2" x1="163.45" y1="6.66" x2="160.35" y2="16.21"/><line class="cls-2" x1="175.61" y1="11.33" x2="171.53" y2="20.5"/><line class="cls-2" x1="198.14" y1="24.33" x2="192.24" y2="32.45"/><line class="cls-2" x1="208.26" y1="32.53" x2="201.54" y2="39.99"/><line class="cls-2" x1="217.47" y1="41.74" x2="210.01" y2="48.46"/><line class="cls-2" x1="225.67" y1="51.86" x2="217.55" y2="57.76"/><line class="cls-2" x1="238.67" y1="74.39" x2="229.5" y2="78.47"/><line class="cls-2" x1="243.34" y1="86.55" x2="233.79" y2="89.65"/><line class="cls-2" x1="246.71" y1="99.13" x2="236.89" y2="101.22"/><line class="cls-2" x1="248.75" y1="111.99" x2="238.77" y2="113.04"/><line class="cls-2" x1="248.75" y1="138.01" x2="238.77" y2="136.96"/><line class="cls-2" x1="246.71" y1="150.87" x2="236.89" y2="148.78"/><line class="cls-2" x1="243.34" y1="163.45" x2="233.79" y2="160.35"/><line class="cls-2" x1="238.67" y1="175.61" x2="229.5" y2="171.53"/><line class="cls-2" x1="225.67" y1="198.14" x2="217.55" y2="192.24"/><line class="cls-2" x1="217.47" y1="208.26" x2="210.01" y2="201.54"/><line class="cls-2" x1="208.26" y1="217.47" x2="201.54" y2="210.01"/><line class="cls-2" x1="198.14" y1="225.67" x2="192.24" y2="217.55"/><line class="cls-2" x1="175.61" y1="238.67" x2="171.53" y2="229.5"/><line class="cls-2" x1="163.45" y1="243.34" x2="160.35" y2="233.79"/><line class="cls-2" x1="150.87" y1="246.71" x2="148.78" y2="236.89"/><line class="cls-2" x1="138.01" y1="248.75" x2="136.96" y2="238.77"/><line class="cls-2" x1="111.99" y1="248.75" x2="113.04" y2="238.77"/><line class="cls-2" x1="99.13" y1="246.71" x2="101.22" y2="236.89"/><line class="cls-2" x1="86.55" y1="243.34" x2="89.65" y2="233.79"/><line class="cls-2" x1="74.39" y1="238.67" x2="78.47" y2="229.5"/><line class="cls-2" x1="51.86" y1="225.67" x2="57.76" y2="217.55"/><line class="cls-2" x1="41.74" y1="217.47" x2="48.46" y2="210.01"/><line class="cls-2" x1="32.53" y1="208.26" x2="39.99" y2="201.54"/><line class="cls-2" x1="24.33" y1="198.14" x2="32.45" y2="192.24"/><line class="cls-2" x1="11.33" y1="175.61" x2="20.5" y2="171.53"/><line class="cls-2" x1="6.66" y1="163.45" x2="16.21" y2="160.35"/><line class="cls-2" x1="3.29" y1="150.87" x2="13.11" y2="148.78"/><line class="cls-2" x1="1.25" y1="138.01" x2="11.23" y2="136.96"/><line class="cls-2" x1="1.25" y1="111.99" x2="11.23" y2="113.04"/><line class="cls-2" x1="3.29" y1="99.13" x2="13.11" y2="101.22"/><line class="cls-2" x1="6.66" y1="86.55" x2="16.21" y2="89.65"/><line class="cls-2" x1="11.33" y1="74.39" x2="20.5" y2="78.47"/><line class="cls-2" x1="24.33" y1="51.86" x2="32.45" y2="57.76"/><line class="cls-2" x1="32.53" y1="41.74" x2="39.99" y2="48.46"/><line class="cls-2" x1="41.74" y1="32.53" x2="48.46" y2="39.99"/><line class="cls-2" x1="51.86" y1="24.33" x2="57.76" y2="32.45"/><line class="cls-2" x1="74.39" y1="11.33" x2="78.47" y2="20.5"/><line class="cls-2" x1="86.55" y1="6.66" x2="89.65" y2="16.21"/><line class="cls-2" x1="99.13" y1="3.29" x2="101.22" y2="13.11"/><line class="cls-2" x1="111.99" y1="1.25" x2="113.04" y2="11.23"/></svg>

After

Width:  |  Height:  |  Size: 4.2 KiB

+1
View File
@@ -0,0 +1 @@
<svg id="Hour_Markers_-_Doubles" data-name="Hour Markers - Doubles" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 250 250"><defs><style>.cls-1{fill:none;stroke:#fff;stroke-linecap:round;stroke-miterlimit:10;stroke-width:2.98px;}</style></defs><title>face-002</title><line class="cls-1" x1="122.01" y1="1.75" x2="122.01" y2="16.67"/><line class="cls-1" x1="186.62" y1="18.26" x2="179.17" y2="31.18"/><line class="cls-1" x1="231.74" y1="63.37" x2="218.82" y2="70.83"/><line class="cls-1" x1="248.25" y1="127.99" x2="233.33" y2="127.99"/><line class="cls-1" x1="231.74" y1="186.62" x2="218.82" y2="179.17"/><line class="cls-1" x1="186.63" y1="231.74" x2="179.17" y2="218.82"/><line class="cls-1" x1="127.99" y1="248.25" x2="127.99" y2="233.33"/><line class="cls-1" x1="63.38" y1="231.74" x2="70.83" y2="218.82"/><line class="cls-1" x1="18.26" y1="186.63" x2="31.18" y2="179.17"/><line class="cls-1" x1="1.75" y1="122.01" x2="16.67" y2="122.01"/><line class="cls-1" x1="18.26" y1="63.38" x2="31.18" y2="70.83"/><line class="cls-1" x1="63.37" y1="18.26" x2="70.83" y2="31.18"/><line class="cls-1" x1="127.99" y1="1.75" x2="127.99" y2="16.67"/><line class="cls-1" x1="248.25" y1="122.01" x2="233.33" y2="122.01"/><line class="cls-1" x1="122.01" y1="248.25" x2="122.01" y2="233.33"/><line class="cls-1" x1="1.75" y1="127.99" x2="16.67" y2="127.99"/></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.2 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.2 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 17 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 15 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.8 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 18 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 17 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.2 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.1 KiB