Fix website styling
|
|
@ -22,7 +22,7 @@ cd frontend
|
|||
npm install
|
||||
```
|
||||
|
||||
You only need to explicitly install Node.js dependencies. Rust's cargo dependencies will be installed automatically on your first build. One dependency in the build chain, `wasm-pack`, will be installed automatically on your system when the Node.js packages are installing. If you prefer to install this manually, you can get it from the [wasm-pack website](https://rustwasm.github.io/wasm-pack/), then install dependencies with `npm install --no-optional`. **This is necessary on Apple Silicon/M1 Macs** until [this bug](https://github.com/rustwasm/wasm-pack/issues/952) is fixed.
|
||||
You only need to explicitly install Node.js dependencies. Rust's cargo dependencies will be installed automatically on your first build. One dependency in the build chain, `wasm-pack`, will be installed automatically on your system when the Node.js packages are installing. If you prefer to install this manually, you can get it from the [wasm-pack website](https://rustwasm.github.io/wasm-pack/), then install your npm dependencies with `npm install --no-optional`.
|
||||
|
||||
To run the project while developing:
|
||||
```
|
||||
|
|
|
|||
|
|
@ -1,16 +1,11 @@
|
|||
:root {
|
||||
--color-walnut: #473a3a;
|
||||
--color-manilla: #f1decd;
|
||||
--color-mustard: #deba92;
|
||||
--color-crimson: #803847;
|
||||
--color-navy: #16323f;
|
||||
--color-white: #ffffff;
|
||||
--color-fog: #eeeeee;
|
||||
--color-black: #000000;
|
||||
--max-width: 1600px;
|
||||
--max-width-plus-padding: calc(var(--max-width) + 40px * 2);
|
||||
--variable-px: Min(1px, 0.15vw);
|
||||
--page-edge-padding: 40px;
|
||||
--border-thickness: 2px;
|
||||
--color-navy: #16323f;
|
||||
--color-walnut: #473a3a;
|
||||
--color-crimson: #803847;
|
||||
--color-mustard: #e5c299;
|
||||
|
||||
--font-size-intro-heading: 60px;
|
||||
--font-size-intro-body: 22px;
|
||||
--font-size-link: 24px;
|
||||
|
|
@ -21,12 +16,20 @@
|
|||
--font-size-article-h2: 24px;
|
||||
--font-size-article-h3: 18px;
|
||||
|
||||
--max-width: 1600px;
|
||||
--max-width-plus-padding: calc(var(--max-width) + 40px * 2);
|
||||
|
||||
--variable-px: Min(1px, 0.15vw);
|
||||
--page-edge-padding: 40px;
|
||||
--border-thickness: 2px;
|
||||
|
||||
@media screen and (max-width: 760px) {
|
||||
--font-size-intro-heading: 40px;
|
||||
--font-size-intro-body: 18px;
|
||||
--font-size-link: 20px;
|
||||
--font-size-heading: 32px;
|
||||
--font-size-body: 16px;
|
||||
|
||||
--page-edge-padding: 28px;
|
||||
}
|
||||
|
||||
|
|
@ -36,8 +39,9 @@
|
|||
--font-size-link: 16px;
|
||||
--font-size-heading: 28px;
|
||||
--font-size-body: 16px;
|
||||
--border-thickness: 1px;
|
||||
|
||||
--page-edge-padding: 20px;
|
||||
--border-thickness: 1px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 400px) {
|
||||
|
|
@ -46,6 +50,7 @@
|
|||
--font-size-link: 14px;
|
||||
--font-size-heading: 24px;
|
||||
--font-size-body: 16px;
|
||||
|
||||
--page-edge-padding: 12px;
|
||||
}
|
||||
}
|
||||
|
|
@ -57,7 +62,7 @@ body {
|
|||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
background: white;
|
||||
background: var(--color-white);
|
||||
font-family: "Inter", sans-serif;
|
||||
line-height: 1.5;
|
||||
font-weight: 500;
|
||||
|
|
|
|||
|
|
@ -125,8 +125,8 @@
|
|||
mask-size: contain;
|
||||
|
||||
&.left {
|
||||
padding-left: 120px;
|
||||
margin-left: -120px;
|
||||
padding-left: 80px;
|
||||
margin-left: -80px;
|
||||
-webkit-mask-image: url("https://static.graphite.rs/textures/torn-edge-left.png");
|
||||
mask-image: url("https://static.graphite.rs/textures/torn-edge-left.png");
|
||||
-webkit-mask-position: top left;
|
||||
|
|
@ -208,16 +208,16 @@
|
|||
}
|
||||
|
||||
@media screen and (max-width: 1000px) {
|
||||
margin-left: -40px;
|
||||
margin-right: -40px;
|
||||
margin-left: calc(-1 * var(--page-edge-padding));
|
||||
margin-right: calc(-1 * var(--page-edge-padding));
|
||||
|
||||
.screenshot-details {
|
||||
margin-left: 40px;
|
||||
margin-right: 40px;
|
||||
margin-left: var(--page-edge-padding);
|
||||
margin-right: var(--page-edge-padding);
|
||||
}
|
||||
|
||||
hr {
|
||||
width: calc(100% - (32px + 40px) * 2);
|
||||
width: calc(100% - (32px + var(--page-edge-padding)) * 2);
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,12 +11,12 @@
|
|||
}
|
||||
|
||||
&.color {
|
||||
background-color: var(--color-fog);
|
||||
background-blend-mode: color-burn;
|
||||
background-color: var(--color-white);
|
||||
background-blend-mode: hard-light;
|
||||
}
|
||||
|
||||
&.light {
|
||||
background-color: var(--color-manilla);
|
||||
background-color: var(--color-fog);
|
||||
background-blend-mode: color-burn;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 8.9 KiB |
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<browserconfig>
|
||||
<msapplication>
|
||||
<tile>
|
||||
<square150x150logo src="/mstile-150x150.png"/>
|
||||
<TileColor>#f1decd</TileColor>
|
||||
</tile>
|
||||
</msapplication>
|
||||
</browserconfig>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
|
@ -0,0 +1,164 @@
|
|||
const FLING_VELOCITY_THRESHOLD = 10;
|
||||
const FLING_VELOCITY_WINDOW_SIZE = 20;
|
||||
|
||||
let carouselImages;
|
||||
let carouselDirectionPrev;
|
||||
let carouselDirectionNext;
|
||||
let carouselDots;
|
||||
let carouselDescriptions;
|
||||
let carouselDragLastClientX;
|
||||
const velocityDeltaWindow = Array.from({ length: FLING_VELOCITY_WINDOW_SIZE }, () => ({ time: 0, delta: 0 }));
|
||||
|
||||
window.addEventListener("DOMContentLoaded", initializeCarousel);
|
||||
window.addEventListener("pointerup", () => dragEnd(false));
|
||||
window.addEventListener("scroll", () => dragEnd(true));
|
||||
window.addEventListener("pointermove", dragMove);
|
||||
|
||||
function initializeCarousel() {
|
||||
carouselImages = document.querySelectorAll(".carousel img");
|
||||
carouselImages.forEach((image) => {
|
||||
image.addEventListener("pointerdown", dragBegin);
|
||||
});
|
||||
|
||||
carouselDirectionPrev = document.querySelector(".carousel-controls .direction.prev");
|
||||
carouselDirectionNext = document.querySelector(".carousel-controls .direction.next");
|
||||
carouselDots = document.querySelectorAll(".carousel-controls .dot");
|
||||
carouselDescriptions = document.querySelectorAll(".screenshot-description p");
|
||||
|
||||
carouselDirectionPrev.addEventListener("click", () => slideDirection("prev", true, false));
|
||||
carouselDirectionNext.addEventListener("click", () => slideDirection("next", true, false));
|
||||
Array.from(carouselDots).forEach((dot) =>
|
||||
dot.addEventListener("click", (event) => {
|
||||
const index = Array.from(carouselDots).indexOf(event.target);
|
||||
slideTo(index, true);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function slideDirection(direction, smooth, clamped = false) {
|
||||
const directionIndexOffset = { prev: -1, next: 1 }[direction];
|
||||
const offsetDotIndex = currentClosestImageIndex() + directionIndexOffset;
|
||||
|
||||
const nextDotIndex = (offsetDotIndex + carouselDots.length) % carouselDots.length;
|
||||
const unwrappedNextDotIndex = clamp(offsetDotIndex, 0, carouselDots.length - 1);
|
||||
|
||||
if (clamped) slideTo(unwrappedNextDotIndex, smooth);
|
||||
else slideTo(nextDotIndex, smooth);
|
||||
}
|
||||
|
||||
function slideTo(index, smooth) {
|
||||
const activeDot = document.querySelector(".carousel-controls .dot.active");
|
||||
activeDot.classList.remove("active");
|
||||
carouselDots[index].classList.add("active");
|
||||
|
||||
const activeDescription = document.querySelector(".screenshot-description p.active");
|
||||
activeDescription.classList.remove("active");
|
||||
carouselDescriptions[index].classList.add("active");
|
||||
|
||||
setCurrentTransform(index * -100, "%", smooth);
|
||||
}
|
||||
|
||||
function currentTransform() {
|
||||
const currentTransformMatrix = window.getComputedStyle(carouselImages[0]).transform;
|
||||
// Grab the X value from the format that looks like: `matrix(1, 0, 0, 1, -1332.13, 0)` or `none`
|
||||
return Number(currentTransformMatrix.split(",")[4] || "0");
|
||||
}
|
||||
|
||||
function setCurrentTransform(x, unit, smooth) {
|
||||
Array.from(carouselImages).forEach((image) => {
|
||||
image.style.transitionTimingFunction = smooth ? "ease-in-out" : "cubic-bezier(0, 0, 0.2, 1)";
|
||||
image.style.transform = `translateX(${x}${unit})`;
|
||||
});
|
||||
}
|
||||
|
||||
function currentClosestImageIndex() {
|
||||
const currentTransformX = -currentTransform();
|
||||
|
||||
const imageWidth = carouselImages[0].getBoundingClientRect().width;
|
||||
return Math.round(currentTransformX / imageWidth);
|
||||
}
|
||||
|
||||
function currentActiveDotIndex() {
|
||||
const activeDot = document.querySelector(".carousel-controls .dot.active");
|
||||
return Array.from(carouselDots).indexOf(activeDot);
|
||||
}
|
||||
|
||||
function dragBegin(event) {
|
||||
event.preventDefault();
|
||||
|
||||
carouselDragLastClientX = event.clientX;
|
||||
|
||||
setCurrentTransform(currentTransform(), "px", false);
|
||||
document.querySelector("#screenshots").classList.add("dragging");
|
||||
}
|
||||
|
||||
function dragEnd(dropWithoutVelocity) {
|
||||
if (!carouselImages) return;
|
||||
|
||||
carouselDragLastClientX = undefined;
|
||||
|
||||
document.querySelector("#screenshots").classList.remove("dragging");
|
||||
|
||||
const onlyRecentVelocityDeltaWindow = velocityDeltaWindow.filter((delta) => delta.time > Date.now() - 1000);
|
||||
const timeRange = Date.now() - (onlyRecentVelocityDeltaWindow[0]?.time ?? NaN);
|
||||
// Weighted (higher by recency) sum of velocity deltas from previous window of frames
|
||||
const recentVelocity = onlyRecentVelocityDeltaWindow.reduce((acc, entry) => {
|
||||
const timeSinceNow = Date.now() - entry.time;
|
||||
const recencyFactorScore = 1 - timeSinceNow / timeRange;
|
||||
|
||||
return acc + entry.delta * recencyFactorScore;
|
||||
}, 0);
|
||||
|
||||
const closestImageIndex = currentClosestImageIndex();
|
||||
const activeDotIndex = currentActiveDotIndex();
|
||||
|
||||
// If the speed is fast enough, slide to the next or previous image in that direction
|
||||
if (Math.abs(recentVelocity) > FLING_VELOCITY_THRESHOLD && !dropWithoutVelocity) {
|
||||
// Positive velocity should go to the previous image
|
||||
if (recentVelocity > 0) {
|
||||
// Don't apply the velocity-based fling if we're already snapping to the next image
|
||||
if (closestImageIndex >= activeDotIndex) {
|
||||
slideDirection("prev", false, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Negative velocity should go to the next image
|
||||
else {
|
||||
// Don't apply the velocity-based fling if we're already snapping to the next image
|
||||
// eslint-disable-next-line no-lonely-if
|
||||
if (closestImageIndex <= activeDotIndex) {
|
||||
slideDirection("next", false, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we didn't slide in a direction due to clear velocity, just snap to the closest image
|
||||
// This can be reached either by not entering the if statement above, or by its inner if statements not returning early and exiting back to this scope
|
||||
slideTo(clamp(closestImageIndex, 0, carouselDots.length - 1), true);
|
||||
}
|
||||
|
||||
function dragMove(event) {
|
||||
if (carouselDragLastClientX === undefined) return;
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
const LEFT_MOUSE_BUTTON = 1;
|
||||
if (!(event.buttons & LEFT_MOUSE_BUTTON)) {
|
||||
dragEnd(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const deltaX = event.clientX - carouselDragLastClientX;
|
||||
velocityDeltaWindow.shift();
|
||||
velocityDeltaWindow.push({ time: Date.now(), delta: deltaX });
|
||||
|
||||
const newTransformX = currentTransform() + deltaX;
|
||||
setCurrentTransform(newTransformX, "px", false);
|
||||
|
||||
carouselDragLastClientX = event.clientX;
|
||||
}
|
||||
|
||||
function clamp(value, min, max) {
|
||||
return Math.min(Math.max(value, min), max);
|
||||
}
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
const NAV_BUTTON_INITIAL_FONT_SIZE = 32;
|
||||
const RIPPLE_ANIMATION_MILLISECONDS = 100;
|
||||
const RIPPLE_WIDTH = 140;
|
||||
const HANDLE_STRETCH = 0.4;
|
||||
|
||||
let ripplesInitialized;
|
||||
let navButtons;
|
||||
let rippleSvg;
|
||||
let ripplePath;
|
||||
let fullRippleHeight;
|
||||
let ripples;
|
||||
let activeRippleIndex;
|
||||
|
||||
window.addEventListener("DOMContentLoaded", initializeRipples);
|
||||
window.addEventListener("resize", () => animate(true));
|
||||
|
||||
function initializeRipples() {
|
||||
ripplesInitialized = true;
|
||||
|
||||
navButtons = document.querySelectorAll("header nav a");
|
||||
rippleSvg = document.querySelector("header .ripple");
|
||||
ripplePath = rippleSvg.querySelector("path");
|
||||
fullRippleHeight = Number.parseInt(window.getComputedStyle(rippleSvg).height, 10) - 4;
|
||||
|
||||
ripples = Array.from(navButtons).map((button) => ({
|
||||
element: button,
|
||||
animationStartTime: null,
|
||||
animationEndTime: null,
|
||||
goingUp: false,
|
||||
}));
|
||||
|
||||
activeRippleIndex = ripples.findIndex((ripple) => ripple.element.getAttribute("href").replace(/\//g, "") === window.location.pathname.replace(/\//g, ""));
|
||||
|
||||
ripples.forEach((ripple) => {
|
||||
const updateTimings = (goingUp) => {
|
||||
const start = ripple.animationStartTime;
|
||||
const now = Date.now();
|
||||
const stop = ripple.animationStartTime + RIPPLE_ANIMATION_MILLISECONDS;
|
||||
|
||||
const elapsed = now - start;
|
||||
const remaining = stop - now;
|
||||
|
||||
ripple.animationStartTime = now < stop ? now - remaining : now;
|
||||
ripple.animationEndTime = now < stop ? now + elapsed : now + RIPPLE_ANIMATION_MILLISECONDS;
|
||||
|
||||
ripple.goingUp = goingUp;
|
||||
animate(false);
|
||||
};
|
||||
|
||||
ripple.element.addEventListener("pointerenter", () => updateTimings(true));
|
||||
ripple.element.addEventListener("pointerleave", () => updateTimings(false));
|
||||
});
|
||||
|
||||
ripples[activeRippleIndex] = {
|
||||
...ripples[activeRippleIndex],
|
||||
animationStartTime: 1,
|
||||
animationEndTime: 1 + RIPPLE_ANIMATION_MILLISECONDS,
|
||||
goingUp: true,
|
||||
};
|
||||
|
||||
setRipples();
|
||||
}
|
||||
|
||||
function animate(forceRefresh) {
|
||||
if (!ripplesInitialized) return;
|
||||
|
||||
const animateThisFrame = ripples.some((ripple) => ripple.animationStartTime && ripple.animationEndTime && Date.now() <= ripple.animationEndTime);
|
||||
|
||||
if (animateThisFrame || forceRefresh) {
|
||||
setRipples();
|
||||
window.requestAnimationFrame(() => animate(false));
|
||||
}
|
||||
}
|
||||
|
||||
function setRipples() {
|
||||
const navButtonFontSize = Number.parseInt(window.getComputedStyle(navButtons[0]).fontSize, 10) || NAV_BUTTON_INITIAL_FONT_SIZE;
|
||||
const mediaQueryScaleFactor = navButtonFontSize / NAV_BUTTON_INITIAL_FONT_SIZE;
|
||||
|
||||
const rippleHeight = fullRippleHeight * (mediaQueryScaleFactor * 0.5 + 0.5);
|
||||
const rippleSvgRect = rippleSvg.getBoundingClientRect();
|
||||
const rippleSvgLeft = rippleSvgRect.left;
|
||||
const rippleSvgWidth = rippleSvgRect.width;
|
||||
|
||||
let path = `M 0,${rippleHeight + 3} `;
|
||||
|
||||
ripples.forEach((ripple) => {
|
||||
if (!ripple.animationStartTime || !ripple.animationEndTime) return;
|
||||
|
||||
const t = Math.min((Date.now() - ripple.animationStartTime) / (ripple.animationEndTime - ripple.animationStartTime), 1);
|
||||
const height = rippleHeight * (ripple.goingUp ? ease(t) : 1 - ease(t));
|
||||
|
||||
const buttonRect = ripple.element.getBoundingClientRect();
|
||||
|
||||
const buttonCenter = buttonRect.width / 2;
|
||||
const rippleCenter = (RIPPLE_WIDTH / 2) * mediaQueryScaleFactor;
|
||||
const rippleOffset = rippleCenter - buttonCenter;
|
||||
|
||||
const rippleStartX = buttonRect.left - rippleSvgLeft - rippleOffset;
|
||||
|
||||
const rippleRadius = (RIPPLE_WIDTH / 2) * mediaQueryScaleFactor;
|
||||
const handleRadius = rippleRadius * HANDLE_STRETCH;
|
||||
|
||||
path += `L ${rippleStartX},${rippleHeight + 3} `;
|
||||
path += `c ${handleRadius},0 ${rippleRadius - handleRadius},${-height} ${rippleRadius},${-height} `;
|
||||
path += `s ${rippleRadius - handleRadius},${height} ${rippleRadius},${height} `;
|
||||
});
|
||||
|
||||
path += `l ${rippleSvgWidth},0`;
|
||||
|
||||
ripplePath.setAttribute("d", path);
|
||||
}
|
||||
|
||||
function ease(x) {
|
||||
return 1 - (1 - x) * (1 - x);
|
||||
}
|
||||
|
After Width: | Height: | Size: 9.3 KiB |
|
After Width: | Height: | Size: 9.0 KiB |
|
After Width: | Height: | Size: 9.7 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 6.6 KiB |
|
|
@ -0,0 +1,85 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="700.000000pt" height="700.000000pt" viewBox="0 0 700.000000 700.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
<g transform="translate(0.000000,700.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000" stroke="none">
|
||||
<path d="M1935 6994 c-186 -39 -328 -137 -415 -287 -24 -39 -51 -84 -61 -99
|
||||
-11 -15 -19 -29 -19 -31 0 -3 -39 -71 -86 -153 -47 -82 -160 -277 -251 -434
|
||||
-90 -157 -169 -292 -174 -300 -5 -8 -55 -96 -112 -195 -113 -196 -393 -681
|
||||
-408 -705 -5 -8 -41 -71 -80 -140 -40 -69 -85 -147 -101 -175 -73 -126 -100
|
||||
-226 -97 -349 3 -109 33 -203 106 -329 69 -117 281 -485 310 -537 11 -19 111
|
||||
-192 223 -385 111 -192 212 -366 222 -385 11 -19 37 -64 58 -100 21 -36 47
|
||||
-81 58 -100 11 -19 59 -102 107 -185 48 -82 95 -163 104 -180 9 -16 49 -86 89
|
||||
-155 40 -69 78 -134 85 -145 77 -134 155 -215 259 -268 145 -74 44 -69 1583
|
||||
-69 1525 0 1434 -4 1570 63 l62 31 304 -217 c167 -120 360 -259 429 -308 69
|
||||
-50 148 -106 175 -125 48 -34 130 -93 150 -110 6 -4 21 -16 35 -26 17 -12 19
|
||||
-16 6 -12 -31 11 -209 55 -246 61 -19 3 -42 8 -50 10 -28 8 -184 26 -285 33
|
||||
-203 13 -1356 5 -1760 -13 -44 -2 -161 -6 -260 -10 -99 -4 -209 -8 -245 -10
|
||||
-36 -2 -121 -6 -190 -10 -191 -9 -276 -14 -380 -20 -90 -5 -125 -8 -315 -20
|
||||
-44 -3 -114 -8 -155 -11 -198 -13 -326 -22 -405 -29 -27 -2 -81 -7 -120 -10
|
||||
-38 -3 -88 -8 -110 -10 -22 -3 -62 -7 -90 -10 -27 -3 -66 -7 -85 -10 -19 -3
|
||||
-55 -7 -80 -10 -25 -4 -64 -11 -88 -16 -23 -5 -59 -12 -80 -15 -74 -11 -307
|
||||
-76 -381 -106 -42 -17 -91 -42 -109 -55 l-33 -25 38 -28 c47 -35 138 -66 218
|
||||
-75 33 -4 71 -9 85 -11 27 -5 291 -11 860 -19 462 -7 617 -12 1355 -40 66 -3
|
||||
181 -7 255 -10 74 -3 178 -7 230 -10 52 -3 142 -7 200 -10 232 -12 407 -28
|
||||
575 -50 17 -2 56 -7 88 -10 32 -4 111 -12 175 -19 104 -12 493 -13 602 -2 19
|
||||
1 78 6 130 11 52 4 102 9 112 10 9 2 48 7 85 10 37 4 75 8 83 10 8 2 35 7 60
|
||||
10 84 11 172 25 205 31 11 2 34 7 50 10 141 25 376 82 477 115 204 67 307 135
|
||||
359 237 20 40 24 61 24 142 0 83 -7 178 -20 301 -3 20 -7 65 -10 100 -3 35 -7
|
||||
84 -10 109 -2 25 -7 73 -9 108 -12 137 -17 188 -21 212 -2 14 -6 61 -10 105
|
||||
-5 74 -8 102 -20 225 -7 68 -15 158 -21 225 -3 33 -7 80 -10 105 -2 25 -6 71
|
||||
-9 102 -2 31 -6 82 -9 112 -3 31 -8 81 -11 111 -3 30 -7 79 -10 108 -3 28 -7
|
||||
79 -10 112 -3 33 -7 84 -10 113 -3 28 -7 76 -10 105 -2 28 -7 75 -9 102 -3 28
|
||||
-8 82 -11 120 -3 39 -8 86 -10 105 -2 19 -7 67 -10 105 -3 39 -8 90 -10 115
|
||||
-3 25 -7 74 -10 110 -3 36 -7 85 -10 110 -5 48 -11 105 -20 210 -3 36 -8 85
|
||||
-10 110 -3 25 -7 74 -10 110 -5 69 -13 141 -21 202 -7 53 -46 144 -110 255
|
||||
-32 54 -66 114 -77 133 -10 19 -61 107 -112 195 -51 88 -102 177 -114 199 -12
|
||||
21 -78 135 -147 255 -68 119 -130 225 -136 236 -6 11 -74 127 -151 259 -76
|
||||
131 -148 255 -159 275 -33 60 -288 501 -335 579 -23 40 -43 75 -43 78 0 10
|
||||
-63 88 -100 122 -78 74 -174 125 -275 147 -48 11 -341 13 -1440 13 -759 0
|
||||
-1389 -2 -1400 -4z m2666 -602 c87 -43 85 -39 309 -427 51 -88 104 -180 118
|
||||
-205 14 -25 33 -58 43 -75 10 -16 32 -55 49 -85 17 -30 40 -71 51 -90 12 -19
|
||||
134 -229 271 -467 l249 -432 -33 -37 c-18 -20 -42 -47 -53 -58 -58 -60 -211
|
||||
-273 -280 -390 -10 -17 -56 -26 -205 -41 -36 -4 -78 -8 -95 -10 -113 -12 -153
|
||||
-17 -175 -20 -14 -2 -56 -7 -95 -11 -38 -4 -81 -8 -95 -9 -14 -2 -34 -3 -45
|
||||
-4 -15 -1 -47 -37 -105 -117 -47 -64 -90 -122 -95 -128 -6 -6 -22 -27 -35 -46
|
||||
-13 -19 -68 -94 -121 -166 l-97 -131 -69 -2 c-145 -3 -301 -21 -457 -52 -94
|
||||
-19 -99 -19 -112 -2 -7 10 -14 21 -14 25 0 3 -21 42 -46 85 -26 43 -57 96 -70
|
||||
119 -13 23 -105 182 -205 355 -100 173 -192 332 -204 354 -13 22 -105 182
|
||||
-205 355 -101 173 -194 335 -208 359 -47 84 -82 146 -92 161 -8 13 -160 278
|
||||
-185 322 -5 10 -80 138 -165 285 -85 147 -167 288 -181 315 -14 26 -31 54 -38
|
||||
62 -24 29 65 158 133 193 76 40 73 40 1310 39 l1201 -1 46 -23z m-2956 -912
|
||||
c43 -74 86 -151 97 -170 11 -19 93 -161 182 -315 239 -412 431 -745 453 -785
|
||||
11 -19 76 -132 145 -250 69 -118 137 -236 151 -262 15 -26 82 -143 150 -260
|
||||
68 -117 195 -337 282 -488 87 -151 176 -303 198 -338 42 -66 56 -77 487 -385
|
||||
74 -53 215 -154 313 -224 l179 -128 -1071 -3 c-1052 -2 -1071 -2 -1123 18 -59
|
||||
23 -113 68 -144 120 -115 194 -164 279 -164 284 0 3 -15 29 -33 58 -19 29 -47
|
||||
78 -64 108 -17 30 -54 96 -83 145 -29 50 -61 106 -72 125 -45 78 -322 559
|
||||
-353 610 -18 30 -103 179 -190 330 -87 151 -170 295 -185 320 -48 81 -58 177
|
||||
-26 253 13 32 221 398 353 622 7 11 38 65 70 120 32 55 64 112 73 126 8 14 47
|
||||
81 85 148 39 67 75 130 80 139 6 9 37 63 69 120 32 56 60 101 61 100 1 -2 37
|
||||
-64 80 -138z m4304 -1486 c1 -32 4 -61 6 -64 2 -3 7 -48 10 -100 3 -52 8 -97
|
||||
10 -100 2 -3 6 -45 10 -95 4 -49 8 -101 10 -115 4 -26 8 -67 25 -240 17 -173
|
||||
21 -214 25 -240 2 -14 6 -65 10 -115 3 -49 8 -97 10 -105 2 -8 7 -51 10 -94 4
|
||||
-43 8 -86 10 -95 1 -9 6 -54 10 -101 4 -47 8 -98 10 -115 2 -16 7 -64 11 -105
|
||||
3 -41 7 -82 9 -90 2 -8 6 -53 10 -100 4 -47 9 -88 11 -92 2 -3 2 -12 -1 -20
|
||||
-4 -10 -20 -13 -53 -12 -71 4 -179 -22 -259 -61 -79 -39 -189 -139 -223 -203
|
||||
-37 -71 -28 -72 -155 19 -64 46 -126 91 -138 99 -12 8 -83 59 -157 112 -74 53
|
||||
-174 125 -223 160 -190 137 -212 153 -215 160 -2 5 -7 8 -12 8 -7 0 -188 126
|
||||
-300 210 -14 10 -106 76 -205 147 -290 208 -315 226 -312 229 7 7 227 42 312
|
||||
49 39 4 110 8 159 9 80 3 91 6 107 27 10 13 65 87 121 164 56 77 106 145 110
|
||||
150 5 6 49 64 97 131 49 66 95 121 102 121 24 0 167 14 186 17 10 2 50 7 88
|
||||
11 39 3 84 8 100 10 17 3 50 7 75 9 25 2 93 10 151 17 l106 12 38 64 c65 110
|
||||
281 394 296 387 3 -2 7 -29 8 -60z"/>
|
||||
<path d="M1314 4324 c-43 -14 -93 -67 -96 -99 -5 -66 5 -92 78 -218 78 -134
|
||||
88 -152 153 -265 20 -35 41 -71 46 -80 13 -21 67 -116 93 -162 11 -19 83 -145
|
||||
161 -278 77 -134 141 -248 141 -253 0 -5 5 -9 10 -9 6 0 10 -4 10 -10 0 -5 27
|
||||
-55 60 -111 33 -55 60 -102 60 -104 0 -2 27 -49 60 -104 33 -56 60 -104 60
|
||||
-107 0 -2 8 -17 18 -32 11 -15 40 -63 67 -108 50 -85 77 -108 136 -118 49 -7
|
||||
116 28 141 74 37 68 11 140 -142 390 -28 47 -807 1395 -842 1460 -43 78 -66
|
||||
108 -91 122 -40 21 -84 26 -123 12z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.8 KiB |
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"name": "Graphite",
|
||||
"short_name": "Graphite",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/android-chrome-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"theme_color": "#f1decd",
|
||||
"background_color": "#f1decd",
|
||||
"display": "standalone"
|
||||
}
|
||||