Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,30 @@ Versions follow [Semantic Versioning](https://semver.org/).

## [Unreleased]

### Changed — homepage shows seven quick actions; "More tools" box removed

Before a file was chosen, the homepage's tool card offered no concrete
operation — just the Convert/Compress toggle and an empty target-format
dropdown — and on the homepage the PDF tools (split, extract, compress)
appeared only as small text links in a "More tools" box below the fold (plus
the footer). This is the first visible step of surfacing operations earlier.

The tool card now shows, under the drop zone, seven secondary "chip" links
under an "Or choose directly" label — Compress PDF, JPG to PDF, Word to PDF,
Split PDF, Extract PDF pages, HEIC to JPG and Compress image (KB/MB) —
followed by an "All tools →" link. All seven point at pages that already
exist; "(KB/MB)" signals file size, not pixel dimensions. They render only on
the homepage — the same tool card is shared by `/compress` and the 12
`/convert/<pair>` pages, which would otherwise show self-links — and step
aside while files are selected, returning when the selection is cleared. The
"More tools" box is gone; its links now live in the chips and the "All tools"
link. The subline above the tool gains "PDF". Redact is no longer teased on
the homepage — it still appears in the footer and on /tools when AI
operations are enabled.

`scripts/i18n.py update` now passes `--ignore-obsolete`, so removed strings
are dropped from the catalogs instead of piling up as `#~` blocks.

### Fixed — FAQ, `/llms.txt`, JSON-LD and README listed an outdated set of formats

The homepage FAQ answer "Which file formats can I convert?" (DE and EN), the
Expand Down
4 changes: 4 additions & 0 deletions app/api/routes/pages.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@ async def index(request: Request):
plans={p.tier: p for p in pricing_mod.saas_plans(locale)},
saas_prices_configured=pricing_mod.saas_prices_configured(),
price_currency=pricing_mod.price_currency(),
# Homepage-only chip row inside the shared convert_tool.html partial
# (docs-internal/operations-visibility-konzept.md) — no other route
# sets this.
show_quick_actions=True,
)


Expand Down
1 change: 1 addition & 0 deletions app/static/css/tailwind.86732528.css

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion app/static/css/tailwind.8be3407b.css

This file was deleted.

12 changes: 12 additions & 0 deletions app/static/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ function setFiles(files) {

document.getElementById('drop-idle').classList.add('hidden');
document.getElementById('drop-selected').classList.remove('hidden');
setQuickActionsVisible(false);
renderFileList();

// Single-file flow: populate the standalone dropdown from the first file's
Expand Down Expand Up @@ -329,6 +330,16 @@ function renderFileList() {
// point at the dedicated split/extract/compress tools instead. #pdf-tools-hint
// is absent on pair pages (partials/convert_tool.html gates it on
// `preset_source`), hence the null-guard.
// Homepage quick-action chips (partials/quick_actions.html) are an idle-state
// shortcut: once files are chosen they would sit between the file list and
// the Convert button, so hide them until the selection is cleared again.
// Server-rendered, so the links stay in the initial HTML. Null-guarded —
// only the homepage renders #quick-actions.
function setQuickActionsVisible(visible) {
const nav = document.getElementById('quick-actions');
if (nav) nav.classList.toggle('hidden', !visible);
}

function updatePdfToolsHint() {
const hint = document.getElementById('pdf-tools-hint');
if (!hint) return;
Expand Down Expand Up @@ -358,6 +369,7 @@ function clearAllFiles(event) {
document.getElementById('file-input').value = '';
document.getElementById('drop-idle').classList.remove('hidden');
document.getElementById('drop-selected').classList.add('hidden');
setQuickActionsVisible(true);
document.getElementById('target-format').innerHTML =
'<option value="">— select a file first —</option>';
document.getElementById('quality-section').classList.add('hidden');
Expand Down
23 changes: 1 addition & 22 deletions app/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<div class="text-center space-y-2">
<h1 class="text-h-page text-ink">{{ _('Convert & Compress Files') }}</h1>
<p class="text-ink-muted text-sm">
{{ _('Images · Documents · Audio · Video · Spreadsheets') }}
{{ _('Images · PDF · Documents · Audio · Video · Spreadsheets') }}
</p>
</div>

Expand Down Expand Up @@ -66,27 +66,6 @@ <h2 class="text-base font-semibold text-white">{{ _('Run FileMorph on your own i
</div>
</section>

{# More tools — IA rework PR 3 (docs-internal/ia-navigation-konzept.md):
merges what used to be two separate teasers (gated Redact + ungated
PDF tools) into one tile row, closed by a link to the full /tools hub.
Redact stays gated on ai_operations_enabled — same rule as the
footer's Tools group and the /tools hub's Redact card — so a
self-host / inert build (where the redact route 404s) never links
it. Jinja comment on purpose: never shipped over the wire. #}
<section class="border border-gray-800 rounded-xl px-5 py-4 space-y-2">
<h2 class="text-base font-semibold text-white">{{ _('More tools') }}</h2>
<p class="text-xs text-gray-400 leading-relaxed">{{ _('Dedicated tools beyond the converter above: split, extract, or compress a PDF, and more.') }}</p>
<div class="flex flex-wrap gap-3 pt-1">
<a href="{{ localized_url('/pdf/split', current_prefix) }}" class="text-sm text-brand hover:underline">{{ _('Split PDF') }} →</a>
<a href="{{ localized_url('/pdf/extract', current_prefix) }}" class="text-sm text-brand hover:underline">{{ _('Extract PDF pages') }} →</a>
<a href="{{ localized_url('/pdf/compress', current_prefix) }}" class="text-sm text-brand hover:underline">{{ _('Compress PDF') }} →</a>
{% if ai_operations_enabled %}
<a href="{{ localized_url('/redact', current_prefix) }}" class="text-sm text-brand hover:underline">{{ _('Redact PII') }} (Pro) →</a>
{% endif %}
<a href="{{ localized_url('/tools', current_prefix) }}" class="text-sm text-brand hover:underline">{{ _('All tools →') }}</a>
</div>
</section>

{% if pricing_enabled %}
<!-- Tier teaser — commercial offer surface. Limits come from
quotas.py and the price strings from PRICE_*_DISPLAY env via
Expand Down
6 changes: 6 additions & 0 deletions app/templates/partials/convert_tool.html
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@
</div>
</div>

{# Homepage-only quick actions (partials/quick_actions.html) — gated on
show_quick_actions (set only by pages.py::index) so /compress and the
12 /convert/<pair> pages, which also render this shared partial, don't
get self-links or diluted chip rows. #}
{% if show_quick_actions %}{% include "partials/quick_actions.html" %}{% endif %}

<!-- Convert: target format -->
<div id="convert-options" class="space-y-4">
<div class="space-y-1">
Expand Down
95 changes: 95 additions & 0 deletions app/templates/partials/quick_actions.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
{# Homepage quick actions (docs-internal/operations-visibility-konzept.md,
section "Startseite"): 7 secondary chip links shown before any file is
picked, replacing the old "More tools" box further down the page. Every
chip targets an existing page — IA rule "every promoted operation has a
URL first" — so nothing here teases an unbuilt feature. Server-rendered,
no JS involved, so link visibility can never differ from the initial
HTML (IA invariant G6). Redact is a paid/gated operation and is
deliberately never one of these idle chips (product-ux.md #3 — free
path before any upsell); it stays in the footer and on /tools when
ai_operations_enabled is set. #}
<nav id="quick-actions" aria-labelledby="quick-actions-label" class="space-y-3">
<div class="flex items-center gap-3">
<span id="quick-actions-label" class="text-xs font-semibold uppercase tracking-wider text-gray-400">
{{ _('Or choose directly') }}
</span>
<span class="flex-1 h-px bg-gray-800" aria-hidden="true"></span>
</div>
<ul class="flex flex-wrap gap-2">
<li>
<a href="{{ localized_url('/pdf/compress', current_prefix) }}"
class="inline-flex items-center gap-2 min-h-11 px-3 py-2 rounded-lg border border-gray-700 bg-gray-900 text-sm font-medium text-gray-200 hover:border-brand hover:text-white transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand">
<svg class="w-4 h-4 text-brand-light" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.8"
d="M9 9V4.5M9 9H4.5M9 9L3.75 3.75M9 15v4.5M9 15H4.5M9 15l-5.25 5.25M15 9h4.5M15 9V4.5M15 9l5.25-5.25M15 15h4.5M15 15v4.5m0-4.5l5.25 5.25" />
</svg>
{{ _('Compress PDF') }}
</a>
</li>
<li>
<a href="{{ localized_url('/convert/jpg-to-pdf', current_prefix) }}"
class="inline-flex items-center gap-2 min-h-11 px-3 py-2 rounded-lg border border-gray-700 bg-gray-900 text-sm font-medium text-gray-200 hover:border-brand hover:text-white transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand">
<svg class="w-4 h-4 text-brand-light" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.8"
d="M2.25 15.75l5.16-5.16a2.25 2.25 0 013.18 0l5.16 5.16m-1.5-1.5l1.41-1.41a2.25 2.25 0 013.18 0l2.91 2.91M3.75 19.5h16.5a1.5 1.5 0 001.5-1.5V6a1.5 1.5 0 00-1.5-1.5H3.75A1.5 1.5 0 002.25 6v12a1.5 1.5 0 001.5 1.5z" />
</svg>
{{ _('JPG to PDF') }}
</a>
</li>
<li>
<a href="{{ localized_url('/convert/docx-to-pdf', current_prefix) }}"
class="inline-flex items-center gap-2 min-h-11 px-3 py-2 rounded-lg border border-gray-700 bg-gray-900 text-sm font-medium text-gray-200 hover:border-brand hover:text-white transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand">
<svg class="w-4 h-4 text-brand-light" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.8"
d="M14 2.5H6.5A1.5 1.5 0 005 4v16a1.5 1.5 0 001.5 1.5h11A1.5 1.5 0 0019 20V7.5L14 2.5z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.8"
d="M14 2.5v5h5M8.5 12.5l1.2 5 1.8-4 1.8 4 1.2-5" />
</svg>
{{ _('Word to PDF') }}
</a>
</li>
<li>
<a href="{{ localized_url('/pdf/split', current_prefix) }}"
class="inline-flex items-center gap-2 min-h-11 px-3 py-2 rounded-lg border border-gray-700 bg-gray-900 text-sm font-medium text-gray-200 hover:border-brand hover:text-white transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand">
<svg class="w-4 h-4 text-brand-light" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.8"
d="M6 9a3 3 0 100-6 3 3 0 000 6zM6 21a3 3 0 100-6 3 3 0 000 6zM20 4L8.12 15.88M14.47 14.48L20 20M8.12 8.12L12 12" />
</svg>
{{ _('Split PDF') }}
</a>
</li>
<li>
<a href="{{ localized_url('/pdf/extract', current_prefix) }}"
class="inline-flex items-center gap-2 min-h-11 px-3 py-2 rounded-lg border border-gray-700 bg-gray-900 text-sm font-medium text-gray-200 hover:border-brand hover:text-white transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand">
<svg class="w-4 h-4 text-brand-light" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.8"
d="M8 7V4.5A1.5 1.5 0 019.5 3h9A1.5 1.5 0 0120 4.5v12a1.5 1.5 0 01-1.5 1.5H16M4 8.5A1.5 1.5 0 015.5 7h9A1.5 1.5 0 0116 8.5v11a1.5 1.5 0 01-1.5 1.5h-9A1.5 1.5 0 014 19.5z" />
</svg>
{{ _('Extract PDF pages') }}
</a>
</li>
<li>
<a href="{{ localized_url('/convert/heic-to-jpg', current_prefix) }}"
class="inline-flex items-center gap-2 min-h-11 px-3 py-2 rounded-lg border border-gray-700 bg-gray-900 text-sm font-medium text-gray-200 hover:border-brand hover:text-white transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand">
<svg class="w-4 h-4 text-brand-light" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.8"
d="M2.25 15.75l5.16-5.16a2.25 2.25 0 013.18 0l5.16 5.16m-1.5-1.5l1.41-1.41a2.25 2.25 0 013.18 0l2.91 2.91M3.75 19.5h16.5a1.5 1.5 0 001.5-1.5V6a1.5 1.5 0 00-1.5-1.5H3.75A1.5 1.5 0 002.25 6v12a1.5 1.5 0 001.5 1.5z" />
</svg>
{{ _('HEIC to JPG') }}
</a>
</li>
<li>
<a href="{{ localized_url('/compress', current_prefix) }}"
class="inline-flex items-center gap-2 min-h-11 px-3 py-2 rounded-lg border border-gray-700 bg-gray-900 text-sm font-medium text-gray-200 hover:border-brand hover:text-white transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand">
<svg class="w-4 h-4 text-brand-light" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.8"
d="M9 9V4.5M9 9H4.5M9 9L3.75 3.75M9 15v4.5M9 15H4.5M9 15l-5.25 5.25M15 9h4.5M15 9V4.5M15 9l5.25-5.25M15 15h4.5M15 15v4.5m0-4.5l5.25 5.25" />
</svg>
{{ _('Compress image (KB/MB)') }}
</a>
</li>
</ul>
<p>
<a href="{{ localized_url('/tools', current_prefix) }}" class="rounded text-sm font-semibold text-brand-light hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand">{{ _('All tools →') }}</a>
</p>
</nav>
Binary file modified locale/de/LC_MESSAGES/messages.mo
Binary file not shown.
31 changes: 18 additions & 13 deletions locale/de/LC_MESSAGES/messages.po
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: FileMorph VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2026-09-25 19:23+0200\n"
"POT-Creation-Date: 2026-09-25 19:53+0200\n"
"PO-Revision-Date: 2026-05-08 11:00+0200\n"
"Last-Translator: FileMorph <hallo@filemorph.io>\n"
"Language: de\n"
Expand Down Expand Up @@ -551,6 +551,9 @@ msgstr "PDF verkleinern"
msgid "Compress a PDF →"
msgstr "PDF verkleinern →"

msgid "Compress image (KB/MB)"
msgstr "Bild verkleinern (KB/MB)"

msgid "Compress to a target size"
msgstr "Auf eine Zielgröße komprimieren"

Expand Down Expand Up @@ -757,13 +760,6 @@ msgstr "Auftragsverarbeitungs-Vertrag (AVV)"
msgid "Deactivated"
msgstr "Deaktiviert"

msgid ""
"Dedicated tools beyond the converter above: split, extract, or compress a"
" PDF, and more."
msgstr ""
"Spezielle Tools zusätzlich zum Konverter oben: PDF aufteilen, Seiten "
"extrahieren, PDF verkleinern — und mehr."

msgid "Delete account"
msgstr "Konto löschen"

Expand Down Expand Up @@ -1206,6 +1202,9 @@ msgstr ""
msgid "Got it"
msgstr "Verstanden"

msgid "HEIC to JPG"
msgstr "HEIC in JPG"

msgid "Hetzner's privacy policy"
msgstr "Hetzners Datenschutzerklärung"

Expand Down Expand Up @@ -1388,8 +1387,8 @@ msgstr ""
" (MP3, WAV, FLAC, OGG, M4A, AAC, WMA, Opus) und Video (MP4, MOV, AVI, "
"MKV, WebM, FLV, WMV)."

msgid "Images · Documents · Audio · Video · Spreadsheets"
msgstr "Bilder · Dokumente · Audio · Video · Tabellen"
msgid "Images · PDF · Documents · Audio · Video · Spreadsheets"
msgstr "Bilder · PDF · Dokumente · Audio · Video · Tabellen"

msgid "Impressum"
msgstr "Impressum"
Expand Down Expand Up @@ -1459,6 +1458,9 @@ msgstr ""
msgid "JPEG / WebP only."
msgstr "Nur JPEG / WebP."

msgid "JPG to PDF"
msgstr "JPG in PDF"

msgid "Joined"
msgstr "Beigetreten"

Expand Down Expand Up @@ -1563,9 +1565,6 @@ msgstr ""
"Begrenzung, damit ein Batch nicht den ganzen Worker-Pool blockiert — "
"Anfragen über dem Limit erhalten"

msgid "More tools"
msgstr "Weitere Tools"

msgid "Most popular"
msgstr "Am beliebtesten"

Expand Down Expand Up @@ -1667,6 +1666,9 @@ msgstr "Öffnen →"
msgid "Operator staff with the"
msgstr "Betreiber-Mitarbeiter mit der"

msgid "Or choose directly"
msgstr "Oder direkt wählen"

msgid "Or open the dashboard manually and click \"Manage billing\":"
msgstr "Oder öffne das Dashboard manuell und klicke auf „Abrechnung verwalten“:"

Expand Down Expand Up @@ -2990,6 +2992,9 @@ msgstr "Warum eine Compliance-Edition?"
msgid "Why →"
msgstr "Warum →"

msgid "Word to PDF"
msgstr "Word in PDF"

msgid ""
"Yes. FileMorph can compress JPEG and WebP images to a target size (for "
"example 5 MB) using a binary search, hitting the target within about ±3 "
Expand Down
Binary file modified locale/en/LC_MESSAGES/messages.mo
Binary file not shown.
Loading
Loading