mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-07 16:09:43 +02:00
fix: harden install.sh — Homebrew bootstrap, dnf/yum fallback, Alpine sudo, PATH cleanup
- Extract ensure_homebrew() called from all macOS install functions (prevents crash if Git checked before Node) - Add dnf/yum fallback in Fedora install functions (fixes Amazon Linux 2 which only has yum) - Add ensure_sudo to Alpine install functions (consistent with all other distros) - Update Fedora/SUSE NodeSource setup to use GPG keyring method (replaces deprecated setup_XX.x script) - Remove dist/ directory from PATH (only use ~/.local/bin symlink) - Collapse identical fish/non-fish branches in setup_sc_alias Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -35,7 +35,7 @@ When user says "COM":
|
|||||||
1. Increment version in BOTH `package.json` AND `CLAUDE.md` (verify they match with `grep version package.json && grep Version CLAUDE.md`)
|
1. Increment version in BOTH `package.json` AND `CLAUDE.md` (verify they match with `grep version package.json && grep Version CLAUDE.md`)
|
||||||
2. Run: `git add -A && git commit -m "chore: bump version to X.XXXX" && git push && npm run build && systemctl --user restart claudeman-web`
|
2. Run: `git add -A && git commit -m "chore: bump version to X.XXXX" && git push && npm run build && systemctl --user restart claudeman-web`
|
||||||
|
|
||||||
**Version**: 0.1571 (must match `package.json` for npm publish)
|
**Version**: 0.1572 (must match `package.json` for npm publish)
|
||||||
|
|
||||||
## Project Overview
|
## Project Overview
|
||||||
|
|
||||||
|
|||||||
@@ -390,6 +390,20 @@ Click the chart icon on any session tab to see a complete timeline of what happe
|
|||||||
curl -fsSL https://raw.githubusercontent.com/Ark0N/claudeman/master/install.sh | bash
|
curl -fsSL https://raw.githubusercontent.com/Ark0N/claudeman/master/install.sh | bash
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Windows (WSL)
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
wsl bash -c "curl -fsSL https://raw.githubusercontent.com/Ark0N/claudeman/master/install.sh | bash"
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Prerequisites:** Claudeman requires tmux, so Windows users need [WSL](https://learn.microsoft.com/en-us/windows/wsl/install). If you don't have WSL yet:
|
||||||
|
> 1. Run `wsl --install` in an admin PowerShell, then reboot
|
||||||
|
> 2. Open **Ubuntu** from the Start menu to complete setup (create your Linux user)
|
||||||
|
> 3. Install Claude CLI inside WSL: `curl -fsSL https://claude.ai/install.sh | bash`
|
||||||
|
> 4. Then run the one-liner above
|
||||||
|
>
|
||||||
|
> After installing, `http://localhost:3000` is accessible from your Windows browser.
|
||||||
|
|
||||||
### npm (alternative)
|
### npm (alternative)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
+71
-40
@@ -298,21 +298,25 @@ run_as_root() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
install_node_macos() {
|
ensure_homebrew() {
|
||||||
info "Installing Node.js via Homebrew..."
|
if command -v brew &>/dev/null; then
|
||||||
|
return 0
|
||||||
if ! command -v brew &>/dev/null; then
|
|
||||||
info "Installing Homebrew first..."
|
|
||||||
/bin/bash -c "$(download_to_stdout https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
|
||||||
|
|
||||||
# Add Homebrew to PATH for Apple Silicon
|
|
||||||
if [[ -f /opt/homebrew/bin/brew ]]; then
|
|
||||||
eval "$(/opt/homebrew/bin/brew shellenv)"
|
|
||||||
elif [[ -f /usr/local/bin/brew ]]; then
|
|
||||||
eval "$(/usr/local/bin/brew shellenv)"
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
info "Installing Homebrew first..."
|
||||||
|
/bin/bash -c "$(download_to_stdout https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||||||
|
|
||||||
|
# Add Homebrew to PATH for Apple Silicon
|
||||||
|
if [[ -f /opt/homebrew/bin/brew ]]; then
|
||||||
|
eval "$(/opt/homebrew/bin/brew shellenv)"
|
||||||
|
elif [[ -f /usr/local/bin/brew ]]; then
|
||||||
|
eval "$(/usr/local/bin/brew shellenv)"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
install_node_macos() {
|
||||||
|
info "Installing Node.js via Homebrew..."
|
||||||
|
ensure_homebrew
|
||||||
brew install node
|
brew install node
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -344,9 +348,25 @@ install_node_fedora() {
|
|||||||
|
|
||||||
ensure_sudo
|
ensure_sudo
|
||||||
|
|
||||||
# Use NodeSource for consistent version across Fedora versions
|
# Import NodeSource GPG key
|
||||||
download_to_stdout "https://rpm.nodesource.com/setup_$TARGET_NODE_VERSION.x" | run_as_root bash -
|
run_as_root rpm --import https://rpm.nodesource.com/gpgkey/nodesource-repo.gpg.key
|
||||||
run_as_root dnf install -y nodejs
|
|
||||||
|
# Create repo file (replaces deprecated setup_XX.x bash script)
|
||||||
|
cat << REPO_EOF | run_as_root tee /etc/yum.repos.d/nodesource.repo > /dev/null
|
||||||
|
[nodesource]
|
||||||
|
name=Node.js Packages for Linux RPM - nodesource
|
||||||
|
baseurl=https://rpm.nodesource.com/pub_${TARGET_NODE_VERSION}.x/nodistro/rpm/\$basearch
|
||||||
|
gpgcheck=1
|
||||||
|
gpgkey=https://rpm.nodesource.com/gpgkey/nodesource-repo.gpg.key
|
||||||
|
enabled=1
|
||||||
|
REPO_EOF
|
||||||
|
|
||||||
|
# Use dnf if available (RHEL 8+, Fedora, AL2023), fall back to yum (RHEL 7, AL2)
|
||||||
|
if command -v dnf &>/dev/null; then
|
||||||
|
run_as_root dnf install -y nodejs
|
||||||
|
else
|
||||||
|
run_as_root yum install -y nodejs
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
install_node_arch() {
|
install_node_arch() {
|
||||||
@@ -367,6 +387,7 @@ install_node_arch() {
|
|||||||
install_node_alpine() {
|
install_node_alpine() {
|
||||||
info "Installing Node.js via apk..."
|
info "Installing Node.js via apk..."
|
||||||
|
|
||||||
|
ensure_sudo
|
||||||
run_as_root apk add --no-cache nodejs npm
|
run_as_root apk add --no-cache nodejs npm
|
||||||
|
|
||||||
# Verify version
|
# Verify version
|
||||||
@@ -383,13 +404,25 @@ install_node_suse() {
|
|||||||
|
|
||||||
ensure_sudo
|
ensure_sudo
|
||||||
|
|
||||||
# Use NodeSource for openSUSE
|
# Import NodeSource GPG key
|
||||||
download_to_stdout "https://rpm.nodesource.com/setup_$TARGET_NODE_VERSION.x" | run_as_root bash -
|
run_as_root rpm --import https://rpm.nodesource.com/gpgkey/nodesource-repo.gpg.key
|
||||||
|
|
||||||
|
# Create repo file (replaces deprecated setup_XX.x bash script)
|
||||||
|
cat << REPO_EOF | run_as_root tee /etc/zypp/repos.d/nodesource.repo > /dev/null
|
||||||
|
[nodesource]
|
||||||
|
name=Node.js Packages for Linux RPM - nodesource
|
||||||
|
baseurl=https://rpm.nodesource.com/pub_${TARGET_NODE_VERSION}.x/nodistro/rpm/\$basearch
|
||||||
|
gpgcheck=1
|
||||||
|
gpgkey=https://rpm.nodesource.com/gpgkey/nodesource-repo.gpg.key
|
||||||
|
enabled=1
|
||||||
|
REPO_EOF
|
||||||
|
|
||||||
run_as_root zypper install -y nodejs
|
run_as_root zypper install -y nodejs
|
||||||
}
|
}
|
||||||
|
|
||||||
install_tmux_macos() {
|
install_tmux_macos() {
|
||||||
info "Installing tmux via Homebrew..."
|
info "Installing tmux via Homebrew..."
|
||||||
|
ensure_homebrew
|
||||||
brew install tmux
|
brew install tmux
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -401,9 +434,13 @@ install_tmux_debian() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
install_tmux_fedora() {
|
install_tmux_fedora() {
|
||||||
info "Installing tmux via dnf..."
|
info "Installing tmux..."
|
||||||
ensure_sudo
|
ensure_sudo
|
||||||
run_as_root dnf install -y tmux
|
if command -v dnf &>/dev/null; then
|
||||||
|
run_as_root dnf install -y tmux
|
||||||
|
else
|
||||||
|
run_as_root yum install -y tmux
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
install_tmux_arch() {
|
install_tmux_arch() {
|
||||||
@@ -414,6 +451,7 @@ install_tmux_arch() {
|
|||||||
|
|
||||||
install_tmux_alpine() {
|
install_tmux_alpine() {
|
||||||
info "Installing tmux via apk..."
|
info "Installing tmux via apk..."
|
||||||
|
ensure_sudo
|
||||||
run_as_root apk add --no-cache tmux
|
run_as_root apk add --no-cache tmux
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -425,6 +463,7 @@ install_tmux_suse() {
|
|||||||
|
|
||||||
install_git_macos() {
|
install_git_macos() {
|
||||||
info "Installing Git via Homebrew..."
|
info "Installing Git via Homebrew..."
|
||||||
|
ensure_homebrew
|
||||||
brew install git
|
brew install git
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -436,9 +475,13 @@ install_git_debian() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
install_git_fedora() {
|
install_git_fedora() {
|
||||||
info "Installing Git via dnf..."
|
info "Installing Git..."
|
||||||
ensure_sudo
|
ensure_sudo
|
||||||
run_as_root dnf install -y git
|
if command -v dnf &>/dev/null; then
|
||||||
|
run_as_root dnf install -y git
|
||||||
|
else
|
||||||
|
run_as_root yum install -y git
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
install_git_arch() {
|
install_git_arch() {
|
||||||
@@ -449,6 +492,7 @@ install_git_arch() {
|
|||||||
|
|
||||||
install_git_alpine() {
|
install_git_alpine() {
|
||||||
info "Installing Git via apk..."
|
info "Installing Git via apk..."
|
||||||
|
ensure_sudo
|
||||||
run_as_root apk add --no-cache git
|
run_as_root apk add --no-cache git
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -588,18 +632,9 @@ setup_sc_alias() {
|
|||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local shell_name
|
echo "" >> "$profile"
|
||||||
shell_name="$(basename "${SHELL:-/bin/bash}")"
|
echo "# Claudeman tmux session shortcut" >> "$profile"
|
||||||
|
echo "alias sc='tmux-chooser'" >> "$profile"
|
||||||
if [[ "$shell_name" == "fish" ]]; then
|
|
||||||
echo "" >> "$profile"
|
|
||||||
echo "# Claudeman tmux session shortcut" >> "$profile"
|
|
||||||
echo "alias sc='tmux-chooser'" >> "$profile"
|
|
||||||
else
|
|
||||||
echo "" >> "$profile"
|
|
||||||
echo "# Claudeman tmux session shortcut" >> "$profile"
|
|
||||||
echo "alias sc='tmux-chooser'" >> "$profile"
|
|
||||||
fi
|
|
||||||
|
|
||||||
info "Added 'sc' alias for tmux-chooser"
|
info "Added 'sc' alias for tmux-chooser"
|
||||||
}
|
}
|
||||||
@@ -838,10 +873,7 @@ main() {
|
|||||||
# Add to PATH
|
# Add to PATH
|
||||||
# ========================================================================
|
# ========================================================================
|
||||||
|
|
||||||
local bin_dir="$INSTALL_DIR/dist"
|
# Create symlink in a common PATH location
|
||||||
add_to_path "$bin_dir"
|
|
||||||
|
|
||||||
# Create symlink in a common PATH location if possible
|
|
||||||
local symlink_dir="$HOME/.local/bin"
|
local symlink_dir="$HOME/.local/bin"
|
||||||
mkdir -p "$symlink_dir" 2>/dev/null || true
|
mkdir -p "$symlink_dir" 2>/dev/null || true
|
||||||
if [[ -d "$symlink_dir" ]]; then
|
if [[ -d "$symlink_dir" ]]; then
|
||||||
@@ -862,7 +894,6 @@ main() {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
# ========================================================================
|
# ========================================================================
|
||||||
# Systemd Service (Linux only)
|
# Systemd Service (Linux only)
|
||||||
# ========================================================================
|
# ========================================================================
|
||||||
@@ -923,7 +954,7 @@ main() {
|
|||||||
# Remind to reload shell if PATH was modified
|
# Remind to reload shell if PATH was modified
|
||||||
local profile
|
local profile
|
||||||
profile=$(detect_shell_profile)
|
profile=$(detect_shell_profile)
|
||||||
if [[ ":$PATH:" != *":$bin_dir:"* ]]; then
|
if [[ ":$PATH:" != *":$symlink_dir:"* ]]; then
|
||||||
echo -e " ${DIM}Restart your shell or run: source $profile${NC}"
|
echo -e " ${DIM}Restart your shell or run: source $profile${NC}"
|
||||||
echo ""
|
echo ""
|
||||||
fi
|
fi
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "claudeman",
|
"name": "claudeman",
|
||||||
"version": "0.1571",
|
"version": "0.1572",
|
||||||
"description": "The missing control plane for Claude Code - run 20 autonomous agents with real-time monitoring and session persistence",
|
"description": "The missing control plane for Claude Code - run 20 autonomous agents with real-time monitoring and session persistence",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
|
|||||||
+183
-34
@@ -880,6 +880,8 @@ html.mobile-init .file-browser-panel {
|
|||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Modal safe area padding - all sides for full-screen modals */
|
/* Modal safe area padding - all sides for full-screen modals */
|
||||||
@@ -901,7 +903,9 @@ html.mobile-init .file-browser-panel {
|
|||||||
.modal-body {
|
.modal-body {
|
||||||
padding: 0.75rem 1rem;
|
padding: 0.75rem 1rem;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-footer,
|
.modal-footer,
|
||||||
@@ -1090,31 +1094,32 @@ html.mobile-init .file-browser-panel {
|
|||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Enable/Stop buttons — full-width touch targets */
|
/* Enable/Stop buttons — compact inline */
|
||||||
.respawn-header .respawn-actions {
|
.respawn-header .respawn-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 0.5rem;
|
gap: 0.4rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.respawn-header .respawn-actions .btn-toolbar {
|
.respawn-header .respawn-actions .btn-toolbar {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-height: 44px !important;
|
min-height: 32px !important;
|
||||||
font-size: 0.85rem !important;
|
font-size: 0.75rem !important;
|
||||||
border-radius: 8px;
|
padding: 0.3rem 0.6rem !important;
|
||||||
|
border-radius: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Duration preset buttons — 44px touch targets in a grid */
|
/* Duration preset buttons — compact grid */
|
||||||
.duration-presets {
|
.duration-presets {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(4, 1fr);
|
grid-template-columns: repeat(4, 1fr);
|
||||||
gap: 0.4rem;
|
gap: 0.3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.duration-preset-btn {
|
.duration-preset-btn {
|
||||||
min-height: 40px;
|
min-height: 30px;
|
||||||
padding: 0.5rem 0.4rem;
|
padding: 0.3rem 0.3rem;
|
||||||
font-size: 0.8rem;
|
font-size: 0.7rem;
|
||||||
border-radius: 8px;
|
border-radius: 6px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1122,12 +1127,12 @@ html.mobile-init .file-browser-panel {
|
|||||||
.duration-custom {
|
.duration-custom {
|
||||||
grid-column: 1 / -1;
|
grid-column: 1 / -1;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
gap: 0.4rem;
|
gap: 0.3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.duration-custom .duration-preset-btn {
|
.duration-custom .duration-preset-btn {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
min-width: 80px;
|
min-width: 60px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.duration-custom-input.visible {
|
.duration-custom-input.visible {
|
||||||
@@ -1136,50 +1141,51 @@ html.mobile-init .file-browser-panel {
|
|||||||
|
|
||||||
.duration-custom-input input {
|
.duration-custom-input input {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-height: 40px;
|
min-height: 30px;
|
||||||
font-size: 16px; /* Prevents iOS zoom */
|
font-size: 16px; /* Prevents iOS zoom */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Preset selector row — stack vertically */
|
/* Preset selector row — compact inline */
|
||||||
.preset-selector {
|
.preset-selector {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
gap: 0.4rem;
|
gap: 0.3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.preset-selector select {
|
.preset-selector select {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-height: 40px;
|
min-height: 32px;
|
||||||
font-size: 16px; /* Prevents iOS zoom */
|
font-size: 16px; /* Prevents iOS zoom */
|
||||||
border-radius: 8px;
|
border-radius: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.preset-selector .btn {
|
.preset-selector .btn {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-height: 40px;
|
min-height: 30px;
|
||||||
font-size: 0.8rem;
|
font-size: 0.7rem;
|
||||||
border-radius: 8px;
|
border-radius: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Textareas — prevent iOS zoom with 16px font */
|
/* Textareas — prevent iOS zoom with 16px font, compact height */
|
||||||
#sessionOptionsModal textarea {
|
#sessionOptionsModal textarea {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
min-height: 56px;
|
min-height: 36px !important;
|
||||||
border-radius: 8px;
|
max-height: 64px;
|
||||||
padding: 0.5rem 0.75rem;
|
border-radius: 6px;
|
||||||
|
padding: 0.35rem 0.6rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Checkboxes — larger touch area */
|
/* Checkboxes — compact touch area */
|
||||||
#sessionOptionsModal .checkbox-inline {
|
#sessionOptionsModal .checkbox-inline {
|
||||||
min-height: 40px;
|
min-height: 30px;
|
||||||
font-size: 0.85rem;
|
font-size: 0.75rem;
|
||||||
padding: 0.25rem 0;
|
padding: 0.15rem 0;
|
||||||
gap: 0.5rem;
|
gap: 0.4rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
#sessionOptionsModal .checkbox-inline input[type="checkbox"] {
|
#sessionOptionsModal .checkbox-inline input[type="checkbox"] {
|
||||||
width: 20px;
|
width: 18px;
|
||||||
height: 20px;
|
height: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Respawn options row — stack if needed */
|
/* Respawn options row — stack if needed */
|
||||||
@@ -1187,10 +1193,153 @@ html.mobile-init .file-browser-panel {
|
|||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Form section headers — more breathing room */
|
/* Form section headers — compact on mobile */
|
||||||
#sessionOptionsModal .form-section-header {
|
#sessionOptionsModal .form-section-header {
|
||||||
|
margin-top: 0.75rem;
|
||||||
|
padding-top: 0.5rem;
|
||||||
|
font-size: 0.65rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Form rows — tighter spacing */
|
||||||
|
#sessionOptionsModal .form-row {
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sessionOptionsModal .form-row label {
|
||||||
|
font-size: 0.65rem;
|
||||||
|
margin-bottom: 0.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Form hints — compact */
|
||||||
|
#sessionOptionsModal .form-hint {
|
||||||
|
font-size: 0.6rem;
|
||||||
|
margin-top: 0.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---- Context Tab: Mobile Optimizations ---- */
|
||||||
|
|
||||||
|
/* Context settings cards — tighter padding */
|
||||||
|
.context-setting {
|
||||||
|
padding: 0.625rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stack context setting header vertically on narrow screens */
|
||||||
|
.context-setting-header {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.context-setting-header .input-suffix-sm input {
|
||||||
|
width: 60px;
|
||||||
|
font-size: 16px; /* Prevents iOS zoom */
|
||||||
|
min-height: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.context-setting input[type="text"] {
|
||||||
|
font-size: 16px; /* Prevents iOS zoom */
|
||||||
|
min-height: 36px;
|
||||||
|
padding: 0.4rem 0.6rem;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Color picker — larger swatches for touch */
|
||||||
|
.color-picker {
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.color-swatch {
|
||||||
|
width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Toggle switches — larger touch area */
|
||||||
|
.form-row-switch {
|
||||||
|
min-height: 40px;
|
||||||
|
gap: 0.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Number inputs in context tab — prevent iOS zoom */
|
||||||
|
.context-settings-grid input[type="number"] {
|
||||||
|
font-size: 16px;
|
||||||
|
min-height: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---- Ralph Tab: Mobile Optimizations ---- */
|
||||||
|
|
||||||
|
/* Ralph limits grid — 2 columns on mobile */
|
||||||
|
.ralph-limits-grid {
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ralph-limits-grid .form-col input[type="number"] {
|
||||||
|
font-size: 16px; /* Prevents iOS zoom */
|
||||||
|
min-height: 36px;
|
||||||
|
padding: 0.4rem 0.5rem;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ralph phrase input — prevent iOS zoom */
|
||||||
|
#modalRalphPhrase {
|
||||||
|
font-size: 16px;
|
||||||
|
min-height: 40px;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save button — full width, proper touch target */
|
||||||
|
.ralph-config-actions {
|
||||||
margin-top: 1rem;
|
margin-top: 1rem;
|
||||||
padding-top: 0.75rem;
|
}
|
||||||
|
|
||||||
|
.ralph-config-actions .btn-toolbar {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 44px;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---- Summary Tab: Mobile Optimizations ---- */
|
||||||
|
|
||||||
|
/* Filter buttons — larger touch targets */
|
||||||
|
.run-summary-filters {
|
||||||
|
gap: 0.3rem;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-btn {
|
||||||
|
padding: 0.35rem 0.75rem;
|
||||||
|
font-size: 0.7rem;
|
||||||
|
min-height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Timeline events — tighter on mobile */
|
||||||
|
.timeline-event {
|
||||||
|
padding: 0.4rem 0.5rem;
|
||||||
|
margin-bottom: 0.25rem;
|
||||||
|
font-size: 0.7rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Summary footer — stack vertically */
|
||||||
|
.run-summary-footer {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.4rem;
|
||||||
|
padding: 0.5rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.run-summary-actions {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.run-summary-actions .btn-toolbar {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 36px;
|
||||||
|
font-size: 0.7rem;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auto-refresh-label {
|
||||||
font-size: 0.7rem;
|
font-size: 0.7rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user