106 lines
3.0 KiB
TypeScript
106 lines
3.0 KiB
TypeScript
import { clsx, type ClassValue } from "clsx"
|
|
import { twMerge } from "tailwind-merge"
|
|
|
|
export function cn(...inputs: ClassValue[]) {
|
|
return twMerge(clsx(inputs))
|
|
}
|
|
|
|
/**
|
|
* Traite le message du footer en remplaçant [LINK] par le lien vers le repository
|
|
*/
|
|
export function processFooterMessage(message: string, repositoryUrl: string): string {
|
|
return message.replace(/\[LINK\]/g, repositoryUrl);
|
|
}
|
|
|
|
/**
|
|
* Traite le message du footer et retourne le texte avec les liens Markdown remplacés
|
|
*/
|
|
export function parseFooterMessage(message: string, repositoryUrl: string): { text: string; links: Array<{ text: string; url: string; start: number; end: number }> } {
|
|
const links: Array<{ text: string; url: string; start: number; end: number }> = [];
|
|
let processedText = message;
|
|
|
|
// Remplacer [texte](GITURL) par le texte du lien
|
|
const linkRegex = /\[([^\]]+)\]\(GITURL\)/g;
|
|
let match;
|
|
let offset = 0;
|
|
|
|
while ((match = linkRegex.exec(message)) !== null) {
|
|
const linkText = match[1]; // Le texte entre crochets
|
|
const fullMatch = match[0]; // Le match complet [texte](GITURL)
|
|
const start = match.index + offset;
|
|
const end = start + linkText.length;
|
|
|
|
links.push({
|
|
text: linkText,
|
|
url: repositoryUrl,
|
|
start,
|
|
end
|
|
});
|
|
|
|
processedText = processedText.replace(fullMatch, linkText);
|
|
offset += linkText.length - fullMatch.length;
|
|
}
|
|
|
|
return { text: processedText, links };
|
|
}
|
|
|
|
/**
|
|
* Génère un slug à partir d'un titre
|
|
*/
|
|
export function generateSlug(title: string): string {
|
|
return title
|
|
.toLowerCase()
|
|
.normalize('NFD')
|
|
.replace(/[\u0300-\u036f]/g, '') // Supprime les accents
|
|
.replace(/[^a-z0-9\s-]/g, '') // Garde seulement lettres, chiffres, espaces et tirets
|
|
.replace(/\s+/g, '-') // Remplace les espaces par des tirets
|
|
.replace(/-+/g, '-') // Remplace les tirets multiples par un seul
|
|
.trim();
|
|
}
|
|
|
|
/**
|
|
* Génère un ID court aléatoire
|
|
*/
|
|
export function generateShortId(): string {
|
|
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
|
let result = '';
|
|
for (let i = 0; i < 8; i++) {
|
|
result += chars.charAt(Math.floor(Math.random() * chars.length));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Formate un montant en euros
|
|
*/
|
|
export function formatCurrency(amount: number): string {
|
|
return new Intl.NumberFormat('fr-FR', {
|
|
style: 'currency',
|
|
currency: 'EUR',
|
|
}).format(amount);
|
|
}
|
|
|
|
/**
|
|
* Formate une date
|
|
*/
|
|
export function formatDate(date: Date | string): string {
|
|
const dateObj = typeof date === 'string' ? new Date(date) : date;
|
|
return dateObj.toLocaleDateString('fr-FR');
|
|
}
|
|
|
|
/**
|
|
* Valide une adresse email
|
|
*/
|
|
export function validateEmail(email: string): boolean {
|
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
return emailRegex.test(email);
|
|
}
|
|
|
|
/**
|
|
* Nettoie le HTML pour éviter les attaques XSS
|
|
*/
|
|
export function sanitizeHtml(html: string): string {
|
|
// Supprime les balises dangereuses
|
|
return html.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '');
|
|
}
|