mirror of
https://github.com/d07RiV/diabloweb.git
synced 2026-06-03 21:41:38 +00:00
touch ui
This commit is contained in:
5833
package-lock.json
generated
5833
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -15,6 +15,7 @@
|
||||
"babel-preset-react-app": "^9.0.0",
|
||||
"camelcase": "^5.2.0",
|
||||
"case-sensitive-paths-webpack-plugin": "2.2.0",
|
||||
"classnames": "^2.2.6",
|
||||
"css-loader": "2.1.1",
|
||||
"dotenv": "6.2.0",
|
||||
"dotenv-expand": "4.2.0",
|
||||
|
||||
223
src/App.js
223
src/App.js
@@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import './App.scss';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import create_fs from './fs';
|
||||
import load_game from './api/loader';
|
||||
@@ -28,15 +29,35 @@ function getDropFile(e) {
|
||||
}
|
||||
}
|
||||
|
||||
const TOUCH_MOVE = 0;
|
||||
const TOUCH_RMB = 1;
|
||||
const TOUCH_SHIFT = 2;
|
||||
|
||||
const Link = ({children, ...props}) => <a target="_blank" rel="noopener noreferrer" {...props}>{children}</a>;
|
||||
|
||||
class App extends React.Component {
|
||||
files = new Map();
|
||||
state = {started: false, loading: false, dropping: 0};
|
||||
state = {started: false, loading: false, touch: false, dropping: 0};
|
||||
cursorPos = {x: 0, y: 0};
|
||||
|
||||
touchButtons = [null, null, null, null, null, null];
|
||||
touchCtx = [null, null, null, null, null, null];
|
||||
touchMods = [false, false, false, false, false, false];
|
||||
touchBelt = [-1, -1, -1, -1, -1, -1];
|
||||
|
||||
fs = create_fs(this);
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.setTouch0 = this.setTouch_.bind(this, 0);
|
||||
this.setTouch1 = this.setTouch_.bind(this, 1);
|
||||
this.setTouch2 = this.setTouch_.bind(this, 2);
|
||||
this.setTouch3 = this.setTouchBelt_.bind(this, 3);
|
||||
this.setTouch4 = this.setTouchBelt_.bind(this, 4);
|
||||
this.setTouch5 = this.setTouchBelt_.bind(this, 5);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
document.addEventListener("drop", this.onDrop, true);
|
||||
document.addEventListener("dragover", this.onDragOver, true);
|
||||
@@ -95,7 +116,20 @@ class App extends React.Component {
|
||||
this.setState({progress: loaded / total});
|
||||
}
|
||||
|
||||
onRender({images, text, clip}) {
|
||||
drawBelt(idx, slot) {
|
||||
if (!this.touchButtons[idx]) {
|
||||
return;
|
||||
}
|
||||
this.touchBelt[idx] = slot;
|
||||
if (slot >= 0) {
|
||||
this.touchButtons[idx].style.display = "block";
|
||||
this.touchCtx[idx].drawImage(this.canvas, 205 + 29 * slot, 357, 28, 28, 0, 0, 28, 28);
|
||||
} else {
|
||||
this.touchButtons[idx].style.display = "none";
|
||||
}
|
||||
}
|
||||
|
||||
onRender({images, text, clip, belt}) {
|
||||
const ctx = this.renderer;
|
||||
if (!ctx) {
|
||||
return;
|
||||
@@ -125,6 +159,23 @@ class App extends React.Component {
|
||||
}
|
||||
ctx.restore();
|
||||
}
|
||||
if (belt) {
|
||||
const used = new Set();
|
||||
let pos = 3;
|
||||
for (let i = 0; i < belt.length && pos < 6; ++i) {
|
||||
if (belt[i] >= 0 && !used.has(belt[i])) {
|
||||
this.drawBelt(pos++, i);
|
||||
used.add(belt[i]);
|
||||
}
|
||||
}
|
||||
for (; pos < 6; ++pos) {
|
||||
this.drawBelt(pos, -1);
|
||||
}
|
||||
} else {
|
||||
this.drawBelt(3, -1);
|
||||
this.drawBelt(4, -1);
|
||||
this.drawBelt(5, -1);
|
||||
}
|
||||
}
|
||||
|
||||
start(file) {
|
||||
@@ -148,10 +199,11 @@ class App extends React.Component {
|
||||
document.addEventListener('contextmenu', this.onMenu, true);
|
||||
|
||||
document.addEventListener('touchstart', this.onTouchStart, {passive: false, capture: true});
|
||||
document.addEventListener('touchmove', this.onTouchStart, {passive: false, capture: true});
|
||||
document.addEventListener('touchend', this.onTouchStart, {passive: false, capture: true});
|
||||
document.addEventListener('touchmove', this.onTouchMove, {passive: false, capture: true});
|
||||
document.addEventListener('touchend', this.onTouchEnd, {passive: false, capture: true});
|
||||
|
||||
document.addEventListener('pointerlockchange', this.onPointerLockChange);
|
||||
document.addEventListener('fullscreenchange', this.onFullscreenChange);
|
||||
window.addEventListener('resize', this.onResize);
|
||||
|
||||
this.setState({started: true});
|
||||
@@ -187,7 +239,7 @@ class App extends React.Component {
|
||||
}
|
||||
}
|
||||
eventMods(e) {
|
||||
return (e.shiftKey ? 1 : 0) + (e.ctrlKey ? 2 : 0) + (e.altKey ? 4 : 0);
|
||||
return ((e.shiftKey || this.touchMods[TOUCH_SHIFT]) ? 1 : 0) + (e.ctrlKey ? 2 : 0) + (e.altKey ? 4 : 0) + (e.touches ? 8 : 0);
|
||||
}
|
||||
|
||||
onResize = () => {
|
||||
@@ -256,34 +308,165 @@ class App extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
touchButton = null;
|
||||
touchCanvas = null;
|
||||
|
||||
onFullscreenChange = () => {
|
||||
this.setState({touch: (document.fullscreenElement === this.element)});
|
||||
}
|
||||
|
||||
setTouchMod(index, value, use) {
|
||||
if (index < 3) {
|
||||
this.touchMods[index] = value;
|
||||
if (this.touchButtons[index]) {
|
||||
this.touchButtons[index].classList.toggle("active", value);
|
||||
}
|
||||
} else if (use && this.touchBelt[index] >= 0) {
|
||||
const now = performance.now();
|
||||
if (!this.beltTime || now - this.beltTime > 750) {
|
||||
this.game("DApi_Char", 49 + this.touchBelt[index]);
|
||||
this.beltTime = now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateTouchButton(touches, release) {
|
||||
let touchOther = null;
|
||||
const btn = this.touchButton;
|
||||
for (let {target, identifier, clientX, clientY} of touches) {
|
||||
if (btn && btn.id === identifier && this.touchButtons[btn.index] === target) {
|
||||
if (touches.length > 1) {
|
||||
btn.stick = false;
|
||||
}
|
||||
btn.clientX = clientX;
|
||||
btn.clientY = clientY;
|
||||
this.touchCanvas = [...touches].find(t => t.identifier !== identifier);
|
||||
if (this.touchCanvas) {
|
||||
this.touchCanvas = {clientX: this.touchCanvas.clientX, clientY: this.touchCanvas.clientY};
|
||||
}
|
||||
delete this.panPos;
|
||||
return this.touchCanvas != null;
|
||||
}
|
||||
const idx = this.touchButtons.indexOf(target);
|
||||
if (idx >= 0 && !touchOther) {
|
||||
touchOther = {id: identifier, index: idx, stick: true, original: this.touchMods[idx], clientX, clientY};
|
||||
}
|
||||
}
|
||||
if (btn && !touchOther && release && btn.stick) {
|
||||
const rect = this.touchButtons[btn.index].getBoundingClientRect();
|
||||
const {clientX, clientY} = btn;
|
||||
if (clientX >= rect.left && clientX < rect.right && clientY >= rect.top && clientY < rect.bottom) {
|
||||
this.setTouchMod(btn.index, !btn.original, true);
|
||||
} else {
|
||||
this.setTouchMod(btn.index, btn.original);
|
||||
}
|
||||
} else if (btn) {
|
||||
this.setTouchMod(btn.index, false);
|
||||
}
|
||||
this.touchButton = touchOther;
|
||||
if (touchOther) {
|
||||
this.setTouchMod(touchOther.index, true);
|
||||
delete this.panPos;
|
||||
} else if (touches.length === 2) {
|
||||
const x = (touches[1].clientX + touches[0].clientX) / 2, y = (touches[1].clientY + touches[0].clientY) / 2;
|
||||
if (this.panPos) {
|
||||
const dx = x - this.panPos.x, dy = y - this.panPos.y;
|
||||
const step = this.canvas.offsetHeight / 12;
|
||||
if (Math.max(Math.abs(dx), Math.abs(dy)) > step) {
|
||||
let key;
|
||||
if (Math.abs(dx) > Math.abs(dy)) {
|
||||
key = (dx > 0 ? 0x25 : 0x27);
|
||||
} else {
|
||||
key = (dy > 0 ? 0x26 : 0x28);
|
||||
}
|
||||
this.game("DApi_Key", 0, 0, key);
|
||||
// key up is ignored anyway
|
||||
this.panPos = {x, y};
|
||||
}
|
||||
} else {
|
||||
this.game("DApi_Mouse", 0, 0, 24, 320, 180);
|
||||
this.game("DApi_Mouse", 2, 1, 24, 320, 180);
|
||||
this.panPos = {x, y};
|
||||
}
|
||||
this.touchCanvas = null;
|
||||
return false;
|
||||
} else {
|
||||
delete this.panPos;
|
||||
}
|
||||
this.touchCanvas = [...touches].find(t => !touchOther || t.identifier !== touchOther.id);
|
||||
if (this.touchCanvas) {
|
||||
this.touchCanvas = {clientX: this.touchCanvas.clientX, clientY: this.touchCanvas.clientY};
|
||||
}
|
||||
return this.touchCanvas != null;
|
||||
}
|
||||
|
||||
onTouchStart = e => {
|
||||
if (!this.canvas || !e.touches.length) return;
|
||||
if (!this.canvas) return;
|
||||
e.preventDefault();
|
||||
this.element.requestFullscreen();
|
||||
const {x, y} = this.mousePos(e.touches[0]);
|
||||
this.game("DApi_Mouse", 0, 0, this.eventMods(e), x, y);
|
||||
this.game("DApi_Mouse", 1, 0, this.eventMods(e), x, y);
|
||||
if (this.updateTouchButton(e.touches, false)) {
|
||||
const {x, y} = this.mousePos(this.touchCanvas);
|
||||
this.game("DApi_Mouse", 0, 0, this.eventMods(e), x, y);
|
||||
if (!this.touchMods[TOUCH_MOVE]) {
|
||||
this.game("DApi_Mouse", 1, this.touchMods[TOUCH_RMB] ? 2 : 1, this.eventMods(e), x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
onTouchMove = e => {
|
||||
if (!this.canvas || !e.touches.length) return;
|
||||
if (!this.canvas) return;
|
||||
e.preventDefault();
|
||||
if (this.updateTouchButton(e.touches, false)) {
|
||||
const {x, y} = this.mousePos(this.touchCanvas);
|
||||
this.game("DApi_Mouse", 0, 0, this.eventMods(e), x, y);
|
||||
}
|
||||
}
|
||||
onTouchEnd = e => {
|
||||
if (!this.canvas) return;
|
||||
e.preventDefault();
|
||||
const prevTc = this.touchCanvas;
|
||||
this.updateTouchButton(e.touches, true);
|
||||
if (prevTc && !this.touchCanvas) {
|
||||
const {x, y} = this.mousePos(prevTc);
|
||||
this.game("DApi_Mouse", 2, 1, this.eventMods(e), x, y);
|
||||
this.game("DApi_Mouse", 2, 2, this.eventMods(e), x, y);
|
||||
}
|
||||
if (!document.fullscreenElement) {
|
||||
this.element.requestFullscreen();
|
||||
}
|
||||
}
|
||||
|
||||
setCanvas = e => this.canvas = e;
|
||||
setElement = e => this.element = e;
|
||||
setKeyboard = e => this.keyboard = e;
|
||||
setTouchMove = e => this.touchMove = e;
|
||||
setTouchRmb = e => this.touchRmb = e;
|
||||
setTouchShift = e => this.touchShift = e;
|
||||
setTouch_(i, e) {
|
||||
this.touchButtons[i] = e;
|
||||
}
|
||||
setTouchBelt_(i, e) {
|
||||
this.touchButtons[i] = e;
|
||||
if (e) {
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.width = 28;
|
||||
canvas.height = 28;
|
||||
e.appendChild(canvas);
|
||||
this.touchCtx[i] = canvas.getContext("2d");
|
||||
} else {
|
||||
this.touchCtx[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const {started, loading, error, progress, dropping} = this.state;
|
||||
const {started, loading, error, progress, dropping, touch} = this.state;
|
||||
return (
|
||||
<div className={"App touch " + (started ? " started" : "") + (dropping ? " dropping" : "")} ref={this.setElement}>
|
||||
<div className={classNames("App", {touch, started, dropping})} ref={this.setElement}>
|
||||
<div className="touch-ui touch-mods">
|
||||
<div className={classNames("touch-button", "touch-button-0", {active: this.touchMods[0]})} ref={this.setTouch0}/>
|
||||
<div className={classNames("touch-button", "touch-button-1", {active: this.touchMods[1]})} ref={this.setTouch1}/>
|
||||
<div className={classNames("touch-button", "touch-button-2", {active: this.touchMods[2]})} ref={this.setTouch2}/>
|
||||
</div>
|
||||
<div className="touch-ui touch-belt">
|
||||
<div className={classNames("touch-button", "touch-button-0")} ref={this.setTouch3}/>
|
||||
<div className={classNames("touch-button", "touch-button-1")} ref={this.setTouch4}/>
|
||||
<div className={classNames("touch-button", "touch-button-2")} ref={this.setTouch5}/>
|
||||
</div>
|
||||
<div className="Body">
|
||||
{!error && (
|
||||
<canvas ref={this.setCanvas} width={640} height={480}/>
|
||||
@@ -320,14 +503,6 @@ class App extends React.Component {
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="touch-ui">
|
||||
<div className="touch-button touch-button-1" ref={this.touchMove}>
|
||||
</div>
|
||||
<div className="touch-button touch-button-2" ref={this.touchRmb}>
|
||||
</div>
|
||||
<div className="touch-button touch-button-3" ref={this.touchShift}>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
113
src/App.scss
113
src/App.scss
@@ -145,74 +145,135 @@ body, #root, .App {
|
||||
.App {
|
||||
.touch-ui {
|
||||
display: none;
|
||||
}
|
||||
&.touch .touch-ui {
|
||||
display: block;
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 25vh;
|
||||
.touch-button {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
width: 20vh;
|
||||
height: 20vh;
|
||||
border-radius: 10vh;
|
||||
background-color: #888;
|
||||
background-color: #444;
|
||||
transform: translate(-50%, -50%);
|
||||
pointer-events: auto;
|
||||
&.active {
|
||||
background-color: #fff;
|
||||
}
|
||||
mask-size: 100% 100%;
|
||||
}
|
||||
.touch-button-1 {
|
||||
.touch-button-0 {
|
||||
top: 16.7vh;
|
||||
}
|
||||
.touch-button-2 {
|
||||
.touch-button-1 {
|
||||
top: 50vh;
|
||||
}
|
||||
.touch-button-3 {
|
||||
.touch-button-2 {
|
||||
top: 83.3vh;
|
||||
}
|
||||
}
|
||||
.touch-ui.touch-mods {
|
||||
left: 0;
|
||||
.touch-button {
|
||||
width: 20vh;
|
||||
height: 20vh;
|
||||
border-radius: 10vh;
|
||||
}
|
||||
.touch-button-0 {
|
||||
mask-image: url(./icons/move.svg);
|
||||
}
|
||||
.touch-button-1 {
|
||||
mask-image: url(./icons/rmb.svg);
|
||||
}
|
||||
.touch-button-2 {
|
||||
mask-image: url(./icons/shift.svg);
|
||||
}
|
||||
}
|
||||
.touch-ui.touch-belt {
|
||||
right: 0;
|
||||
.touch-button {
|
||||
width: 14vh;
|
||||
height: 14vh;
|
||||
font-size: 1vh;
|
||||
border-radius: 20%;
|
||||
overflow: hidden;
|
||||
background-color: #000;
|
||||
border: 2px solid #444;
|
||||
canvas {
|
||||
position: absolute;
|
||||
left: 5%;
|
||||
top: 5%;
|
||||
width: 90%;
|
||||
height: 90%;
|
||||
}
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
border-radius: 20%;
|
||||
box-shadow: inset 0 0 1em 1.5em #000;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.touch .touch-ui {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
@media (max-aspect-ratio: 880/480) {
|
||||
.App.touch .touch-ui {
|
||||
.App .touch-ui {
|
||||
width: calc(50vw - 200vh / 3);
|
||||
}
|
||||
}
|
||||
@media (max-aspect-ratio: 832/480) {
|
||||
.App.touch .touch-ui {
|
||||
.App .touch-ui {
|
||||
width: 20vh;
|
||||
}
|
||||
}
|
||||
@media (max-aspect-ratio: 640/480) {
|
||||
.App.touch .touch-ui {
|
||||
top: auto;
|
||||
.App .touch-ui {
|
||||
width: auto;
|
||||
right: 0;
|
||||
height: 20vw;
|
||||
.touch-button {
|
||||
top: 50%;
|
||||
}
|
||||
.touch-button-0 {
|
||||
left: 16.7vw;
|
||||
}
|
||||
.touch-button-1 {
|
||||
left: 50vw;
|
||||
}
|
||||
.touch-button-2 {
|
||||
left: 83.3vw;
|
||||
}
|
||||
}
|
||||
.App .touch-ui.touch-mods {
|
||||
top: auto;
|
||||
right: 0;
|
||||
.touch-button {
|
||||
width: 20vw;
|
||||
height: 20vw;
|
||||
border-radius: 10vw;
|
||||
}
|
||||
.touch-button-1 {
|
||||
left: 16.7vw;
|
||||
}
|
||||
.touch-button-2 {
|
||||
left: 50vw;
|
||||
}
|
||||
.touch-button-3 {
|
||||
left: 83.3vw;
|
||||
}
|
||||
.App .touch-ui.touch-belt {
|
||||
bottom: auto;
|
||||
left: 0;
|
||||
.touch-button {
|
||||
width: 14vw;
|
||||
height: 14vw;
|
||||
font-size: 1vw;
|
||||
}
|
||||
}
|
||||
}
|
||||
@media (max-aspect-ratio: 640/736) {
|
||||
.App.touch .touch-ui {
|
||||
.App .touch-ui {
|
||||
height: calc(50vh - 75vw / 2);
|
||||
}
|
||||
}
|
||||
@media (max-aspect-ratio: 640/800) {
|
||||
.App.touch .touch-ui {
|
||||
.App .touch-ui {
|
||||
height: 25vw;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -8,6 +8,7 @@ const worker = self;
|
||||
|
||||
let files = null;
|
||||
let renderBatch = null;
|
||||
let drawBelt = null;
|
||||
|
||||
const DApi = {
|
||||
exit_error(error) {
|
||||
@@ -18,8 +19,10 @@ const DApi = {
|
||||
renderBatch = {
|
||||
images: [],
|
||||
text: [],
|
||||
clip: null
|
||||
clip: null,
|
||||
belt: drawBelt,
|
||||
};
|
||||
drawBelt = null;
|
||||
},
|
||||
draw_blit(x, y, w, h, data) {
|
||||
if (ImageData.length) {
|
||||
@@ -40,6 +43,9 @@ const DApi = {
|
||||
worker.postMessage({action: "render", batch: renderBatch});
|
||||
renderBatch = null;
|
||||
},
|
||||
draw_belt(items) {
|
||||
drawBelt = items.slice();
|
||||
},
|
||||
|
||||
get_file_size(path) {
|
||||
const data = files.get(path.toLowerCase());
|
||||
|
||||
3
src/icons/move.svg
Normal file
3
src/icons/move.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid meet" viewBox="0 0 640 640" width="640" height="640"><defs><path d="M326.88 298.88C326.88 298.88 326.88 298.88 326.88 298.88C314.75 298.88 304.92 289.04 304.92 276.91C304.92 273.13 304.92 242.92 304.92 239.14C304.92 227.01 314.75 217.17 326.88 217.17C326.88 217.17 326.88 217.17 326.88 217.17C339.02 217.17 348.85 227.01 348.85 239.14C348.85 241.66 348.85 254.25 348.85 276.91C342.3 291.56 334.97 298.88 326.88 298.88Z" id="a3YmE0kYNk"></path><path d="M360.46 232.22C360.46 237.46 360.46 279.36 360.46 284.6C360.46 296.93 352.38 307.55 340.76 312.34C340.76 314.22 340.76 323.6 340.76 340.5L454.07 340.5C454.07 283.76 454.07 252.23 454.07 245.93C454.07 192.37 409.2 148.96 353.86 148.96C352.99 148.96 348.62 148.96 340.76 148.96L340.76 204.48C353.89 214.75 360.46 224 360.46 232.22Z" id="a123Rizl1h"></path><path d="M199.7 421.97C199.7 475.53 244.57 518.94 299.91 518.94C305.3 518.94 348.47 518.94 353.86 518.94C409.2 518.94 454.07 475.53 454.07 421.97C454.07 417.08 454.07 392.62 454.07 348.59L199.7 348.59C199.7 392.62 199.7 417.08 199.7 421.97Z" id="a2PRuZ4XyI"></path><path d="M313.01 312.34C301.39 307.55 293.31 296.93 293.31 284.6C293.31 279.36 293.31 237.46 293.31 232.22C293.31 219.89 301.39 209.27 313.01 204.48C313.01 200.78 313.01 182.27 313.01 148.96C305.15 148.96 300.78 148.96 299.91 148.96C244.57 148.96 199.7 192.37 199.7 245.93C199.7 252.23 199.7 283.76 199.7 340.5L313.01 340.5C313.01 323.6 313.01 314.22 313.01 312.34Z" id="bOlZ8Knrm"></path><path d="M494.43 269.5L563.35 340.5L494.43 411.5L494.43 366.49L461.92 366.49L461.92 314.39L494.43 314.39L494.43 269.5Z" id="c2jJXhIrng"></path><path d="M158.97 269.5L90.06 340.5L158.97 411.5L158.97 366.49L191.49 366.49L191.49 314.39L158.97 314.39L158.97 269.5Z" id="ke7zAJ37M"></path><path d="M397.89 110.9L326.88 41.99L255.88 110.9L300.9 110.9L300.9 143.42L352.99 143.42L352.99 110.9L397.89 110.9Z" id="a4iiHlu6Tc"></path><path d="M397.41 556.21L326.41 625.13L255.41 556.21L300.42 556.21L300.42 523.7L352.52 523.7L352.52 556.21L397.41 556.21Z" id="b2XGLcPStX"></path></defs><g><g><g><use xlink:href="#a3YmE0kYNk" opacity="1" fill="#020202" fill-opacity="1"></use><g><use xlink:href="#a3YmE0kYNk" opacity="1" fill-opacity="0" stroke="#000000" stroke-width="1" stroke-opacity="0"></use></g></g><g><use xlink:href="#a123Rizl1h" opacity="1" fill="#020202" fill-opacity="1"></use><g><use xlink:href="#a123Rizl1h" opacity="1" fill-opacity="0" stroke="#000000" stroke-width="1" stroke-opacity="0"></use></g></g><g><use xlink:href="#a2PRuZ4XyI" opacity="1" fill="#020202" fill-opacity="1"></use><g><use xlink:href="#a2PRuZ4XyI" opacity="1" fill-opacity="0" stroke="#000000" stroke-width="1" stroke-opacity="0"></use></g></g><g><use xlink:href="#bOlZ8Knrm" opacity="1" fill="#020202" fill-opacity="1"></use><g><use xlink:href="#bOlZ8Knrm" opacity="1" fill-opacity="0" stroke="#000000" stroke-width="1" stroke-opacity="0"></use></g></g><g><use xlink:href="#c2jJXhIrng" opacity="1" fill="#000000" fill-opacity="1"></use></g><g><use xlink:href="#ke7zAJ37M" opacity="1" fill="#000000" fill-opacity="1"></use></g><g><use xlink:href="#a4iiHlu6Tc" opacity="1" fill="#000000" fill-opacity="1"></use></g><g><use xlink:href="#b2XGLcPStX" opacity="1" fill="#000000" fill-opacity="1"></use></g></g></g></svg>
|
||||
|
After Width: | Height: | Size: 3.4 KiB |
3
src/icons/rmb.svg
Normal file
3
src/icons/rmb.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid meet" viewBox="0 0 640 640" width="640" height="640"><defs><path d="M313.25 276.99C313.25 276.99 313.25 276.99 313.25 276.99C298.37 276.99 286.31 264.93 286.31 250.05C286.31 245.42 286.31 208.36 286.31 203.73C286.31 188.85 298.37 176.79 313.25 176.79C313.25 176.79 313.25 176.79 313.25 176.79C328.13 176.79 340.19 188.85 340.19 203.73C340.19 206.82 340.19 222.26 340.19 250.05C332.15 268.01 323.17 276.99 313.25 276.99Z" id="bwtT01FaN"></path><path d="M354.42 195.25C354.42 201.67 354.42 253.06 354.42 259.48C354.42 274.61 344.51 287.62 330.26 293.5C330.26 295.8 330.26 307.31 330.26 328.03L469.22 328.03C469.22 258.45 469.22 219.79 469.22 212.06C469.22 146.38 414.2 93.13 346.33 93.13C345.26 93.13 339.91 93.13 330.26 93.13L330.26 161.23C346.37 173.82 354.42 185.16 354.42 195.25Z" id="a1ALqApg4B"></path><clipPath id="clipbywTQrek4"><use xlink:href="#a1ALqApg4B" opacity="1"></use></clipPath><path d="M157.28 427.94C157.28 493.62 212.3 546.87 280.16 546.87C286.78 546.87 339.72 546.87 346.33 546.87C414.2 546.87 469.22 493.62 469.22 427.94C469.22 421.94 469.22 391.95 469.22 337.96L157.28 337.96C157.28 391.95 157.28 421.94 157.28 427.94Z" id="aGiF88xvk"></path><path d="M296.23 293.5C281.99 287.62 272.08 274.61 272.08 259.48C272.08 253.06 272.08 201.67 272.08 195.25C272.08 180.12 281.99 167.11 296.23 161.23C296.23 156.69 296.23 133.99 296.23 93.13C286.59 93.13 281.24 93.13 280.16 93.13C212.3 93.13 157.28 146.38 157.28 212.06C157.28 219.79 157.28 258.45 157.28 328.03L296.23 328.03C296.23 307.31 296.23 295.8 296.23 293.5Z" id="acQhG8yZH"></path></defs><g><g><g><use xlink:href="#bwtT01FaN" opacity="1" fill="#020202" fill-opacity="1"></use><g><use xlink:href="#bwtT01FaN" opacity="1" fill-opacity="0" stroke="#000000" stroke-width="1" stroke-opacity="0"></use></g></g><g><g clip-path="url(#clipbywTQrek4)"><use xlink:href="#a1ALqApg4B" opacity="1" fill-opacity="0" stroke="#000000" stroke-width="26" stroke-opacity="1"></use></g></g><g><use xlink:href="#aGiF88xvk" opacity="1" fill="#020202" fill-opacity="1"></use><g><use xlink:href="#aGiF88xvk" opacity="1" fill-opacity="0" stroke="#000000" stroke-width="1" stroke-opacity="0"></use></g></g><g><use xlink:href="#acQhG8yZH" opacity="1" fill="#020202" fill-opacity="1"></use><g><use xlink:href="#acQhG8yZH" opacity="1" fill-opacity="0" stroke="#000000" stroke-width="1" stroke-opacity="0"></use></g></g></g></g></svg>
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
3
src/icons/shift.svg
Normal file
3
src/icons/shift.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid meet" viewBox="0 0 640 640" width="640" height="640"><defs><path d="M439.52 108.04C477.06 108.04 507.5 138.47 507.5 176.02C507.5 240.02 507.5 357.26 507.5 419.57C507.5 461.8 473.26 496.04 431.03 496.04C371.33 496.04 264.71 496.04 204.02 496.04C164.52 496.04 132.5 464.02 132.5 424.52C132.5 361.22 132.5 245.68 132.5 183.09C132.5 141.64 166.1 108.04 207.55 108.04C267.54 108.04 378.11 108.04 439.52 108.04Z" id="c2OL5KwjUK"></path><clipPath id="clipaGcWUxBty"><use xlink:href="#c2OL5KwjUK" opacity="1"></use></clipPath><path d="M366 349.57L282 268.04L198 349.57L251.25 349.57L251.25 416.04L312.89 416.04L312.89 349.57L366 349.57Z" id="i5MOx8YLhh"></path></defs><g><g><g><g clip-path="url(#clipaGcWUxBty)"><use xlink:href="#c2OL5KwjUK" opacity="1" fill-opacity="0" stroke="#000000" stroke-width="52" stroke-opacity="1"></use></g></g><g><use xlink:href="#i5MOx8YLhh" opacity="1" fill="#000000" fill-opacity="1"></use></g></g></g></svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
Reference in New Issue
Block a user