added QR code generation

This commit is contained in:
Gamosoft 2026-02-09 18:55:55 +01:00
parent 26aa37066f
commit 4ca909b1a8
12 changed files with 95 additions and 15 deletions

View File

@ -277,6 +277,7 @@ function noteApp() {
showShareModal: false, showShareModal: false,
shareInfo: null, shareInfo: null,
shareLoading: false, shareLoading: false,
showShareQR: false,
shareLinkCopied: false, shareLinkCopied: false,
_sharedNotePaths: new Set(), // O(1) lookup for shared note indicators _sharedNotePaths: new Set(), // O(1) lookup for shared note indicators
@ -5378,13 +5379,40 @@ function noteApp() {
this.closeQuickSwitcher(); this.closeQuickSwitcher();
}, },
// Close share modal and reset state after animation
closeShareModal() {
this.showShareModal = false;
// Delay state reset until modal is fully hidden
setTimeout(() => {
this.showShareQR = false;
this.shareInfo = null;
this.shareLoading = false;
}, 200);
},
// Generate QR code for share URL
generateQRCode(url) {
if (!url || typeof qrcode === 'undefined') return '';
try {
const qr = qrcode(0, 'M'); // 0 = auto version, M = medium error correction
qr.addData(url);
qr.make();
return qr.createDataURL(4); // 4 = module size in pixels
} catch (e) {
console.error('QR code generation failed:', e);
return '';
}
},
// Open share modal and fetch current share status // Open share modal and fetch current share status
async openShareModal() { async openShareModal() {
if (!this.currentNote) return; if (!this.currentNote) return;
this.showShareModal = true; // Reset state BEFORE showing modal to prevent flicker
this.shareLoading = true; this.showShareQR = false;
this.shareInfo = null; this.shareInfo = null;
this.shareLoading = true;
this.showShareModal = true;
try { try {
const notePath = this.currentNote.replace('.md', ''); const notePath = this.currentNote.replace('.md', '');

View File

@ -109,6 +109,8 @@
<!-- vis-network for graph visualization (v9.1.9) --> <!-- vis-network for graph visualization (v9.1.9) -->
<script src="https://unpkg.com/vis-network@9.1.9/standalone/umd/vis-network.min.js"></script> <script src="https://unpkg.com/vis-network@9.1.9/standalone/umd/vis-network.min.js"></script>
<!-- QR Code generator for share links -->
<script src="https://cdn.jsdelivr.net/npm/qrcode-generator@1.4.4/qrcode.min.js"></script>
<!-- Theme styles will be loaded dynamically --> <!-- Theme styles will be loaded dynamically -->
<link rel="stylesheet" id="theme-stylesheet" href=""> <link rel="stylesheet" id="theme-stylesheet" href="">
@ -3007,8 +3009,8 @@
<!-- Share Modal --> <!-- Share Modal -->
<div x-show="showShareModal" <div x-show="showShareModal"
@click.self="showShareModal = false" @click.self="closeShareModal()"
@keydown.escape.window="showShareModal && (showShareModal = false)" @keydown.escape.window="showShareModal && closeShareModal()"
class="fixed inset-0 flex items-center justify-center" class="fixed inset-0 flex items-center justify-center"
style="background-color: rgba(0, 0, 0, 0.5); z-index: 1100;" style="background-color: rgba(0, 0, 0, 0.5); z-index: 1100;"
x-cloak> x-cloak>
@ -3073,6 +3075,36 @@
</button> </button>
</div> </div>
<!-- QR Code -->
<div class="mb-4 flex flex-col items-center">
<button
@click="showShareQR = !showShareQR"
class="text-sm flex items-center gap-1 mb-2 transition-colors"
style="color: var(--text-secondary);"
onmouseover="this.style.color='var(--text-primary)'"
onmouseout="this.style.color='var(--text-secondary)'"
>
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v1m6 11h2m-6 0h-2v4m0-11v3m0 0h.01M12 12h4.01M16 20h4M4 12h4m12 0h.01M5 8h2a1 1 0 001-1V5a1 1 0 00-1-1H5a1 1 0 00-1 1v2a1 1 0 001 1zm12 0h2a1 1 0 001-1V5a1 1 0 00-1-1h-2a1 1 0 00-1 1v2a1 1 0 001 1zM5 20h2a1 1 0 001-1v-2a1 1 0 00-1-1H5a1 1 0 00-1 1v2a1 1 0 001 1z"></path>
</svg>
<span x-text="showShareQR ? t('share.hide_qr') : t('share.show_qr')"></span>
<svg class="w-3 h-3 transition-transform" :class="showShareQR ? 'rotate-180' : ''" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
</svg>
</button>
<div x-show="showShareQR"
x-transition:enter="transition ease-out duration-200"
x-transition:enter-start="opacity-0 transform scale-95"
x-transition:enter-end="opacity-100 transform scale-100"
x-transition:leave="transition ease-in duration-150"
x-transition:leave-start="opacity-100 transform scale-100"
x-transition:leave-end="opacity-0 transform scale-95"
class="p-3 rounded-lg"
style="background-color: white;">
<img :src="generateQRCode(shareInfo?.url)" alt="QR Code" class="w-32 h-32" />
</div>
</div>
<!-- Revoke sharing --> <!-- Revoke sharing -->
<button <button
@click="revokeShareLink()" @click="revokeShareLink()"
@ -3088,7 +3120,7 @@
<!-- Close button --> <!-- Close button -->
<div class="mt-4 pt-4 border-t" style="border-color: var(--border-primary);"> <div class="mt-4 pt-4 border-t" style="border-color: var(--border-primary);">
<button <button
@click="showShareModal = false" @click="closeShareModal()"
class="w-full px-4 py-2 rounded font-medium transition-colors" class="w-full px-4 py-2 rounded font-medium transition-colors"
style="background-color: var(--bg-tertiary); color: var(--text-primary);" style="background-color: var(--bg-tertiary); color: var(--text-primary);"
onmouseover="this.style.backgroundColor='var(--bg-hover)'" onmouseover="this.style.backgroundColor='var(--bg-hover)'"

View File

@ -127,7 +127,9 @@
"stop_sharing": "Freigabe beenden", "stop_sharing": "Freigabe beenden",
"confirm_revoke": "Sind Sie sicher, dass Sie die Freigabe dieser Notiz beenden möchten? Der Freigabelink funktioniert dann nicht mehr.", "confirm_revoke": "Sind Sie sicher, dass Sie die Freigabe dieser Notiz beenden möchten? Der Freigabelink funktioniert dann nicht mehr.",
"error_creating": "Fehler beim Erstellen des Freigabelinks: {{error}}", "error_creating": "Fehler beim Erstellen des Freigabelinks: {{error}}",
"error_revoking": "Fehler beim Widerrufen des Freigabelinks: {{error}}" "error_revoking": "Fehler beim Widerrufen des Freigabelinks: {{error}}",
"show_qr": "QR-Code anzeigen",
"hide_qr": "QR-Code ausblenden"
}, },
"quick_switcher": { "quick_switcher": {

View File

@ -126,7 +126,9 @@
"stop_sharing": "Stop Sharing", "stop_sharing": "Stop Sharing",
"confirm_revoke": "Are you sure you want to stop sharing this note? The share link will no longer work.", "confirm_revoke": "Are you sure you want to stop sharing this note? The share link will no longer work.",
"error_creating": "Failed to create share link: {{error}}", "error_creating": "Failed to create share link: {{error}}",
"error_revoking": "Failed to revoke share link: {{error}}" "error_revoking": "Failed to revoke share link: {{error}}",
"show_qr": "Show QR Code",
"hide_qr": "Hide QR Code"
}, },
"quick_switcher": { "quick_switcher": {

View File

@ -127,7 +127,9 @@
"stop_sharing": "Stop Sharing", "stop_sharing": "Stop Sharing",
"confirm_revoke": "Are you sure you want to stop sharing this note? The share link will no longer work.", "confirm_revoke": "Are you sure you want to stop sharing this note? The share link will no longer work.",
"error_creating": "Failed to create share link: {{error}}", "error_creating": "Failed to create share link: {{error}}",
"error_revoking": "Failed to revoke share link: {{error}}" "error_revoking": "Failed to revoke share link: {{error}}",
"show_qr": "Show QR Code",
"hide_qr": "Hide QR Code"
}, },
"quick_switcher": { "quick_switcher": {

View File

@ -127,7 +127,9 @@
"stop_sharing": "Dejar de compartir", "stop_sharing": "Dejar de compartir",
"confirm_revoke": "¿Estás seguro de que quieres dejar de compartir esta nota? El enlace dejará de funcionar.", "confirm_revoke": "¿Estás seguro de que quieres dejar de compartir esta nota? El enlace dejará de funcionar.",
"error_creating": "Error al crear el enlace: {{error}}", "error_creating": "Error al crear el enlace: {{error}}",
"error_revoking": "Error al revocar el enlace: {{error}}" "error_revoking": "Error al revocar el enlace: {{error}}",
"show_qr": "Mostrar código QR",
"hide_qr": "Ocultar código QR"
}, },
"quick_switcher": { "quick_switcher": {

View File

@ -127,7 +127,9 @@
"stop_sharing": "Arrêter le partage", "stop_sharing": "Arrêter le partage",
"confirm_revoke": "Êtes-vous sûr de vouloir arrêter le partage de cette note ? Le lien ne fonctionnera plus.", "confirm_revoke": "Êtes-vous sûr de vouloir arrêter le partage de cette note ? Le lien ne fonctionnera plus.",
"error_creating": "Échec de la création du lien : {{error}}", "error_creating": "Échec de la création du lien : {{error}}",
"error_revoking": "Échec de la révocation du lien : {{error}}" "error_revoking": "Échec de la révocation du lien : {{error}}",
"show_qr": "Afficher le code QR",
"hide_qr": "Masquer le code QR"
}, },
"quick_switcher": { "quick_switcher": {

View File

@ -126,7 +126,9 @@
"stop_sharing": "Interrompi condivisione", "stop_sharing": "Interrompi condivisione",
"confirm_revoke": "Sei sicuro di voler interrompere la condivisione di questa nota? Il link non funzionerà più.", "confirm_revoke": "Sei sicuro di voler interrompere la condivisione di questa nota? Il link non funzionerà più.",
"error_creating": "Impossibile creare il link: {{error}}", "error_creating": "Impossibile creare il link: {{error}}",
"error_revoking": "Impossibile revocare il link: {{error}}" "error_revoking": "Impossibile revocare il link: {{error}}",
"show_qr": "Mostra codice QR",
"hide_qr": "Nascondi codice QR"
}, },
"quick_switcher": { "quick_switcher": {

View File

@ -126,7 +126,9 @@
"stop_sharing": "共有を停止", "stop_sharing": "共有を停止",
"confirm_revoke": "このノートの共有を停止してもよろしいですか?共有リンクは機能しなくなります。", "confirm_revoke": "このノートの共有を停止してもよろしいですか?共有リンクは機能しなくなります。",
"error_creating": "共有リンクの作成に失敗しました: {{error}}", "error_creating": "共有リンクの作成に失敗しました: {{error}}",
"error_revoking": "共有リンクの取り消しに失敗しました: {{error}}" "error_revoking": "共有リンクの取り消しに失敗しました: {{error}}",
"show_qr": "QRコードを表示",
"hide_qr": "QRコードを非表示"
}, },
"quick_switcher": { "quick_switcher": {

View File

@ -126,7 +126,9 @@
"stop_sharing": "Прекратить доступ", "stop_sharing": "Прекратить доступ",
"confirm_revoke": "Вы уверены, что хотите прекратить доступ к этой заметке? Ссылка перестанет работать.", "confirm_revoke": "Вы уверены, что хотите прекратить доступ к этой заметке? Ссылка перестанет работать.",
"error_creating": "Не удалось создать ссылку: {{error}}", "error_creating": "Не удалось создать ссылку: {{error}}",
"error_revoking": "Не удалось отозвать ссылку: {{error}}" "error_revoking": "Не удалось отозвать ссылку: {{error}}",
"show_qr": "Показать QR-код",
"hide_qr": "Скрыть QR-код"
}, },
"quick_switcher": { "quick_switcher": {

View File

@ -126,7 +126,9 @@
"stop_sharing": "Prenehaj deliti", "stop_sharing": "Prenehaj deliti",
"confirm_revoke": "Ali ste prepričani, da želite prenehati deliti ta zapis? Povezava ne bo več delovala.", "confirm_revoke": "Ali ste prepričani, da želite prenehati deliti ta zapis? Povezava ne bo več delovala.",
"error_creating": "Napaka pri ustvarjanju povezave: {{error}}", "error_creating": "Napaka pri ustvarjanju povezave: {{error}}",
"error_revoking": "Napaka pri preklicu povezave: {{error}}" "error_revoking": "Napaka pri preklicu povezave: {{error}}",
"show_qr": "Prikaži QR kodo",
"hide_qr": "Skrij QR kodo"
}, },
"quick_switcher": { "quick_switcher": {

View File

@ -126,7 +126,9 @@
"stop_sharing": "停止分享", "stop_sharing": "停止分享",
"confirm_revoke": "您确定要停止分享此笔记吗?分享链接将不再有效。", "confirm_revoke": "您确定要停止分享此笔记吗?分享链接将不再有效。",
"error_creating": "创建分享链接失败:{{error}}", "error_creating": "创建分享链接失败:{{error}}",
"error_revoking": "撤销分享链接失败:{{error}}" "error_revoking": "撤销分享链接失败:{{error}}",
"show_qr": "显示二维码",
"hide_qr": "隐藏二维码"
}, },
"quick_switcher": { "quick_switcher": {