Add changelog footer (#126)

This commit is contained in:
Estee Tey 2025-05-03 21:03:01 +08:00 committed by GitHub
parent fa973dcc3a
commit 718278a53c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
39 changed files with 887 additions and 125 deletions

1
.gitignore vendored
View File

@ -13,6 +13,7 @@ dist
dist-ssr
coverage
*.local
crowdin.yml
/cypress/videos/
/cypress/screenshots/

View File

@ -1,38 +0,0 @@
## V0
Feat:
- Generate QR codes with custom colors and styles
- Support for various output formats, including SVG and PNG
- Copy to clipboard
- UI respects user's light/dark mode preferences
- Randomize style button
- Available in 29 languages thanks to [deepl-translate-github-action](https://github.com/lyqht/deepl-translate-github-action)
- Save & Load QR Code config
## V0.1
Feat:
- Upload custom image for logo
Misc/Fixes:
- Fix inconsistencies in button & input styling, refactoring of styles
- Added feature of logo image upload
- Fix missing inputs for background color and border-radius
## V0.2
Feat:
- Presets: Pre-crafted QR code styles are available as immediate usage/ reference. Current presets available: padletPreset, uiliciousPreset, supabasePreset, vercelLightPreset, vercelDarkPreset.
Misc/Fixes:
- Refactoring of styles
## V0.3
New presets:
- vueJsPreset, vuei18nPreset, pejuangKodePreset
Misc/Fixes:
- Reorder inputs for colors to be together
- Improve styling for desktop using flex-wrap
- Sort presets by alphabetical order except for default

View File

@ -1,29 +0,0 @@
#
# Basic Crowdin CLI configuration
# See https://crowdin.github.io/crowdin-cli/configuration for more information
# See https://support.crowdin.com/developer/configuration-file/ for all available options
#
# Defines whether to preserve the original directory structure in the Crowdin project
# Recommended to set to true
#
"preserve_hierarchy": true
#
# Files configuration.
# See https://support.crowdin.com/developer/configuration-file/ for all available options
#
files: [
{
#
# Source files filter
# e.g. "/resources/en/*.json"
#
"source": "locales/en.json",
#
# Translation files filter
# e.g. "/resources/%two_letters_code%/%original_file_name%"
#
"translation": "locales/%two_letters_code%.json",
}
]

View File

@ -228,5 +228,11 @@
"Message": "Message",
"Frame text": "Frame text",
"QR codes will be generated using the frame settings you have set above.": "QR codes will be generated using the frame settings you have set above.",
"Configure frame settings": "Configure frame settings"
}
"Configure frame settings": "Configure frame settings",
"View changelog": "View changelog",
"Changelog": "Changelog",
"Close": "Close",
"Error": "Error",
"Failed to load changelog": "Failed to load changelog",
"Loading...": "Loading..."
}

View File

@ -228,5 +228,11 @@
"Message": "الرسالة",
"Frame text": "نص الإطار",
"QR codes will be generated using the frame settings you have set above.": "سيتم إنشاء رموز QR باستخدام إعدادات الإطار التي قمت بتعيينها أعلاه.",
"Configure frame settings": "تكوين إعدادات الإطار"
}
"Configure frame settings": "تكوين إعدادات الإطار",
"View changelog": "عرض سجل التغييرات",
"Changelog": "سجل التغييرات",
"Close": "إغلاق",
"Error": "خطأ",
"Failed to load changelog": "فشل تحميل سجل التغيير",
"Loading...": "جاري التحميل..."
}

View File

@ -228,5 +228,11 @@
"Message": "Message",
"Frame text": "Frame text",
"QR codes will be generated using the frame settings you have set above.": "QR codes will be generated using the frame settings you have set above.",
"Configure frame settings": "Configure frame settings"
}
"Configure frame settings": "Configure frame settings",
"View changelog": "View changelog",
"Changelog": "Changelog",
"Close": "Close",
"Error": "Error",
"Failed to load changelog": "Failed to load changelog",
"Loading...": "Loading..."
}

View File

@ -228,5 +228,11 @@
"Message": "Zpráva",
"Frame text": "Text rámečku",
"QR codes will be generated using the frame settings you have set above.": "Kódy QR se vygenerují pomocí nastavení rámečku, které jste nastavili výše.",
"Configure frame settings": "Konfigurace nastavení rámu"
}
"Configure frame settings": "Konfigurace nastavení rámu",
"View changelog": "Zobrazit seznam změn",
"Changelog": "Seznam změn",
"Close": "Zavřít",
"Error": "Chyba",
"Failed to load changelog": "Nepodařilo se načíst seznam změn",
"Loading...": "Načítání..."
}

View File

@ -228,5 +228,11 @@
"Message": "Besked",
"Frame text": "Ramme-tekst",
"QR codes will be generated using the frame settings you have set above.": "QR-koder genereres ved hjælp af de rammeindstillinger, du har angivet ovenfor.",
"Configure frame settings": "Konfigurer rammeindstillinger"
}
"Configure frame settings": "Konfigurer rammeindstillinger",
"View changelog": "Se ændringslog",
"Changelog": "Changelog",
"Close": "Luk",
"Error": "Fejl",
"Failed to load changelog": "Kunne ikke indlæse changelog",
"Loading...": "Indlæser..."
}

View File

@ -228,5 +228,11 @@
"Message": "Message",
"Frame text": "Frame text",
"QR codes will be generated using the frame settings you have set above.": "QR codes will be generated using the frame settings you have set above.",
"Configure frame settings": "Configure frame settings"
}
"Configure frame settings": "Configure frame settings",
"View changelog": "View changelog",
"Changelog": "Changelog",
"Close": "Close",
"Error": "Error",
"Failed to load changelog": "Failed to load changelog",
"Loading...": "Loading..."
}

View File

@ -228,5 +228,11 @@
"Message": "Μήνυμα",
"Frame text": "Κείμενο πλαισίου",
"QR codes will be generated using the frame settings you have set above.": "Οι κωδικοί QR θα δημιουργηθούν χρησιμοποιώντας τις ρυθμίσεις πλαισίου που έχετε ορίσει παραπάνω.",
"Configure frame settings": "Διαμόρφωση ρυθμίσεων πλαισίου"
}
"Configure frame settings": "Διαμόρφωση ρυθμίσεων πλαισίου",
"View changelog": "Προβολή καταλόγου αλλαγών",
"Changelog": "Changelog",
"Close": "Κλείστε το",
"Error": "Σφάλμα",
"Failed to load changelog": "Απέτυχε να φορτώσει το changelog",
"Loading...": "Φόρτωση..."
}

View File

@ -228,5 +228,11 @@
"Message": "Message",
"Frame text": "Frame text",
"QR codes will be generated using the frame settings you have set above.": "QR codes will be generated using the frame settings you have set above.",
"Configure frame settings": "Configure frame settings"
}
"Configure frame settings": "Configure frame settings",
"View changelog": "View changelog",
"Changelog": "Changelog",
"Close": "Close",
"Error": "Error",
"Failed to load changelog": "Failed to load changelog",
"Loading...": "Loading..."
}

View File

@ -228,5 +228,11 @@
"Message": "Mensaje",
"Frame text": "Texto del marco",
"QR codes will be generated using the frame settings you have set above.": "Los códigos QR se generarán utilizando la configuración del marco que ha establecido anteriormente.",
"Configure frame settings": "Configurar los ajustes del marco"
}
"Configure frame settings": "Configurar los ajustes del marco",
"View changelog": "Ver el registro de cambios",
"Changelog": "Registro de cambios",
"Close": "Cerrar",
"Error": "Error",
"Failed to load changelog": "Error al cargar el registro de cambios",
"Loading...": "Cargando..."
}

View File

@ -228,5 +228,11 @@
"Message": "Viesti",
"Frame text": "Kehyksen teksti",
"QR codes will be generated using the frame settings you have set above.": "QR-koodit luodaan käyttämällä edellä määrittämiäsi kehysasetuksia.",
"Configure frame settings": "Kehysasetusten määrittäminen"
}
"Configure frame settings": "Kehysasetusten määrittäminen",
"View changelog": "Näytä muutosluettelo",
"Changelog": "Changelog",
"Close": "Sulje",
"Error": "Virhe",
"Failed to load changelog": "Changelogin lataaminen epäonnistui",
"Loading...": "Ladataan..."
}

View File

@ -228,5 +228,11 @@
"Message": "Message",
"Frame text": "Texte du cadre",
"QR codes will be generated using the frame settings you have set above.": "Les codes QR seront générés en utilisant les paramètres de cadre que vous avez définis ci-dessus.",
"Configure frame settings": "Configurer les paramètres du cadre"
}
"Configure frame settings": "Configurer les paramètres du cadre",
"View changelog": "Voir le journal des modifications",
"Changelog": "Changelog",
"Close": "Fermer",
"Error": "Erreur",
"Failed to load changelog": "Échec du chargement du changelog",
"Loading...": "Chargement..."
}

View File

@ -228,5 +228,11 @@
"Message": "Message",
"Frame text": "Frame text",
"QR codes will be generated using the frame settings you have set above.": "QR codes will be generated using the frame settings you have set above.",
"Configure frame settings": "Configure frame settings"
}
"Configure frame settings": "Configure frame settings",
"View changelog": "View changelog",
"Changelog": "Changelog",
"Close": "Close",
"Error": "Error",
"Failed to load changelog": "Failed to load changelog",
"Loading...": "Loading..."
}

View File

@ -228,5 +228,11 @@
"Message": "Üzenet",
"Frame text": "Keret szöveg",
"QR codes will be generated using the frame settings you have set above.": "A QR-kódok a fent beállított keretbeállítások alapján lesznek létrehozva.",
"Configure frame settings": "Keretbeállítások konfigurálása"
}
"Configure frame settings": "Keretbeállítások konfigurálása",
"View changelog": "Változásnapló megtekintése",
"Changelog": "Changelog",
"Close": "Zárja be a",
"Error": "Hiba",
"Failed to load changelog": "Nem sikerült betölteni a changelogot",
"Loading...": "Betöltés..."
}

View File

@ -228,5 +228,11 @@
"Message": "Messaggio",
"Frame text": "Testo della cornice",
"QR codes will be generated using the frame settings you have set above.": "I codici QR verranno generati utilizzando le impostazioni della cornice impostate in precedenza.",
"Configure frame settings": "Configurare le impostazioni della cornice"
}
"Configure frame settings": "Configurare le impostazioni della cornice",
"View changelog": "Visualizza il changelog",
"Changelog": "Changelog",
"Close": "Chiudere",
"Error": "Errore",
"Failed to load changelog": "Non è riuscito a caricare il changelog",
"Loading...": "Caricamento..."
}

View File

@ -228,5 +228,11 @@
"Message": "メッセージ",
"Frame text": "フレームテキスト",
"QR codes will be generated using the frame settings you have set above.": "QRコードは、上記で設定したフレーム設定を使用して生成されます。",
"Configure frame settings": "フレームの設定"
}
"Configure frame settings": "フレームの設定",
"View changelog": "変更履歴を見る",
"Changelog": "変更履歴",
"Close": "閉じる",
"Error": "エラー",
"Failed to load changelog": "変更履歴の読み込みに失敗しました",
"Loading...": "読み込み中..."
}

View File

@ -228,5 +228,11 @@
"Message": "메시지",
"Frame text": "프레임 텍스트",
"QR codes will be generated using the frame settings you have set above.": "위에서 설정한 프레임 설정을 사용하여 QR 코드가 생성됩니다.",
"Configure frame settings": "프레임 설정 구성"
}
"Configure frame settings": "프레임 설정 구성",
"View changelog": "변경 로그 보기",
"Changelog": "변경 로그",
"Close": "닫기",
"Error": "오류",
"Failed to load changelog": "변경 로그를 로드하지 못했습니다.",
"Loading...": "로드 중..."
}

View File

@ -228,5 +228,11 @@
"Message": "Bericht",
"Frame text": "Frame tekst",
"QR codes will be generated using the frame settings you have set above.": "QR-codes worden gegenereerd met behulp van de frame-instellingen die je hierboven hebt ingesteld.",
"Configure frame settings": "Frame-instellingen configureren"
}
"Configure frame settings": "Frame-instellingen configureren",
"View changelog": "Bekijk lijst met wijzigingen",
"Changelog": "Changelog",
"Close": "Sluit",
"Error": "Fout",
"Failed to load changelog": "Changelog niet geladen",
"Loading...": "Aan het laden..."
}

View File

@ -228,5 +228,11 @@
"Message": "Message",
"Frame text": "Frame text",
"QR codes will be generated using the frame settings you have set above.": "QR codes will be generated using the frame settings you have set above.",
"Configure frame settings": "Configure frame settings"
}
"Configure frame settings": "Configure frame settings",
"View changelog": "View changelog",
"Changelog": "Changelog",
"Close": "Close",
"Error": "Error",
"Failed to load changelog": "Failed to load changelog",
"Loading...": "Loading..."
}

View File

@ -228,5 +228,11 @@
"Message": "Wiadomość",
"Frame text": "Tekst ramki",
"QR codes will be generated using the frame settings you have set above.": "Kody QR zostaną wygenerowane przy użyciu ustawień ramki określonych powyżej.",
"Configure frame settings": "Konfiguracja ustawień ramki"
}
"Configure frame settings": "Konfiguracja ustawień ramki",
"View changelog": "Wyświetl dziennik zmian",
"Changelog": "Dziennik zmian",
"Close": "Zamknij",
"Error": "Błąd",
"Failed to load changelog": "Nie udało się załadować dziennika zmian",
"Loading...": "Ładowanie..."
}

View File

@ -228,5 +228,11 @@
"Message": "Mensagem",
"Frame text": "Texto do quadro",
"QR codes will be generated using the frame settings you have set above.": "Os códigos QR serão gerados usando as configurações de quadro que você definiu acima.",
"Configure frame settings": "Configurar definições de quadro"
}
"Configure frame settings": "Configurar definições de quadro",
"View changelog": "Ver changelog",
"Changelog": "Registro de alterações",
"Close": "Fechar",
"Error": "Erro",
"Failed to load changelog": "Falha ao carregar o changelog",
"Loading...": "Carregando..."
}

View File

@ -228,5 +228,11 @@
"Message": "Mesaj",
"Frame text": "Text cadru",
"QR codes will be generated using the frame settings you have set above.": "Codurile QR vor fi generate folosind setările cadrului pe care le-ați setat mai sus.",
"Configure frame settings": "Configurați setările cadrului"
}
"Configure frame settings": "Configurați setările cadrului",
"View changelog": "Vezi changelog",
"Changelog": "Changelog",
"Close": "Închidere",
"Error": "Eroare",
"Failed to load changelog": "A eșuat încărcarea jurnalului de schimbări",
"Loading...": "Încărcare..."
}

View File

@ -228,5 +228,11 @@
"Message": "Сообщение",
"Frame text": "Текст рамки",
"QR codes will be generated using the frame settings you have set above.": "QR-коды будут генерироваться с использованием настроек рамки, которые вы задали выше.",
"Configure frame settings": "Настройка параметров кадра"
}
"Configure frame settings": "Настройка параметров кадра",
"View changelog": "Посмотреть журнал изменений",
"Changelog": "Changelog",
"Close": "Закрыть",
"Error": "Ошибка",
"Failed to load changelog": "Не удалось загрузить журнал изменений",
"Loading...": "Загрузка..."
}

View File

@ -228,5 +228,11 @@
"Message": "Message",
"Frame text": "Frame text",
"QR codes will be generated using the frame settings you have set above.": "QR codes will be generated using the frame settings you have set above.",
"Configure frame settings": "Configure frame settings"
}
"Configure frame settings": "Configure frame settings",
"View changelog": "View changelog",
"Changelog": "Changelog",
"Close": "Close",
"Error": "Error",
"Failed to load changelog": "Failed to load changelog",
"Loading...": "Loading..."
}

View File

@ -228,5 +228,11 @@
"Message": "Meddelande",
"Frame text": "Ramtext",
"QR codes will be generated using the frame settings you have set above.": "QR-koderna genereras med hjälp av de inställningar för ramen som du har angett ovan.",
"Configure frame settings": "Konfigurera inställningar för ram"
}
"Configure frame settings": "Konfigurera inställningar för ram",
"View changelog": "Visa ändringslogg",
"Changelog": "Changelog",
"Close": "Nära",
"Error": "Fel",
"Failed to load changelog": "Misslyckades med att ladda changelog",
"Loading...": "Laddar..."
}

View File

@ -228,5 +228,11 @@
"Message": "Mesaj",
"Frame text": "Çerçeve metni",
"QR codes will be generated using the frame settings you have set above.": "QR kodları, yukarıda belirlediğiniz çerçeve ayarları kullanılarak oluşturulacaktır.",
"Configure frame settings": "Çerçeve ayarlarını yapılandırma"
}
"Configure frame settings": "Çerçeve ayarlarını yapılandırma",
"View changelog": "Değişiklik günlüğünü görüntüle",
"Changelog": "Değişiklik Günlüğü",
"Close": "Kapat",
"Error": "Hata",
"Failed to load changelog": "Değişiklik günlüğü yüklenemedi",
"Loading...": "Yükleniyor..."
}

View File

@ -228,5 +228,11 @@
"Message": "Повідомлення",
"Frame text": "Текст кадру",
"QR codes will be generated using the frame settings you have set above.": "QR-коди будуть згенеровані з використанням налаштувань фрейму, які ви встановили вище.",
"Configure frame settings": "Налаштуйте параметри кадру"
}
"Configure frame settings": "Налаштуйте параметри кадру",
"View changelog": "Переглянути журнал змін",
"Changelog": "Журнал змін",
"Close": "Закрити",
"Error": "Помилка.",
"Failed to load changelog": "Не вдалося завантажити журнал змін",
"Loading...": "Завантаження..."
}

View File

@ -228,5 +228,11 @@
"Message": "Message",
"Frame text": "Frame text",
"QR codes will be generated using the frame settings you have set above.": "QR codes will be generated using the frame settings you have set above.",
"Configure frame settings": "Configure frame settings"
}
"Configure frame settings": "Configure frame settings",
"View changelog": "View changelog",
"Changelog": "Changelog",
"Close": "Close",
"Error": "Error",
"Failed to load changelog": "Failed to load changelog",
"Loading...": "Loading..."
}

View File

@ -228,5 +228,11 @@
"Message": "訊息",
"Frame text": "框架文字",
"QR codes will be generated using the frame settings you have set above.": "QR 代碼會使用您在上面設定的框架設定來產生。",
"Configure frame settings": "設定框架設定"
}
"Configure frame settings": "設定框架設定",
"View changelog": "查看變更日誌",
"Changelog": "變更日誌",
"Close": "關閉",
"Error": "錯誤",
"Failed to load changelog": "載入更新記錄失敗",
"Loading...": "載入中..."
}

View File

@ -13,6 +13,7 @@
"lint": "eslint --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore --ignore-pattern \"*.json\"",
"format": "prettier --write",
"postinstall": "husky install",
"generate-changelog": "sh scripts/generate-version.sh",
"generate-splash": "node scripts/generate-splash-screens.js"
},
"lint-staged": {
@ -23,6 +24,7 @@
},
"dependencies": {
"@floating-ui/vue": "^1.1.6",
"@types/marked": "^6.0.0",
"@vitejs/plugin-vue": "^5.2.1",
"@vitejs/plugin-vue-jsx": "^3.1.0",
"@vue/tsconfig": "^0.5.1",
@ -36,6 +38,7 @@
"html5-qrcode": "^2.3.8",
"jszip": "^3.10.1",
"lucide-vue-next": "^0.321.0",
"marked": "^15.0.11",
"qr-code-styling": "^1.9.2",
"radix-vue": "^1.9.17",
"reka-ui": "^2.0.2",
@ -50,6 +53,7 @@
"devDependencies": {
"@playwright/test": "^1.51.1",
"@rushstack/eslint-patch": "^1.10.5",
"@tailwindcss/typography": "^0.5.16",
"@types/dom-to-image": "^2.6.7",
"@types/node": "^20.17.23",
"@vue/eslint-config-prettier": "^8.0.0",

50
pnpm-lock.yaml generated
View File

@ -8,6 +8,9 @@ dependencies:
'@floating-ui/vue':
specifier: ^1.1.6
version: 1.1.6(vue@3.5.13)
'@types/marked':
specifier: ^6.0.0
version: 6.0.0
'@vitejs/plugin-vue':
specifier: ^5.2.1
version: 5.2.3(vite@5.4.18)(vue@3.5.13)
@ -47,6 +50,9 @@ dependencies:
lucide-vue-next:
specifier: ^0.321.0
version: 0.321.0(vue@3.5.13)
marked:
specifier: ^15.0.11
version: 15.0.11
qr-code-styling:
specifier: ^1.9.2
version: 1.9.2
@ -85,6 +91,9 @@ devDependencies:
'@rushstack/eslint-patch':
specifier: ^1.10.5
version: 1.11.0
'@tailwindcss/typography':
specifier: ^0.5.16
version: 0.5.16(tailwindcss@3.4.17)
'@types/dom-to-image':
specifier: ^2.6.7
version: 2.6.7
@ -2028,6 +2037,18 @@ packages:
tslib: 2.8.1
dev: false
/@tailwindcss/typography@0.5.16(tailwindcss@3.4.17):
resolution: {integrity: sha512-0wDLwCVF5V3x3b1SGXPCDcdsbDHMBe+lkFzBRaHeLvNi+nrrnZ1lA18u+OTWO8iSWU2GxUOCvlXtDuqftc1oiA==}
peerDependencies:
tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1'
dependencies:
lodash.castarray: 4.4.0
lodash.isplainobject: 4.0.6
lodash.merge: 4.6.2
postcss-selector-parser: 6.0.10
tailwindcss: 3.4.17
dev: true
/@tanstack/virtual-core@3.13.6:
resolution: {integrity: sha512-cnQUeWnhNP8tJ4WsGcYiX24Gjkc9ALstLbHcBj1t3E7EimN6n6kHH+DPV4PpDnuw00NApQp+ViojMj1GRdwYQg==}
dev: false
@ -2056,6 +2077,13 @@ packages:
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
dev: true
/@types/marked@6.0.0:
resolution: {integrity: sha512-jmjpa4BwUsmhxcfsgUit/7A9KbrC48Q0q8KvnY107ogcjGgTFDlIL3RpihNpx2Mu1hM4mdFQjoVc4O6JoGKHsA==}
deprecated: This is a stub types definition. marked provides its own type definitions, so you do not need this installed.
dependencies:
marked: 15.0.11
dev: false
/@types/node@20.17.30:
resolution: {integrity: sha512-7zf4YyHA+jvBNfVrk2Gtvs6x7E8V+YDW05bNfG2XkWDJfYRXrTiP/DsB2zSYTaHX0bGIujTBQdMVAhb+j7mwpg==}
dependencies:
@ -4231,10 +4259,18 @@ packages:
p-locate: 5.0.0
dev: true
/lodash.castarray@4.4.0:
resolution: {integrity: sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==}
dev: true
/lodash.debounce@4.0.8:
resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==}
dev: true
/lodash.isplainobject@4.0.6:
resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==}
dev: true
/lodash.merge@4.6.2:
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
dev: true
@ -4289,6 +4325,12 @@ packages:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.0
/marked@15.0.11:
resolution: {integrity: sha512-1BEXAU2euRCG3xwgLVT1y0xbJEld1XOrmRJpUwRCcy7rxhSCwMrmEu9LXoPhHSCJG41V7YcQ2mjKRr5BA3ITIA==}
engines: {node: '>= 18'}
hasBin: true
dev: false
/math-intrinsics@1.1.0:
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
engines: {node: '>= 0.4'}
@ -4637,6 +4679,14 @@ packages:
postcss: 8.5.3
postcss-selector-parser: 6.1.2
/postcss-selector-parser@6.0.10:
resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==}
engines: {node: '>=4'}
dependencies:
cssesc: 3.0.0
util-deprecate: 1.0.2
dev: true
/postcss-selector-parser@6.1.2:
resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==}
engines: {node: '>=4'}

168
public/CHANGELOG.md Normal file
View File

@ -0,0 +1,168 @@
## v0.17.1 (2025-04-26)
- 🐛 fix(QRCodeScan.vue): improve URL detection regex to support more comprehensive URLs
([#125](https://github.com/lyqht/mini-qr/pull/125))
## v0.16.0 (2025-04-25)
- ✨ Add frame text support for batch QR code generation
([#117](https://github.com/lyqht/mini-qr/pull/117))
## v0.15.0 (2025-03-30)
- ✨ Add data templates for QR codes
([#109](https://github.com/lyqht/mini-qr/pull/109))
- ✨ Add Playwright E2E testing framework
([#106](https://github.com/lyqht/mini-qr/pull/106))
- 🐛 italian translations
([#109](https://github.com/lyqht/mini-qr/pull/109))
- 🐛 fix(QRCodeCreate.vue): add overflow-hidden class to the element-to-export div to prevent overflow issues
([#109](https://github.com/lyqht/mini-qr/pull/109))
- 🔧 New Crowdin updates
([#108](https://github.com/lyqht/mini-qr/pull/108))
- Remove svg export option
([#112](https://github.com/lyqht/mini-qr/pull/112))
## v0.14.0 (2025-03-17)
- ✨ Add camera switching feature to QR code scanner
([#103](https://github.com/lyqht/mini-qr/pull/103))
- ✨ Add QR code frame feature with customizable text and styling
([#100](https://github.com/lyqht/mini-qr/pull/100))
- ✨ Add jpg export
([#99](https://github.com/lyqht/mini-qr/pull/99))
- 🐛 Update README.md
([#104](https://github.com/lyqht/mini-qr/pull/104))
- 🔧 Add translations
([#104](https://github.com/lyqht/mini-qr/pull/104))
## v0.13.0 (2025-03-12)
- Improve QR code mobile drawer styling
([#97](https://github.com/lyqht/mini-qr/pull/97))
## v0.11.0 (2025-02-25)
- 🔧 chore(package.json): update dependencies versions
([#89](https://github.com/lyqht/mini-qr/pull/89))
## v0.10.0 (2024-11-01)
- 🔧 Update Crowdin configuration file
([#86](https://github.com/lyqht/mini-qr/pull/86))
- Put icon into language selector
([#87](https://github.com/lyqht/mini-qr/pull/87))
- add hackomania 2025 qr code preset
([#86](https://github.com/lyqht/mini-qr/pull/86))
## v0.9.3 (2024-10-23)
- ✨ Add plain preset
([#66](https://github.com/lyqht/mini-qr/pull/66))
## v0.9.2 (2024-10-06)
- ✨ Add contributing guidelines
([#57](https://github.com/lyqht/mini-qr/pull/57))
- 🐛 border radius not respected for svg output
([#62](https://github.com/lyqht/mini-qr/pull/62))
- 🐛 svg output not rendering in image editor softwares
([#54](https://github.com/lyqht/mini-qr/pull/54))
## v0.9.1 (2024-10-06)
- 🐛 svg output not rendering in image editor softwares
([#54](https://github.com/lyqht/mini-qr/pull/54))
## v0.8.0 (2024-08-13)
- 🐛 Update README.md
([#54](https://github.com/lyqht/mini-qr/pull/54))
- Batch data export
([#53](https://github.com/lyqht/mini-qr/pull/53))
- 🔧 chore(deps): bump vite from 5.1.2 to 5.1.7
([#49](https://github.com/lyqht/mini-qr/pull/49))
## v0.7.0 (2024-08-08)
- ✨ Add support for error correction levels
([#46](https://github.com/lyqht/mini-qr/pull/46))
## v0.6.1 (2024-02-16)
- ✨ support transparent background
([#42](https://github.com/lyqht/mini-qr/pull/42))
- ✨ Added Docker support
([#37](https://github.com/lyqht/mini-qr/pull/37))
- 🐛 a11y issues
([#37](https://github.com/lyqht/mini-qr/pull/37))
- 🔧 translation of locales/en.json
([#37](https://github.com/lyqht/mini-qr/pull/37))
- add video demo
([#37](https://github.com/lyqht/mini-qr/pull/37))
## v0.6.0 (2024-02-13)
- 🐛 combobox dark mode ui
([#37](https://github.com/lyqht/mini-qr/pull/37))
- 🐛 Fix dark mode ui
([#36](https://github.com/lyqht/mini-qr/pull/36))
- 🐛 styling on mobile viewport
([#35](https://github.com/lyqht/mini-qr/pull/35))
- update dependencies
([#35](https://github.com/lyqht/mini-qr/pull/35))
## v0.5.0 (2024-01-05)
- ✨ Add shadcn-vue combobox components
([#30](https://github.com/lyqht/mini-qr/pull/30))
- 🔧 update translate github action to only run if PRs are merged
([#30](https://github.com/lyqht/mini-qr/pull/30))
- 🔧 translation of locales/en.json
([#30](https://github.com/lyqht/mini-qr/pull/30))
## v0.4.0 (2023-12-31)
- 🔧 translation of locales/en.json
([#30](https://github.com/lyqht/mini-qr/pull/30))
- Feature: Save & Load preset from local storage
([#28](https://github.com/lyqht/mini-qr/pull/28))
- Hide copy to clipboard if API is not supported on the browser
([#27](https://github.com/lyqht/mini-qr/pull/27))
## v0.3.0 (2023-08-07)
- ✨ Add SupabasePurple & ViteConf2023 presets
([#19](https://github.com/lyqht/mini-qr/pull/19))
- 🐛 fix(presets.ts): update Padlet preset image URL
([#23](https://github.com/lyqht/mini-qr/pull/23))
- 🐛 og image
([#19](https://github.com/lyqht/mini-qr/pull/19))
- 🐛 missing preset typing
([#16](https://github.com/lyqht/mini-qr/pull/16))
- Upgraded dependencies
([#25](https://github.com/lyqht/mini-qr/pull/25))
- A11y fixes
([#16](https://github.com/lyqht/mini-qr/pull/16))
### v0.2.0 (2023-08-06)
- ✨ Add Presets: Pre-crafted QR code styles available (padletPreset, uiliciousPreset, supabasePreset, vercelLightPreset, vercelDarkPreset)
- 🐛 Refactor styles
### v0.1.0 (2023-08-03)
- ✨ Upload custom image for logo
- 🐛 Fix inconsistencies in button & input styling
- 🐛 Refactor styles
- 🐛 Fix missing inputs for background color and border-radius
### v0.0.0 (2023-03-25)
- ✨ Generate QR codes with custom colors and styles
- ✨ Support SVG and PNG output formats
- ✨ Add Copy to clipboard feature
- ✨ UI respects light/dark mode preferences
- ✨ Add Randomize style button
- 🔧 Available in 29 languages (via deepl-translate-github-action)
- ✨ Save & Load QR Code config

225
scripts/generate-version.sh Executable file
View File

@ -0,0 +1,225 @@
#!/bin/bash
# Create public directory if it doesn't exist
mkdir -p public
# Clear the changelog file before starting
> public/CHANGELOG.md
# Get all tags sorted by version number (v prefix is handled)
tags=($(git for-each-ref --sort=-version:refname --format '%(refname:short)' refs/tags/v*))
# Process each tag
for ((i=0; i<${#tags[@]}; i++)); do
tag="${tags[$i]}"
# Get the range for commits
if [ $i -eq 0 ]; then
range="$tag..HEAD"
else
next_tag="${tags[$i-1]}"
range="$tag..$next_tag"
fi
# Add a newline before each version section *except* the very first one
if [ $i -gt 0 ]; then
echo "" >> public/CHANGELOG.md
fi
# Arrays to store different types of commits
features=()
fixes=()
translations=()
others=()
# Get commits in this range
while IFS= read -r commit_msg; do
# Skip version bump commits
if [[ $commit_msg =~ ^v[0-9]+\.[0-9]+\.[0-9]+ ]]; then
continue
fi
# Skip chore, docs, style, refactor commits unless they have a PR number
if [[ $commit_msg =~ ^(chore|docs|style|refactor) && ! $commit_msg =~ \(#[0-9]+\) ]]; then
continue
fi
# Skip commits that are just version numbers
if [[ $commit_msg =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
continue
fi
# Extract PR number if exists
if [[ $commit_msg =~ \(#([0-9]+)\) ]]; then
pr_num=${BASH_REMATCH[1]}
commit_msg=${commit_msg/ (#$pr_num)/}
fi
# Remove file-specific prefixes like "fix(QRCodeScan.vue):"
# Quote the regex to prevent shell interpretation issues
if [[ $commit_msg =~ '^[a-zA-Z]+\([^)]+\):' ]]; then
commit_msg=${commit_msg#*): }
fi
# Format the commit message
formatted_msg=""
commit_type="other"
# First try conventional commit format
if [[ $commit_msg =~ ^feat: ]]; then
formatted_msg="- ✨ ${commit_msg#feat: }"
commit_type="feature"
elif [[ $commit_msg =~ ^fix: ]]; then
formatted_msg="- 🐛 ${commit_msg#fix: }"
commit_type="fix"
elif [[ $commit_msg =~ ^perf: ]]; then
formatted_msg="- ⚡️ ${commit_msg#perf: }"
commit_type="other"
elif [[ $commit_msg =~ ^chore: ]]; then
formatted_msg="- 🔧 ${commit_msg#chore: }"
commit_type="other"
elif [[ $commit_msg =~ ^docs: ]]; then
formatted_msg="- 📝 ${commit_msg#docs: }"
commit_type="other"
elif [[ $commit_msg =~ ^style: ]]; then
formatted_msg="- 💄 ${commit_msg#style: }"
commit_type="other"
elif [[ $commit_msg =~ ^refactor: ]]; then
formatted_msg="- ♻️ ${commit_msg#refactor: }"
commit_type="other"
elif [[ $commit_msg =~ ^test: ]]; then
formatted_msg="- ✅ ${commit_msg#test: }"
commit_type="other"
# Then try without colon
elif [[ $commit_msg =~ ^feat ]]; then
formatted_msg="- ✨ ${commit_msg#feat }"
commit_type="feature"
elif [[ $commit_msg =~ ^fix ]]; then
formatted_msg="- 🐛 ${commit_msg#fix }"
commit_type="fix"
elif [[ $commit_msg =~ ^perf ]]; then
formatted_msg="- ⚡️ ${commit_msg#perf }"
commit_type="other"
elif [[ $commit_msg =~ ^chore ]]; then
formatted_msg="- 🔧 ${commit_msg#chore }"
commit_type="other"
elif [[ $commit_msg =~ ^docs ]]; then
formatted_msg="- 📝 ${commit_msg#docs }"
commit_type="other"
elif [[ $commit_msg =~ ^style ]]; then
formatted_msg="- 💄 ${commit_msg#style }"
commit_type="other"
elif [[ $commit_msg =~ ^refactor ]]; then
formatted_msg="- ♻️ ${commit_msg#refactor }"
commit_type="other"
elif [[ $commit_msg =~ ^test ]]; then
formatted_msg="- ✅ ${commit_msg#test }"
commit_type="other"
# Translation detection
elif [[ $commit_msg =~ [Tt]ranslat(e|ion|ions)|locales|i18n|[Cc]rowdin ]]; then
formatted_msg="- 🔧 ${commit_msg}"
commit_type="translation"
# Finally, try to infer type from content
else
# Common feature-related words
if [[ $commit_msg =~ ^Add|^Create|^Implement|^Support ]]; then
formatted_msg="- ✨ ${commit_msg}"
commit_type="feature"
# Common fix-related words
elif [[ $commit_msg =~ ^Fix|^Resolve|^Correct|improve|^Update ]]; then
formatted_msg="- 🐛 ${commit_msg}"
commit_type="fix"
# Common translation-related words (fallback)
elif [[ $commit_msg =~ [Tt]ranslat(e|ion|ions)|locales|i18n|[Cc]rowdin ]]; then
formatted_msg="- 🔧 ${commit_msg}"
commit_type="translation"
# Common refactor-related words
elif [[ $commit_msg =~ ^Refactor|^Restructure|^Reorganize ]]; then
formatted_msg="- ♻️ ${commit_msg}"
commit_type="other"
# Common docs-related words
elif [[ $commit_msg =~ ^Document|^Update.*docs|^Add.*docs ]]; then
formatted_msg="- 📝 ${commit_msg}"
commit_type="other"
else
formatted_msg="- ${commit_msg}"
commit_type="other"
fi
fi
# Add PR link if exists
if [ -n "$pr_num" ]; then
formatted_msg="$formatted_msg\n ([#$pr_num](https://github.com/lyqht/mini-qr/pull/$pr_num))"
fi
# Add to appropriate array
if [ "$commit_type" = "feature" ]; then
features+=("$formatted_msg")
elif [ "$commit_type" = "fix" ]; then
fixes+=("$formatted_msg")
elif [ "$commit_type" = "translation" ]; then
translations+=("$formatted_msg")
else
others+=("$formatted_msg")
fi
done < <(git log --pretty=format:"%s" "$range")
# Only add version section if there are any commits
if [ ${#features[@]} -gt 0 ] || [ ${#fixes[@]} -gt 0 ] || [ ${#translations[@]} -gt 0 ] || [ ${#others[@]} -gt 0 ]; then
# Get the date of the tag
tag_date=$(git log -1 --format=%ai "$tag" | cut -d' ' -f1)
# Write the tag and date
echo "## $tag ($tag_date)" >> public/CHANGELOG.md
echo "" >> public/CHANGELOG.md
# Write features first
for msg in "${features[@]}"; do
echo -e "$msg" >> public/CHANGELOG.md
done
# Write fixes second
for msg in "${fixes[@]}"; do
echo -e "$msg" >> public/CHANGELOG.md
done
# Write translations third
for msg in "${translations[@]}"; do
echo -e "$msg" >> public/CHANGELOG.md
done
# Write others last
for msg in "${others[@]}"; do
echo -e "$msg" >> public/CHANGELOG.md
done
echo "" >> public/CHANGELOG.md
fi
done
# Directly append the hardcoded historical changelog entries
echo "" >> public/CHANGELOG.md # Add a separator line
echo "### v0.2.0 (2023-08-06)" >> public/CHANGELOG.md
echo "" >> public/CHANGELOG.md
echo "- ✨ Add Presets: Pre-crafted QR code styles available (padletPreset, uiliciousPreset, supabasePreset, vercelLightPreset, vercelDarkPreset)" >> public/CHANGELOG.md
echo "- 🐛 Refactor styles" >> public/CHANGELOG.md
echo "" >> public/CHANGELOG.md
echo "### v0.1.0 (2023-08-03)" >> public/CHANGELOG.md
echo "" >> public/CHANGELOG.md
echo "- ✨ Upload custom image for logo" >> public/CHANGELOG.md
echo "- 🐛 Fix inconsistencies in button & input styling" >> public/CHANGELOG.md
echo "- 🐛 Refactor styles" >> public/CHANGELOG.md
echo "- 🐛 Fix missing inputs for background color and border-radius" >> public/CHANGELOG.md
echo "" >> public/CHANGELOG.md
echo "### v0.0.0 (2023-03-25)" >> public/CHANGELOG.md
echo "" >> public/CHANGELOG.md
echo "- ✨ Generate QR codes with custom colors and styles" >> public/CHANGELOG.md
echo "- ✨ Support SVG and PNG output formats" >> public/CHANGELOG.md
echo "- ✨ Add Copy to clipboard feature" >> public/CHANGELOG.md
echo "- ✨ UI respects light/dark mode preferences" >> public/CHANGELOG.md
echo "- ✨ Add Randomize style button" >> public/CHANGELOG.md
echo "- 🔧 Available in 29 languages (via deepl-translate-github-action)" >> public/CHANGELOG.md
echo "- ✨ Save & Load QR Code config" >> public/CHANGELOG.md

View File

@ -3,6 +3,7 @@ import LanguageSelector from '@/components/LanguageSelector.vue'
import MobileMenu from '@/components/MobileMenu.vue'
import QRCodeScan from '@/components/QRCodeScan.vue'
import QRCodeCreate from '@/components/QRCodeCreate.vue'
import AppFooter from '@/components/AppFooter.vue'
import useDarkModePreference from '@/utils/useDarkModePreference'
import { computed, ref, onMounted, onUnmounted } from 'vue'
import { useI18n } from 'vue-i18n'
@ -283,6 +284,7 @@ const isModeToggleDisabled = computed(() => {
</div>
</div>
</div>
<AppFooter />
</main>
</template>

View File

@ -0,0 +1,111 @@
<script setup lang="ts">
import { marked } from 'marked'
import { ref, onMounted } from 'vue'
import { useI18n } from 'vue-i18n'
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
DialogClose
} from '@/components/ui/dialog'
import { X } from 'lucide-vue-next'
const { t } = useI18n()
const version = ref('...')
const changelogContent = ref<string | null>(null)
const isLoading = ref(true)
async function fetchAndProcessChangelog() {
if (changelogContent.value === null) {
isLoading.value = true
try {
const response = await fetch('/CHANGELOG.md')
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}
const markdown = await response.text()
const versionMatch = markdown.match(/^##\s+(v\d+\.\d+\.\d+)/m)
if (versionMatch && versionMatch[1]) {
version.value = versionMatch[1]
} else {
version.value = 'N/A'
}
changelogContent.value = await marked.parse(markdown)
} catch (error) {
console.error('Failed to fetch or process changelog:', error)
version.value = t('Error')
changelogContent.value = `<p>${t('Failed to load changelog')}</p>`
} finally {
isLoading.value = false
}
}
}
onMounted(() => {
fetchAndProcessChangelog()
})
</script>
<template>
<footer
class="fixed inset-x-0 bottom-0 hidden p-4 text-sm text-zinc-600 dark:text-zinc-400 md:flex md:justify-center"
>
<div class="flex items-center gap-2">
<span>{{ t('Created by') }}</span>
<a
href="https://github.com/lyqht"
target="_blank"
class="text-zinc-900 hover:text-zinc-700 dark:text-zinc-100 dark:hover:text-zinc-300"
>Estee Tey 🐧🌻</a
>
<span>|</span>
<Dialog>
<DialogTrigger as-child>
<button class="secondary-button" :aria-label="t('View changelog')" :disabled="isLoading">
{{ isLoading ? '...' : version }}
</button>
</DialogTrigger>
<DialogContent class="flex max-h-[80vh] flex-col sm:max-w-md" @open-auto-focus.prevent>
<DialogHeader>
<DialogTitle>{{ t('Changelog') }}</DialogTitle>
<DialogClose
class="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground"
>
<X class="size-4" />
<span class="sr-only">{{ t('Close') }}</span>
</DialogClose>
</DialogHeader>
<div class="flex-1 overflow-y-auto pr-2">
<DialogDescription
as="div"
class="prose prose-sm max-w-none text-start dark:prose-invert prose-li:my-1"
>
<div v-if="isLoading">Loading...</div>
<div v-else-if="changelogContent" v-html="changelogContent"></div>
<div v-else>{{ t('Failed to load changelog') }}</div>
</DialogDescription>
</div>
</DialogContent>
</Dialog>
</div>
</footer>
</template>
<style scoped>
/* Restore original footer background styles */
footer {
background: rgba(255, 255, 255, 0.8);
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
}
.dark footer {
background: rgba(24, 24, 27, 0.8);
}
</style>

View File

@ -3,6 +3,17 @@ import { ref, onMounted, onUnmounted } from 'vue'
import { useFloating, offset, flip, shift, autoUpdate } from '@floating-ui/vue'
import LanguageSelector from '@/components/LanguageSelector.vue'
import { useI18n } from 'vue-i18n'
import { marked } from 'marked'
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
DialogClose
} from '@/components/ui/dialog'
import { X } from 'lucide-vue-next'
defineProps<{
isDarkMode: boolean
@ -19,6 +30,38 @@ const isOpen = ref(false)
const reference = ref<HTMLElement | null>(null)
const floating = ref<HTMLElement | null>(null)
const version = ref('...')
const changelogContent = ref<string | null>(null)
const isLoadingChangelog = ref(true)
async function fetchAndProcessChangelog() {
if (changelogContent.value === null) {
isLoadingChangelog.value = true
try {
const response = await fetch('/CHANGELOG.md')
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}
const markdown = await response.text()
const versionMatch = markdown.match(/^##\s+(v\d+\.\d+\.\d+)/m)
if (versionMatch && versionMatch[1]) {
version.value = versionMatch[1]
} else {
version.value = 'N/A'
}
changelogContent.value = await marked.parse(markdown)
} catch (error) {
console.error('Failed to fetch or process changelog:', error)
version.value = t('Error')
changelogContent.value = `<p>${t('Failed to load changelog')}</p>`
} finally {
isLoadingChangelog.value = false
}
}
}
const { floatingStyles } = useFloating(reference, floating, {
placement: 'bottom-end',
middleware: [offset(5), flip(), shift()],
@ -48,6 +91,7 @@ const handleClickOutside = (event: MouseEvent) => {
onMounted(() => {
document.addEventListener('click', handleClickOutside)
fetchAndProcessChangelog()
})
onUnmounted(() => {
@ -76,8 +120,45 @@ onUnmounted(() => {
v-if="isOpen"
ref="floating"
:style="floatingStyles"
class="z-50 w-64 rounded-md border border-zinc-300 bg-white p-4 shadow-lg dark:border-zinc-700 dark:bg-zinc-800"
class="relative z-50 w-64 rounded-md border border-zinc-300 bg-white p-4 shadow-lg dark:border-zinc-700 dark:bg-zinc-800"
>
<Dialog>
<DialogTrigger as-child>
<button
class="secondary-button absolute end-4 top-4"
:aria-label="t('View changelog')"
:disabled="isLoadingChangelog"
>
{{ isLoadingChangelog ? '...' : version }}
</button>
</DialogTrigger>
<DialogContent
class="flex max-h-[80vh] w-[90vw] flex-col sm:max-w-md"
@open-auto-focus.prevent
>
<DialogHeader>
<DialogTitle>{{ t('Changelog') }}</DialogTitle>
<DialogClose
class="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground"
>
<X class="size-4" />
<span class="sr-only">{{ t('Close') }}</span>
</DialogClose>
</DialogHeader>
<div class="flex-1 overflow-y-auto pr-2">
<DialogDescription
as="div"
class="prose prose-sm max-w-none text-start dark:prose-invert prose-li:my-1"
>
<div v-if="isLoadingChangelog">Loading...</div>
<div v-else-if="changelogContent" v-html="changelogContent"></div>
<div v-else>{{ t('Failed to load changelog') }}</div>
</DialogDescription>
</div>
</DialogContent>
</Dialog>
<div class="flex flex-col gap-4">
<!-- App title -->
<div class="flex items-center">
@ -158,6 +239,24 @@ onUnmounted(() => {
<div class="px-2 py-1.5">
<LanguageSelector />
</div>
<!-- Divider -->
<hr class="border-zinc-200 dark:border-zinc-700 md:hidden" />
<!-- Footer Section for Mobile (hidden on md and up) -->
<div
class="relative flex flex-col gap-2 text-sm text-zinc-600 dark:text-zinc-400 md:hidden"
>
<div class="flex items-center justify-center gap-1">
<span>{{ t('Created by') }}</span>
<a
href="https://github.com/lyqht"
target="_blank"
class="text-zinc-900 hover:text-zinc-700 dark:text-zinc-100 dark:hover:text-zinc-300"
>Estee Tey 🐧🌻</a
>
</div>
</div>
</div>
</div>
</div>

View File

@ -1,4 +1,5 @@
import animate from 'tailwindcss-animate'
import typography from '@tailwindcss/typography'
/** @type {import('tailwindcss').Config} */
export const content = [
@ -84,4 +85,4 @@ export const theme = {
}
}
}
export const plugins = [animate]
export const plugins = [animate, typography]