You've already forked random-web-tools
first commit
This commit is contained in:
71
src/App.vue
Normal file
71
src/App.vue
Normal file
@ -0,0 +1,71 @@
|
||||
<template>
|
||||
<div
|
||||
class="w-full flex flex-col sm:flex-row flex-grow"
|
||||
:class="{ 'sidebar-toggle': sidebarToggle }">
|
||||
<aside
|
||||
class="hidden md:block h-screen overflow-y-auto no-scrollbar border-r">
|
||||
<Sidebar/>
|
||||
</aside>
|
||||
|
||||
<main role="main" class="w-full h-full flex-grow overflow-auto p-3">
|
||||
<RouterView/>
|
||||
</main>
|
||||
|
||||
<button class="sidebar-toggle-btn md:hidden" v-on:click="toggleSidebar">
|
||||
<svg class="svg-icon" style="width: 30px; height: 30px;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M682.666667 682.666667h170.666666v170.666666h-170.666666v-170.666666z m-256 0h170.666666v170.666666h-170.666666v-170.666666z m-256 0h170.666666v170.666666H170.666667v-170.666666z m512-256h170.666666v170.666666h-170.666666v-170.666666z m-256 0h170.666666v170.666666h-170.666666v-170.666666z m-256 0h170.666666v170.666666H170.666667v-170.666666z m512-256h170.666666v170.666666h-170.666666V170.666667z m-256 0h170.666666v170.666666h-170.666666V170.666667zM170.666667 170.666667h170.666666v170.666666H170.666667V170.666667z" fill="#000000" /></svg>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { RouterView } from 'vue-router'
|
||||
import Sidebar from '@/components/Sidebar.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Sidebar,
|
||||
RouterView,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
sidebarToggle: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
toggleSidebar() {
|
||||
this.sidebarToggle = !this.sidebarToggle;
|
||||
|
||||
this.emitter.emit('sidebar.toggle');
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
aside {
|
||||
width: 480px;
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.sidebar-toggle {
|
||||
aside {
|
||||
display: block;
|
||||
width: 100%;
|
||||
max-width: initial;
|
||||
}
|
||||
|
||||
main {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&-btn {
|
||||
right: 10px;
|
||||
bottom: 10px;
|
||||
position: fixed;
|
||||
z-index: 1000;
|
||||
background-color: white;
|
||||
border-radius: 5px;
|
||||
padding: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
23
src/app.js
Normal file
23
src/app.js
Normal file
@ -0,0 +1,23 @@
|
||||
import { createApp } from 'vue'
|
||||
import { createPinia } from 'pinia'
|
||||
import axios from 'axios'
|
||||
import VueAxios from 'vue-axios'
|
||||
import mitt from 'mitt';
|
||||
|
||||
import './assets/app.scss'
|
||||
|
||||
import App from './App.vue'
|
||||
import router from './router'
|
||||
|
||||
axios.defaults.withCredentials = true;
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
app.config.globalProperties.emitter = mitt();
|
||||
|
||||
app.use(createPinia())
|
||||
app.use(VueAxios, axios)
|
||||
|
||||
app.use(router)
|
||||
|
||||
app.mount('#app')
|
27
src/assets/app.scss
Normal file
27
src/assets/app.scss
Normal file
@ -0,0 +1,27 @@
|
||||
@import "tailwindcss/base";
|
||||
@import "tailwindcss/components";
|
||||
@import "tailwindcss/utilities";
|
||||
|
||||
|
||||
/**
|
||||
* Components
|
||||
*/
|
||||
input[type=text], input[type=number], textarea {
|
||||
@apply appearance-none border leading-tight focus:outline-none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tools
|
||||
*/
|
||||
.tool-title {
|
||||
@apply font-bold;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.input-group {
|
||||
@apply flex flex-col mb-3;
|
||||
}
|
||||
|
||||
.input-group > label {
|
||||
font-style: italic;
|
||||
}
|
31
src/components/Sidebar.vue
Normal file
31
src/components/Sidebar.vue
Normal file
@ -0,0 +1,31 @@
|
||||
<template>
|
||||
<header class="flex">
|
||||
<span class="my-auto ml-2 font-bold">Tools</span>
|
||||
</header>
|
||||
|
||||
<hr class="mt-2 mb-2">
|
||||
|
||||
<nav class="flex flex-col ml-2">
|
||||
<router-link v-for="[key, value] of Object.entries(menuRoutes)" :to="{name:key}" tag="button">{{ value }}</router-link>
|
||||
</nav>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "Sidebar",
|
||||
components: {},
|
||||
data() {
|
||||
return {
|
||||
menuRoutes: {
|
||||
'home': 'Home',
|
||||
'sql_split_in': 'SQL split IN',
|
||||
'str_to_upper': 'Str to upper',
|
||||
'str_to_lower': 'Str to lower',
|
||||
},
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
40
src/router/index.js
Normal file
40
src/router/index.js
Normal file
@ -0,0 +1,40 @@
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
routes: [
|
||||
/**
|
||||
* General
|
||||
*/
|
||||
{
|
||||
path: '/',
|
||||
name: 'home',
|
||||
component: () => import('../views/HomeView.vue'),
|
||||
},
|
||||
|
||||
/**
|
||||
* String manipulation
|
||||
*/
|
||||
{
|
||||
path: '/str_to_upper',
|
||||
name: 'str_to_upper',
|
||||
component: () => import('../views/StrToUpper.vue'),
|
||||
},
|
||||
{
|
||||
path: '/str_to_lower',
|
||||
name: 'str_to_lower',
|
||||
component: () => import('../views/StrToLower.vue'),
|
||||
},
|
||||
|
||||
/**
|
||||
* SQL manipulation
|
||||
*/
|
||||
{
|
||||
path: '/sql_split_in',
|
||||
name: 'sql_split_in',
|
||||
component: () => import('../views/SQLSplitInView.vue'),
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
export default router
|
0
src/stores/.gitkeep
Normal file
0
src/stores/.gitkeep
Normal file
7
src/utils/unproxy.js
Normal file
7
src/utils/unproxy.js
Normal file
@ -0,0 +1,7 @@
|
||||
function unproxy(obj) {
|
||||
return JSON.parse(JSON.stringify(obj));
|
||||
}
|
||||
|
||||
export {
|
||||
unproxy,
|
||||
}
|
36
src/utils/useDebouncedRef.js
Normal file
36
src/utils/useDebouncedRef.js
Normal file
@ -0,0 +1,36 @@
|
||||
import { ref, customRef } from 'vue'
|
||||
|
||||
const debounce = (fn, delay = 0, immediate = false) => {
|
||||
let timeout
|
||||
return (...args) => {
|
||||
if (immediate && !timeout) fn(...args)
|
||||
clearTimeout(timeout)
|
||||
|
||||
timeout = setTimeout(() => {
|
||||
fn(...args)
|
||||
}, delay)
|
||||
}
|
||||
}
|
||||
|
||||
const useDebouncedRef = (initialValue, delay, immediate) => {
|
||||
const state = ref(initialValue)
|
||||
const debouncedRef = customRef((track, trigger) => ({
|
||||
get() {
|
||||
track()
|
||||
return state.value
|
||||
},
|
||||
set: debounce(
|
||||
value => {
|
||||
state.value = value
|
||||
trigger()
|
||||
},
|
||||
delay,
|
||||
immediate
|
||||
),
|
||||
}))
|
||||
return debouncedRef
|
||||
}
|
||||
|
||||
export {
|
||||
useDebouncedRef,
|
||||
}
|
7
src/views/HomeView.vue
Normal file
7
src/views/HomeView.vue
Normal file
@ -0,0 +1,7 @@
|
||||
<template>
|
||||
/home
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
</style>
|
103
src/views/SQLSplitInView.vue
Normal file
103
src/views/SQLSplitInView.vue
Normal file
@ -0,0 +1,103 @@
|
||||
<template>
|
||||
<h2 class="tool-title">SQL split IN</h2>
|
||||
<hr class="mt-5 mb-5">
|
||||
|
||||
<div class="input-group">
|
||||
<label for="field_name">Field name</label>
|
||||
<input id="field_name" v-model="toolData.fieldName" placeholder="D.ID" type="text">
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<label for="data">Data</label>
|
||||
<textarea id="data" v-model="toolData.data" style="height: 150px"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<label for="data_delimiter">Delimiter</label>
|
||||
<input id="data_delimiter" v-model="toolData.dataDelimiter" placeholder="," type="text">
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<label>Wrap in quotes</label>
|
||||
|
||||
<div>
|
||||
<input id="wrap_in_quotes_no" value="" name="wrap_in_quotes" v-model="toolData.wrapInQuotes" type="radio"> <label for="wrap_in_quotes_no">No</label><br>
|
||||
<input id="wrap_in_quotes_single" value="single" name="wrap_in_quotes" v-model="toolData.wrapInQuotes" type="radio"> <label for="wrap_in_quotes_single">Single</label><br>
|
||||
<input id="wrap_in_quotes_double" value="double" name="wrap_in_quotes" v-model="toolData.wrapInQuotes" type="radio"> <label for="wrap_in_quotes_double">Double</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<label for="chunk_by">Chunk by</label>
|
||||
<input id="chunk_by" v-model="toolData.chunkBy" placeholder="900" type="number">
|
||||
</div>
|
||||
|
||||
<hr class="mt-5 mb-5">
|
||||
|
||||
<div class="input-group">
|
||||
<label for="result">Result</label>
|
||||
<textarea id="result" v-model="toolResult" style="height: 150px"></textarea>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
function arrayChunk(arr, chunkSize) {
|
||||
const res = [];
|
||||
while (arr.length > 0) {
|
||||
const chunk = arr.splice(0, chunkSize);
|
||||
res.push(chunk);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
toolData: {
|
||||
fieldName: '',
|
||||
data: '',
|
||||
dataDelimiter: '',
|
||||
wrapInQuotes: '',
|
||||
chunkBy: 900,
|
||||
},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
toolResult() {
|
||||
let data = this.toolData.data
|
||||
.split(this.toolData.dataDelimiter ? this.toolData.dataDelimiter : '\n');
|
||||
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
let value = data[i];
|
||||
|
||||
switch (this.toolData.wrapInQuotes) {
|
||||
case 'single':
|
||||
value = "'" + value.replace("'", "\\'") + "'";
|
||||
break;
|
||||
case 'double':
|
||||
value = '"' + value.replace('"', '\\"') + '"';
|
||||
break;
|
||||
}
|
||||
|
||||
data[i] = value;
|
||||
}
|
||||
|
||||
data = arrayChunk(data, this.toolData.chunkBy);
|
||||
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
let chunk = data[i];
|
||||
|
||||
|
||||
|
||||
data[i] = '(' + chunk.join(',') + ')';
|
||||
}
|
||||
|
||||
return '(' + this.toolData.fieldName + ' IN ' + data.join(' OR ' + this.toolData.fieldName + ' IN ') + ')';
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
</style>
|
37
src/views/StrToLower.vue
Normal file
37
src/views/StrToLower.vue
Normal file
@ -0,0 +1,37 @@
|
||||
<template>
|
||||
<h2 class="tool-title">Str to lower</h2>
|
||||
<hr class="mt-5 mb-5">
|
||||
|
||||
<div class="input-group">
|
||||
<label for="data">Data</label>
|
||||
<textarea id="data" v-model="toolData.data" style="height: 150px"></textarea>
|
||||
</div>
|
||||
|
||||
<hr class="mt-5 mb-5">
|
||||
|
||||
<div class="input-group">
|
||||
<label for="result">Result</label>
|
||||
<textarea id="result" v-model="toolResult" style="height: 150px"></textarea>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
toolData: {
|
||||
data: '',
|
||||
},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
toolResult() {
|
||||
return this.toolData.data.toLocaleLowerCase();
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
</style>
|
37
src/views/StrToUpper.vue
Normal file
37
src/views/StrToUpper.vue
Normal file
@ -0,0 +1,37 @@
|
||||
<template>
|
||||
<h2 class="tool-title">Str to upper</h2>
|
||||
<hr class="mt-5 mb-5">
|
||||
|
||||
<div class="input-group">
|
||||
<label for="data">Data</label>
|
||||
<textarea id="data" v-model="toolData.data" style="height: 150px"></textarea>
|
||||
</div>
|
||||
|
||||
<hr class="mt-5 mb-5">
|
||||
|
||||
<div class="input-group">
|
||||
<label for="result">Result</label>
|
||||
<textarea id="result" v-model="toolResult" style="height: 150px"></textarea>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
toolData: {
|
||||
data: '',
|
||||
},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
toolResult() {
|
||||
return this.toolData.data.toLocaleUpperCase();
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
</style>
|
Reference in New Issue
Block a user