You've already forked random-web-tools
Refactor views structure
This commit is contained in:
78
src/views/general/DummyImage.vue
Normal file
78
src/views/general/DummyImage.vue
Normal file
@ -0,0 +1,78 @@
|
||||
<template>
|
||||
<h2 class="tool-title">Dummy image</h2>
|
||||
<hr class="mt-5 mb-5">
|
||||
|
||||
<div class="input-group">
|
||||
<label>Dimensions</label>
|
||||
<div style="display: flex">
|
||||
<input class="input" v-model="toolData.width" v-on:keyup="result" v-on:change="result" placeholder="500"
|
||||
type="number" style="width: 70px">px
|
||||
<span style="padding: 0 10px">x</span>
|
||||
<input class="input" v-model="toolData.height" v-on:keyup="result" v-on:change="result" placeholder="500"
|
||||
type="number" style="width: 70px">px
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<label for="result">Background colour</label>
|
||||
<input class="input" v-model="toolData.color_bg" v-on:change="result" type="color">
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<label for="result">Text colour</label>
|
||||
<input class="input" v-model="toolData.color_text" v-on:change="result" type="color">
|
||||
</div>
|
||||
|
||||
<hr class="mt-5 mb-5">
|
||||
|
||||
<div class="input-group">
|
||||
<label for="result">Result</label>
|
||||
<div :style="{'width': toolData.width, 'height': toolData.height}">
|
||||
<canvas ref="canvas" :width="toolData.width" :height="toolData.height"
|
||||
style="max-width: 50vw; max-height: 50vh;"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
toolData: {
|
||||
width: 500,
|
||||
height: 500,
|
||||
color_bg: "#000000",
|
||||
color_text: "#ffffff"
|
||||
},
|
||||
toolResult: ""
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.result();
|
||||
},
|
||||
methods: {
|
||||
result() {
|
||||
const ctx = this.$refs.canvas.getContext("2d");
|
||||
|
||||
// Set background color
|
||||
ctx.fillStyle = this.toolData.color_bg;
|
||||
ctx.fillRect(0, 0, this.toolData.width, this.toolData.height);
|
||||
|
||||
// Set text color and font
|
||||
ctx.fillStyle = this.toolData.color_text;
|
||||
ctx.font = "bold 30px Arial";
|
||||
|
||||
// Draw text on the canvas
|
||||
const text = `${this.toolData.width}x${this.toolData.height}`;
|
||||
const textWidth = ctx.measureText(text).width;
|
||||
const x = (this.toolData.width - textWidth) / 2;
|
||||
const y = this.toolData.height / 2 + 10;
|
||||
ctx.fillText(text, x, y);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
</style>
|
57
src/views/general/ExplainCrontab.vue
Normal file
57
src/views/general/ExplainCrontab.vue
Normal file
@ -0,0 +1,57 @@
|
||||
<template>
|
||||
<h2 class="tool-title">Explain crontab</h2>
|
||||
<hr class="mt-5 mb-5">
|
||||
|
||||
<div class="input-group">
|
||||
<label for="data">Data</label>
|
||||
<input id="data" class="input" v-model="toolData.data" v-on:keyup="result" placeholder="* * * * *" type="text">
|
||||
</div>
|
||||
|
||||
<hr class="mt-5 mb-5">
|
||||
|
||||
<div class="input-group">
|
||||
<label for="result">Result</label>
|
||||
<MonacoEditor name="result" language="json" :value="toolResult"></MonacoEditor>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import cronstrue from "cronstrue";
|
||||
import MonacoEditor from "@/components/MonacoEditor.vue";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
MonacoEditor
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
toolData: {
|
||||
data: "* * * * *"
|
||||
},
|
||||
toolResult: ""
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.toolResult = cronstrue.toString(this.toolData.data, {
|
||||
use24HourTimeFormat: true,
|
||||
verbose: true
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
result() {
|
||||
try {
|
||||
this.toolResult = cronstrue.toString(this.toolData.data, {
|
||||
use24HourTimeFormat: true,
|
||||
verbose: true
|
||||
});
|
||||
} catch (e) {
|
||||
this.toolResult = "invalid syntax";
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
</style>
|
104
src/views/general/FileBase64EncodeDecode.vue
Normal file
104
src/views/general/FileBase64EncodeDecode.vue
Normal file
@ -0,0 +1,104 @@
|
||||
<template>
|
||||
<h2 class="tool-title">File base64 encode/decode</h2>
|
||||
<hr class="mt-5 mb-5">
|
||||
|
||||
<div class="input-group" v-if="toolData.base64Mode === 'encode'">
|
||||
<label for="data">Data</label>
|
||||
<input type="file" ref="fileEncodeUpload" @change="encode" />
|
||||
</div>
|
||||
<div class="input-group" v-if="toolData.base64Mode === 'decode'">
|
||||
<label for="data">Data</label>
|
||||
<textarea id="data" v-model="toolData.data"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="input-group" v-if="toolData.base64Mode === 'encode'">
|
||||
<label>Strip mime/type</label>
|
||||
|
||||
<div>
|
||||
<input id="strip_mime" name="strip_mime" v-model="toolData.stripMime" v-on:change="encode" type="checkbox"> <label
|
||||
for="strip_mime">strip mime</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<label>Mode</label>
|
||||
|
||||
<div>
|
||||
<input id="base64_mode_encode" value="encode" name="base64_mode" v-model="toolData.base64Mode" type="radio">
|
||||
<label for="base64_mode_encode">file -> base64</label><br>
|
||||
<input id="base64_mode_decode" value="decode" name="base64_mode" v-model="toolData.base64Mode" type="radio">
|
||||
<label for="base64_mode_decode">base64 -> file</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="mt-5 mb-5">
|
||||
|
||||
<div class="input-group" v-if="toolData.base64Mode === 'encode'">
|
||||
<label for="result">Result</label>
|
||||
<MonacoEditor name="result" language="text" :value="toolResult"></MonacoEditor>
|
||||
</div>
|
||||
<div class="input-group" v-if="toolData.base64Mode === 'decode'">
|
||||
<label for="result">Result</label>
|
||||
<button v-on:click="decode">Decode & download</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MonacoEditor from "@/components/MonacoEditor.vue";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
MonacoEditor
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
toolData: {
|
||||
data: "",
|
||||
base64Mode: "encode",
|
||||
stripMime: true
|
||||
},
|
||||
toolResult: ""
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
encode() {
|
||||
const file = this.$refs.fileEncodeUpload.files[0];
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onload = () => {
|
||||
if (this.toolData.stripMime) {
|
||||
this.toolResult = reader.result.split(",")[1];
|
||||
} else {
|
||||
this.toolResult = reader.result;
|
||||
}
|
||||
};
|
||||
|
||||
if (file) {
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
},
|
||||
decode() {
|
||||
const byteCharacters = atob(this.toolData.data.split(",")[1] ?? this.toolData.data);
|
||||
const byteNumbers = new Array(byteCharacters.length);
|
||||
|
||||
// create file
|
||||
for (let i = 0; i < byteCharacters.length; i++) {
|
||||
byteNumbers[i] = byteCharacters.charCodeAt(i);
|
||||
}
|
||||
|
||||
const byteArray = new Uint8Array(byteNumbers);
|
||||
const blob = new Blob([byteArray], { type: "application/octet-stream" });
|
||||
|
||||
// download
|
||||
const link = document.createElement("a");
|
||||
link.href = URL.createObjectURL(blob);
|
||||
link.download = "file";
|
||||
link.click();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
</style>
|
7
src/views/general/HomeView.vue
Normal file
7
src/views/general/HomeView.vue
Normal file
@ -0,0 +1,7 @@
|
||||
<template>
|
||||
/home
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
</style>
|
371
src/views/general/HumansTxt.vue
Normal file
371
src/views/general/HumansTxt.vue
Normal file
@ -0,0 +1,371 @@
|
||||
<template>
|
||||
<h2 class="tool-title">humans.txt generator</h2>
|
||||
<hr class="mt-5 mb-5">
|
||||
|
||||
<div class="input-group">
|
||||
<label>Team
|
||||
<button @click="addTeamGroup">+</button>
|
||||
</label>
|
||||
<div class="humans-group" v-for="(group, groupIndex) in toolData.team" :key="groupIndex">
|
||||
<div v-for="(field, fieldIndex) in group" :key="fieldIndex">
|
||||
<input class="input" v-model="field.key" v-on:keyup="result" placeholder="Key" type="text">
|
||||
<input class="input" v-model="field.value" v-on:keyup="result" placeholder="Value" type="text">
|
||||
<button @click="removeTeamField(groupIndex, fieldIndex)">🞩</button>
|
||||
<button @click="moveTeamFieldUp(groupIndex, fieldIndex)" v-show="fieldIndex !== 0">↑</button>
|
||||
<button @click="moveTeamFieldDown(groupIndex, fieldIndex)" v-show="fieldIndex !== group.length - 1">↓</button>
|
||||
</div>
|
||||
|
||||
<button @click="addTeamField(groupIndex)">+</button>
|
||||
<button @click="removeTeamGroup(groupIndex)">🞩</button>
|
||||
<button @click="moveTeamGroupUp(groupIndex)" v-show="groupIndex !== 0">↑</button>
|
||||
<button @click="moveTeamGroupDown(groupIndex)" v-show="groupIndex !== toolData.team.length - 1">↓</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="mt-5 mb-5">
|
||||
|
||||
<div class="input-group">
|
||||
<label>Thanks
|
||||
<button @click="addThanksGroup">+</button>
|
||||
</label>
|
||||
<div class="humans-group" v-for="(group, groupIndex) in toolData.thanks" :key="groupIndex">
|
||||
<div v-for="(field, fieldIndex) in group" :key="fieldIndex">
|
||||
<input class="input" v-model="field.key" v-on:keyup="result" placeholder="Key" type="text">
|
||||
<input class="input" v-model="field.value" v-on:keyup="result" placeholder="Value" type="text">
|
||||
<button @click="removeThanksField(groupIndex, fieldIndex)">🞩</button>
|
||||
<button @click="moveThanksFieldUp(groupIndex, fieldIndex)" v-show="fieldIndex !== 0">↑</button>
|
||||
<button @click="moveThanksFieldDown(groupIndex, fieldIndex)" v-show="fieldIndex !== group.length - 1">↓</button>
|
||||
</div>
|
||||
|
||||
<button @click="addThanksField(groupIndex)">+</button>
|
||||
<button @click="removeThanksGroup(groupIndex)">🞩</button>
|
||||
<button @click="moveThanksGroupUp(groupIndex)" v-show="groupIndex !== 0">↑</button>
|
||||
<button @click="moveThanksGroupDown(groupIndex)" v-show="groupIndex !== toolData.thanks.length - 1">↓</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="mt-5 mb-5">
|
||||
|
||||
<div class="input-group">
|
||||
<label>Site info
|
||||
<button @click="addSite">+</button>
|
||||
</label>
|
||||
<div v-for="(info, fieldIndex) in toolData.site" :key="fieldIndex">
|
||||
<input class="input" v-model="info.key" v-on:keyup="result" placeholder="Key" type="text">
|
||||
<input class="input" v-model="info.value" v-on:keyup="result" placeholder="Value" type="text">
|
||||
<button @click="removeSiteField(fieldIndex)">🞩</button>
|
||||
<button @click="moveSiteUp(fieldIndex)" v-show="fieldIndex !== 0">↑</button>
|
||||
<button @click="moveSiteDown(fieldIndex)" v-show="fieldIndex !== toolData.site.length - 1">↓</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="mt-5 mb-5">
|
||||
|
||||
<div class="input-group">
|
||||
<label>Import humans.txt
|
||||
<button @click="importHumans">Import</button>
|
||||
</label>
|
||||
<textarea v-model="toolData.importedHumansTxt" style="height: 250px"></textarea>
|
||||
</div>
|
||||
|
||||
<hr class="mt-5 mb-5">
|
||||
|
||||
<div class="input-group">
|
||||
<label for="result">Result</label>
|
||||
<MonacoEditor name="result" language="text" :value="toolResult"></MonacoEditor>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MonacoEditor from "@/components/MonacoEditor.vue";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
MonacoEditor
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
toolData: {
|
||||
team: [
|
||||
[
|
||||
{ key: "", value: "" }
|
||||
]
|
||||
],
|
||||
thanks: [
|
||||
[
|
||||
{ key: "", value: "" }
|
||||
]
|
||||
],
|
||||
site: [
|
||||
{ key: "", value: "" }
|
||||
],
|
||||
importedHumansTxt: ""
|
||||
},
|
||||
toolResult: ""
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.importHumans();
|
||||
this.result();
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* Team
|
||||
*/
|
||||
addTeamGroup() {
|
||||
this.toolData.team.push([{ key: "", value: "" }]);
|
||||
},
|
||||
addTeamField(groupIndex) {
|
||||
this.toolData.team[groupIndex].push({ key: "", value: "" });
|
||||
},
|
||||
removeTeamField(groupIndex, fieldIndex) {
|
||||
this.toolData.team[groupIndex].splice(fieldIndex, 1);
|
||||
|
||||
if (this.toolData.team[groupIndex].length == 0) {
|
||||
this.removeTeamGroup(groupIndex);
|
||||
}
|
||||
|
||||
this.result();
|
||||
},
|
||||
removeTeamGroup(groupIndex) {
|
||||
this.toolData.team.splice(groupIndex, 1);
|
||||
this.result();
|
||||
},
|
||||
moveTeamGroupUp(groupIndex) {
|
||||
if (groupIndex > 0) {
|
||||
const temp = this.toolData.team[groupIndex];
|
||||
this.toolData.team[groupIndex] = this.toolData.team[groupIndex - 1];
|
||||
this.toolData.team[groupIndex - 1] = temp;
|
||||
}
|
||||
|
||||
this.result();
|
||||
},
|
||||
moveTeamGroupDown(groupIndex) {
|
||||
if (groupIndex < this.toolData.team.length - 1) {
|
||||
const temp = this.toolData.team[groupIndex];
|
||||
this.toolData.team[groupIndex] = this.toolData.team[groupIndex + 1];
|
||||
this.toolData.team[groupIndex + 1] = temp;
|
||||
}
|
||||
|
||||
this.result();
|
||||
},
|
||||
moveTeamFieldUp(groupIndex, fieldIndex) {
|
||||
if (fieldIndex > 0) {
|
||||
const temp = this.toolData.team[groupIndex][fieldIndex];
|
||||
this.toolData.team[groupIndex][fieldIndex] = this.toolData.team[groupIndex][fieldIndex - 1];
|
||||
this.toolData.team[groupIndex][fieldIndex - 1] = temp;
|
||||
}
|
||||
|
||||
this.result();
|
||||
},
|
||||
moveTeamFieldDown(groupIndex, fieldIndex) {
|
||||
if (fieldIndex < this.toolData.team[groupIndex].length - 1) {
|
||||
const temp = this.toolData.team[groupIndex][fieldIndex];
|
||||
this.toolData.team[groupIndex][fieldIndex] = this.toolData.team[groupIndex][fieldIndex + 1];
|
||||
this.toolData.team[groupIndex][fieldIndex + 1] = temp;
|
||||
}
|
||||
|
||||
this.result();
|
||||
},
|
||||
|
||||
/**
|
||||
* Thank
|
||||
*/
|
||||
addThanksGroup() {
|
||||
this.toolData.thanks.push([{ key: "", value: "" }]);
|
||||
},
|
||||
addThanksField(groupIndex) {
|
||||
this.toolData.thanks[groupIndex].push({ key: "", value: "" });
|
||||
},
|
||||
removeThanksField(groupIndex, fieldIndex) {
|
||||
this.toolData.thanks[groupIndex].splice(fieldIndex, 1);
|
||||
|
||||
if (this.toolData.thanks[groupIndex].length == 0) {
|
||||
this.removeThanksGroup(groupIndex);
|
||||
}
|
||||
|
||||
this.result();
|
||||
},
|
||||
removeThanksGroup(groupIndex) {
|
||||
this.toolData.thanks.splice(groupIndex, 1);
|
||||
this.result();
|
||||
},
|
||||
moveThanksGroupUp(groupIndex) {
|
||||
if (groupIndex > 0) {
|
||||
const temp = this.toolData.thanks[groupIndex];
|
||||
this.toolData.thanks[groupIndex] = this.toolData.thanks[groupIndex - 1];
|
||||
this.toolData.thanks[groupIndex - 1] = temp;
|
||||
}
|
||||
|
||||
this.result();
|
||||
},
|
||||
moveThanksGroupDown(groupIndex) {
|
||||
if (groupIndex < this.toolData.thanks.length - 1) {
|
||||
const temp = this.toolData.thanks[groupIndex];
|
||||
this.toolData.thanks[groupIndex] = this.toolData.thanks[groupIndex + 1];
|
||||
this.toolData.thanks[groupIndex + 1] = temp;
|
||||
}
|
||||
|
||||
this.result();
|
||||
},
|
||||
moveThanksFieldUp(groupIndex, fieldIndex) {
|
||||
if (fieldIndex > 0) {
|
||||
const temp = this.toolData.thanks[groupIndex][fieldIndex];
|
||||
this.toolData.thanks[groupIndex][fieldIndex] = this.toolData.thanks[groupIndex][fieldIndex - 1];
|
||||
this.toolData.thanks[groupIndex][fieldIndex - 1] = temp;
|
||||
}
|
||||
|
||||
this.result();
|
||||
},
|
||||
moveThanksFieldDown(groupIndex, fieldIndex) {
|
||||
if (fieldIndex < this.toolData.thanks[groupIndex].length - 1) {
|
||||
const temp = this.toolData.thanks[groupIndex][fieldIndex];
|
||||
this.toolData.thanks[groupIndex][fieldIndex] = this.toolData.thanks[groupIndex][fieldIndex + 1];
|
||||
this.toolData.thanks[groupIndex][fieldIndex + 1] = temp;
|
||||
}
|
||||
|
||||
this.result();
|
||||
},
|
||||
/**
|
||||
* Site
|
||||
*/
|
||||
addSite() {
|
||||
this.toolData.site.push({ label: "", value: "" });
|
||||
},
|
||||
removeSiteField(fieldIndex) {
|
||||
this.toolData.site.splice(fieldIndex, 1);
|
||||
|
||||
this.result();
|
||||
},
|
||||
moveSiteUp(index) {
|
||||
if (index > 0) {
|
||||
const temp = this.toolData.site[index];
|
||||
this.toolData.site[index] = this.toolData.site[index - 1];
|
||||
this.toolData.site[index - 1] = temp;
|
||||
}
|
||||
|
||||
this.result();
|
||||
},
|
||||
moveSiteDown(index) {
|
||||
if (index < this.toolData.site.length - 1) {
|
||||
const temp = this.toolData.site[index];
|
||||
this.toolData.site[index] = this.toolData.site[index + 1];
|
||||
this.toolData.site[index + 1] = temp;
|
||||
}
|
||||
|
||||
this.result();
|
||||
},
|
||||
|
||||
/**
|
||||
* Import
|
||||
*/
|
||||
importHumans() {
|
||||
const lines = this.toolData.importedHumansTxt.split("\n");
|
||||
let currentSection = null;
|
||||
|
||||
this.toolData.team = [];
|
||||
this.toolData.thanks = [];
|
||||
this.toolData.site = [];
|
||||
|
||||
let currentGroup = [];
|
||||
|
||||
for (const line of lines) {
|
||||
if (line.toLowerCase().startsWith("/* TEAM */".toLowerCase())) {
|
||||
currentSection = "team";
|
||||
} else if (line.toLowerCase().startsWith("/* THANKS */".toLowerCase())) {
|
||||
currentSection = "thanks";
|
||||
} else if (line.toLowerCase().startsWith("/* SITE */".toLowerCase())) {
|
||||
currentSection = "site";
|
||||
} else if (line.trim() !== "") {
|
||||
if (currentSection === "team") {
|
||||
const [key, value] = line.split(":");
|
||||
currentGroup.push({ key: key.trim(), value: value.trim() });
|
||||
} else if (currentSection === "thanks") {
|
||||
const [key, value] = line.split(":");
|
||||
currentGroup.push({ key: key.trim(), value: value.trim() });
|
||||
} else if (currentSection === "site") {
|
||||
const [key, value] = line.split(":");
|
||||
this.toolData.site.push({ key: key.trim(), value: value.trim() });
|
||||
}
|
||||
} else if (line.trim() === "" && currentSection === "team") {
|
||||
if (currentGroup.length > 0) {
|
||||
this.toolData.team.push(currentGroup);
|
||||
currentGroup = [];
|
||||
}
|
||||
} else if (line.trim() === "" && currentSection === "thanks") {
|
||||
if (currentGroup.length > 0) {
|
||||
this.toolData.thanks.push(currentGroup);
|
||||
currentGroup = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (currentGroup.length > 0) {
|
||||
this.toolData.team.push(currentGroup);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Generate
|
||||
*/
|
||||
result() {
|
||||
let output = "";
|
||||
|
||||
if (this.toolData.team.length) {
|
||||
output += "/* TEAM */\n";
|
||||
|
||||
for (const group of this.toolData.team) {
|
||||
let groupOutput = "";
|
||||
for (const field of group) {
|
||||
if (field.key.trim() !== "" && field.value.trim() !== "") {
|
||||
groupOutput += `\t${field.key.trim()}: ${field.value.trim()}\n`;
|
||||
}
|
||||
}
|
||||
if (groupOutput !== "") {
|
||||
output += groupOutput + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.toolData.thanks.length) {
|
||||
output += "/* THANKS */\n";
|
||||
|
||||
for (const group of this.toolData.thanks) {
|
||||
let groupOutput = "";
|
||||
for (const field of group) {
|
||||
if (field.key.trim() !== "" && field.value.trim() !== "") {
|
||||
groupOutput += `\t${field.key.trim()}: ${field.value.trim()}\n`;
|
||||
}
|
||||
}
|
||||
if (groupOutput !== "") {
|
||||
output += groupOutput + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.toolData.site.length) {
|
||||
output += "/* SITE */\n";
|
||||
for (const info of this.toolData.site) {
|
||||
if (info.key.trim() !== "" && info.value.trim() !== "") {
|
||||
output += `\t${info.key.trim()}: ${info.value.trim()}\n`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.toolResult = output;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.humans-group {
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.humans-group:nth-child(odd) {
|
||||
background-color: #f7f7f7;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
181
src/views/general/QRCode.vue
Normal file
181
src/views/general/QRCode.vue
Normal file
@ -0,0 +1,181 @@
|
||||
<template>
|
||||
<h2 class="tool-title">QR code</h2>
|
||||
<hr class="mt-5 mb-5">
|
||||
|
||||
<!-- Type options -->
|
||||
<div class="input-group">
|
||||
<label for="text">Data:</label>
|
||||
<textarea id="data" v-model="toolData.options.text" v-on:keyup="result"></textarea>
|
||||
</div>
|
||||
|
||||
<!-- Basic options -->
|
||||
<div class="input-group">
|
||||
<label for="width">Width:</label>
|
||||
<input id="width" v-model.number="toolData.options.width" v-on:change="result" v-on:keyup="result" type="number">
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<label for="height">Height:</label>
|
||||
<input id="height" v-model.number="toolData.options.height" v-on:change="result" v-on:keyup="result" type="number">
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<label for="height">White border:</label>
|
||||
<input id="quietZone" v-model.number="toolData.options.quietZone" v-on:change="result" v-on:keyup="result"
|
||||
type="number">
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<label for="correctLevel">Correct Level:</label>
|
||||
<div>
|
||||
<select id="correctLevel" v-model="toolData.options.correctLevel" v-on:change="result">
|
||||
<option value="L">L</option>
|
||||
<option value="M">M</option>
|
||||
<option value="Q">Q</option>
|
||||
<option value="H">H</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Logo options -->
|
||||
<div class="input-group">
|
||||
<label for="logoUpload">Logo Upload:</label>
|
||||
<div>
|
||||
<input type="file" id="logoUpload" ref="logoUpload" @change="handleLogoUpload" accept="image/*">
|
||||
<button @click="removeLogo">🞩</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Background Image options -->
|
||||
<div class="input-group">
|
||||
<label for="backgroundImageUpload">Background Image Upload:</label>
|
||||
<div>
|
||||
<input type="file" id="backgroundImageUpload" ref="backgroundImageUpload" @change="handleBackgroundImageUpload"
|
||||
accept="image/*">
|
||||
<button @click="removeBackgroundImage">🞩</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<label for="backgroundImageAlpha">Background Image Alpha:</label>
|
||||
<input id="backgroundImageAlpha" v-model.number="toolData.options.backgroundImageAlpha" step="0.1" min="0" max="1"
|
||||
v-on:change="result" v-on:keyup="result" type="number">
|
||||
</div>
|
||||
|
||||
<!--
|
||||
<div class="input-group">
|
||||
<label for="autoColor">Auto Color:</label>
|
||||
<div>
|
||||
<input id="autoColor" v-model="toolData.options.autoColor" v-on:change="result" type="checkbox">
|
||||
</div>
|
||||
</div>
|
||||
-->
|
||||
|
||||
<!-- Drawing method option -->
|
||||
<div class="input-group">
|
||||
<label for="drawer">Drawer:</label>
|
||||
<div>
|
||||
<select id="drawer" v-model="toolData.options.drawer">
|
||||
<option value="canvas">Canvas</option>
|
||||
<option value="svg">SVG</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="mt-5 mb-5">
|
||||
|
||||
<div class="input-group">
|
||||
<label>Result</label>
|
||||
|
||||
<div ref="qrcodeContainer"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import QRCode from "easyqrcodejs";
|
||||
import { unproxy } from "../../utils/unproxy";
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
toolData: {
|
||||
options: {
|
||||
text: "",
|
||||
width: 256,
|
||||
height: 256,
|
||||
correctLevel: "L",
|
||||
logo: "",
|
||||
quietZone: 10,
|
||||
logoBackgroundTransparent: true,
|
||||
backgroundImage: "",
|
||||
backgroundImageAlpha: 1,
|
||||
autoColor: true,
|
||||
drawer: "canvas"
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.toolData.options.text = " ";
|
||||
this.result();
|
||||
this.toolData.options.text = "";
|
||||
},
|
||||
methods: {
|
||||
result() {
|
||||
// Clear previous QR code
|
||||
this.$refs.qrcodeContainer.innerHTML = "";
|
||||
|
||||
let options = unproxy(this.toolData.options);
|
||||
|
||||
// convert correction levels
|
||||
options.correctLevel = {
|
||||
"L": QRCode.CorrectLevel.L,
|
||||
"M": QRCode.CorrectLevel.M,
|
||||
"Q": QRCode.CorrectLevel.Q,
|
||||
"H": QRCode.CorrectLevel.H
|
||||
}[options.correctLevel];
|
||||
|
||||
console.log(options.correctLevel);
|
||||
|
||||
// Generate the QR code
|
||||
new QRCode(this.$refs.qrcodeContainer, options);
|
||||
},
|
||||
|
||||
handleLogoUpload(event) {
|
||||
const file = event.target.files[0];
|
||||
if (file) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
this.toolData.options.logo = e.target.result;
|
||||
this.result();
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
},
|
||||
handleBackgroundImageUpload(event) {
|
||||
const file = event.target.files[0];
|
||||
if (file) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
this.toolData.options.backgroundImage = e.target.result;
|
||||
this.result();
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
},
|
||||
|
||||
removeLogo() {
|
||||
this.toolData.options.logo = "";
|
||||
this.result();
|
||||
},
|
||||
removeBackgroundImage() {
|
||||
this.toolData.options.backgroundImage = "";
|
||||
this.result();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
</style>
|
102
src/views/general/TableToMarkdownTable.vue
Normal file
102
src/views/general/TableToMarkdownTable.vue
Normal file
@ -0,0 +1,102 @@
|
||||
<template>
|
||||
<h2 class="tool-title">Table to Markdown table</h2>
|
||||
<hr class="mt-5 mb-5">
|
||||
|
||||
<div class="input-group">
|
||||
<label for="data">Data (paste from excel)</label>
|
||||
<textarea id="data" v-model="toolData.data" v-on:keyup="result"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<label for="style">Table Style</label>
|
||||
<div>
|
||||
<select id="style" v-model="toolData.selectedStyle" v-on:change="result">
|
||||
<option value="">Default</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<label>Transpose table</label>
|
||||
|
||||
<div>
|
||||
<input id="transpose" name="transpose" v-model="toolData.transpose" v-on:change="result" type="checkbox"> <label
|
||||
for="transpose">transpose</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="mt-5 mb-5">
|
||||
|
||||
<div class="input-group">
|
||||
<label for="result">Result</label>
|
||||
<MonacoEditor name="result" language="text" :value="toolResult"></MonacoEditor>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { unproxy } from "@/utils/unproxy";
|
||||
import MonacoEditor from "@/components/MonacoEditor.vue";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
MonacoEditor
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
toolData: {
|
||||
data: "",
|
||||
selectedStyle: "",
|
||||
transpose: false
|
||||
},
|
||||
toolResult: ""
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
result() {
|
||||
let rows = unproxy(this.toolData.data).split("\n");
|
||||
let numCols = rows[0].split("\t").length;
|
||||
|
||||
// Transpose the table if the option is selected
|
||||
if (this.toolData.transpose) {
|
||||
const transposedData = [];
|
||||
for (let j = 0; j < numCols; j++) {
|
||||
const newRow = [];
|
||||
for (let i = 0; i < rows.length; i++) {
|
||||
newRow.push(rows[i].split("\t")[j] || "");
|
||||
}
|
||||
transposedData.push(newRow.join("\t"));
|
||||
}
|
||||
rows = transposedData;
|
||||
numCols = rows[0].split("\t").length;
|
||||
}
|
||||
|
||||
let output = "";
|
||||
|
||||
// Generate header row
|
||||
output += "| " + rows[0].split("\t").join(" | ") + " |\n";
|
||||
|
||||
// Generate separator row based on selected style
|
||||
switch (this.toolData.selectedStyle) {
|
||||
default:
|
||||
output += "| " + "-".repeat(numCols).split("").join(" | ") + " |\n";
|
||||
break;
|
||||
}
|
||||
|
||||
// Generate data rows
|
||||
for (let i = 1; i < rows.length; i++) {
|
||||
if (this.toolData.selectedStyle === "grid") {
|
||||
output += "| " + rows[i].split("\t").join(" | ") + " |\n";
|
||||
} else {
|
||||
output += "| " + rows[i].split("\t").join(" | ") + " |\n";
|
||||
}
|
||||
}
|
||||
|
||||
this.toolResult = output;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
</style>
|
59
src/views/general/TableToMediawikiTable.vue
Normal file
59
src/views/general/TableToMediawikiTable.vue
Normal file
@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<h2 class="tool-title">Table to Mediawiki table</h2>
|
||||
<hr class="mt-5 mb-5">
|
||||
|
||||
<div class="input-group">
|
||||
<label for="data">Data (paste from excel)</label>
|
||||
<textarea id="data" v-model="toolData.data" v-on:keyup="result"></textarea>
|
||||
</div>
|
||||
|
||||
<hr class="mt-5 mb-5">
|
||||
|
||||
<div class="input-group">
|
||||
<label for="result">Result</label>
|
||||
<MonacoEditor name="result" language="text" :value="toolResult"></MonacoEditor>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { unproxy } from "@/utils/unproxy";
|
||||
import MonacoEditor from "@/components/MonacoEditor.vue";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
MonacoEditor
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
toolData: {
|
||||
data: ""
|
||||
},
|
||||
toolResult: ""
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
result() {
|
||||
let output = "{| class=\"wikitable\"\n";
|
||||
|
||||
const rows = unproxy(this.toolData.data).split("\n");
|
||||
for (let i = 0; i < rows.length; i++) {
|
||||
const cells = rows[i].split("\t");
|
||||
output += "|-\n";
|
||||
|
||||
for (let j = 0; j < cells.length; j++) {
|
||||
output += i === 0 ? "! " : "| ";
|
||||
output += cells[j].trim() + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
output += "|}";
|
||||
|
||||
this.toolResult = output;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
</style>
|
162
src/views/general/UnixTimestamp.vue
Normal file
162
src/views/general/UnixTimestamp.vue
Normal file
@ -0,0 +1,162 @@
|
||||
<template>
|
||||
<h2 class="tool-title">Unix timestamp</h2>
|
||||
<hr class="mt-5 mb-5">
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Format</th>
|
||||
<th>Date & Time</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(value, format) in currentTimestampFormatted" :key="format">
|
||||
<td>{{ format }}</td>
|
||||
<td>{{ value }}</td>
|
||||
<td>
|
||||
<button @click="copyTimestamp(value)">📋</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<hr class="mt-5 mb-5">
|
||||
|
||||
<div class="input-group">
|
||||
<label for="inputTimestamp">Enter timestamp</label>
|
||||
|
||||
<div>
|
||||
<input id="inputTimestamp" type="number" v-model="toolData.inputTimestamp" :placeholder="currentTimestamp">
|
||||
<button @click="convertFromUnix">Convert</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<label>Enter Date & Time</label>
|
||||
|
||||
<div>
|
||||
<table class="table-date-and-time">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Year</th>
|
||||
<th>Month</th>
|
||||
<th>Day</th>
|
||||
<th>Hour (24)</th>
|
||||
<th>Minute</th>
|
||||
<th>Second</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><input type="number" v-model="toolData.inputYear"></td>
|
||||
<td><input type="number" v-model="toolData.inputMonth"></td>
|
||||
<td><input type="number" v-model="toolData.inputDay"></td>
|
||||
<td><input type="number" v-model="toolData.inputHour"></td>
|
||||
<td><input type="number" v-model="toolData.inputMinute"></td>
|
||||
<td><input type="number" v-model="toolData.inputSecond"></td>
|
||||
<td>
|
||||
<button @click="convertToUnix">Convert →</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import moment from "moment";
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
toolData: {
|
||||
inputTimestamp: "",
|
||||
inputYear: moment().year(),
|
||||
inputMonth: moment().month() + 1,
|
||||
inputDay: moment().day(),
|
||||
inputHour: moment().hour(),
|
||||
inputMinute: moment().minute(),
|
||||
inputSecond: moment().second()
|
||||
},
|
||||
currentTimestamp: 0,
|
||||
currentTimestampFormatted: {}
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
const updateCurrentTimestamp = () => {
|
||||
this.currentTimestamp = moment().unix();
|
||||
|
||||
this.currentTimestampFormatted = {
|
||||
"UTC": moment().utc().format("YYYY-MM-DDTHH:mm:ss[Z]"),
|
||||
// 'UTC (local)': moment().format('YYYY-MM-DDTHH:mm:ssZZ'),
|
||||
// 'ISO 8601': moment().toISOString(),
|
||||
// 'RFC 2822': moment().format('ddd, DD MMM YYYY HH:mm:ss ZZ'),
|
||||
// 'RFC 850': moment().format('dddd, DD-MMM-YY HH:mm:ss [UTC]'),
|
||||
// 'RFC 1036': moment().format('ddd, DD MMM YY HH:mm:ss ZZ'),
|
||||
// 'RFC 1123': moment().format('ddd, DD MMM YYYY HH:mm:ss ZZ'),
|
||||
// 'RFC 822': moment().format('ddd, DD MMM YY HH:mm:ss ZZ'),
|
||||
// 'RFC 3339': moment().format('YYYY-MM-DDTHH:mm:ssZZ'),
|
||||
// 'COOKIE': moment().format('dddd, DD-MMM-YYYY HH:mm:ss [UTC]'),
|
||||
// 'RSS': moment().format('ddd, DD MMM YYYY HH:mm:ss ZZ'),
|
||||
"Unix Epoch": moment().unix(),
|
||||
"YYYY-DD-MM": moment().format("YYYY/MM/DD"),
|
||||
"SQL DATETIME": moment().toISOString().replaceAll(/[ZT]|(\.[0-9]{3})/g, " "),
|
||||
"YYYY/DD/MM HH:MM:SS AM/PM": moment().format("YYYY/MM/DD HH:mm:ss A")
|
||||
// 'DD.MM.YYYY HH:MM:SS': moment().format('DD.MM.YYYY HH:mm:ss'),
|
||||
};
|
||||
};
|
||||
updateCurrentTimestamp();
|
||||
|
||||
setInterval(updateCurrentTimestamp, 1000);
|
||||
},
|
||||
methods: {
|
||||
convertFromUnix() {
|
||||
let timestamp = this.toolData.inputTimestamp.length ? this.toolData.inputTimestamp : this.currentTimestamp;
|
||||
|
||||
const date = moment.unix(timestamp);
|
||||
|
||||
this.toolData.inputYear = date.year();
|
||||
this.toolData.inputMonth = date.month() + 1;
|
||||
this.toolData.inputDay = date.day();
|
||||
this.toolData.inputHour = date.hour();
|
||||
this.toolData.inputMinute = date.minute();
|
||||
this.toolData.inputSecond = date.second();
|
||||
|
||||
},
|
||||
convertToUnix() {
|
||||
const date = moment({
|
||||
year: this.toolData.inputYear,
|
||||
month: this.toolData.inputMonth - 1, // Months are 0-indexed
|
||||
day: this.toolData.inputDay,
|
||||
hour: this.toolData.inputHour,
|
||||
minute: this.toolData.inputMinute,
|
||||
second: this.toolData.inputSecond
|
||||
});
|
||||
|
||||
this.toolData.inputTimestamp = date.unix();
|
||||
},
|
||||
copyTimestamp(text) {
|
||||
navigator.clipboard.writeText(text)
|
||||
.then(() => {
|
||||
// console.log('Timestamp copied to clipboard!');
|
||||
})
|
||||
.catch(err => {
|
||||
// console.error('Failed to copy: ', err);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.table-date-and-time th {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.table-date-and-time td input {
|
||||
width: 80px;
|
||||
}
|
||||
</style>
|
Reference in New Issue
Block a user