Compare commits

..

54 Commits

Author SHA1 Message Date
Corentin Thomasset
ed176c7b8c 1.5.0 2020-06-23 09:40:58 +02:00
Corentin Thomasset
e152651a4b chore: updated version
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-23 09:40:50 +02:00
Corentin Thomasset
a20858dfb8 feat: added qr-code generator
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-23 00:01:14 +02:00
Corentin Thomasset
b75603f311 docs: create tool guideline
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-22 21:15:50 +02:00
Corentin Thomasset
d27c133a66 fix: CHANGELOG.md version
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-22 20:55:16 +02:00
Corentin Thomasset
bd64eb9dbe 1.4.0 2020-06-22 20:54:35 +02:00
Corentin Thomasset
ac54250e8a refactor: changed app title
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-22 20:53:53 +02:00
Corentin Thomasset
e0e7715ce6 feat: added canonical url
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-22 18:42:19 +02:00
Corentin Thomasset
aa3a424f10 docs: updated README.md
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-21 18:45:12 +02:00
Corentin Thomasset
03e073d4f0 feat: git memo
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-21 18:42:19 +02:00
Corentin Thomasset
cb0e3f91db feat: git memo
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-21 18:34:17 +02:00
Corentin Thomasset
c8c0dceb21 refactor: globalised code style
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-21 18:33:56 +02:00
Corentin Thomasset
ba5e07d063 refactor: home page layout
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-21 18:33:17 +02:00
Corentin Thomasset
9e94a985ca feat: ga monitor app version
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-21 18:32:44 +02:00
Corentin Thomasset
a14a7338f8 feat: added call to action
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-21 18:31:56 +02:00
Corentin Thomasset
b65472ce96 feat: condensed + colored sidenav
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-21 11:31:22 +02:00
Corentin Thomasset
87f269a792 Merge branch 'master' of github.com:CorentinTh/it-tools 2020-06-15 22:26:00 +02:00
Corentin Thomasset
27f957a098 fix: added version in CHANGELOG.md
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-15 22:22:37 +02:00
Corentin Thomasset
551738f559 1.3.0 2020-06-15 22:12:46 +02:00
Corentin Thomasset
8f7b7f628e docs: checked Lorem ipsum generator in roadmap
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-15 22:12:46 +02:00
Corentin Thomasset
46514cf71b feat: fixed icons width in sidebar
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-15 22:12:46 +02:00
Corentin Thomasset
78157b4cb5 feat: fixed icons width in sidebar
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-15 22:12:46 +02:00
Corentin Thomasset
bf4260f926 docs: checked markdown editor in roadmap
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-15 22:12:46 +02:00
Corentin Thomasset
9fc566e55a refactor: now using marked for changelog
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-15 22:12:46 +02:00
Corentin Thomasset
507d961cd8 feat: added MarkdownEditor.vue
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-15 22:12:46 +02:00
Corentin Thomasset
0631a7f750 chore: added stuff to roadmap
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-15 22:12:46 +02:00
Corentin Thomasset
99ffe08d01 chore: update CHANGELOG.md
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-15 22:12:46 +02:00
Corentin Thomasset
fcc1335f97 refactor: removed lazyLoad method
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-15 22:12:46 +02:00
Corentin THOMASSET
3988d33218 chore: updated changelog 2020-06-15 22:12:46 +02:00
Alexander Janke
ecb4b1bb7b Use vue-typecast
https://vuejs.org/v2/guide/forms.html#number
2020-06-15 22:12:46 +02:00
Corentin Thomasset
b63c4b5415 refactor: lazy-loading tools routes
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-15 22:12:46 +02:00
Corentin Thomasset
26bda68f41 fix: ordered contributors by contribution count
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-15 22:12:46 +02:00
Corentin Thomasset
f9f80b4e3a fix: replace next by version
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-15 22:12:46 +02:00
Corentin Thomasset
f50c5cb91b 1.3.0 2020-06-15 22:10:09 +02:00
Corentin Thomasset
da1da1d269 docs: checked Lorem ipsum generator in roadmap
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-15 22:10:08 +02:00
Corentin Thomasset
4129169e2b feat: fixed icons width in sidebar
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-15 22:10:08 +02:00
Corentin Thomasset
cffbfe3e39 feat: fixed icons width in sidebar
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-15 22:10:08 +02:00
Corentin Thomasset
583ce878d2 docs: checked markdown editor in roadmap
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-15 22:10:08 +02:00
Corentin Thomasset
c179f6a800 refactor: now using marked for changelog
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-15 22:10:08 +02:00
Corentin Thomasset
7944fd9f17 feat: added MarkdownEditor.vue
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-15 22:10:08 +02:00
Corentin Thomasset
84763e1d5f chore: added stuff to roadmap
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-15 22:10:08 +02:00
Corentin Thomasset
ab56a3b598 chore: update CHANGELOG.md
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-15 22:10:08 +02:00
Corentin Thomasset
b7d7454df5 refactor: removed lazyLoad method
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-15 22:10:08 +02:00
Corentin THOMASSET
b730c1d1b4 chore: updated changelog 2020-06-15 22:10:08 +02:00
Alexander Janke
f6da2a44e5 Use vue-typecast
https://vuejs.org/v2/guide/forms.html#number
2020-06-15 22:10:08 +02:00
Corentin Thomasset
89713c4986 refactor: lazy-loading tools routes
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-15 22:10:08 +02:00
Corentin Thomasset
3401fa4cf1 fix: ordered contributors by contribution count
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-15 22:10:08 +02:00
Corentin Thomasset
2a7abceba1 fix: replace next by version
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-15 22:10:08 +02:00
Corentin Thomasset
cd9a2318fd fix: added parseFloat in isInt
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-09 08:22:26 +02:00
Corentin Thomasset
0ebe60e21e 1.2.1 2020-06-09 08:22:26 +02:00
Corentin Thomasset
634147f0b3 chore: update CHANGELOG.md
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-09 08:22:26 +02:00
dotvirus
318691837e Use Number.isInteger 2020-06-09 08:22:26 +02:00
Corentin Thomasset
17f3e7de35 refactor: proper validation rules
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-09 08:22:26 +02:00
Corentin Thomasset
aa4fb5ffff fix: added quantity validation rules
Signed-off-by: Corentin Thomasset <corentin.thomasset74@gmail.com>
2020-06-09 08:22:26 +02:00
18 changed files with 592 additions and 23 deletions

View File

@@ -3,7 +3,15 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## Next
## 1.5.0
- [feat] added [qr-code generator](/#/qrcode-generator)
## 1.4.0
- [ui] condensed + colored sidenav
- [feat] added [git memo](/#/git-memo)
- [refactor] changed app title
## 1.3.0
- [fix] [GithubContributors] ordered contributors by contribution count
- [refactor] used vue-typecasting for number inputs
- [feat] lazy loading tools routes

View File

@@ -17,14 +17,17 @@ Here is an unordered list of the current functionalities, and some that may come
- [x] Text information
- [x] Markdown editor
- [x] Lorem ipsum text generator
- [x] Git memo (cheat sheet)
- [x] QR code generator
- [ ] CSS memo (cheat sheet)
- [ ] REGEX memo (cheat sheet) + tester?
- [ ] Image exif editor/remover
- [ ] QR code generator
- [ ] Bip39 pass-phrase generator
- [ ] Crontab friendly generator
- [ ] Image format converter?
- [ ] Image cropper
- [ ] Image resizer
- [ ] HTTP client (w/ axios)
- [ ] HTTP client (w/ axios + cors proxy)
- [ ] Math expression evaluator
- [ ] Math expression graph
@@ -49,6 +52,29 @@ npm run lint
## Contribute
**Pull requests are welcome !** Feel free to contribute.
### Add a tool
To add a tool you just have to create a vue component in [src/routes/tools](./src/routes/tools), example:
```vue
<template>
<v-card class="single-card">
<v-card-title>My component</v-card-title>
<v-card-text>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</v-card-text>
</v-card>
</template>
<script>
export default {
name: "My component"
}
</script>
<style scoped lang="less">
</style>
```
Then, update the file [router.js](./src/router.js) specifying info of the component.
Use [fontawesome 5](https://fontawesome.com/icons?d=gallery&m=free) for icons.
## Credits
Coded with ❤️ by [Corentin Thomasset](//corentin-thomasset.fr).

7
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "it-tools",
"version": "1.3.0",
"version": "1.5.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -9990,6 +9990,11 @@
"integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=",
"dev": true
},
"qrcode.vue": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/qrcode.vue/-/qrcode.vue-1.7.0.tgz",
"integrity": "sha512-R7t6Y3fDDtcU7L4rtqwGUDP9xD64gJhIwpfjhRCTKmBoYF6SS49PIJHRJ048cse6OI7iwTwgyy2C46N9Ygoc6g=="
},
"qs": {
"version": "6.5.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",

View File

@@ -1,7 +1,7 @@
{
"name": "it-tools",
"description": "",
"version": "1.3.0",
"version": "1.5.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
@@ -15,6 +15,7 @@
"core-js": "^3.6.4",
"dompurify": "^2.0.11",
"marked": "^1.1.0",
"qrcode.vue": "^1.7.0",
"register-service-worker": "^1.7.1",
"roboto-fontface": "*",
"vue": "^2.6.11",

View File

@@ -5,7 +5,8 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
<title>IT Tools - Set of handy developer tools</title>
<link rel="canonical" href="https://it-tools.tech">
<meta itemprop="name" content="IT-Tools">
<meta property="og:title" content="IT-Tools">
<meta name="twitter:title" content="IT-Tools">

View File

@@ -1,7 +1,7 @@
<template>
<v-app id="inspire">
<vue-headful
:title="currentRoute ? `${currentRoute.text} - IT-Tools` : 'IT-Tools'"
:title="currentRoute ? `${currentRoute.text} - IT Tools` : 'IT Tools - Set of handy developer tools'"
:description="currentRoute ? currentRoute.description: 'Aggregated set of useful tools that every developer may need once in a while.'"
:keywords="currentRoute ? currentRoute.keywords: null"
image="/img/banner.png"
@@ -11,7 +11,7 @@
<SearchBar class="hidden-sm-and-up"/>
</template>
<v-list dense>
<v-list dense id="navigation-list">
<div v-for="section in items" :key="section.title">
<v-subheader class="mt-4 pl-4">{{section.title}}</v-subheader>
@@ -126,10 +126,16 @@
html {
overflow-y: auto !important;
}
code{
background-color: rgba(0, 0, 0, 0.15) !important;
box-shadow: none !important;
color: #9a9a9a !important;
font-weight: normal !important;
}
.pretty-scrollbar{
&::-webkit-scrollbar {
width: 5px!important;
height: 5px !important;
}
/* Track */
@@ -149,6 +155,18 @@
}
}
#navigation-list{
div:first-child .v-subheader{
margin-top: 0 !important;
}
.v-list-item__action{
margin: 8px 25px 8px 0;
.v-icon{
color: #4CAF50 !important;
}
}
}
.v-navigation-drawer__content{
.pretty-scrollbar;

View File

@@ -4,7 +4,9 @@
<p class="text-justify">
Welcome to <strong>IT-Tools</strong>! This wonderful website, originally created with by
<a href="//corentin-thomasset.fr">Corentin Thomasset</a>, aggregate a set of useful tools
that every developer may need once in a while.
that every developer may need once in a while. And don't forget to add <strong>IT-Tools</strong> to your
shortcut bar (press <code>{{ isMacOS ? 'Cmd' : 'Ctrl' }} +
D</code>).
</p>
@@ -30,7 +32,10 @@
<script>
export default {
name: "Abstract"
name: "Abstract",
data: () => ({
isMacOS: navigator.platform.toUpperCase().indexOf('MAC') >= 0
})
}
</script>

View File

@@ -0,0 +1,58 @@
<template>
<v-text-field v-model="color" hide-details class="ma-0 pa-0" outlined :label="label" v-on:input="$emit('input', color)">
<template v-slot:append>
<v-menu v-model="menu" top nudge-bottom="101" nudge-left="16" :close-on-content-click="false">
<template v-slot:activator="{ on }">
<div :style="swatchStyle" v-on="on" />
</template>
<v-card>
<v-card-text class="pa-0">
<v-color-picker v-model="color" flat v-on:input="$emit('input', color)"/>
</v-card-text>
</v-card>
</v-menu>
</template>
</v-text-field>
</template>
<script>
// From: https://codepen.io/JamieCurnow/pen/KKPjraK
export default {
name: "ColorInput",
props:{
value: {
type: String,
default: '#FFFFFF'
},
label:String
},
data: () => ({
menu: false,
color:''
}),
mounted() {
this.color = this.value
},
computed: {
swatchStyle() {
const { color, menu } = this
return {
backgroundColor: color,
cursor: 'pointer',
height: '30px',
width: '30px',
borderRadius: menu ? '50%' : '4px',
transition: 'border-radius 200ms ease-in-out'
}
}
}
}
</script>
<style scoped lang="less">
::v-deep .v-input__append-inner{
margin-top: 13px;
}
</style>

View File

@@ -0,0 +1,43 @@
<template>
<div class="copyable-code-content" @click="copy($slots.default[0].text)">
<pre class="pretty-scrollbar"><slot></slot></pre>
<v-icon>far fa-copy</v-icon>
</div>
</template>
<script>
import {copyable} from "../mixins/copyable.mixin";
export default {
name: "CopyableCodeContent",
mixins: [copyable]
}
</script>
<style lang="less" scoped>
.copyable-code-content {
cursor: pointer;
background-color: rgba(0, 0, 0, 0.1);
border-radius: 4px;
padding: 8px 15px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
pre {
flex: 1;
overflow-x: auto;
}
.v-icon {
opacity: 0;
}
&:hover {
.v-icon {
opacity: 1;
}
}
}
</style>

View File

@@ -0,0 +1,73 @@
<template>
<div class="memo-viewer" v-bind:style="{ columns: `auto ${colWidth}` }">
<div class="section" v-for="(group,i) in memo" :key="i">
<h2>{{group.section}}</h2>
<div class="tip" v-for="(tips,i) in group.child" :key="i">
<v-card>
<v-card-text>
<template v-for="tip in (Array.isArray(tips) ? tips : [tips])">
<p :key="tip.text">{{tip.text}}</p>
<CopyableCodeContent class="code" :key="tip.code">{{tip.code}}</CopyableCodeContent>
</template>
</v-card-text>
</v-card>
</div>
</div>
</div>
</template>
<script>
import CopyableCodeContent from "./CopyableCodeContent";
export default {
name: "MemoViewer",
props: {
memo: Array,
colWidth: {
type: String,
default: '400px'
}
},
components: {
CopyableCodeContent
}
}
</script>
<style lang="less" scoped>
.memo-viewer {
column-gap: 30px;
column-rule: 1px solid #37373961;
column-fill: auto;
}
.section {
break-inside: avoid-column;
display: inline-block;
margin-bottom: 20px;
width: 100%;
h2 {
margin: 25px 0 15px;
display: inline-block;
}
.tip {
margin: 20px 0;
.v-card{
background-color: rgba(47, 46, 46, 0.44);
}
p {
margin-bottom: 10px;
&:not(:first-child){
margin-top: 16px;
}
}
}
}
</style>

View File

@@ -0,0 +1,10 @@
import {copyToClipboard} from "../utils/helpers";
export const copyable = {
methods: {
copy(text, toastText = 'Copied to clipboard !'){
copyToClipboard(text);
this.$toast.success(toastText)
}
}
}

View File

@@ -5,6 +5,12 @@ import router from "../router";
if(process.env.VUE_APP_GANALYTICS){
Vue.use(VueAnalytics, {
id: process.env.VUE_APP_GANALYTICS,
router
router,
set:[
{
field: 'dimension1',
value: process.env.APPLICATION_VERSION
}
]
})
}

View File

@@ -109,6 +109,30 @@ const toolsComponents = [
keywords: ['text', 'dolor', 'sit', 'placeholder', 'fill', 'dummy']
}
],
},
{
title: 'Memos',
child: [
{
text: 'Git memo',
path: '/git-memo',
icon: 'fa-code-branch',
component: () => import('./routes/tools/GitMemo'),
keywords: ['git', 'push', 'rebase', 'merge', 'tag', 'commit', 'checkout']
}
]
},
{
title: 'Miscellaneous',
child: [
{
text: 'QR Code generator',
path: '/qrcode-generator',
icon: 'fa-qrcode',
component: () => import('./routes/tools/QRCodeGenerator'),
keywords: []
}
]
}
];

View File

@@ -9,9 +9,7 @@
</v-card-text>
</v-card>
</v-col>
</v-row>
<v-row justify="center" align="center">
<v-col cols="12" lg="8" md="12">
<v-col cols="12" lg="5" md="12">
<v-card class="card-auto">
<v-card-text>
<div class="card-wrapper ">
@@ -56,7 +54,7 @@
flex-wrap: wrap;
div {
flex: 0 1 20%;
flex: 0 1 33%;
@media only screen and (max-width: 800px) {
flex: 0 1 33%;

View File

@@ -0,0 +1,154 @@
<template>
<v-row>
<v-col cols="12" xl="12">
<v-card>
<v-card-title>Git Memo</v-card-title>
<v-card-text>
<MemoViewer :memo="tips"/>
</v-card-text>
</v-card>
</v-col>
</v-row>
</template>
<script>
import MemoViewer from "../../components/MemoViewer";
export default {
name: "GitMemo",
data: () => ({
tips: [
{
section: 'Get started',
child: [
{
text: 'Create a git repo',
code: 'git init'
},
{
text: 'Clone an existing repository',
code: 'git clone [repo url]'
},
{
text: 'Add current files to next commit',
code: 'git add .'
},
{
text: 'Commit tracked files changes',
code: 'git commit -am "[commit message]"'
},
{
text: 'List files that has changed',
code: 'git status'
},
{
text: 'List changes in tracked files',
code: 'git diff'
}
]
},
{
section: 'Basic configuration',
child: [
{
text: 'Set the name that will be associated to every operation',
code: 'git config --global user.name "[nom]"'
},
{
text: 'Set the email address that will be associated to every operation',
code: 'git config --global user.email "[email]"'
},
{
text: 'Tell git to always push tags',
code: 'git config --global push.followTags true'
}
]
},
{
section: 'I\'ve made a mistake',
child: [
{
text: 'Change last commit message',
code: 'git commit --amend'
},
{
text: 'Undo most recent commit and keep changes',
code: 'git reset HEAD~1'
},
{
text: 'Undo most recent commit and get rid of changes',
code: 'git reset HEAD~1 --hard'
},
{
text: 'Reset branch to remote state',
code: 'git fetch origin\ngit reset --hard origin/[branch-name]'
}
]
},
{
section: 'Setup SSH',
child: [
[
{
text: '1). Generate an SSH key.',
code: 'ssh-keygen -t rsa -b 4096 -C "[email]"'
},
{
text: '2). Start the ssh-agent in the background.',
code: 'eval "$(ssh-agent -s)"'
},
{
text: '3). Add your SSH private key to the ssh-agent.',
code: 'ssh-add ~/.ssh/id_rsa'
},
{
text: '4). Add your SSH public key to your git server (for github: Settings -> SSH and GPG keys)',
code: 'cat ~/.ssh/id_rsa.pub'
},
{
text: '5). (Optional) Testing your SSH connection',
code: 'ssh -T git@github.com'
},
]
]
},
{
section: 'Merge and rebase',
child: [
{
text: 'Merge a branch into the current',
code: 'git merge [branch]'
},
{
text: 'Abort merge (conflicts)',
code: 'git merge --abort'
},
{
text: 'Continue merge after resolving conflicts',
code: 'git merge --continue'
},
{
text: 'Rebase a branch into the current',
code: 'git rebase [branch]'
},
{
text: 'Rebase merge (conflicts)',
code: 'git merge --abort'
},
{
text: 'Continue rebase after resolving conflicts',
code: 'git merge --continue'
},
]
},
]
}),
components: {
MemoViewer
}
}
</script>
<style lang="less" scoped>
</style>

View File

@@ -58,12 +58,6 @@
h1{
margin-bottom: 15px;
}
code{
background-color: rgba(0, 0, 0, 0.3) !important;
box-shadow: none;
color: #9a9a9a;
font-weight: normal;
}
pre {
width: 100%;

View File

@@ -0,0 +1,137 @@
<template>
<v-card class="single-card">
<v-card-title>QR-code generator</v-card-title>
<v-card-text>
<v-row justify="center" align="center">
<v-col cols="12" lg="6" sm="12">
<v-text-field
outlined
v-model="value"
label="Data"
:rules="rules.value"
/>
<v-slider v-model="size" min="100" max="1920" label="Size (preview will not change): " thumb-label/>
<v-select
outlined
v-model="level"
:items="levels"
label="Error resistance"
/>
<v-row>
<v-col cols="12" md="6" sm="12">
<ColorInput v-model="fgcolor" label="Foreground color"/>
</v-col>
<v-col cols="12" md="6" sm="12">
<ColorInput v-model="bgcolor" label="Background color"/>
</v-col>
</v-row>
</v-col>
<v-col cols="12" lg="6" sm="12" class="text-center">
<qrcode-vue
:value="input"
:size="size"
:level="level"
:background="bgcolor"
:foreground="fgcolor"
render-as="svg"
class-name="qrcode-wrapper"
/>
</v-col>
</v-row>
<div class="text-center mt-3 mb-sm-2">
<v-btn @click="download('png')" class="mr-1" color="primary">download as png</v-btn>
<v-btn @click="download('svg')" class="ml-1" color="primary">download as svg</v-btn>
</div>
</v-card-text>
</v-card>
</template>
<script>
import QrcodeVue from 'qrcode.vue'
import colors from "color-name";
import ColorInput from "../../components/ColorInput";
import {downloadBase64File} from "../../utils/helpers";
export default {
name: "QRCodeGenerator",
data: () => ({
value: 'https://it-tools.tech',
size: 300,
level: 'M',
bgcolor: '#ffffff',
fgcolor: '#000000',
levels: [
{text: 'Low', value: 'L'},
{text: 'Medium', value: 'M'},
{text: 'Quartile', value: 'Q'},
{text: 'High', value: 'H'}
],
rules: {
value: [
v => v.length > 0 || 'Value is needed'
],
color: [
v => {
v = v.trim()
const isFFFFFF = /^#(?:[0-9a-fA-F]{6})$/.test(v);
const isFFF = /^#(?:[0-9a-fA-F]{3})$/.test(v);
const isRGB = /^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/.test(v);
const isHSL = /^hsl\((\d+),\s*(\d+)%,\s*(\d+)%\)$/.test(v);
const isKeyword = v in colors;
const isTransparent = v === 'transparent';
return isFFFFFF || isFFF || isKeyword || isTransparent || isRGB || isHSL || 'Incorrect color.'
}
]
}
}),
methods: {
download(type) {
const svgEl = this.$el.querySelector('.qrcode-wrapper svg');
const svgString = new XMLSerializer().serializeToString(svgEl);
const svgUrl = `data:image/svg+xml;base64,${btoa(svgString)}`;
if (type === 'png') {
const canvas = document.createElement("canvas");
canvas.width = this.size;
canvas.height = this.size;
const ctx = canvas.getContext("2d");
const image = new Image();
image.onload = function () {
ctx.drawImage(image, 0, 0);
const result = canvas.toDataURL();
downloadBase64File(result, 'qr-code');
};
image.src = svgUrl;
} else {
downloadBase64File(svgUrl, 'qr-code');
}
}
},
computed: {
input() {
return this.value
}
},
components: {
QrcodeVue,
ColorInput
}
}
</script>
<style scoped lang="less">
::v-deep .qrcode-wrapper {
& > * {
width: 300px !important;
height: 300px !important;
}
}
</style>

View File

@@ -41,6 +41,13 @@ const randFromArray = (array) => array[Math.floor(Math.random() * array.length)]
const randIntFromInterval = (min, max) => Math.floor(Math.random() * (max - min) + min)
const downloadBase64File = (dataUrl, name = 'file') => {
const a = document.createElement("a");
a.href = dataUrl;
a.download = name;
a.click();
}
export {
copyToClipboard,
fileIsImage,
@@ -48,5 +55,6 @@ export {
isInt,
debounce,
randFromArray,
randIntFromInterval
randIntFromInterval,
downloadBase64File
}