Files
Aether/frontend/src/components/pdf.css
T
HoneyandClaude Opus 5 31a027c93a feat(aether): initial commit – self-hosted Cloud, Phasen 1–7
Go-Backend (chi, pgx, golang-migrate) + React/TS-Frontend als PWA.
Enthalten: Auth inkl. OIDC, Dateien mit Versionen und Papierkorb,
Freigaben (Links + intern), WebDAV, Gruppenordner, Admin/Theming,
Volltextsuche mit OCR, eigener PDF-Betrachter und WOPI-Office
(Collabora/OnlyOffice).

Nicht im Repo: deploy/.env (Sitzungsschlüssel, DB- und Admin-Passwort)
sowie alle Daten- und Build-Verzeichnisse – siehe .gitignore.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-24 09:25:36 +02:00

209 lines
5.5 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* Textebene von PDF.js.
*
* Der Block unten ist **wörtlich** aus pdfjs-dist/web/pdf_viewer.css
* übernommen, nur die Klasse heißt `.pdf-textLayer` statt `.textLayer`.
*
* Beim ersten Anlauf hatte ich ihn von Hand gekürzt – „wir zeigen nur Seiten
* an, der Rest ist Werkzeugleiste". Dabei fielen drei Zeilen weg, die wie
* Kleinkram aussahen und keiner waren:
*
* --min-font-size / --text-scale-factor / scale(var(--min-font-size-inv))
*
* PDF.js misst beim ersten Aufbau, wie klein der Browser Schrift überhaupt
* noch darstellt (Chrome erzwingt eine Mindestgröße), setzt daraus
* `--min-font-size` und rechnet sie mit der Skalierung wieder heraus. Ohne
* dieses Paar wird jede kleine Schrift vom Browser aufgeblasen: Die
* unsichtbaren Textstücke sitzen dann größer da als die gemalten Buchstaben
* darunter – zu sehen erst beim **Markieren**, wo die Auswahl als grobe,
* versetzte Kästen über dem Text lag statt auf ihm.
*
* Deshalb hier nichts mehr von Hand kürzen. Was die Datei mitbringt, gehört
* zusammen; was wir zusätzlich wollen, steht darunter.
*/
.pdf-textLayer{
color-scheme:only light;
position:absolute;
text-align:initial;
inset:0;
overflow:clip;
opacity:1;
line-height:1;
letter-spacing:normal;
word-spacing:normal;
-webkit-text-size-adjust:none;
-moz-text-size-adjust:none;
text-size-adjust:none;
forced-color-adjust:none;
transform-origin:0 0;
caret-color:CanvasText;
z-index:0;
&.highlighting{
touch-action:none;
}
:is(span, br){
color:transparent;
position:absolute;
white-space:pre;
cursor:text;
transform-origin:0% 0%;
-webkit-user-select:text;
-moz-user-select:text;
user-select:text;
}
--min-font-size:1;
--text-scale-factor:calc(var(--total-scale-factor) * var(--min-font-size));
--min-font-size-inv:calc(1 / var(--min-font-size));
> :not(.markedContent),
.markedContent span:not(.markedContent){
z-index:1;
--font-height:0;
font-size:calc(var(--text-scale-factor) * var(--font-height));
--scale-x:1;
--rotate:0deg;
transform:rotate(var(--rotate)) scaleX(var(--scale-x)) scale(var(--min-font-size-inv));
}
.markedContent{
display:contents;
}
span[role="img"]{
-webkit-user-select:none;
-moz-user-select:none;
user-select:none;
cursor:default;
}
.highlight{
--highlight-bg-color:rgb(180 0 170 / 0.25);
--highlight-selected-bg-color:rgb(0 100 0 / 0.25);
--highlight-backdrop-filter:none;
--highlight-selected-backdrop-filter:none;
@media screen and (forced-colors: active){
--highlight-bg-color:transparent;
--highlight-selected-bg-color:transparent;
--highlight-backdrop-filter:var(--hcm-highlight-filter);
--highlight-selected-backdrop-filter:var(
--hcm-highlight-selected-filter
);
}
margin:-1px;
padding:1px;
background-color:var(--highlight-bg-color);
backdrop-filter:var(--highlight-backdrop-filter);
border-radius:4px;
&.appended{
position:initial;
}
&.begin{
border-radius:4px 0 0 4px;
}
&.end{
border-radius:0 4px 4px 0;
}
&.middle{
border-radius:0;
}
&.selected{
background-color:var(--highlight-selected-bg-color);
backdrop-filter:var(--highlight-selected-backdrop-filter);
scroll-margin-top:50px;
}
}
::-moz-selection{
background:rgba(0 0 255 / 0.25);
background:color-mix(in srgb, AccentColor, transparent 50%);
color:transparent;
}
::selection{
background:rgba(0 0 255 / 0.25);
background:color-mix(in srgb, AccentColor, transparent 50%);
color:transparent;
}
&.selectionRendering{
::-moz-selection{
background:transparent;
color:transparent;
}
::selection{
background:transparent;
color:transparent;
}
}
br::-moz-selection{
background:transparent;
}
br::selection{
background:transparent;
}
.endOfContent{
display:block;
position:absolute;
inset:100% 0 0;
z-index:0;
cursor:default;
-webkit-user-select:none;
-moz-user-select:none;
user-select:none;
}
&.selecting .endOfContent{
top:0;
}
}
/*
* Fundstellen der Suche.
*
* Eine eigene Ebene über der Textebene, kein <mark> im Text. Warum, steht
* ausführlich in PdfViewer.tsx bei `paint` – kurz: Der Grund eines <mark>
* ragte oben aus der Textebene heraus, und die schneidet ab (`overflow:
* clip`). Das sah man als angeschnittene Streifen. Diese Ebene schneidet
* nichts ab; die Kästen sind dieselben, die der Browser beim Markieren mit
* der Maus malt.
*
* `pointer-events: none`, damit die Ebene das Markieren mit der Maus nicht
* abfängt – darunter liegt die Schrift, die man auswählen können soll.
*
* Die Farbe bleibt durchsichtig: Der lesbare Text steht auf dem gemalten Bild
* *darunter*. Mit 0,95 Deckkraft lag ein satter Block über dem Wort, und
* ausgerechnet das gesuchte Wort war das einzige, das man nicht mehr lesen
* konnte. Der Betrachter von PDF.js selbst arbeitet aus demselben Grund mit
* 0,25.
*/
.pdf-hitLayer {
position: absolute;
inset: 0;
z-index: 1;
pointer-events: none;
}
.pdf-hit {
position: absolute;
background: rgba(245, 158, 11, 0.3);
border-radius: 2px;
}
.pdf-hit.pdf-hit-current {
background: rgba(245, 158, 11, 0.55);
/* Der aktuelle Treffer bekommt zusätzlich eine Kante statt noch mehr Farbe –
Deckkraft würde wieder das Wort verschlucken. */
box-shadow: 0 0 0 1px rgba(180, 83, 9, 0.75);
}