From b47399335ae62590fd2dd1897f21b89de7d98eaa Mon Sep 17 00:00:00 2001 From: noah Date: Mon, 9 Mar 2026 23:01:59 +0100 Subject: [PATCH] fix: install.sh falls back to ~/.local/bin with PATH hint, redesign terminal section as interactive TUI simulation --- install.sh | 80 +++++++++++++++--- src/app/page.tsx | 208 ++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 247 insertions(+), 41 deletions(-) diff --git a/install.sh b/install.sh index 6230dd4..aa8ad34 100755 --- a/install.sh +++ b/install.sh @@ -5,7 +5,6 @@ set -e REPO="noauf/Transmute" BINARY="transmute" -INSTALL_DIR="/usr/local/bin" # Detect OS OS="$(uname -s)" @@ -39,19 +38,20 @@ fi ASSET="${BINARY}-${OS}-${ARCH}.${EXT}" -echo "Transmute CLI installer" -echo "======================" +echo "" +echo " Transmute CLI installer" +echo " ======================" echo "" echo " OS: $OS" echo " Arch: $ARCH" echo "" # Get latest release tag -echo "Fetching latest release..." +echo " Fetching latest release..." TAG=$(curl -fsSL "https://api.github.com/repos/${REPO}/releases/latest" | grep '"tag_name"' | head -1 | sed 's/.*"tag_name": *"\([^"]*\)".*/\1/') if [ -z "$TAG" ]; then - echo "Error: could not determine latest release" + echo " Error: could not determine latest release" exit 1 fi @@ -84,26 +84,82 @@ elif [ -f "${TMP_DIR}/${BINARY}-${OS}-${ARCH}/${BINARY}" ]; then fi if [ -z "$BIN_PATH" ]; then - echo "Error: could not find ${BINARY} binary in archive" + echo " Error: could not find ${BINARY} binary in archive" exit 1 fi chmod +x "$BIN_PATH" -# Install -echo " Installing to ${INSTALL_DIR}/${BINARY}..." -if [ -w "$INSTALL_DIR" ]; then +# Determine install directory — try in order of preference +INSTALL_DIR="" +NEEDS_PATH_HINT="" + +if [ -w "/usr/local/bin" ]; then + INSTALL_DIR="/usr/local/bin" +elif command -v sudo >/dev/null 2>&1; then + # Try sudo to /usr/local/bin + echo " Installing to /usr/local/bin (requires sudo)..." + if sudo mv "$BIN_PATH" "/usr/local/bin/${BINARY}" 2>/dev/null; then + sudo chmod +x "/usr/local/bin/${BINARY}" + INSTALL_DIR="/usr/local/bin" + fi +fi + +# Fallback: ~/.local/bin (no sudo needed) +if [ -z "$INSTALL_DIR" ]; then + INSTALL_DIR="${HOME}/.local/bin" + mkdir -p "$INSTALL_DIR" mv "$BIN_PATH" "${INSTALL_DIR}/${BINARY}" + chmod +x "${INSTALL_DIR}/${BINARY}" + + # Check if ~/.local/bin is in PATH + case ":${PATH}:" in + *":${INSTALL_DIR}:"*) ;; + *) + NEEDS_PATH_HINT="true" + ;; + esac else - echo " (requires sudo)" - sudo mv "$BIN_PATH" "${INSTALL_DIR}/${BINARY}" + if [ -f "$BIN_PATH" ]; then + mv "$BIN_PATH" "${INSTALL_DIR}/${BINARY}" + chmod +x "${INSTALL_DIR}/${BINARY}" + fi fi echo "" echo " Installed transmute $TAG to ${INSTALL_DIR}/${BINARY}" echo "" + +# If we installed to a dir not in PATH, tell the user how to fix it +if [ "$NEEDS_PATH_HINT" = "true" ]; then + SHELL_NAME="$(basename "$SHELL")" + case "$SHELL_NAME" in + zsh) RC_FILE="~/.zshrc" ;; + bash) RC_FILE="~/.bashrc" ;; + fish) RC_FILE="~/.config/fish/config.fish" ;; + *) RC_FILE="your shell config" ;; + esac + + echo " To make it globally available, add ~/.local/bin to your PATH:" + echo "" + if [ "$SHELL_NAME" = "fish" ]; then + echo " fish_add_path ${INSTALL_DIR}" + else + echo " echo 'export PATH=\"\$HOME/.local/bin:\$PATH\"' >> ${RC_FILE}" + fi + echo "" + echo " Then restart your terminal, or run:" + echo "" + if [ "$SHELL_NAME" = "fish" ]; then + echo " fish_add_path ${INSTALL_DIR}" + else + echo " export PATH=\"\$HOME/.local/bin:\$PATH\"" + fi + echo "" +fi + echo " Get started:" echo " transmute *.png Convert all PNGs" -echo " transmute ./files/ Convert all files in a directory" +echo " transmute ./photos/ Convert all files in a directory" echo " transmute --help Show all options" echo "" diff --git a/src/app/page.tsx b/src/app/page.tsx index 575c83d..84f0dad 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -585,6 +585,138 @@ function FinderWindow() { ); } +/* ─── TUI File Rows (simulated Bubble Tea interface) ─── */ + +const tuiFiles = [ + { icon: '\u{1F5BC}', name: 'vacation-photo.heic', ext: 'HEIC', size: '2.4 MB', target: 'webp', category: '#f472b6', selected: true }, + { icon: '\u{1F4C4}', name: 'quarterly-report.docx', ext: 'DOCX', size: '1.8 MB', target: 'pdf', category: '#60a5fa', selected: true }, + { icon: '\u{1F3B5}', name: 'podcast-episode.flac', ext: 'FLAC', size: '48 MB', target: 'mp3', category: '#a78bfa', selected: true }, + { icon: '\u{1F4CA}', name: 'user-analytics.csv', ext: 'CSV', size: '340 KB', target: 'json', category: '#34d399', selected: true }, + { icon: '\u{1F3AC}', name: 'screen-recording.mov', ext: 'MOV', size: '126 MB', target: 'mp4', category: '#fb923c', selected: true }, + { icon: '\u{1F524}', name: 'brand-font.ttf', ext: 'TTF', size: '420 KB', target: 'woff2', category: '#2dd4bf', selected: false }, +]; + +type TUIStatus = 'idle' | 'converting' | 'done'; + +function TUIFileRows() { + const [cursorIdx, setCursorIdx] = useState(0); + const [statuses, setStatuses] = useState(Array(tuiFiles.length).fill('idle')); + const cycleRef = useRef(0); + + useEffect(() => { + // Animate: cycle cursor down, then run a conversion animation, then reset + const cycle = () => { + const thisCycle = ++cycleRef.current; + + // Phase 1: Cursor moves down the list + tuiFiles.forEach((_, i) => { + setTimeout(() => { + if (cycleRef.current !== thisCycle) return; + setCursorIdx(i); + }, i * 400); + }); + + // Phase 2: Start conversion sequence after cursor finishes + const convStart = tuiFiles.length * 400 + 600; + tuiFiles.forEach((f, i) => { + if (!f.selected) return; + setTimeout(() => { + if (cycleRef.current !== thisCycle) return; + setStatuses(prev => { const n = [...prev]; n[i] = 'converting'; return n; }); + }, convStart + i * 500); + setTimeout(() => { + if (cycleRef.current !== thisCycle) return; + setStatuses(prev => { const n = [...prev]; n[i] = 'done'; return n; }); + }, convStart + i * 500 + 800); + }); + + // Phase 3: Reset after all done + const totalTime = convStart + tuiFiles.length * 500 + 2500; + setTimeout(() => { + if (cycleRef.current !== thisCycle) return; + setStatuses(Array(tuiFiles.length).fill('idle')); + setCursorIdx(0); + cycle(); + }, totalTime); + }; + + cycle(); + return () => { cycleRef.current++; }; + }, []); + + return ( +
+ {tuiFiles.map((f, i) => { + const isCursor = i === cursorIdx; + const status = statuses[i]; + return ( +
+ {/* Cursor + checkbox */} +
+ {isCursor ? ( + {'>'} + ) : ( + {' '} + )} +
+
+ {f.selected ? ( + {'\u25CF'} + ) : ( + {'\u25CB'} + )} +
+ + {/* Icon + ext badge + name */} +
+ {f.icon} + {f.ext} + + {f.name} + +
+ + {/* Size */} +
+ {f.size} +
+ + {/* Format selector */} +
+ {isCursor ? ( + + {'< '} + {f.target} + {' >'} + + ) : ( + {f.target} + )} +
+ + {/* Status */} +
+ {status === 'idle' && ( + idle + )} + {status === 'converting' && ( + converting... + )} + {status === 'done' && ( + done + )} +
+
+ ); + })} +
+ ); +} + /* ─── Main Page ─── */ export default function LandingPage() { @@ -963,12 +1095,12 @@ export default function LandingPage() { Prefer the command line?

- Transmute has a full-featured CLI with an interactive TUI. Batch convert files, use glob patterns, pipe into scripts. + A full interactive TUI. Navigate files, pick formats, and batch convert without leaving your terminal.

- Terminal + transmute ./photos/
- {/* Terminal body */} -
- {/* Install command */} -
- $ -
- curl -fsSL - https://raw.githubusercontent.com/noauf/Transmute/main/install.sh - | - sh + {/* TUI body — simulated Bubble Tea interface with cream bg */} +
+ {/* TUI title bar */} +
+
+ transmute + 6 files {'\u00B7'} 5 selected
+ ? help
- {/* Simulated output */} -
-
Transmute CLI installer
-
OS: darwin Arch: arm64
-
Latest version: v0.1.0
-
Installed transmute v0.1.0
+ + {/* Divider */} +
{'\u2500'.repeat(80)}
+ + {/* Column header */} +
+
Name
+
Size
+
Convert to
+
Status
- {/* Usage examples */} -
- $ - transmute *.png + + {/* File rows */} + + + {/* Divider */} +
{'\u2500'.repeat(80)}
+ + {/* Bottom bar */} +
+ + Convert 5 files [c] + + + up/down navigate left/right format space select a all q quit + + + {'\u2191\u2193'} nav {'\u2190\u2192'} fmt spc sel q quit +
-
Convert all PNGs in current directory
-
- $ - transmute ./photos/ -d ./output/ -
-
Batch convert a whole directory
+
+
+ + {/* Install command below the TUI */} +
+
+ $ + curl -fsSL https://raw.githubusercontent.com/noauf/Transmute/main/install.sh | sh