-
- {t('app.recipes.lede', 'Ready-to-go installers that run as real operations: probe, derive, apply, verify. Secrets are asked for mid-run and kept in the vault.')}
-
+
}
+ info={t('app.recipes.lede', 'Ready-to-go installers that run as real operations: probe, derive, apply, verify. Secrets are asked for mid-run and kept in the vault.')}
+ steps={[
+ { icon:
, label: t('app.recipes.stepProbe', 'Probe'), info: t('app.recipes.stepProbeInfo', 'Check the target server meets the requirements.') },
+ { icon:
, label: t('app.recipes.stepApply', 'Apply'), info: t('app.recipes.stepApplyInfo', 'Derive settings and run the install as a real operation.') },
+ { icon:
, label: t('app.recipes.stepSecrets', 'Secrets'), info: t('app.recipes.stepSecretsInfo', 'Secrets are asked for mid-run and kept in the vault.') },
+ { icon:
, label: t('app.recipes.stepVerify', 'Verify'), info: t('app.recipes.stepVerifyInfo', 'Confirm the service came up healthy.') },
+ ]}
+ >
+ {t('app.recipes.headerLine', 'One-click installers')}
+
setCategory(cat)}
>
{cat === 'all' ? t('common.labels.all', 'All') : cat}
@@ -214,7 +227,7 @@ export default function Recipes() {
{(recipe.requirements?.cpuCores)
&& {recipe.requirements.cpuCores} vCPU }
{(recipe.requirements?.memoryMB)
- && {formatBytes(recipe.requirements.memoryMB * GB, { decimals: 0 })} }
+ && {formatBytes(recipe.requirements.memoryMB * MB, { decimals: 0 })} }
{(recipe.requirements?.diskGB)
&& {formatBytes(recipe.requirements.diskGB * GB, { decimals: 0 })} }
{(recipe.requirements?.igpu && recipe.requirements.igpu !== 'none')
diff --git a/frontend/src/styles/pages/_recipes.scss b/frontend/src/styles/pages/_recipes.scss
index b978a35f..5755acca 100644
--- a/frontend/src/styles/pages/_recipes.scss
+++ b/frontend/src/styles/pages/_recipes.scss
@@ -5,29 +5,25 @@
&__head {
display: flex;
- align-items: flex-end;
- gap: $spacing-lg;
+ flex-direction: column;
+ gap: $spacing-md;
margin-bottom: $spacing-md;
}
- &__lede {
+ &__intro {
flex: 1;
min-width: 0;
- margin: 0;
- color: var(--text-secondary);
- font-size: $text-sm;
- line-height: 1.55;
- max-width: 640px;
}
&__search {
display: flex;
align-items: center;
gap: $space-2;
- width: 260px;
+ width: 100%;
+ max-width: 360px;
height: $control-md;
padding: 0 $space-3;
- border: 1px solid var(--border-color);
+ border: 1px solid var(--border-default);
border-radius: $radius-control;
background: var(--bg-card);
color: var(--text-tertiary);
@@ -48,16 +44,27 @@
flex-wrap: wrap;
gap: $space-2;
margin-bottom: $spacing-md;
+ }
- .sk-pill {
- cursor: pointer;
- opacity: 0.72;
+ &__cat {
+ display: inline-flex;
+ align-items: center;
+ min-height: $control-sm;
+ padding: 0 $space-3;
+ border: 1px solid var(--border-default);
+ border-radius: $radius-full;
+ background: var(--bg-card);
+ color: var(--text-secondary);
+ font-size: $text-sm;
+ font-weight: $font-weight-medium;
+ cursor: pointer;
- &.is-active {
- opacity: 1;
- border-color: var(--primary-color);
- color: var(--primary-color);
- }
+ &:hover { color: var(--text-primary); }
+
+ &.is-active {
+ border-color: var(--accent);
+ background: var(--accent-bg);
+ color: var(--accent);
}
}
@@ -87,7 +94,7 @@
flex-direction: column;
gap: $space-3;
padding: $spacing-md;
- border: 1px solid var(--border-color);
+ border: 1px solid var(--border-default);
border-radius: $radius-card;
background: var(--bg-card);
@@ -105,8 +112,8 @@
height: 34px; // geometry: icon tile
flex-shrink: 0;
border-radius: $radius-control;
- background: color-mix(in srgb, var(--primary-color) 12%, transparent);
- color: var(--primary-color);
+ background: var(--accent-bg);
+ color: var(--accent);
}
&__id {
@@ -152,7 +159,7 @@
span {
padding: $space-hair $space-2;
border-radius: $radius-badge;
- border: 1px solid var(--border-color);
+ border: 1px solid var(--border-default);
font-size: $text-xs;
color: var(--text-tertiary);
@@ -201,7 +208,7 @@
width: 100%;
height: $control-md;
padding: 0 $space-3;
- border: 1px solid var(--border-color);
+ border: 1px solid var(--border-default);
border-radius: $radius-control;
background: var(--bg-input, var(--bg-card));
color: var(--text-primary);
@@ -220,7 +227,7 @@
width: 100%;
padding: $space-3 $space-3;
border: none;
- border-bottom: 1px solid var(--border-color);
+ border-bottom: 1px solid var(--border-default);
background: transparent;
color: var(--text-primary);
cursor: pointer;
@@ -231,9 +238,9 @@
&:hover { background: var(--bg-hover, rgba(128, 128, 128, 0.06)); }
&.is-on {
- background: color-mix(in srgb, var(--primary-color) 8%, transparent);
+ background: var(--accent-bg);
- svg { color: var(--primary-color); }
+ svg { color: var(--accent); }
}
}
@@ -242,11 +249,11 @@
height: 14px;
flex-shrink: 0;
border-radius: 50%;
- border: 1.5px solid var(--border-color);
+ border: 1.5px solid var(--border-default);
.is-on & {
- border-color: var(--primary-color);
- box-shadow: inset 0 0 0 3.5px var(--primary-color); // geometry: draws the radio's inner dot
+ border-color: var(--accent);
+ box-shadow: inset 0 0 0 3.5px var(--accent); // geometry: draws the radio's inner dot
}
}
@@ -298,7 +305,7 @@
align-items: center;
gap: $space-2;
padding: $space-2 $space-3;
- border-bottom: 1px solid var(--border-color);
+ border-bottom: 1px solid var(--border-default);
font-size: $text-sm;
&:last-child { border-bottom: none; }
@@ -325,7 +332,7 @@
align-items: center;
gap: $space-2;
padding: $space-2 $space-3;
- border-bottom: 1px solid var(--border-color);
+ border-bottom: 1px solid var(--border-default);
font-size: $text-sm;
&:last-child { border-bottom: none; }
@@ -336,6 +343,6 @@
&__url {
font-size: $text-xs;
- color: var(--primary-color);
+ color: var(--accent);
}
}