mirror of
https://github.com/JMP-MS/ASPIC.git
synced 2026-10-27 17:17:08 +00:00
397 lines
19 KiB
HTML
397 lines
19 KiB
HTML
<!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>
|