Drive installs through the common ISO pipeline, carry install intent in configurator JSON, and finalize Limine boot setup from the ISO.
347 lines
9.4 KiB
Bash
Executable File
347 lines
9.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Preview Omarchy installer UI concepts without building or booting the ISO.
|
|
# Usage: bin/omarchy-install-ui-preview [dashboard|matrix|forge|logs]
|
|
set -euo pipefail
|
|
|
|
concept="${1:-dashboard}"
|
|
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
|
|
|
LOGO_PATH="${OMARCHY_PREVIEW_LOGO:-}"
|
|
if [[ -z $LOGO_PATH ]]; then
|
|
for candidate in \
|
|
"$SCRIPT_DIR/../../omarchy-installer/logo.txt" \
|
|
"$SCRIPT_DIR/../configs/airootfs/usr/share/omarchy/logo.txt" \
|
|
"/usr/share/omarchy/logo.txt"; do
|
|
if [[ -f $candidate ]]; then
|
|
LOGO_PATH="$candidate"
|
|
break
|
|
fi
|
|
done
|
|
fi
|
|
|
|
CSI=$'\033['
|
|
RESET="${CSI}0m"
|
|
BOLD="${CSI}1m"
|
|
DIM="${CSI}2m"
|
|
HIDE_CURSOR="${CSI}?25l"
|
|
SHOW_CURSOR="${CSI}?25h"
|
|
CLEAR="${CSI}2J${CSI}H"
|
|
HOME="${CSI}H"
|
|
CLEAR_LINE="${CSI}2K"
|
|
CLEAR_TO_END="${CSI}J"
|
|
GREEN="${CSI}38;5;150m"
|
|
BLUE="${CSI}38;5;111m"
|
|
PURPLE="${CSI}38;5;141m"
|
|
YELLOW="${CSI}38;5;221m"
|
|
RED="${CSI}38;5;203m"
|
|
GRAY="${CSI}38;5;245m"
|
|
DARK="${CSI}38;5;238m"
|
|
|
|
logo_width() {
|
|
if [[ -n ${LOGO_PATH:-} && -f $LOGO_PATH ]]; then
|
|
awk '{ if (length > max) max = length } END { print max+0 }' "$LOGO_PATH"
|
|
else
|
|
printf '78\n'
|
|
fi
|
|
}
|
|
|
|
LOGO_WIDTH="$(logo_width)"
|
|
(( LOGO_WIDTH > 0 )) || LOGO_WIDTH=78
|
|
CONTENT_WIDTH="${OMARCHY_PREVIEW_WIDTH:-$LOGO_WIDTH}"
|
|
(( CONTENT_WIDTH > 0 )) || CONTENT_WIDTH="$LOGO_WIDTH"
|
|
|
|
phases=(
|
|
"Preparing live environment"
|
|
"Partitioning target disk"
|
|
"Installing base system"
|
|
"Installing Omarchy packages"
|
|
"Building Limine UKI"
|
|
"Configuring Snapper"
|
|
"Validating boot setup"
|
|
"Finishing"
|
|
)
|
|
|
|
logs=(
|
|
"pacman-key: populating archlinux keyring"
|
|
"mount: /mnt ready"
|
|
"pacstrap: installing linux btrfs-progs limine"
|
|
"pacman: installing omarchy"
|
|
"useradd: creating ryan with /etc/skel defaults"
|
|
"limine-update: generating omarchy_linux.efi"
|
|
"snapper: creating root config"
|
|
"efibootmgr: registered Limine"
|
|
"validation: UKI present, fstab present, boot entry present"
|
|
)
|
|
|
|
whimsy=(
|
|
"making Linux feel like home"
|
|
"installing the good defaults"
|
|
"putting the system in order"
|
|
"setting up a civilized desktop"
|
|
"clearing the path to Hyprland"
|
|
"preparing the command line sanctuary"
|
|
"teaching pacman the house rules"
|
|
"laying down the Tokyo Night carpet"
|
|
"arranging the sharp tools safely"
|
|
"keeping the boot path clean"
|
|
"giving Limine the keys"
|
|
"making snapshots worth having"
|
|
"saving future you a few hours"
|
|
"choosing boring where boring wins"
|
|
"leaving room for your dotfiles"
|
|
"tightening the last few screws"
|
|
)
|
|
|
|
cleanup() {
|
|
printf '%s%s' "$RESET" "$SHOW_CURSOR"
|
|
}
|
|
trap cleanup EXIT INT TERM
|
|
|
|
term_cols() {
|
|
# Match install/helpers/presentation.sh: read the real tty dimensions even
|
|
# if stdout is redirected through a pipe/process substitution.
|
|
if [[ -e /dev/tty ]]; then
|
|
local size
|
|
size=$(stty size 2>/dev/null </dev/tty || true)
|
|
if [[ -n $size ]]; then
|
|
printf '%s\n' "${size#* }"
|
|
return
|
|
fi
|
|
fi
|
|
tput cols 2>/dev/null || echo 100
|
|
}
|
|
|
|
term_rows() {
|
|
if [[ -e /dev/tty ]]; then
|
|
local size
|
|
size=$(stty size 2>/dev/null </dev/tty || true)
|
|
if [[ -n $size ]]; then
|
|
printf '%s\n' "${size%% *}"
|
|
return
|
|
fi
|
|
fi
|
|
tput lines 2>/dev/null || echo 32
|
|
}
|
|
|
|
repeat() {
|
|
local char="$1" count="$2"
|
|
local out=""
|
|
for ((i=0; i<count; i++)); do out+="$char"; done
|
|
printf '%s' "$out"
|
|
}
|
|
|
|
left_padding() {
|
|
local width="${1:-$CONTENT_WIDTH}"
|
|
local cols
|
|
cols=$(term_cols)
|
|
local pad=$(( (cols - width) / 2 ))
|
|
(( pad < 0 )) && pad=0
|
|
printf '%*s' "$pad" ''
|
|
}
|
|
|
|
logo_padding() {
|
|
# Exact equivalent of the installer's:
|
|
# PADDING_LEFT=$(((TERM_WIDTH - LOGO_WIDTH) / 2))
|
|
left_padding "$LOGO_WIDTH"
|
|
}
|
|
|
|
visible_len() {
|
|
# ANSI color/control codes should not affect centering.
|
|
local text="$1"
|
|
text="$(printf '%b' "$text" | sed -E $'s/\x1b\\[[0-9;?]*[A-Za-z]//g')"
|
|
printf '%s' "${#text}"
|
|
}
|
|
|
|
center() {
|
|
# Match the real installer's gum-style layout: fixed content width shifted by
|
|
# a computed left gutter, rather than trying to center against the full tty.
|
|
local text="$1" width="${2:-$CONTENT_WIDTH}"
|
|
local len
|
|
len="$(visible_len "$text")"
|
|
local inner_pad=$(( (width - len) / 2 ))
|
|
(( inner_pad < 0 )) && inner_pad=0
|
|
printf '\r%s%s%*s%b%s\n' "$CLEAR_LINE" "$(left_padding "$width")" "$inner_pad" '' "$text" "$RESET"
|
|
}
|
|
|
|
line_at() {
|
|
local width="${1:-$CONTENT_WIDTH}" indent="${2:-0}"
|
|
shift 2
|
|
printf '\r%s%s%*s' "$CLEAR_LINE" "$(left_padding "$width")" "$indent" ''
|
|
printf '%b' "$*"
|
|
}
|
|
|
|
blank_line() {
|
|
printf '\r%s\n' "$CLEAR_LINE"
|
|
}
|
|
|
|
progress_bar() {
|
|
local pct="$1" width="${2:-36}"
|
|
local filled=$(( pct * width / 100 ))
|
|
local empty=$(( width - filled ))
|
|
printf '%s%s%s%s%s %3d%%' "$GREEN" "$(repeat █ "$filled")" "$DARK" "$(repeat ░ "$empty")" "$RESET" "$pct"
|
|
}
|
|
|
|
logo() {
|
|
if [[ -n ${LOGO_PATH:-} && -f $LOGO_PATH ]]; then
|
|
cat "$LOGO_PATH"
|
|
else
|
|
printf 'Omarchy\n'
|
|
fi
|
|
}
|
|
|
|
render_logo() {
|
|
# Draw the logo like clear_logo does: one left gutter derived from the max
|
|
# logo width, then the logo text exactly as stored in logo.txt.
|
|
local pad
|
|
pad="$(logo_padding)"
|
|
while IFS= read -r line; do
|
|
printf '\r%s%s%b%s%b\n' "$CLEAR_LINE" "$pad" "$GREEN" "$line" "$RESET"
|
|
done < <(logo)
|
|
}
|
|
|
|
current_log() {
|
|
local i="$1"
|
|
printf '%s' "${logs[$(( i % ${#logs[@]} ))]}"
|
|
}
|
|
|
|
current_whimsy() {
|
|
local frame="$1" phase_idx="${2:-0}"
|
|
# Change slower than the spinner so it feels intentional, not jittery.
|
|
printf '%s' "${whimsy[$(( (phase_idx * 3 + frame / 16) % ${#whimsy[@]} ))]}"
|
|
}
|
|
|
|
render_dashboard() {
|
|
local frame="$1" phase_idx=$(( frame / 12 ))
|
|
(( phase_idx >= ${#phases[@]} )) && phase_idx=$((${#phases[@]} - 1))
|
|
local pct=$(( frame * 100 / 95 ))
|
|
(( pct > 100 )) && pct=100
|
|
|
|
printf '%s' "$HOME"
|
|
blank_line
|
|
render_logo
|
|
blank_line
|
|
center "Phase $((phase_idx + 1))/${#phases[@]} ${phases[$phase_idx]}" "$CONTENT_WIDTH"
|
|
blank_line
|
|
line_at "$CONTENT_WIDTH" $(( (CONTENT_WIDTH - 40) / 2 )) ""
|
|
progress_bar "$pct" 34
|
|
printf '\n'
|
|
blank_line
|
|
center "Now: $(current_log "$frame")" "$CONTENT_WIDTH"
|
|
blank_line
|
|
local spin=("◐" "◓" "◑" "◒")
|
|
center "${GREEN}${spin[$((frame % 4))]} $(current_whimsy "$frame" "$phase_idx") ${RESET}" "$CONTENT_WIDTH"
|
|
blank_line
|
|
center "${DIM}Press Ctrl-C to quit${RESET}" "$CONTENT_WIDTH"
|
|
}
|
|
|
|
render_matrix() {
|
|
local frame="$1" rows cols
|
|
rows=$(term_rows); cols=$(term_cols)
|
|
(( rows > 34 )) && rows=34
|
|
(( cols > 110 )) && cols=110
|
|
local words=(pacstrap limine btrfs snapper uki kernel hyprland omarchy archlinux)
|
|
|
|
printf '%s' "$HOME"
|
|
printf '%s%s' "$DIM" "$PURPLE"
|
|
center "TOKYO NIGHT PACKAGE RAIN" "$cols"
|
|
printf '%s' "$RESET"
|
|
echo
|
|
|
|
for ((r=2; r<rows-7; r++)); do
|
|
line=""
|
|
for ((c=0; c<cols; c+=10)); do
|
|
if (( (r + c + frame) % 7 == 0 )); then
|
|
word="${words[$(((r + c + frame) % ${#words[@]}))]}"
|
|
line+="${GREEN}${word:0:9}${RESET}"
|
|
elif (( (r * c + frame) % 19 == 0 )); then
|
|
line+="${BLUE}│${RESET} "
|
|
else
|
|
line+=" "
|
|
fi
|
|
done
|
|
printf '%b\n' "${line:0:cols}"
|
|
done
|
|
|
|
local phase_idx=$(( frame / 10 ))
|
|
(( phase_idx >= ${#phases[@]} )) && phase_idx=$((${#phases[@]} - 1))
|
|
echo
|
|
center "${BOLD}${GREEN}${phases[$phase_idx]}${RESET}" "$cols"
|
|
center "${GRAY}$(current_log "$frame")${RESET}" "$cols"
|
|
}
|
|
|
|
render_forge() {
|
|
local frame="$1" phase_idx=$(( frame / 12 ))
|
|
(( phase_idx >= ${#phases[@]} )) && phase_idx=$((${#phases[@]} - 1))
|
|
local sparks=("·" "∙" "*" "✦" "✧" "⋆")
|
|
local hammer=("⚒" " " "⚒" " ")
|
|
local pct=$(( frame * 100 / 95 ))
|
|
(( pct > 100 )) && pct=100
|
|
|
|
printf '%s' "$HOME"
|
|
printf '%s' "$YELLOW"
|
|
center "THE OMARCHY FORGE" 80
|
|
printf '%s\n\n' "$RESET"
|
|
|
|
center " ${sparks[$((frame % 6))]} ${sparks[$(((frame+2) % 6))]} ${sparks[$(((frame+4) % 6))]}" 80
|
|
center " ${YELLOW}${hammer[$((frame % 4))]}${RESET}" 80
|
|
center " _____________" 80
|
|
center " / \\" 80
|
|
center " ____/ ARCH ROOTFS \____" 80
|
|
center " / \_______________/ \\" 80
|
|
center " / BTRFS │ LIMINE │ UKI \\" 80
|
|
center " \_________│__________│______/" 80
|
|
echo
|
|
center "${GREEN}${phases[$phase_idx]}${RESET}" 80
|
|
echo
|
|
line_at 80 22 ""
|
|
progress_bar "$pct" 36
|
|
echo -e "\n"
|
|
center "${GRAY}$(current_log "$frame")${RESET}" 80
|
|
}
|
|
|
|
render_logs() {
|
|
local frame="$1" phase_idx=$(( frame / 12 ))
|
|
(( phase_idx >= ${#phases[@]} )) && phase_idx=$((${#phases[@]} - 1))
|
|
local pct=$(( frame * 100 / 95 ))
|
|
(( pct > 100 )) && pct=100
|
|
|
|
printf '%s' "$HOME"
|
|
render_logo
|
|
blank_line
|
|
line_at "$CONTENT_WIDTH" 0 "${BOLD}Omarchy Install${RESET}\n"
|
|
line_at "$CONTENT_WIDTH" 0 ""
|
|
progress_bar "$pct" 50
|
|
printf '\n'
|
|
blank_line
|
|
line_at "$CONTENT_WIDTH" 0 "${GREEN}${phases[$phase_idx]}${RESET}\n"
|
|
blank_line
|
|
|
|
local start=$(( frame - 12 ))
|
|
(( start < 0 )) && start=0
|
|
for ((i=start; i<=frame; i++)); do
|
|
line_at "$CONTENT_WIDTH" 2 "${GRAY}→${RESET} [$(printf '%02d:%02d' "$((i / 3))" "$(((i * 7) % 60))")] $(current_log "$i")\n"
|
|
done
|
|
blank_line
|
|
line_at "$CONTENT_WIDTH" 0 "${DIM}This is the boring/debuggable mode: curated progress plus log tail.${RESET}\n"
|
|
}
|
|
|
|
case "$concept" in
|
|
dashboard|matrix|forge|logs) ;;
|
|
-h|--help|help)
|
|
echo "Usage: $0 [dashboard|matrix|forge|logs]"
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "Unknown concept: $concept" >&2
|
|
echo "Usage: $0 [dashboard|matrix|forge|logs]" >&2
|
|
exit 2
|
|
;;
|
|
esac
|
|
|
|
printf '%s%s' "$HIDE_CURSOR" "$CLEAR"
|
|
for ((frame=0; frame<=96; frame++)); do
|
|
"render_$concept" "$frame"
|
|
printf '%s' "$CLEAR_TO_END"
|
|
sleep 0.08
|
|
done
|