mirror of
https://github.com/alesimula/Murine-launcher.git
synced 2026-10-28 09:43:42 +00:00
WEBSITE - WIP - icon shapes - editor fixes + fit to top left quarter
This commit is contained in:
1 parent
e5623ed823
commit
ea5f458a95
3 files changed
+23
-16
No files matched your search
+1
-1
@@ -5,7 +5,7 @@ description: >-
|
||||
url: "https://alesimula.github.io"
|
||||
baseurl: ""
|
||||
|
||||
version: "1.0.16" #Website version - increase to invalidate cached resources
|
||||
version: "1.0.17" #Website version - increase to invalidate cached resources
|
||||
github_repo: "alesimula/Murine-launcher"
|
||||
icon_url: "https://raw.githubusercontent.com/alesimula/Murine-launcher/refs/heads/main/image/app_icon/icon_browser_fullsize.svg"
|
||||
icon_freeform_url: "https://raw.githubusercontent.com/alesimula/Murine-launcher/refs/heads/main/image/app_icon/icon_freeform.svg"
|
||||
|
||||
@@ -152,12 +152,6 @@
|
||||
const k = Math.min(kx, ky), cx = lockX ? 50 : bb.x + bb.width / 2, cy = lockY ? 50 : bb.y + bb.height / 2;
|
||||
return list.map((s) => transform(s, k, cx, cy, 50, 50));
|
||||
}
|
||||
// Puts `sh` where `old` was: same centre, longest side as long as old's.
|
||||
function placeLike(sh, old) {
|
||||
const a = measure(shapePath(old)), b = measure(shapePath(sh));
|
||||
const k = Math.max(a.width, a.height) / Math.max(b.width, b.height, 0.01);
|
||||
return { ...transform(sh, k, b.x + b.width / 2, b.y + b.height / 2, a.x + a.width / 2, a.y + a.height / 2), mirror: old.mirror };
|
||||
}
|
||||
const presetShapes = (name) => (Object.hasOwn(FIXED, name)
|
||||
? [{ fixed: name, a: 1, x: 0, y: 0, mirror: 'none' }]
|
||||
: [{ pts: fit(PRESETS[name]()), mirror: 'none' }]);
|
||||
@@ -400,7 +394,7 @@
|
||||
h.setAttribute('x', c.x - 2); h.setAttribute('y', c.y - 2);
|
||||
});
|
||||
}
|
||||
$('se-fit-shape').hidden = $('se-mirror').hidden = !moving;
|
||||
$('se-fit-tools').hidden = $('se-mirror').hidden = !moving;
|
||||
for (const b of $('se-mirror').querySelectorAll('button')) b.setAttribute('aria-pressed', b.dataset.mirror === shapes[active].mirror);
|
||||
|
||||
renderCards();
|
||||
@@ -642,6 +636,14 @@
|
||||
|
||||
// Move mode's buttons on the canvas: fit this shape, and mirroring.
|
||||
$('se-fit-shape').onclick = () => { checkpoint(); shapes[active] = fitted([shapes[active]])[0]; sync(); render(); };
|
||||
// The shape's own outline (not its mirrored copies) into the top-left quarter, centred there: an ear
|
||||
// mirrored left/right or both ways then fills the other quarters.
|
||||
$('se-fit-quarter').onclick = () => {
|
||||
const bb = measure(shapePath(shapes[active])), k = 50 / Math.max(bb.width, bb.height, 0.01);
|
||||
checkpoint();
|
||||
shapes[active] = transform(shapes[active], k, bb.x + bb.width / 2, bb.y + bb.height / 2, 25, 25);
|
||||
sync(); render();
|
||||
};
|
||||
$('se-mirror').addEventListener('click', (e) => {
|
||||
const b = e.target.closest('[data-mirror]');
|
||||
if (!b || b.dataset.mirror === shapes[active].mirror) return;
|
||||
@@ -691,8 +693,8 @@
|
||||
$('se-gen').onclick = () => {
|
||||
const n = clamp(+$('se-sides').value || 6, 3, 24), inner = clamp(+$('se-inner').value || 100, 10, 100) / 100;
|
||||
const num = (id, max) => clamp(+$(id).value || 0, 0, max); // empty or junk input counts as 0
|
||||
const made = { pts: fit(polygon(n, inner, +$('se-rot').value || 0, num('se-gen-r', 50), num('se-gen-ir', 50), num('se-gen-s', 100) / 100)), mirror: 'none' };
|
||||
replaceShape(placeLike(made, shapes[active])); // takes the selected shape's place and size
|
||||
const pts = fit(polygon(n, inner, +$('se-rot').value || 0, num('se-gen-r', 50), num('se-gen-ir', 50), num('se-gen-s', 100) / 100));
|
||||
replaceShape({ pts, mirror: 'none' }); // a fresh full-size shape: no leftover mirroring either
|
||||
};
|
||||
|
||||
$('se-show-grid').onchange = (e) => { grid.show = e.target.checked; drawGrid(); };
|
||||
@@ -750,7 +752,7 @@
|
||||
// ---------- presets ----------
|
||||
|
||||
// A preset in the grid replaces the whole icon; picked from the "+" card it is added as new shapes,
|
||||
// at half size in the middle and in Move mode, ready to be placed.
|
||||
// full canvas size and in Move mode, ready to be resized and placed.
|
||||
const tile = (name) => {
|
||||
const b = document.createElement('button');
|
||||
b.type = 'button';
|
||||
@@ -765,7 +767,7 @@
|
||||
const a = tile(name);
|
||||
a.onclick = () => {
|
||||
checkpoint();
|
||||
shapes.push(...presetShapes(name).map((s) => transform(s, 0.5, 50, 50, 50, 50)));
|
||||
shapes.push(...presetShapes(name));
|
||||
active = shapes.length - 1; sel = -1; mode = 'move';
|
||||
sync(); addDialog.close(); render();
|
||||
};
|
||||
|
||||
@@ -111,7 +111,8 @@ noindex: true # and out of search engines
|
||||
@media (prefers-reduced-motion: reduce) { .se-shake { animation: none; } }
|
||||
.se-stage-btn, .se-mirror button { display: inline-flex; align-items: center; justify-content: center; padding: 0;
|
||||
border-radius: var(--md-shape-full); color: var(--md-primary); cursor: pointer; }
|
||||
.se-stage-btn { position: absolute; top: 10px; right: 10px; width: 40px; height: 40px;
|
||||
.se-stage-tools { position: absolute; top: 10px; right: 10px; display: flex; gap: 6px; }
|
||||
.se-stage-btn { width: 40px; height: 40px;
|
||||
border: 1px solid var(--md-outline-variant); background: var(--md-surface-container-low); box-shadow: var(--md-shadow); }
|
||||
.se-mirror { position: absolute; left: 10px; bottom: 10px; display: flex; gap: 2px; padding: 3px;
|
||||
border-radius: var(--md-shape-full); border: 1px solid var(--md-outline-variant);
|
||||
@@ -120,7 +121,8 @@ noindex: true # and out of search engines
|
||||
.se-mirror button[aria-pressed="true"] { background: var(--md-primary-container); color: var(--md-on-primary-container); }
|
||||
.se-mirror svg { width: 20px; height: 20px; }
|
||||
.se-stage-btn:hover, .se-mirror button:hover { background: var(--md-surface-container-high); }
|
||||
.se-stage-btn[hidden], .se-mirror[hidden] { display: none; }
|
||||
.se-stage-tools[hidden], .se-mirror[hidden] { display: none; }
|
||||
.se-stage-btn svg { width: 22px; height: 22px; }
|
||||
/* Shape cards under the canvas. */
|
||||
.se-cards { display: flex; gap: 10px; overflow-x: auto; padding: 12px 2px 6px; }
|
||||
.se-card { position: relative; flex: 0 0 104px; display: flex; flex-direction: column; align-items: center;
|
||||
@@ -180,7 +182,10 @@ noindex: true # and out of search engines
|
||||
<rect class="se-resize" width="4" height="4" style="cursor: nesw-resize"/>
|
||||
</g>
|
||||
</svg>
|
||||
<button id="se-fit-shape" class="se-stage-btn" type="button" title="Fit this shape to the box" aria-label="Fit this shape to the box" hidden><span class="material-symbols-outlined" aria-hidden="true"></span></button>
|
||||
<div id="se-fit-tools" class="se-stage-tools" hidden>
|
||||
<button id="se-fit-quarter" class="se-stage-btn" type="button" title="Fit this shape into the top-left quarter" aria-label="Fit this shape into the top-left quarter"><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="3.5" y="3.5" width="17" height="17" rx="2" fill="none" stroke="currentColor" stroke-width="1.8" stroke-dasharray="3 2"/><rect x="5.5" y="5.5" width="6.5" height="6.5" rx="1.5" fill="currentColor"/></svg></button>
|
||||
<button id="se-fit-shape" class="se-stage-btn" type="button" title="Fit this shape to the box" aria-label="Fit this shape to the box"><span class="material-symbols-outlined" aria-hidden="true"></span></button>
|
||||
</div>
|
||||
<div id="se-mirror" class="se-mirror" role="group" aria-label="Mirror" hidden>
|
||||
<button type="button" data-mirror="none" title="No mirroring" aria-label="No mirroring"><svg viewBox="0 0 20 20" fill="currentColor"><path d="M6 4l6 6-6 6z"/></svg></button>
|
||||
<button type="button" data-mirror="h" title="Mirror left and right" aria-label="Mirror left and right"><svg viewBox="0 0 20 20" fill="currentColor"><path d="M10 2v16" stroke="currentColor" stroke-width="1.2" stroke-dasharray="2 1.6" fill="none"/><path d="M2 5l5 5-5 5zM18 5l-5 5 5 5z"/></svg></button>
|
||||
@@ -303,7 +308,7 @@ noindex: true # and out of search engines
|
||||
<span class="material-symbols-outlined"></span> <!-- close -->
|
||||
</button>
|
||||
</div>
|
||||
<p class="contact-modal-desc">Pick a starting point. It's added at half size in the middle, ready to move and resize.</p>
|
||||
<p class="contact-modal-desc">Pick a starting point. It's added at full size, ready to move and resize.</p>
|
||||
<div id="se-add-grid" class="se-presets"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user