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
|
npm run lint
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ export default [
|
|||||||
'no-unused-vars': 'off',
|
'no-unused-vars': 'off',
|
||||||
'no-undef': 'off',
|
'no-undef': 'off',
|
||||||
'no-debugger': 'off',
|
'no-debugger': 'off',
|
||||||
|
'indent': ['error', 2]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export function useExtension() {
|
|||||||
extensionCheckInterval = setInterval(() => {
|
extensionCheckInterval = setInterval(() => {
|
||||||
window.postMessage({ type: 'TOOLS_APP_PING' }, '*')
|
window.postMessage({ type: 'TOOLS_APP_PING' }, '*')
|
||||||
if (Date.now() - lastPongTime > TIMEOUT_THRESHOLD) {
|
if (Date.now() - lastPongTime > TIMEOUT_THRESHOLD) {
|
||||||
isExtensionReady.value = false
|
isExtensionReady.value = false
|
||||||
}
|
}
|
||||||
}, PING_INTERVAL)
|
}, PING_INTERVAL)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,115 +1,115 @@
|
|||||||
import { useLocalStorage } from './useLocalStorage'
|
import { useLocalStorage } from './useLocalStorage'
|
||||||
|
|
||||||
export function useUrlCleaner() {
|
export function useUrlCleaner() {
|
||||||
const cleanedHistory = useLocalStorage('url-cleaner-history', [])
|
const cleanedHistory = useLocalStorage('url-cleaner-history', [])
|
||||||
const isWatchEnabled = useLocalStorage('url-cleaner-watch-enabled', false)
|
const isWatchEnabled = useLocalStorage('url-cleaner-watch-enabled', false)
|
||||||
|
|
||||||
const defaultExceptions = [
|
const defaultExceptions = [
|
||||||
{ id: 'yt', domainPattern: '*.youtube.com', keepParams: ['v', 't'], keepHash: false, keepAllParams: false, isEnabled: true, isDefault: true },
|
{ 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 }
|
{ id: 'yt-short', domainPattern: 'youtu.be', keepParams: ['t'], keepHash: false, keepAllParams: false, isEnabled: true, isDefault: true }
|
||||||
]
|
]
|
||||||
const exceptions = useLocalStorage('url-cleaner-exceptions', defaultExceptions)
|
const exceptions = useLocalStorage('url-cleaner-exceptions', defaultExceptions)
|
||||||
|
|
||||||
const matchDomain = (pattern, domain) => {
|
const matchDomain = (pattern, domain) => {
|
||||||
// Escape regex chars except *
|
// Escape regex chars except *
|
||||||
const regexString = '^' + pattern.replace(/[.+^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '.*') + '$'
|
const regexString = '^' + pattern.replace(/[.+^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '.*') + '$'
|
||||||
return new RegExp(regexString, 'i').test(domain)
|
return new RegExp(regexString, 'i').test(domain)
|
||||||
}
|
}
|
||||||
|
|
||||||
const processUrl = (text, autoClipboard = false, writeClipboardFn = null) => {
|
const processUrl = (text, autoClipboard = false, writeClipboardFn = null) => {
|
||||||
try {
|
try {
|
||||||
// Basic URL validation
|
// Basic URL validation
|
||||||
if (!text.match(/^https?:\/\//i)) {
|
if (!text.match(/^https?:\/\//i)) {
|
||||||
if (autoClipboard) return text
|
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
|
if (!matchedRule.keepHash) {
|
||||||
let cleanedUrl = text
|
urlObj.hash = ''
|
||||||
|
}
|
||||||
try {
|
} else {
|
||||||
const urlObj = new URL(text)
|
if (urlObj.search || urlObj.hash) {
|
||||||
const hostname = urlObj.hostname
|
urlObj.search = ''
|
||||||
|
urlObj.hash = ''
|
||||||
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
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const removeEntry = (id) => {
|
cleanedUrl = urlObj.toString()
|
||||||
cleanedHistory.value = cleanedHistory.value.filter(item => item.id !== id)
|
} catch (e) {
|
||||||
}
|
return text
|
||||||
|
}
|
||||||
|
|
||||||
const clearHistory = () => {
|
if (cleanedUrl === text && autoClipboard) {
|
||||||
cleanedHistory.value = []
|
return text
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
const newLength = cleanedUrl.length
|
||||||
cleanedHistory,
|
const savedChars = originalLength - newLength
|
||||||
isWatchEnabled,
|
const savedPercent = originalLength > 0 ? Math.round((savedChars / originalLength) * 100) : 0
|
||||||
exceptions,
|
|
||||||
defaultExceptions,
|
const entry = {
|
||||||
processUrl,
|
id: Date.now(),
|
||||||
removeEntry,
|
original: text,
|
||||||
clearHistory
|
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
|
// Allow custom color via directive value
|
||||||
if (binding.value && typeof binding.value === 'string') {
|
if (binding.value && typeof binding.value === 'string') {
|
||||||
circle.style.backgroundColor = binding.value;
|
circle.style.backgroundColor = binding.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
el.appendChild(circle);
|
el.appendChild(circle);
|
||||||
|
|||||||
@@ -212,6 +212,12 @@ body {
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
::placeholder {
|
||||||
|
color: var(--text-muted);
|
||||||
|
opacity: 1;
|
||||||
|
/* Override Firefox default opacity */
|
||||||
|
}
|
||||||
|
|
||||||
.tool-textarea {
|
.tool-textarea {
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
resize: none;
|
resize: none;
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
import QRCode from 'qrcode'
|
import QRCode from 'qrcode'
|
||||||
|
|
||||||
self.onmessage = async (e) => {
|
self.onmessage = async (e) => {
|
||||||
const { id, text, ecc } = e.data
|
const { id, text, ecc } = e.data
|
||||||
|
|
||||||
if (!text) {
|
if (!text) {
|
||||||
self.postMessage({ id, svgContent: '' })
|
self.postMessage({ id, svgContent: '' })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const svgContent = await QRCode.toString(text, {
|
const svgContent = await QRCode.toString(text, {
|
||||||
type: 'svg',
|
type: 'svg',
|
||||||
errorCorrectionLevel: ecc,
|
errorCorrectionLevel: ecc,
|
||||||
margin: 1,
|
margin: 1,
|
||||||
})
|
})
|
||||||
|
|
||||||
self.postMessage({ id, svgContent })
|
self.postMessage({ id, svgContent })
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
self.postMessage({ id, error: err.message })
|
self.postMessage({ id, error: err.message })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user