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-installer"
|
|
"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
|