V1.007 Premiers paramétrages de l'écran de fond

This commit is contained in:
2026-09-02 22:39:17 +00:00
parent 5ed02a8020
commit 7120d4d65e
8 changed files with 448 additions and 21 deletions
+396
View File
@@ -0,0 +1,396 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ASPIC — Écran de fond (essai)</title>
<style>
/* ecran_fond.html — 2 septembre 2026
Premier essai de l'écran de fond "bureau à l'ancienne" (voir journal de
développement, section 28, et réflexions stratégiques, section 11).
Volontairement minimal pour ce test : affichage plein écran de l'image
de référence, sans aucun objet cliquable/fonctionnel — juste de quoi
voir le rendu réel après identification, avant d'aller plus loin.
Image mise à jour le 2 septembre 2026 (soir) — nouvelle version sans
tableau en liège, recadrée par Jean-Marc lui-même après un premier essai
où le "cover" rognait le bas de l'image sur son écran (proportions
d'écran différentes du 16:9 de l'image). Passage de background-size
"cover" à "contain" à cette occasion : l'image entière reste désormais
toujours visible, quelle que soit la proportion de l'écran, quitte à
laisser une bande de la couleur du mur de part et d'autre plutôt que de
rogner — plus robuste qu'un recadrage qui ne marche que pour une
proportion d'écran précise.
Image recadrée une 2ᵉ fois (toujours le 2 septembre 2026) : Jean-Marc a
utilisé une lecture de fenêtre temporaire (affichée le temps du recadrage
puis retirée) pour recadrer directement à ses proportions d'écran
réelles — les bandes "contain" restent le filet de sécurité pour tout
autre écran, mais ne devraient plus apparaître chez lui. Nouvelle image
1024×457 : toutes les coordonnées ci-dessous ont été remesurées sur
cette version (celles mesurées sur la précédente, 1280×650, ne
s'appliquent plus). */
@font-face{
font-family:"Metro DF";
src:url('MetroDF.woff2') format('woff2'),url('MetroDF.ttf') format('truetype');
font-weight:normal;font-style:normal;font-display:swap;
}
*{box-sizing:border-box;}
html,body{
margin:0;padding:0;border:0;width:100%;height:100%;overflow:hidden;
font-family:"Segoe UI","Arial",sans-serif;
}
body{
/* Couleur échantillonnée sur le mur de la photo, pour que les bandes
laissées par "contain" (si la proportion de l'écran diffère de celle
de l'image) se fondent avec la scène plutôt que de créer un bord net. */
background:#ad580d url('ecran_fond.jpg') center center / contain no-repeat;
position:relative;
}
/* Étiquette "Contacts" sur la tranche du 1er classeur (2 septembre 2026,
essai). Positionnée en JS plutôt qu'en CSS pur : comme l'image est en
"contain", sa taille et sa position réelles à l'écran changent avec la
proportion de la fenêtre — même calcul que "background-size:contain"
refait à la main pour caler ce texte sur l'étiquette blanche, quelle
que soit la fenêtre. Coordonnées mesurées sur ecran_fond.jpg (image de
référence 1280×650) : rectangle d'étiquette à peu près x:[54,91],
y:[376,481] sur cette image. rotate(-90deg) : lecture bas → haut,
comme demandé (on tourne la tête pour lire), plutôt que haut → bas. */
#etiquette-contacts{
position:fixed;
transform:translate(-50%,-50%) rotate(-90deg);
transform-origin:center;
white-space:nowrap;
color:#2a2a2a;
font-family:"Segoe UI","Arial",sans-serif;
font-weight:600;
letter-spacing:0.03em;
pointer-events:none;
user-select:none;
}
/* Zone cliquable calée sur la tranche visible (face plate, sans le
dessus incliné) du 1er classeur — même principe de positionnement en
JS que l'étiquette ci-dessus. Pas d'habillage visuel par défaut (le
classeur photographié suffit), juste un léger éclaircissement au survol
pour signaler que c'est cliquable, en plus du curseur et de l'infobulle. */
#classeur-contacts{
position:fixed;
display:block;
box-shadow:inset 0 0 0 0 rgba(255,255,255,0);
transition:box-shadow .12s ease;
}
#classeur-contacts:hover{
box-shadow:inset 0 0 0 2px rgba(255,255,255,.7);
}
/* Chevalet en bas à droite (2 septembre 2026, essai — simplifié le même
jour à la demande de Jean-Marc) : plus que le prénom de l'utilisateur
connecté (USR_Prenom), la société retirée ("l'utilisateur la connaît
déjà"). Une seule ligne, donc plus de place pour une police nettement
plus grande — c'était le point d'origine du problème de lisibilité.
Donnée réelle de la session (preferences.php, voir script), jamais de
texte figé. Ellipsis de sécurité si un prénom venait à être long. */
#chevalet{
position:fixed;
display:flex;align-items:center;justify-content:center;
text-align:center;
color:#333;
font-family:"Segoe UI","Arial",sans-serif;
font-weight:700;
pointer-events:none;
user-select:none;
overflow:hidden;
}
#chevalet-nom{
white-space:nowrap;
max-width:100%;
overflow:hidden;
text-overflow:ellipsis;
}
/* Micro cliquable (2 septembre 2026, essai — retouché le même jour après
retour de Jean-Marc). Deux éléments distincts, superposés mais avec des
rôles différents :
- #micro-desk : la zone cliquable/survolable RÉELLE, calée sur tout le
silhouette du micro (pied, tige, corps, tête) — pas seulement la
petite tête. Corrige le souci remonté : l'infobulle ne se déclenchait
qu'en survolant précisément la petite grille du haut, zone trop
étroite pour être fiable à la souris. Invisible (pas de fond), juste
le curseur + l'infobulle (title) + le clic.
- #micro-icone : uniquement l'icône elle-même, petite, calée sur le
rond noir de la tête (voir positionner()). pointer-events:none pour
laisser passer le clic/survol vers #micro-desk en dessous. Le léger
liseré au survol (auparavant sur le bouton) est maintenant affiché
ici via le sélecteur de fratrie ~ quand #micro-desk est survolé, pour
rester visuellement au niveau de la tête plutôt qu'engober tout le
micro d'un cadre. Icônes redessinées en SVG à partir de
mic_repos.png / mic_ecoute.png (déjà utilisées pour le bouton micro
du bandeau, voir micro.js) — recolorées, sans le disque rouge
d'origine, pour se fondre dans la grille plutôt que ressortir comme
un autocollant. Fermé = glyphe micro en gris clair ; ouvert = barres
façon vu-mètre en --rouge-micro, animées (voir @keyframes) — "les
barres qui bougent" demandé par Jean-Marc. Toggle en pur JS pour ce
test : ne déclenche pas encore la reconnaissance vocale de micro.js. */
#micro-desk{
position:fixed;
border:none;background:transparent;padding:0;margin:0;
cursor:pointer;
}
#micro-icone{
position:fixed;
display:flex;align-items:center;justify-content:center;
border-radius:50%;
pointer-events:none;
box-shadow:0 0 0 0 rgba(255,255,255,0);
transition:box-shadow .12s ease;
}
#micro-desk:hover ~ #micro-icone{
box-shadow:0 0 0 3px rgba(255,255,255,.3);
}
#micro-icone svg{
width:70%;height:70%;display:block;
}
#micro-icone svg[hidden]{display:none;}
#glyphe-repos{
fill:#d9d9d3;
opacity:.92;
}
#glyphe-ecoute{
fill:#e14a5c; /* proche de --rouge-micro (#D9364B) de liste_contacts.html */
}
#glyphe-ecoute .barre{
transform-box:fill-box;
transform-origin:50% 100%;
animation:pulse-barre 1s ease-in-out infinite;
}
#glyphe-ecoute .barre:nth-child(1){ animation-delay:-.6s; }
#glyphe-ecoute .barre:nth-child(2){ animation-delay:-.3s; }
#glyphe-ecoute .barre:nth-child(3){ animation-delay:0s; }
#glyphe-ecoute .barre:nth-child(4){ animation-delay:-.45s; }
@keyframes pulse-barre{
0%,100%{ transform:scaleY(.55); }
50%{ transform:scaleY(1); }
}
/* Numéro de version, sur le bureau. Même source que #statut-version dans
liste_contacts.html (version.php, voir commentaire de chargerVersion()
ci-dessous) : jamais de numéro figé en dur, pour rester juste même si
la version évolue sans repasser par cet écran. Repositionné le
2 septembre 2026 : plus à droite (bord droit de l'écran plutôt que
calé sur le chevalet) et plus bas, juste au-dessus de la bande claire
qui marque la tranche avant du bureau. Couleur assombrie et rendue
opaque (au lieu d'une transparence à 62%) à la demande de Jean-Marc —
reste plus sobre que les objets fonctionnels, mais plus affirmée
qu'avant. */
#version-desk{
position:fixed;
color:#3a2712;
font-family:"Segoe UI","Arial",sans-serif;
font-weight:700;
letter-spacing:0.02em;
text-align:right;
white-space:nowrap;
pointer-events:none;
user-select:none;
}
</style>
</head>
<body>
<a id="classeur-contacts" href="liste_contacts.html" title="Ouvrir le classeur des contacts"></a>
<div id="etiquette-contacts">Contacts</div>
<div id="chevalet">
<div id="chevalet-nom"></div>
</div>
<button id="micro-desk" type="button"></button>
<div id="micro-icone">
<svg id="glyphe-repos" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M12 14c1.66 0 3-1.34 3-3V5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3z"/>
<path d="M17 11c0 2.76-2.24 5-5 5s-5-2.24-5-5H5c0 3.53 2.61 6.43 6 6.92V21h2v-3.08c3.39-.49 6-3.39 6-6.92h-2z"/>
</svg>
<svg id="glyphe-ecoute" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" hidden>
<rect class="barre" x="2" y="14" width="3.5" height="7" rx="1"/>
<rect class="barre" x="8" y="9" width="3.5" height="12" rx="1"/>
<rect class="barre" x="14" y="4" width="3.5" height="17" rx="1"/>
<rect class="barre" x="20" y="11" width="3.5" height="10" rx="1"/>
</svg>
</div>
<div id="version-desk"></div>
<script>
// Référence de l'image : 1024×457 (voir ecran_fond.jpg — 2ᵉ recadrage du
// 2 septembre 2026). Toutes les coordonnées ci-dessous sont exprimées en
// pixels de CETTE image de référence, puis converties en fraction pour
// rester calées quelle que soit la taille réelle d'affichage (voir calcul
// dans positionner()).
const IMG_W = 1024, IMG_H = 457;
// Centre de l'étiquette du 1er classeur, remesuré une 3ᵉ fois le
// 2 septembre 2026 : la mesure précédente (69) incluait par erreur
// l'étiquette du classeur bleu voisin dans le calcul du centre ligne par
// ligne (les deux étiquettes, blanches toutes les deux, se touchent
// presque et le seuil de luminosité ne les distinguait pas) — d'où un
// texte qui débordait vers la droite, dans le classeur bleu, au lieu de
// rester dans le classeur bleu-vert. Remesuré en isolant la seule
// première plage claire (x<80) sur plusieurs lignes : rectangle
// d'étiquette réel x:[44,71], y:[240,324], centre (57.5, 282).
const ETIQ_CENTRE_X_FRAC = 57.5 / IMG_W;
const ETIQ_CENTRE_Y_FRAC = 282 / IMG_H;
const ETIQ_POLICE_FRAC = 19 / IMG_W;
// Rectangle de la tranche visible du 1er classeur (face plate, sans le
// dessus incliné), mesuré sur ecran_fond.jpg : x:[37,78], y:[224,397].
const CLASSEUR_X1 = 37, CLASSEUR_X2 = 78;
const CLASSEUR_Y1 = 224, CLASSEUR_Y2 = 397;
// Rectangle de la partie blanche du chevalet, mesuré sur ecran_fond.jpg :
// x:[860,982], y:[359,394] — léger retrait (marge intérieure) pour ne pas
// coller le texte au cadre en bois.
const CHEVALET_X1 = 866, CHEVALET_X2 = 976;
const CHEVALET_Y1 = 362, CHEVALET_Y2 = 391;
// Une seule ligne désormais (prénom seul) : le chevalet est bas et
// large, la police peut être nettement plus grande qu'avant.
const CHEVALET_POLICE_FRAC = 18 / IMG_W;
// Zone cliquable/survolable du micro : tout le silhouette du micro, du
// pied à la tête (bras de la nacelle inclus), mesurée sur ecran_fond.jpg :
// x:[465,543], y:[236,406].
const MICRO_ZONE_X1 = 465, MICRO_ZONE_X2 = 543;
const MICRO_ZONE_Y1 = 236, MICRO_ZONE_Y2 = 406;
// Centre du rond noir en haut du micro (grille), pour l'icône seule —
// remonté le 2 septembre 2026 (icône perçue trop basse avec 268) : la
// pointe du dôme est à y≈242, sa partie courbe se termine vers y≈260
// avant de devenir un cylindre à largeur quasi constante (mesh) jusqu'à
// y≈308. Centre replacé dans le haut du dôme, pas dans le cylindre :
// (512, 255), diamètre réduit à ~22px pour ne pas déborder au-dessus de
// la pointe (y=242).
const ICONE_CENTRE_X = 512, ICONE_CENTRE_Y = 255;
const ICONE_TAILLE_FRAC = 22 / IMG_W;
// Coin haut-droit du texte de version (2 septembre 2026, repositionné) :
// plus près du bord droit de l'écran (1024 de large) qu'aligné sur le
// chevalet, et juste au-dessus de la bande claire de la tranche avant du
// bureau — mesurée sur ecran_fond.jpg vers y:[442,450] ; le texte est
// calé pour se terminer avant, vers y=436.
const VERSION_X = 1012, VERSION_Y = 424;
const VERSION_POLICE_FRAC = 11 / IMG_W;
function positionner() {
const vw = window.innerWidth, vh = window.innerHeight;
const ratioImg = IMG_W / IMG_H;
const ratioVp = vw / vh;
let dispW, dispH, offX, offY;
if (ratioVp > ratioImg) {
dispH = vh; dispW = dispH * ratioImg;
offX = (vw - dispW) / 2; offY = 0;
} else {
dispW = vw; dispH = dispW / ratioImg;
offX = 0; offY = (vh - dispH) / 2;
}
const etiquette = document.getElementById('etiquette-contacts');
etiquette.style.left = (offX + ETIQ_CENTRE_X_FRAC * dispW) + 'px';
etiquette.style.top = (offY + ETIQ_CENTRE_Y_FRAC * dispH) + 'px';
etiquette.style.fontSize = (ETIQ_POLICE_FRAC * dispW) + 'px';
const classeur = document.getElementById('classeur-contacts');
classeur.style.left = (offX + (CLASSEUR_X1 / IMG_W) * dispW) + 'px';
classeur.style.top = (offY + (CLASSEUR_Y1 / IMG_H) * dispH) + 'px';
classeur.style.width = (((CLASSEUR_X2 - CLASSEUR_X1) / IMG_W) * dispW) + 'px';
classeur.style.height = (((CLASSEUR_Y2 - CLASSEUR_Y1) / IMG_H) * dispH) + 'px';
const chevalet = document.getElementById('chevalet');
chevalet.style.left = (offX + (CHEVALET_X1 / IMG_W) * dispW) + 'px';
chevalet.style.top = (offY + (CHEVALET_Y1 / IMG_H) * dispH) + 'px';
chevalet.style.width = (((CHEVALET_X2 - CHEVALET_X1) / IMG_W) * dispW) + 'px';
chevalet.style.height = (((CHEVALET_Y2 - CHEVALET_Y1) / IMG_H) * dispH) + 'px';
chevalet.style.fontSize = (CHEVALET_POLICE_FRAC * dispW) + 'px';
const microDesk = document.getElementById('micro-desk');
microDesk.style.left = (offX + (MICRO_ZONE_X1 / IMG_W) * dispW) + 'px';
microDesk.style.top = (offY + (MICRO_ZONE_Y1 / IMG_H) * dispH) + 'px';
microDesk.style.width = (((MICRO_ZONE_X2 - MICRO_ZONE_X1) / IMG_W) * dispW) + 'px';
microDesk.style.height = (((MICRO_ZONE_Y2 - MICRO_ZONE_Y1) / IMG_H) * dispH) + 'px';
const microIcone = document.getElementById('micro-icone');
const iconeTaille = ICONE_TAILLE_FRAC * dispW;
microIcone.style.left = (offX + (ICONE_CENTRE_X / IMG_W) * dispW - iconeTaille / 2) + 'px';
microIcone.style.top = (offY + (ICONE_CENTRE_Y / IMG_H) * dispH - iconeTaille / 2) + 'px';
microIcone.style.width = iconeTaille + 'px';
microIcone.style.height = iconeTaille + 'px';
const versionDesk = document.getElementById('version-desk');
versionDesk.style.left = (offX + (VERSION_X / IMG_W) * dispW - 200) + 'px';
versionDesk.style.width = '200px';
versionDesk.style.top = (offY + (VERSION_Y / IMG_H) * dispH) + 'px';
versionDesk.style.fontSize = (VERSION_POLICE_FRAC * dispW) + 'px';
}
window.addEventListener('resize', positionner);
positionner();
// Bascule ouvert/fermé du micro du bureau — pur affichage pour ce test
// (icône + infobulle), ne démarre pas encore la reconnaissance vocale
// réelle de micro.js. Fermé par défaut à l'arrivée sur l'écran.
let microOuvert = false;
function appliquerEtatMicroDesk() {
const bouton = document.getElementById('micro-desk');
const glyphRepos = document.getElementById('glyphe-repos');
const glyphEcoute = document.getElementById('glyphe-ecoute');
// setAttribute/removeAttribute plutôt que la propriété .hidden : sur un
// <svg> inline, la réflexion de .hidden s'est révélée peu fiable au test
// (attribut inchangé malgré l'affectation) — passage par l'attribut DOM
// directement pour un résultat garanti.
if (microOuvert) {
glyphRepos.setAttribute('hidden', '');
glyphEcoute.removeAttribute('hidden');
bouton.title = 'Le micro est ouvert, cliquez pour le fermer';
} else {
glyphRepos.removeAttribute('hidden');
glyphEcoute.setAttribute('hidden', '');
bouton.title = 'Le micro est fermé, cliquez pour l\'ouvrir';
}
}
document.getElementById('micro-desk').addEventListener('click', () => {
microOuvert = !microOuvert;
appliquerEtatMicroDesk();
});
appliquerEtatMicroDesk();
// Identité affichée sur le chevalet : preferences.php (voir journal
// section 22), qui renvoie USR_Prenom (ajouté le 2 septembre 2026 dans
// ASP_Users à la demande de Jean-Marc). Société retirée de l'affichage
// le même jour ("l'utilisateur la connaît déjà") — plus besoin d'aller
// chercher USR_Societe ici. Repli silencieux (mêmes principes que
// chargerPreferences()) si la session n'est pas active.
async function chargerIdentiteChevalet() {
const elNom = document.getElementById('chevalet-nom');
try {
const reponsePrefs = await fetch('preferences.php');
if (!reponsePrefs.ok) throw new Error('HTTP ' + reponsePrefs.status);
const prefs = await reponsePrefs.json();
elNom.textContent = prefs.USR_Prenom || prefs.USR_Code || '—';
} catch (erreur) {
console.error('Erreur de chargement de preferences.php (chevalet) :', erreur);
elNom.textContent = 'Prénom';
}
}
chargerIdentiteChevalet();
// Numéro de version affiché sur le bureau : même endpoint que
// #statut-version dans liste_contacts.html (chargerVersion(), voir
// journal). Repli silencieux si non joignable (fichier hors serveur, ou
// version.php absent de ce dossier) : l'écran reste utilisable sans.
async function chargerVersionDesk() {
try {
const reponse = await fetch('version.php');
if (!reponse.ok) throw new Error('HTTP ' + reponse.status);
const data = await reponse.json();
if (data.version) document.getElementById('version-desk').textContent = data.version;
} catch (erreur) {
console.error('Erreur de chargement de version.php (bureau) :', erreur);
}
}
chargerVersionDesk();
// Lien visible "→ Liste des tâches" retiré le 2 septembre 2026 à la
// demande de Jean-Marc. Échap conservé comme échappatoire silencieuse
// (même logique que le reste de l'appli), pour ne pas rester bloqué sur
// cet écran tant qu'il ne porte aucun objet fonctionnel.
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
window.location.href = 'liste_todolist.html';
}
});
</script>
</body>
</html>