- Champ Présentation prérempli avec le texte Grav, suivi modifié/synchro (textOverride undefined = suit Grav, sinon figé ; bouton Réinitialiser) - Fix génération PDF : savePortfolio écrit en atomique (temp+rename) pour éviter la corruption de lecture par l'autosave concurrent du rendu print - Toast d'échec de génération explicite (message serveur) - Refonte architecture visuelle, fond unifié white/tint/full, dispositions couverture bandeau/colonne, instantané public complet, index 3 lignes
31 lines
931 B
TypeScript
31 lines
931 B
TypeScript
// Copie presse-papier robuste : l'API `navigator.clipboard` n'existe qu'en
|
|
// contexte sécurisé (HTTPS ou localhost) ; en HTTP sur IP LAN elle est absente,
|
|
// d'où un repli via un <textarea> temporaire + `document.execCommand('copy')`.
|
|
export async function copyToClipboard(text: string): Promise<boolean> {
|
|
if (import.meta.server) return false
|
|
|
|
if (navigator.clipboard && window.isSecureContext) {
|
|
try {
|
|
await navigator.clipboard.writeText(text)
|
|
return true
|
|
} catch {
|
|
// contexte sécurisé mais copie refusée → on tente le repli
|
|
}
|
|
}
|
|
|
|
try {
|
|
const ta = document.createElement('textarea')
|
|
ta.value = text
|
|
ta.setAttribute('readonly', '')
|
|
ta.style.position = 'fixed'
|
|
ta.style.top = '-9999px'
|
|
document.body.appendChild(ta)
|
|
ta.select()
|
|
const ok = document.execCommand('copy')
|
|
document.body.removeChild(ta)
|
|
return ok
|
|
} catch {
|
|
return false
|
|
}
|
|
}
|