move default modules from /modules/default to /defaultmodules (#4019)
Since the project's inception, I've missed a clear separation between default and third-party modules. This increases complexity within the project (exclude `modules`, but not `modules/default`), but the mixed use is particularly problematic in Docker setups. Therefore, with this pull request, I'm moving the default modules to a different directory. ~~I've chosen `default/modules`, but I'm not bothered about it; `defaultmodules` or something similar would work just as well.~~ Changed to `defaultmodules`. Let me know if there's a majority in favor of this change.
6
defaultmodules/clock/README.md
Normal 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
defaultmodules/clock/clock.js
Normal 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
defaultmodules/clock/clock_styles.css
Normal 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
defaultmodules/clock/faces/face-001.svg
Normal 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
defaultmodules/clock/faces/face-002.svg
Normal 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 |
1
defaultmodules/clock/faces/face-003.svg
Normal file
|
After Width: | Height: | Size: 7.2 KiB |
1
defaultmodules/clock/faces/face-004.svg
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
1
defaultmodules/clock/faces/face-005.svg
Normal file
|
After Width: | Height: | Size: 17 KiB |
1
defaultmodules/clock/faces/face-006.svg
Normal file
|
After Width: | Height: | Size: 15 KiB |
1
defaultmodules/clock/faces/face-007.svg
Normal file
|
After Width: | Height: | Size: 11 KiB |
1
defaultmodules/clock/faces/face-008.svg
Normal file
|
After Width: | Height: | Size: 6.8 KiB |
1
defaultmodules/clock/faces/face-009.svg
Normal file
|
After Width: | Height: | Size: 18 KiB |
1
defaultmodules/clock/faces/face-010.svg
Normal file
|
After Width: | Height: | Size: 17 KiB |
1
defaultmodules/clock/faces/face-011.svg
Normal file
|
After Width: | Height: | Size: 7.2 KiB |
1
defaultmodules/clock/faces/face-012.svg
Normal file
|
After Width: | Height: | Size: 7.1 KiB |