You've already forked random-web-tools
Add home page tiles
This commit is contained in:
78
src/views/generators/DummyImage.vue
Normal file
78
src/views/generators/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>
|
179
src/views/generators/IbanGenerator.vue
Normal file
179
src/views/generators/IbanGenerator.vue
Normal file
@ -0,0 +1,179 @@
|
||||
<template>
|
||||
<h2 class="tool-title">IBAN generator</h2>
|
||||
<hr class="mt-5 mb-5">
|
||||
|
||||
<div class="input-group">
|
||||
<label for="style">Country</label>
|
||||
<div>
|
||||
<select id="style" v-model="toolData.country" v-on:change="result">
|
||||
<option value="">Select Country</option>
|
||||
<option v-for="(structure, code) in ibanStructure" :key="code" :value="code">
|
||||
{{ structure.country }}
|
||||
</option>
|
||||
</select>
|
||||
</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 MonacoEditor from "@/components/MonacoEditor.vue";
|
||||
|
||||
function generateRandomNumber(length) {
|
||||
let result = "";
|
||||
for (let i = 0; i < length; i++) {
|
||||
result += Math.floor(Math.random() * 10);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function generateRandomString(length) {
|
||||
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
let result = '';
|
||||
for (let i = 0; i < length; i++) {
|
||||
result += characters.charAt(Math.floor(Math.random() * characters.length));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function mod97(string) {
|
||||
let checksum = string.slice(0, 2);
|
||||
for (let i = 2; i < string.length; i += 7) {
|
||||
checksum = (parseInt(checksum + string.slice(i, i + 7), 10) % 97).toString().padStart(2, '0');
|
||||
}
|
||||
return parseInt(checksum);
|
||||
}
|
||||
|
||||
function calculateCheckDigits(iban) {
|
||||
const rearranged = iban.slice(4) + iban.slice(0, 4);
|
||||
const digits = rearranged.split('').map(char => {
|
||||
if (char >= 'A' && char <= 'Z') {
|
||||
return (char.charCodeAt(0) - 55).toString();
|
||||
}
|
||||
return char;
|
||||
}).join('');
|
||||
const remainder = mod97(digits);
|
||||
return ('0' + (98 - remainder)).slice(-2);
|
||||
}
|
||||
|
||||
export default {
|
||||
components: {
|
||||
MonacoEditor
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
toolData: {
|
||||
country: "",
|
||||
},
|
||||
toolResult: "",
|
||||
ibanStructure: {
|
||||
AD: { country: "Andorra", length: 24, structure: "F04F04F12" },
|
||||
AE: { country: "United Arab Emirates", length: 23, structure: "F03F16" },
|
||||
AT: { country: "Austria", length: 20, structure: "F05F11" },
|
||||
BA: { country: "Bosnia and Herzegovina", length: 20, structure: "F03F03F08F02" },
|
||||
BE: { country: "Belgium", length: 16, structure: "F03F07F02" },
|
||||
BG: { country: "Bulgaria", length: 22, structure: "U04F04F02F08" },
|
||||
BH: { country: "Bahrain", length: 22, structure: "U04F14" },
|
||||
BR: { country: "Brazil", length: 29, structure: "F08F05F10U01U01" },
|
||||
CH: { country: "Switzerland", length: 21, structure: "F05U12" },
|
||||
CY: { country: "Cyprus", length: 28, structure: "F03F05U16" },
|
||||
CZ: { country: "Czech Republic", length: 24, structure: "F04F06F10" },
|
||||
DE: { country: "Germany", length: 22, structure: "F08F10" },
|
||||
DK: { country: "Denmark", length: 18, structure: "F04F09F01" },
|
||||
EE: { country: "Estonia", length: 20, structure: "F02F02F11F01" },
|
||||
ES: { country: "Spain", length: 24, structure: "F04F04F01F01F10" },
|
||||
FI: { country: "Finland", length: 18, structure: "F06F07F01" },
|
||||
FR: { country: "France", length: 27, structure: "F05F05U11F02" },
|
||||
GB: { country: "United Kingdom", length: 22, structure: "U04F06F08" },
|
||||
GE: { country: "Georgia", length: 22, structure: "U02F16" },
|
||||
GI: { country: "Gibraltar", length: 23, structure: "U04U15" },
|
||||
GR: { country: "Greece", length: 27, structure: "F03F04U16" },
|
||||
HR: { country: "Croatia", length: 21, structure: "F07F10" },
|
||||
HU: { country: "Hungary", length: 28, structure: "F03F04F01F15F01" },
|
||||
IE: { country: "Ireland", length: 22, structure: "U04F06F08" },
|
||||
IL: { country: "Israel", length: 23, structure: "F03F03F13" },
|
||||
IS: { country: "Iceland", length: 26, structure: "F04F02F06F10" },
|
||||
IT: { country: "Italy", length: 27, structure: "U01F05F05U12" },
|
||||
JO: { country: "Jordan", length: 30, structure: "U04F04U18" },
|
||||
KW: { country: "Kuwait", length: 30, structure: "U04U22" },
|
||||
KZ: { country: "Kazakhstan", length: 20, structure: "F03U13" },
|
||||
LB: { country: "Lebanon", length: 28, structure: "F04U20" },
|
||||
LI: { country: "Liechtenstein", length: 21, structure: "F05U12" },
|
||||
LT: { country: "Lithuania", length: 20, structure: "F05F11" },
|
||||
LU: { country: "Luxembourg", length: 20, structure: "F03U13" },
|
||||
LV: { country: "Latvia", length: 21, structure: "U04U13" },
|
||||
MC: { country: "Monaco", length: 27, structure: "F05F05U11F02" },
|
||||
MD: { country: "Moldova", length: 24, structure: "U02F18" },
|
||||
ME: { country: "Montenegro", length: 22, structure: "F03F13F02" },
|
||||
MK: { country: "North Macedonia", length: 19, structure: "F03U10F02" },
|
||||
MR: { country: "Mauritania", length: 27, structure: "F05F05F11F02" },
|
||||
MT: { country: "Malta", length: 31, structure: "U04F05U18" },
|
||||
MU: { country: "Mauritius", length: 30, structure: "U04F02F02F12F03U03" },
|
||||
NL: { country: "Netherlands", length: 18, structure: "U04F10" },
|
||||
NO: { country: "Norway", length: 15, structure: "F04F06F01" },
|
||||
PK: { country: "Pakistan", length: 24, structure: "U04U16" },
|
||||
PL: { country: "Poland", length: 28, structure: "F08F16" },
|
||||
PT: { country: "Portugal", length: 25, structure: "F04F04F11F02" },
|
||||
QA: { country: "Qatar", length: 29, structure: "U04U21" },
|
||||
RO: { country: "Romania", length: 24, structure: "U04U16" },
|
||||
RS: { country: "Serbia", length: 22, structure: "F03F13F02" },
|
||||
SA: { country: "Saudi Arabia", length: 24, structure: "F02U18" },
|
||||
SE: { country: "Sweden", length: 24, structure: "F03F16F01" },
|
||||
SI: { country: "Slovenia", length: 19, structure: "F05F08F02" },
|
||||
SK: { country: "Slovakia", length: 24, structure: "F04F06F10" },
|
||||
SM: { country: "San Marino", length: 27, structure: "U01F05F05U12" },
|
||||
TN: { country: "Tunisia", length: 24, structure: "F02F03F13F02" },
|
||||
TR: { country: "Turkey", length: 26, structure: "F05U01U16" },
|
||||
UA: { country: "Ukraine", length: 29, structure: "F06F19" },
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
result() {
|
||||
if (!this.toolData.country.length) {
|
||||
this.toolResult = 'Select a country';
|
||||
return;
|
||||
}
|
||||
|
||||
const structure = this.ibanStructure[this.toolData.country];
|
||||
if (!structure) {
|
||||
this.toolResult = 'Unsupported country';
|
||||
return;
|
||||
}
|
||||
|
||||
let iban = this.toolData.country + '00'; // Add placeholder check digits
|
||||
const parts = structure.structure.match(/([FU])(\d+)/g);
|
||||
|
||||
for (const part of parts) {
|
||||
const type = part[0];
|
||||
const length = parseInt(part.slice(1));
|
||||
|
||||
switch (type) {
|
||||
case 'F':
|
||||
iban += generateRandomNumber(length);
|
||||
break;
|
||||
case 'U':
|
||||
iban += generateRandomString(length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate and replace check digits
|
||||
const checkDigits = calculateCheckDigits(iban);
|
||||
iban = iban.slice(0, 2) + checkDigits + iban.slice(4);
|
||||
|
||||
this.toolResult = iban;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
</style>
|
181
src/views/generators/QRCode.vue
Normal file
181
src/views/generators/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>
|
Reference in New Issue
Block a user