diff --git a/frontend/src/App.vue b/frontend/src/App.vue
index 3c9f826..61d3838 100644
--- a/frontend/src/App.vue
+++ b/frontend/src/App.vue
@@ -258,12 +258,21 @@
{ key: "status", label: "Status" },
{ key: "actions", label: "" }
];
+// created_at values arrive as UTC ISO strings; render the server timestamp
+// as local "YYYY-MM-DD HH:mm" — the kit timeline draws it in a narrow
+// .timeline-time, where a compact fixed format reads better than Locale
+const formatTimestamp = (iso) => {
+ const date = new Date(iso);
+ if (Number.isNaN(date.getTime())) return iso;
+ const pad = (n) => String(n).padStart(2, "0");
+ return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}`;
+};
const versionItems = computed(() =>
versions.value.map((version) => ({
key: String(version.id),
title: `Version ${version.version_number}`,
- time: version.created_at,
- text: `${version.fields.length} fields`,
+ time: formatTimestamp(version.created_at),
+ text: `${version.fields.length} ${version.fields.length === 1 ? "field" : "fields"}`,
icon: "ph-clock-counter-clockwise",
raw: version
}))
@@ -271,7 +280,7 @@
const auditRows = computed(() =>
auditEvents.value.map((event) => ({
id: event.id,
- time: event.created_at,
+ time: formatTimestamp(event.created_at),
action: event.action,
channel: event.channel,
ip: event.ip_address || "—",
@@ -1193,6 +1202,9 @@
:visible-field-keys="revealedVisibleFields"
@toggle-field-visibility="toggleRevealedField"
/>
+
+ {{ item.text }}
—
-
+
+
diff --git a/frontend/src/styles.css b/frontend/src/styles.css
index f31deec..948f4fc 100644
--- a/frontend/src/styles.css
+++ b/frontend/src/styles.css
@@ -48,21 +48,9 @@
}
}
-.modal.a-show .modal-backdrop {
- animation: gnexus-creds-modal-backdrop 0.18s ease-out both;
-}
-
-.modal.a-show .modal-dialog {
- animation: gnexus-creds-modal-dialog 0.22s ease-out both;
-}
-
-.modal.a-hide .modal-backdrop {
- animation: gnexus-creds-modal-backdrop-out 0.22s ease-in both;
-}
-
-.modal.a-hide .modal-dialog {
- animation: gnexus-creds-modal-dialog-out 0.28s ease-in both;
-}
+/* Kit 1.0 owns modal + toast transitions itself, via .a-show/.a-hide state
+ classes and CSS transitions (dialog: margin-top 200px -> 0 + opacity;
+ toast: bottom -100px -> 15px). No app-side keyframes here. */
.secrets-page {
display: grid;
@@ -233,7 +221,7 @@
.create-modal-body {
display: grid;
- gap: 12px;
+ gap: 15px;
width: min(900px, calc(100vw - 48px));
max-width: 100%;
}
@@ -278,7 +266,12 @@
.modal-section {
display: grid;
- gap: 10px;
+ gap: 15px;
+}
+
+.modal-section + .modal-section {
+ padding-top: 15px;
+ border-top: 2px solid rgba(192, 202, 245, 0.08);
}
.create-fields {
@@ -370,6 +363,20 @@
}
}
+/* Vertical rail linking the markers (kit 1.0 ships no connector). The
+ marker is a 40px box in the first grid column, so its center sits at
+ 19px; the rail stops 18px short of the next marker, matching the
+ .timeline-content bottom padding. */
+.timeline-item:not(:last-child)::before {
+ content: "";
+ position: absolute;
+ left: 19px;
+ top: 44px;
+ bottom: 0;
+ width: 2px;
+ background: rgba(192, 202, 245, 0.24);
+}
+
/* Page header compact fixes */
.page-header.page-header-compact {
overflow: initial;
@@ -471,62 +478,4 @@
}
}
-@keyframes gnexus-creds-modal-backdrop {
- from {
- opacity: 0;
- }
-
- to {
- opacity: 1;
- }
-}
-
-@keyframes gnexus-creds-modal-dialog {
- from {
- opacity: 0;
- transform: translateY(-18px);
- }
-
- to {
- opacity: 1;
- transform: translateY(0);
- }
-}
-
-@keyframes gnexus-creds-modal-backdrop-out {
- from {
- opacity: 1;
- }
-
- to {
- opacity: 0;
- }
-}
-
-@keyframes gnexus-creds-modal-dialog-out {
- from {
- opacity: 1;
- transform: translateY(0);
- }
-
- to {
- opacity: 0;
- transform: translateY(-18px);
- }
-}
-
-@keyframes gnexus-creds-toast-in {
- from {
- bottom: -100px;
- opacity: 0;
- }
-
- to {
- bottom: 15px;
- opacity: 1;
- }
-}
-
-.toast.a-show {
- animation: gnexus-creds-toast-in 0.28s ease both;
-}
+/* Toast + modal entry/exit animations are kit-owned (see note above). */