Skip to content

Commit f2e0022

Browse files
committed
fix(QR Code Generator): more styling, SVG, image upload
- Use pp-qr-code-styling to allow image upload, SVG and more styling options (except gradient) - Emit Console/Terminal Escape QRCode Fix CorentinTh#621 and CorentinTh#592
1 parent e876d03 commit f2e0022

File tree

8 files changed

+446
-49
lines changed

8 files changed

+446
-49
lines changed

components.d.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,24 +127,26 @@ declare module '@vue/runtime-core' {
127127
MetaTagGenerator: typeof import('./src/tools/meta-tag-generator/meta-tag-generator.vue')['default']
128128
MimeTypes: typeof import('./src/tools/mime-types/mime-types.vue')['default']
129129
NavbarButtons: typeof import('./src/components/NavbarButtons.vue')['default']
130+
NCheckbox: typeof import('naive-ui')['NCheckbox']
130131
NCode: typeof import('naive-ui')['NCode']
131132
NCollapseTransition: typeof import('naive-ui')['NCollapseTransition']
133+
NColorPicker: typeof import('naive-ui')['NColorPicker']
132134
NConfigProvider: typeof import('naive-ui')['NConfigProvider']
133135
NDivider: typeof import('naive-ui')['NDivider']
134136
NEllipsis: typeof import('naive-ui')['NEllipsis']
137+
NForm: typeof import('naive-ui')['NForm']
135138
NFormItem: typeof import('naive-ui')['NFormItem']
136139
NGi: typeof import('naive-ui')['NGi']
137140
NGrid: typeof import('naive-ui')['NGrid']
138141
NH1: typeof import('naive-ui')['NH1']
139142
NH3: typeof import('naive-ui')['NH3']
140143
NIcon: typeof import('naive-ui')['NIcon']
144+
NImage: typeof import('naive-ui')['NImage']
141145
NInputNumber: typeof import('naive-ui')['NInputNumber']
142-
NLabel: typeof import('naive-ui')['NLabel']
143146
NLayout: typeof import('naive-ui')['NLayout']
144147
NLayoutSider: typeof import('naive-ui')['NLayoutSider']
145148
NMenu: typeof import('naive-ui')['NMenu']
146149
NScrollbar: typeof import('naive-ui')['NScrollbar']
147-
NSpin: typeof import('naive-ui')['NSpin']
148150
NumeronymGenerator: typeof import('./src/tools/numeronym-generator/numeronym-generator.vue')['default']
149151
OtpCodeGeneratorAndValidator: typeof import('./src/tools/otp-code-generator-and-validator/otp-code-generator-and-validator.vue')['default']
150152
PasswordStrengthAnalyser: typeof import('./src/tools/password-strength-analyser/password-strength-analyser.vue')['default']

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,9 @@
7979
"pdf-signature-reader": "^1.4.2",
8080
"pinia": "^2.0.34",
8181
"plausible-tracker": "^0.3.8",
82+
"pp-qr-code": "^0.6.3",
8283
"qrcode": "^1.5.1",
84+
"qrcode-terminal-nooctal": "^0.12.1",
8385
"sql-formatter": "^13.0.0",
8486
"ua-parser-js": "^1.0.35",
8587
"ulid": "^2.3.0",

pnpm-lock.yaml

Lines changed: 28 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/composable/downloadBase64.ts

Lines changed: 47 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1-
import { extension as getExtensionFromMime } from 'mime-types';
1+
import { extension as getExtensionFromMimeType, extension as getMimeTypeFromExtension } from 'mime-types';
22
import type { Ref } from 'vue';
33
import _ from 'lodash';
44

5-
export { getMimeTypeFromBase64, useDownloadFileFromBase64 };
5+
export {
6+
getMimeTypeFromBase64,
7+
getMimeTypeFromExtension, getExtensionFromMimeType,
8+
useDownloadFileFromBase64, useDownloadFileFromBase64Refs,
9+
};
610

711
const commonMimeTypesSignatures = {
812
'JVBERi0': 'application/pdf',
@@ -36,30 +40,55 @@ function getFileExtensionFromMimeType({
3640
defaultExtension?: string
3741
}) {
3842
if (mimeType) {
39-
return getExtensionFromMime(mimeType) ?? defaultExtension;
43+
return getExtensionFromMimeType(mimeType) ?? defaultExtension;
4044
}
4145

4246
return defaultExtension;
4347
}
4448

45-
function useDownloadFileFromBase64({ source, filename }: { source: Ref<string>; filename?: string }) {
46-
return {
47-
download() {
48-
if (source.value === '') {
49-
throw new Error('Base64 string is empty');
50-
}
49+
function downloadFromBase64({ sourceValue, filename, extension, fileMimeType }:
50+
{ sourceValue: string; filename?: string; extension?: string; fileMimeType?: string }) {
51+
if (sourceValue === '') {
52+
throw new Error('Base64 string is empty');
53+
}
54+
55+
const defaultExtension = extension ?? 'txt';
56+
const { mimeType } = getMimeTypeFromBase64({ base64String: sourceValue });
57+
let base64String = sourceValue;
58+
if (!mimeType) {
59+
const targetMimeType = fileMimeType ?? getMimeTypeFromExtension(defaultExtension);
60+
base64String = `data:${targetMimeType};base64,${sourceValue}`;
61+
}
62+
63+
const cleanExtension = extension ?? getFileExtensionFromMimeType(
64+
{ mimeType, defaultExtension });
65+
let cleanFileName = filename ?? `file.${cleanExtension}`;
66+
if (extension && !cleanFileName.endsWith(`.${extension}`)) {
67+
cleanFileName = `${cleanFileName}.${cleanExtension}`;
68+
}
5169

52-
const { mimeType } = getMimeTypeFromBase64({ base64String: source.value });
53-
const base64String = mimeType
54-
? source.value
55-
: `data:text/plain;base64,${source.value}`;
70+
const a = document.createElement('a');
71+
a.href = base64String;
72+
a.download = cleanFileName;
73+
a.click();
74+
}
5675

57-
const cleanFileName = filename ?? `file.${getFileExtensionFromMimeType({ mimeType })}`;
76+
function useDownloadFileFromBase64(
77+
{ source, filename, extension, fileMimeType }:
78+
{ source: Ref<string>; filename?: string; extension?: string; fileMimeType?: string }) {
79+
return {
80+
download() {
81+
downloadFromBase64({ sourceValue: source.value, filename, extension, fileMimeType });
82+
},
83+
};
84+
}
5885

59-
const a = document.createElement('a');
60-
a.href = base64String;
61-
a.download = cleanFileName;
62-
a.click();
86+
function useDownloadFileFromBase64Refs(
87+
{ source, filename, extension }:
88+
{ source: Ref<string>; filename?: Ref<string>; extension?: Ref<string> }) {
89+
return {
90+
download() {
91+
downloadFromBase64({ sourceValue: source.value, filename: filename?.value, extension: extension?.value });
6392
},
6493
};
6594
}

src/composable/queryParams.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { useRouteQuery } from '@vueuse/router';
22
import { computed } from 'vue';
3+
import { useStorage } from '@vueuse/core';
34

4-
export { useQueryParam };
5+
export { useQueryParam, useQueryParamOrStorage };
56

67
const transformers = {
78
number: {
@@ -33,3 +34,31 @@ function useQueryParam<T>({ name, defaultValue }: { name: string; defaultValue:
3334
},
3435
});
3536
}
37+
38+
function useQueryParamOrStorage<T>({ name, storageName, defaultValue }: { name: string; storageName: string; defaultValue?: T }) {
39+
const type = typeof defaultValue;
40+
const transformer = transformers[type as keyof typeof transformers] ?? transformers.string;
41+
42+
const storageRef = useStorage(storageName, defaultValue);
43+
const storageDefaultValue = storageRef.value ?? defaultValue;
44+
45+
const proxy = useRouteQuery(name, transformer.toQuery(storageDefaultValue as never));
46+
47+
const ref = computed<T>({
48+
get() {
49+
return transformer.fromQuery(proxy.value) as unknown as T;
50+
},
51+
set(value) {
52+
proxy.value = transformer.toQuery(value as never);
53+
},
54+
});
55+
56+
watch(
57+
ref,
58+
(newValue) => {
59+
storageRef.value = newValue;
60+
},
61+
);
62+
63+
return ref;
64+
}

0 commit comments

Comments
 (0)