dsadas
All checks were successful
Deploy / deploy-staging (push) Successful in 5s
Deploy / deploy-production (push) Has been skipped

This commit is contained in:
2026-05-04 03:03:30 +02:00
parent c81e89dc3f
commit c3ba24e939
4 changed files with 318 additions and 298 deletions

View File

@@ -1,27 +1,36 @@
#fx-rates-app {
padding: 1rem 0 2rem;
}
.fx-stack {
#fx-rates-app,
#fx-rates-currencies {
display: grid;
gap: 1rem;
gap: 16px;
}
.fx-card {
background: var(--panel-bg, #fff);
border: 1px solid rgba(15, 23, 42, 0.12);
border-radius: 8px;
padding: 1rem;
.fx-submenu-row {
display: flex;
gap: 14px;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
}
.fx-card h1,
.fx-card h2 {
.fx-section-head {
display: flex;
justify-content: space-between;
gap: 16px;
align-items: flex-start;
flex-wrap: wrap;
}
.fx-section-head h2,
.section-box h2,
.card-box h2 {
margin: 0 0 0.5rem;
}
.fx-card p {
.fx-section-head p,
.section-box p,
.card-box p {
margin: 0 0 0.75rem;
color: #5b6573;
color: var(--muted);
}
.fx-card-head {
@@ -38,40 +47,6 @@
flex-wrap: wrap;
}
.fx-button {
appearance: none;
border: 1px solid #d0d7e2;
background: #fff;
color: #1c2734;
border-radius: 8px;
padding: 0.7rem 1rem;
cursor: pointer;
}
.fx-button--primary {
background: #1c2734;
color: #fff;
border-color: #1c2734;
}
.fx-button--ghost {
background: #fff4fb;
border-color: #f5b7d7;
color: #ff8a00;
}
.fx-button--accent {
background: linear-gradient(90deg, #ff006a 0%, #ff9e00 100%);
color: #111827;
border-color: transparent;
font-weight: 700;
}
.fx-button[disabled] {
opacity: 0.6;
cursor: wait;
}
.fx-form-grid {
display: grid;
gap: 0.75rem;
@@ -90,29 +65,30 @@
.fx-form-grid span,
.fx-block span {
font-size: 0.9rem;
color: #5b6573;
color: var(--muted);
}
.fx-form-grid input,
.fx-form-grid select,
.fx-block input {
width: 100%;
border: 1px solid #d0d7e2;
border-radius: 8px;
border: 1px solid var(--line);
border-radius: 12px;
padding: 0.7rem 0.8rem;
background: var(--surface-strong);
color: var(--text);
}
.fx-message {
margin-bottom: 0.9rem;
color: #1c2734;
color: var(--text);
}
.fx-message.is-error {
color: #b42318;
color: #d92d20;
}
.fx-message.is-success {
color: #027a48;
color: color-mix(in srgb, var(--accent-green) 78%, var(--text));
}
.fx-table-wrap {
@@ -127,7 +103,7 @@
.fx-table th,
.fx-table td {
text-align: left;
border-bottom: 1px solid #eef2f6;
border-bottom: 1px solid var(--line);
padding: 0.65rem 0.4rem;
}
@@ -141,13 +117,13 @@
min-height: 1.5rem;
font-size: 1rem;
font-weight: 700;
color: #1c2734;
color: var(--text);
}
.fx-card-meta {
display: grid;
gap: 0.35rem;
color: #5b6573;
color: var(--muted);
font-size: 0.95rem;
text-align: right;
}
@@ -156,7 +132,6 @@
display: flex;
gap: 0.75rem;
flex-wrap: wrap;
margin-bottom: 1rem;
}
.fx-action-row form {
@@ -175,22 +150,27 @@
display: grid;
gap: 1rem;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
margin: 1rem 0 1.25rem;
}
.fx-mini-card {
.fx-card-grid {
display: grid;
gap: 0.2rem;
gap: 16px;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}
.fx-mini-label,
.fx-field-label {
font-size: 0.9rem;
color: #6a7383;
color: var(--muted);
letter-spacing: 0.18em;
text-transform: uppercase;
}
.fx-card-value {
font-size: 1.2rem;
font-weight: 700;
}
.fx-currency-selection-row {
display: flex;
flex-wrap: wrap;
@@ -216,11 +196,11 @@
.fx-input,
.fx-select {
width: 100%;
border: 1px solid #d0d7e2;
border: 1px solid var(--line);
border-radius: 18px;
padding: 0.8rem 1rem;
background: #fff;
color: #1c2734;
background: var(--surface-strong);
color: var(--text);
}
.fx-field {
@@ -234,11 +214,11 @@
display: inline-flex;
align-items: center;
gap: 0.6rem;
border: 1px solid #d0d7e2;
border: 1px solid var(--line);
border-radius: 999px;
padding: 0.7rem 1rem;
background: #fff;
color: #1c2734;
background: var(--surface-strong);
color: var(--text);
}
.fx-token {
@@ -247,12 +227,12 @@
.fx-token:hover,
.fx-suggestion:hover {
border-color: rgba(255, 158, 0, 0.45);
background: rgba(255, 244, 251, 0.9);
border-color: color-mix(in srgb, var(--brand-accent-3) 45%, transparent);
background: color-mix(in srgb, var(--brand-accent) 6%, var(--surface-strong));
}
.fx-token-close {
color: #ff9e00;
color: var(--brand-accent-3);
font-weight: 700;
text-transform: uppercase;
}
@@ -269,11 +249,11 @@
}
.fx-suggestion strong {
color: #111827;
color: var(--text);
}
.fx-text {
color: #5b6573;
color: var(--muted);
}
.fx-history-date {
@@ -285,10 +265,10 @@
.fx-info-button {
width: 1.4rem;
height: 1.4rem;
border: 1px solid #d0d7e2;
border: 1px solid var(--line);
border-radius: 999px;
background: #fff;
color: #5b6573;
background: var(--surface-strong);
color: var(--muted);
font-size: 0.78rem;
font-weight: 700;
line-height: 1;
@@ -304,6 +284,11 @@
flex-direction: column;
}
.fx-submenu-row,
.fx-card-head {
align-items: flex-start;
}
.fx-currency-search {
flex: 1 1 auto;
width: 100%;

View File

@@ -1,6 +1,6 @@
{
"eyebrow": "Modul",
"title": "FX-Rates",
"title": "Waehrungskurse",
"description": "Zentrale Verwaltung fuer Waehrungskurse, Snapshots und FX-API-Abrufe.",
"actions": [
{ "label": "Setup", "href": "/modules/setup/fx-rates", "variant": "secondary" }

View File

@@ -117,47 +117,65 @@ $tabs = [
['label' => 'Waehrungen', 'href' => '/module/fx-rates/currencies', 'active' => true],
];
?>
<?= module_shell_header('fx-rates', [
'title' => 'Waehrungskurse',
'tabs' => $tabs,
'actions' => [
['label' => 'Setup', 'href' => '/modules/setup/fx-rates', 'variant' => 'secondary', 'size' => 'sm'],
],
]) ?>
<div id="fx-rates-currencies" data-page='<?= e(is_string($currencyPageData) ? $currencyPageData : '{}') ?>'>
<div class="fx-stack">
<div class="fx-card">
<div class="submenu-box">
<div class="fx-submenu-row">
<nav class="module-tabs" aria-label="Unterseiten von Waehrungskurse">
<?php foreach ($tabs as $tab): ?>
<a
class="<?= !empty($tab['active']) ? 'module-button module-button--tab-active' : 'module-button module-button--tab' ?>"
href="<?= e((string) $tab['href']) ?>"
><?= e((string) $tab['label']) ?></a>
<?php endforeach; ?>
</nav>
<div class="module-submenu-actions">
<a class="module-button module-button--secondary module-button--small" href="/modules/setup/fx-rates">Setup</a>
</div>
</div>
</div>
<?php if ($notice !== ''): ?>
<section class="section-box">
<div class="fx-message is-success"><?= e($notice) ?></div>
</section>
<?php elseif ($error !== ''): ?>
<section class="section-box">
<div class="fx-message is-error"><?= e($error) ?></div>
</section>
<?php endif; ?>
<section class="section-box">
<div class="fx-section-head">
<div>
<h2>Waehrungs-Update</h2>
<p>Auswahl wird in den FX-Rates-Einstellungen gespeichert und steht damit auf Handy und Desktop gleich zur Verfuegung.</p>
<p>Auswahl wird in den Waehrungskurs-Einstellungen gespeichert und steht damit auf Handy und Desktop gleich zur Verfuegung.</p>
</div>
</div>
<div class="fx-action-row">
<form method="post">
<input type="hidden" name="fx_action" value="refresh_rates">
<button type="submit" class="fx-button fx-button--accent">Alle Wechselkurse aktualisieren</button>
<button type="submit" class="module-button module-button--primary">Alle Wechselkurse aktualisieren</button>
</form>
<form method="post">
<input type="hidden" name="fx_action" value="sync_catalog">
<button type="submit" class="fx-button fx-button--ghost">Waehrungskatalog sync</button>
<button type="submit" class="module-button module-button--ghost">Waehrungskatalog sync</button>
</form>
</div>
</section>
<div class="fx-mini-grid">
<div class="fx-mini-card">
<div class="fx-card-grid">
<section class="card-box">
<div class="fx-mini-label">Fiat</div>
<div><?= e((string) $fiatCount) ?> Waehrungen</div>
</div>
<div class="fx-mini-card">
<div class="fx-card-value"><?= e((string) $fiatCount) ?> Waehrungen</div>
</section>
<section class="card-box">
<div class="fx-mini-label">Krypto</div>
<div><?= e((string) $cryptoCount) ?> Waehrungen</div>
</div>
<div class="fx-card-value"><?= e((string) $cryptoCount) ?> Waehrungen</div>
</section>
</div>
<section class="section-box">
<div class="fx-field-label">Bevorzugte Waehrungen fuer Anzeige</div>
<div class="fx-currency-selection-row">
<div class="fx-token-list fx-token-list--inline" data-fx-token-list></div>
@@ -177,12 +195,12 @@ $tabs = [
<input type="hidden" name="fx_action" value="save_selection">
<input type="hidden" name="display_base_currency" value="<?= e($displayBaseCurrency) ?>" data-fx-display-base-hidden>
<div data-fx-hidden-preferred></div>
<button type="submit" class="fx-button fx-button--ghost">Auswahl speichern</button>
<button type="submit" class="module-button module-button--ghost">Auswahl speichern</button>
</form>
</div>
</div>
</section>
<div class="fx-card">
<section class="section-box">
<div class="fx-card-head">
<div>
<h2>Letzte 15 Kurs-Uploads</h2>
@@ -265,7 +283,5 @@ $tabs = [
</tbody>
</table>
</div>
</section>
</div>
</div>
</div>
<?= module_shell_footer() ?>

View File

@@ -58,30 +58,51 @@ $pageData = json_encode([
'preferred_currencies' => $preferredCurrencies,
'recent_fetches' => $recentFetches,
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$tabs = [
['label' => 'Ueberblick', 'href' => '/module/fx-rates', 'active' => true],
['label' => 'Waehrungen', 'href' => '/module/fx-rates/currencies'],
];
?>
<?= module_shell_header('fx-rates', [
'title' => 'Waehrungskurse',
'actions' => [
['label' => 'Setup', 'href' => '/modules/setup/fx-rates', 'variant' => 'secondary', 'size' => 'sm'],
['label' => 'Aktuelle Kurse abrufen', 'href' => '/module/fx-rates?refresh=1', 'variant' => 'secondary', 'size' => 'sm'],
],
]) ?>
<div id="fx-rates-app" data-page='<?= e(is_string($pageData) ? $pageData : '{}') ?>'>
<div class="fx-stack">
<div class="fx-card">
<div class="submenu-box">
<div class="fx-submenu-row">
<nav class="module-tabs" aria-label="Unterseiten von Waehrungskurse">
<?php foreach ($tabs as $tab): ?>
<a
class="<?= !empty($tab['active']) ? 'module-button module-button--tab-active' : 'module-button module-button--tab' ?>"
href="<?= e((string) $tab['href']) ?>"
><?= e((string) $tab['label']) ?></a>
<?php endforeach; ?>
</nav>
<div class="module-submenu-actions">
<a class="module-button module-button--secondary module-button--small" href="/modules/setup/fx-rates">Setup</a>
<a class="module-button module-button--secondary module-button--small" href="/module/fx-rates?refresh=1">Aktuelle Kurse abrufen</a>
</div>
</div>
</div>
<?php if ($notice !== ''): ?>
<section class="section-box">
<div class="fx-message is-success"><?= e($notice) ?></div>
</section>
<?php elseif ($error !== ''): ?>
<section class="section-box">
<div class="fx-message is-error"><?= e($error) ?></div>
</section>
<?php endif; ?>
<section class="section-box">
<div class="fx-section-head">
<div>
<h2>Umrechnung</h2>
<p>Umrechnung auf Basis des letzten verfuegbaren Kurses zwischen den bevorzugten Waehrungen.</p>
</div>
</div>
<p class="fx-api-note">
API-Self-Describe-Endpoint:
<a href="<?= e($apiDescribeUrl) ?>" target="_blank" rel="noopener noreferrer"><?= e($apiDescribeUrl) ?></a>
</p>
<h2>Umrechnung</h2>
<p>Umrechnung auf Basis des letzten verfuegbaren Kurses zwischen den bevorzugten Waehrungen.</p>
<div class="fx-form-grid">
<label>
<span>Quellwaehrung</span>
@@ -105,9 +126,9 @@ $pageData = json_encode([
</label>
</div>
<div class="fx-convert-result" data-bind="convert-result">Noch keine Umrechnung berechnet.</div>
</div>
</section>
<div class="fx-card">
<section class="section-box">
<div class="fx-card-head">
<div>
<h2>Kursverlauf</h2>
@@ -131,7 +152,5 @@ $pageData = json_encode([
</tbody>
</table>
</div>
</section>
</div>
</div>
</div>
<?= module_shell_footer() ?>