chore(lint): enforce 2-space indent & add gpg pre-commit hook
This commit is contained in:
@@ -1 +1,11 @@
|
||||
# Check if GPG signing is enabled
|
||||
gpg_sign=$(git config --get commit.gpgsign || echo "false")
|
||||
|
||||
if [ "$gpg_sign" != "true" ]; then
|
||||
echo "Error: GPG signing is not enabled or properly configured!"
|
||||
echo "Please enable it globally using: git config --global commit.gpgsign true"
|
||||
echo "Or locally by running: git config commit.gpgsign true"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
npm run lint
|
||||
|
||||
@@ -33,6 +33,7 @@ export default [
|
||||
'no-unused-vars': 'off',
|
||||
'no-undef': 'off',
|
||||
'no-debugger': 'off',
|
||||
'indent': ['error', 2]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -31,7 +31,7 @@ export function useExtension() {
|
||||
extensionCheckInterval = setInterval(() => {
|
||||
window.postMessage({ type: 'TOOLS_APP_PING' }, '*')
|
||||
if (Date.now() - lastPongTime > TIMEOUT_THRESHOLD) {
|
||||
isExtensionReady.value = false
|
||||
isExtensionReady.value = false
|
||||
}
|
||||
}, PING_INTERVAL)
|
||||
}
|
||||
|
||||
@@ -1,115 +1,115 @@
|
||||
import { useLocalStorage } from './useLocalStorage'
|
||||
|
||||
export function useUrlCleaner() {
|
||||
const cleanedHistory = useLocalStorage('url-cleaner-history', [])
|
||||
const isWatchEnabled = useLocalStorage('url-cleaner-watch-enabled', false)
|
||||
const cleanedHistory = useLocalStorage('url-cleaner-history', [])
|
||||
const isWatchEnabled = useLocalStorage('url-cleaner-watch-enabled', false)
|
||||
|
||||
const defaultExceptions = [
|
||||
{ id: 'yt', domainPattern: '*.youtube.com', keepParams: ['v', 't'], keepHash: false, keepAllParams: false, isEnabled: true, isDefault: true },
|
||||
{ id: 'yt-short', domainPattern: 'youtu.be', keepParams: ['t'], keepHash: false, keepAllParams: false, isEnabled: true, isDefault: true }
|
||||
]
|
||||
const exceptions = useLocalStorage('url-cleaner-exceptions', defaultExceptions)
|
||||
const defaultExceptions = [
|
||||
{ id: 'yt', domainPattern: '*.youtube.com', keepParams: ['v', 't'], keepHash: false, keepAllParams: false, isEnabled: true, isDefault: true },
|
||||
{ id: 'yt-short', domainPattern: 'youtu.be', keepParams: ['t'], keepHash: false, keepAllParams: false, isEnabled: true, isDefault: true }
|
||||
]
|
||||
const exceptions = useLocalStorage('url-cleaner-exceptions', defaultExceptions)
|
||||
|
||||
const matchDomain = (pattern, domain) => {
|
||||
// Escape regex chars except *
|
||||
const regexString = '^' + pattern.replace(/[.+^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '.*') + '$'
|
||||
return new RegExp(regexString, 'i').test(domain)
|
||||
}
|
||||
const matchDomain = (pattern, domain) => {
|
||||
// Escape regex chars except *
|
||||
const regexString = '^' + pattern.replace(/[.+^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '.*') + '$'
|
||||
return new RegExp(regexString, 'i').test(domain)
|
||||
}
|
||||
|
||||
const processUrl = (text, autoClipboard = false, writeClipboardFn = null) => {
|
||||
try {
|
||||
// Basic URL validation
|
||||
if (!text.match(/^https?:\/\//i)) {
|
||||
if (autoClipboard) return text
|
||||
const processUrl = (text, autoClipboard = false, writeClipboardFn = null) => {
|
||||
try {
|
||||
// Basic URL validation
|
||||
if (!text.match(/^https?:\/\//i)) {
|
||||
if (autoClipboard) return text
|
||||
}
|
||||
|
||||
const originalLength = text.length
|
||||
let cleanedUrl = text
|
||||
|
||||
try {
|
||||
const urlObj = new URL(text)
|
||||
const hostname = urlObj.hostname
|
||||
|
||||
const matchedRule = exceptions.value.find(rule =>
|
||||
rule.isEnabled && matchDomain(rule.domainPattern, hostname)
|
||||
)
|
||||
|
||||
if (matchedRule) {
|
||||
if (!matchedRule.keepAllParams) {
|
||||
const params = new URLSearchParams(urlObj.search)
|
||||
const keys = Array.from(params.keys())
|
||||
|
||||
for (const key of keys) {
|
||||
if (!matchedRule.keepParams.includes(key)) {
|
||||
params.delete(key)
|
||||
}
|
||||
}
|
||||
urlObj.search = params.toString()
|
||||
}
|
||||
|
||||
const originalLength = text.length
|
||||
let cleanedUrl = text
|
||||
|
||||
try {
|
||||
const urlObj = new URL(text)
|
||||
const hostname = urlObj.hostname
|
||||
|
||||
const matchedRule = exceptions.value.find(rule =>
|
||||
rule.isEnabled && matchDomain(rule.domainPattern, hostname)
|
||||
)
|
||||
|
||||
if (matchedRule) {
|
||||
if (!matchedRule.keepAllParams) {
|
||||
const params = new URLSearchParams(urlObj.search)
|
||||
const keys = Array.from(params.keys())
|
||||
|
||||
for (const key of keys) {
|
||||
if (!matchedRule.keepParams.includes(key)) {
|
||||
params.delete(key)
|
||||
}
|
||||
}
|
||||
urlObj.search = params.toString()
|
||||
}
|
||||
|
||||
if (!matchedRule.keepHash) {
|
||||
urlObj.hash = ''
|
||||
}
|
||||
} else {
|
||||
if (urlObj.search || urlObj.hash) {
|
||||
urlObj.search = ''
|
||||
urlObj.hash = ''
|
||||
}
|
||||
}
|
||||
|
||||
cleanedUrl = urlObj.toString()
|
||||
} catch (e) {
|
||||
return text
|
||||
}
|
||||
|
||||
if (cleanedUrl === text && autoClipboard) {
|
||||
return text
|
||||
}
|
||||
|
||||
const newLength = cleanedUrl.length
|
||||
const savedChars = originalLength - newLength
|
||||
const savedPercent = originalLength > 0 ? Math.round((savedChars / originalLength) * 100) : 0
|
||||
|
||||
const entry = {
|
||||
id: Date.now(),
|
||||
original: text,
|
||||
cleaned: cleanedUrl,
|
||||
savedPercent,
|
||||
timestamp: new Date().toLocaleTimeString()
|
||||
}
|
||||
|
||||
cleanedHistory.value.unshift(entry)
|
||||
|
||||
if (cleanedHistory.value.length > 50) {
|
||||
cleanedHistory.value.pop()
|
||||
}
|
||||
|
||||
if (autoClipboard && savedChars > 0 && writeClipboardFn) {
|
||||
writeClipboardFn(cleanedUrl)
|
||||
}
|
||||
|
||||
return cleanedUrl
|
||||
} catch (e) {
|
||||
console.error('Error processing URL:', e)
|
||||
return text
|
||||
if (!matchedRule.keepHash) {
|
||||
urlObj.hash = ''
|
||||
}
|
||||
} else {
|
||||
if (urlObj.search || urlObj.hash) {
|
||||
urlObj.search = ''
|
||||
urlObj.hash = ''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const removeEntry = (id) => {
|
||||
cleanedHistory.value = cleanedHistory.value.filter(item => item.id !== id)
|
||||
}
|
||||
cleanedUrl = urlObj.toString()
|
||||
} catch (e) {
|
||||
return text
|
||||
}
|
||||
|
||||
const clearHistory = () => {
|
||||
cleanedHistory.value = []
|
||||
}
|
||||
if (cleanedUrl === text && autoClipboard) {
|
||||
return text
|
||||
}
|
||||
|
||||
return {
|
||||
cleanedHistory,
|
||||
isWatchEnabled,
|
||||
exceptions,
|
||||
defaultExceptions,
|
||||
processUrl,
|
||||
removeEntry,
|
||||
clearHistory
|
||||
const newLength = cleanedUrl.length
|
||||
const savedChars = originalLength - newLength
|
||||
const savedPercent = originalLength > 0 ? Math.round((savedChars / originalLength) * 100) : 0
|
||||
|
||||
const entry = {
|
||||
id: Date.now(),
|
||||
original: text,
|
||||
cleaned: cleanedUrl,
|
||||
savedPercent,
|
||||
timestamp: new Date().toLocaleTimeString()
|
||||
}
|
||||
|
||||
cleanedHistory.value.unshift(entry)
|
||||
|
||||
if (cleanedHistory.value.length > 50) {
|
||||
cleanedHistory.value.pop()
|
||||
}
|
||||
|
||||
if (autoClipboard && savedChars > 0 && writeClipboardFn) {
|
||||
writeClipboardFn(cleanedUrl)
|
||||
}
|
||||
|
||||
return cleanedUrl
|
||||
} catch (e) {
|
||||
console.error('Error processing URL:', e)
|
||||
return text
|
||||
}
|
||||
}
|
||||
|
||||
const removeEntry = (id) => {
|
||||
cleanedHistory.value = cleanedHistory.value.filter(item => item.id !== id)
|
||||
}
|
||||
|
||||
const clearHistory = () => {
|
||||
cleanedHistory.value = []
|
||||
}
|
||||
|
||||
return {
|
||||
cleanedHistory,
|
||||
isWatchEnabled,
|
||||
exceptions,
|
||||
defaultExceptions,
|
||||
processUrl,
|
||||
removeEntry,
|
||||
clearHistory
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ const Ripple = {
|
||||
|
||||
// Allow custom color via directive value
|
||||
if (binding.value && typeof binding.value === 'string') {
|
||||
circle.style.backgroundColor = binding.value;
|
||||
circle.style.backgroundColor = binding.value;
|
||||
}
|
||||
|
||||
el.appendChild(circle);
|
||||
|
||||
@@ -212,6 +212,12 @@ body {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
::placeholder {
|
||||
color: var(--text-muted);
|
||||
opacity: 1;
|
||||
/* Override Firefox default opacity */
|
||||
}
|
||||
|
||||
.tool-textarea {
|
||||
font-family: monospace;
|
||||
resize: none;
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import QRCode from 'qrcode'
|
||||
|
||||
self.onmessage = async (e) => {
|
||||
const { id, text, ecc } = e.data
|
||||
const { id, text, ecc } = e.data
|
||||
|
||||
if (!text) {
|
||||
self.postMessage({ id, svgContent: '' })
|
||||
return
|
||||
}
|
||||
if (!text) {
|
||||
self.postMessage({ id, svgContent: '' })
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const svgContent = await QRCode.toString(text, {
|
||||
type: 'svg',
|
||||
errorCorrectionLevel: ecc,
|
||||
margin: 1,
|
||||
})
|
||||
try {
|
||||
const svgContent = await QRCode.toString(text, {
|
||||
type: 'svg',
|
||||
errorCorrectionLevel: ecc,
|
||||
margin: 1,
|
||||
})
|
||||
|
||||
self.postMessage({ id, svgContent })
|
||||
} catch (err) {
|
||||
self.postMessage({ id, error: err.message })
|
||||
}
|
||||
self.postMessage({ id, svgContent })
|
||||
} catch (err) {
|
||||
self.postMessage({ id, error: err.message })
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user