From e431c57fb21f73b8ff753016921ab9b359afe2d6 Mon Sep 17 00:00:00 2001 From: UmedjonBA Date: Sat, 29 Aug 2026 22:51:04 +0300 Subject: [PATCH 1/3] webapp-maker 1.0.0: turn websites into desktop apps New plugin: a floating panel that creates web-app launchers - name, URL, optional chromium flags and icon override. Fetches the site's own icon, writes an escaped .desktop entry, and opens the site in a dedicated browser app window (no tabs, no URL bar) via a bundled launch script copied into the plugin data dir, so launchers survive plugin updates. The panel also lists every web app it created, with one-click removal that can never touch a regular application's launcher. Co-Authored-By: Claude Fable 5 --- webapp-maker/README.md | 94 ++++++++ webapp-maker/panel.luau | 297 +++++++++++++++++++++++++ webapp-maker/plugin.toml | 26 +++ webapp-maker/scripts/webapp-install.sh | 173 ++++++++++++++ webapp-maker/scripts/webapp-launch.sh | 35 +++ webapp-maker/scripts/webapp-remove.sh | 24 ++ webapp-maker/thumbnail.webp | Bin 0 -> 59980 bytes webapp-maker/translations/en.json | 30 +++ webapp-maker/translations/ru.json | 30 +++ 9 files changed, 709 insertions(+) create mode 100644 webapp-maker/README.md create mode 100644 webapp-maker/panel.luau create mode 100644 webapp-maker/plugin.toml create mode 100755 webapp-maker/scripts/webapp-install.sh create mode 100755 webapp-maker/scripts/webapp-launch.sh create mode 100755 webapp-maker/scripts/webapp-remove.sh create mode 100644 webapp-maker/thumbnail.webp create mode 100644 webapp-maker/translations/en.json create mode 100644 webapp-maker/translations/ru.json diff --git a/webapp-maker/README.md b/webapp-maker/README.md new file mode 100644 index 00000000..5d92f887 --- /dev/null +++ b/webapp-maker/README.md @@ -0,0 +1,94 @@ +# Webapp Maker + +Turn websites into desktop applications: fill in a name and a URL, and get a +launcher entry with the site's own icon that opens in a dedicated browser app +window — no tabs, no URL bar. The same panel lists every web app it created, +with one-click removal. + +## Plugin + +| Field | Value | +| --- | --- | +| ID | `umedbazarov/webapp-maker` | +| Entries | Panel: `panel` | + +## Requirements + +- A chromium-family browser (Chromium, Chrome, Brave, Vivaldi, Edge, …) for + the app windows — that engine family is the only one with an `--app` mode. + If your default browser is one of them it is used; otherwise the first + installed one is picked. Firefox alone is not enough. +- `bash`, `chmod`, `cp`, `curl`, `file`, `grep`, `head`, `mkdir`, `rm`, + `sed`, `setsid`, `tr` and `xdg-settings`, required — used by the bundled + scripts to fetch the site icon, write the `.desktop` entry, resolve the + default browser and launch the app window. +- `gtk-update-icon-cache`, `update-desktop-database` and `notify-send`, + optional — icon-cache/database refresh and the fallback "no browser found" + notification; each is skipped when absent. + +## Usage + +The plugin has no bar widget. Open the panel from the plugin's row in +Settings, or bind it in your compositor: + +```sh +noctalia msg panel-open umedbazarov/webapp-maker:panel +``` + +Fill in the form: + +- **Name** and **URL** are required (`https://` is added automatically). +- **Chromium launch flags** (optional) are stored in the launcher and passed + to the browser on every start — e.g. `--proxy-server=http://127.0.0.1:1080` + to route one site through a proxy, or `--incognito`. +- **Icon** (optional): empty fetches the site's own icon (apple-touch-icon, + then the well-known path, then a favicon service); or give an image URL, a + local file path, or the name of an installed theme icon. + +**Create** writes `~/.local/share/applications/.desktop` and installs +the icon into the hicolor theme; the app immediately appears in Noctalia's +launcher and any other application menu. The **Installed** section at the +bottom lists every web app this mechanism created (and only those — regular +applications are never touched); the trash button removes the launcher and +its icon. + +The `.desktop` entries execute a launch script the plugin copies into its +own data directory, so launchers keep working across plugin updates. If the +plugin is uninstalled, already-created web apps keep working too; removing +them afterwards is a matter of deleting their `.desktop` files. + +## Settings + +| Setting | Type | Default | Description | +| --- | --- | --- | --- | +| `env_file` | `string` | *(empty)* | A file sourced before the install command — e.g. one exporting `HTTPS_PROXY` so site icons download through a proxy. Empty disables it. | + +## Notes + +- **Commands spawned.** Creating: the bundled `scripts/webapp-install.sh` + (`curl` for the site page and icon — the only network access, `file` to + verify the download is an image, `sed`/`tr`/`grep` for parsing and + freedesktop escaping). Listing: `grep -l` over + `~/.local/share/applications/*.desktop`. Removing: the bundled + `scripts/webapp-remove.sh` (`rm` of the entry and icon). Launching (from + the created `.desktop`, not from the panel): `scripts/webapp-launch.sh` — + `xdg-settings` to resolve the default browser, then `setsid + --app=` plus the stored flags. +- **Files written.** `~/.local/share/applications/.desktop`, the icon + under `~/.local/share/icons/hicolor/256x256/apps/`, and a copy of the + launch script in the plugin's data directory. Values written into + `.desktop` files are escaped per the freedesktop spec (both string and + Exec quoting), and app names may not contain `/`. +- **No privileges.** Everything runs as the user; nothing touches system + configuration. +- Removal only ever deletes launchers whose `Exec` runs the plugin's launch + script, so a name clash with a real application cannot delete it. + +## Credits + +Inspired by Omarchy's `omarchy-webapp-install` tooling (MIT), rebuilt as a +self-contained Noctalia panel plugin. + +## License + +MIT. diff --git a/webapp-maker/panel.luau b/webapp-maker/panel.luau new file mode 100644 index 00000000..b5a4016e --- /dev/null +++ b/webapp-maker/panel.luau @@ -0,0 +1,297 @@ +--!nonstrict +-- Webapp Maker: a floating centered panel - a form that creates web-app +-- launchers, plus the list of installed web apps with one-click removal. +-- No bar widget; open the panel via IPC (bind it in your compositor): +-- noctalia msg panel-open umedbazarov/webapp-maker:panel +-- +-- All real work happens in the bundled shell scripts (scripts/) through +-- noctalia.runAsync - the panel handlers only assemble commands, keeping +-- well inside the plugin CPU budget. webapp-launch.sh is copied into the +-- plugin's data directory on open, and .desktop entries reference that +-- stable copy, so launchers keep working across plugin updates. +-- +-- ui.input is uncontrolled: value seeds once per formRev, edits flow +-- through named global onChange handlers into the `form` table. + +local form = { name = "", url = "", flags = "", icon = "" } +local formRev = 0 +local busy = false +local status = nil -- { ok = boolean, text = string } + +local apps = {} -- installed web-app names (basename of the .desktop) +local deleting = {} -- name -> true while its removal runs + +local render + +local function tr(key, args) + return noctalia.tr(key, args) +end + +local function cfg(key, fallback) + -- getConfig returns nil until the setting is materialized in + -- settings.toml; the manifest default is NOT substituted by the runtime. + local value = noctalia.getConfig(key) + if value == nil then + return fallback + end + return value +end + +local function trim(value) + return (tostring(value or ""):gsub("^%s+", ""):gsub("%s+$", "")) +end + +local function shellQuote(value) + return "'" .. tostring(value):gsub("'", "'\\''") .. "'" +end + +local function normalizeUrl(url) + if url ~= "" and url:match("^%a[%w+.%-]*:") == nil then + return "https://" .. url + end + return url +end + +local function scriptPath(name) + return (noctalia.pluginDir() or ".") .. "/scripts/" .. name +end + +-- The stable copy of the launch script that .desktop entries point at: the +-- data directory survives plugin updates, the materialized code dir may not. +local function launcherPath() + local dir = noctalia.pluginDataDir() + return dir ~= nil and (dir .. "/webapp-launch") or nil +end + +local launcherReady = false + +local function ensureLauncher() + local target = launcherPath() + if target == nil then + return + end + noctalia.runAsync("cp -f " .. shellQuote(scriptPath("webapp-launch.sh")) .. " " .. shellQuote(target) + .. " && chmod +x " .. shellQuote(target), function(result) + launcherReady = (result.exitCode or 1) == 0 + end) +end + +-- Optional environment file sourced before install/launch commands (the +-- env_file setting) - e.g. to export HTTPS_PROXY for icon downloads. +local function envPrefix() + local envFile = trim(tostring(cfg("env_file", ""))) + if envFile == "" then + return "" + end + return ". " .. shellQuote(envFile) .. " 2>/dev/null; " +end + +-- ── Installed list ────────────────────────────────────────────────────────── + +local function refreshApps() + local cmd = "grep -l '^Exec=.*webapp-launch' ~/.local/share/applications/*.desktop 2>/dev/null | tr '\\r' '\\n'" + noctalia.runAsync(cmd, function(result) + apps = {} + for line in (result.stdout or ""):gmatch("[^\n]+") do + local name = line:match("([^/]+)%.desktop%s*$") + if name ~= nil then + table.insert(apps, name) + end + end + table.sort(apps) + deleting = {} + render() + end) +end + +local function removeApp(name) + if deleting[name] == true then + return + end + deleting[name] = true + render() + noctalia.runAsync("bash " .. shellQuote(scriptPath("webapp-remove.sh")) .. " " .. shellQuote(name) .. " 2>&1", function(result) + if (result.exitCode or 1) ~= 0 then + local out = trim(result.stdout) + status = { ok = false, text = out ~= "" and out or tr("err_remove_failed") } + else + status = { ok = true, text = tr("ok_removed", { name = name }) } + end + refreshApps() + end) +end + +-- ── Field handlers (uncontrolled inputs accumulate into `form`) ───────────── + +function onFld_name(v) form.name = tostring(v or "") end +function onFld_url(v) form.url = tostring(v or "") end +function onFld_flags(v) form.flags = tostring(v or "") end +function onFld_icon(v) form.icon = tostring(v or "") end + +-- ── Creating ──────────────────────────────────────────────────────────────── + +local function create() + if busy then + return + end + + local name = trim(form.name) + local url = normalizeUrl(trim(form.url)) + if name == "" or url == "" then + status = { ok = false, text = tr("err_required") } + render() + return + end + if name:find("/", 1, true) ~= nil then + status = { ok = false, text = tr("err_slash") } + render() + return + end + + busy = true + status = nil + render() + + local launcher = launcherPath() + if launcher == nil then + busy = false + status = { ok = false, text = tr("err_failed") } + render() + return + end + if not launcherReady then + -- The copy from onOpen may still be in flight on a very fresh open; + -- fire it again so the .desktop never points at a missing file. + ensureLauncher() + end + + local args = { "--launcher " .. shellQuote(launcher) } + local flags = trim(form.flags) + if flags ~= "" then + table.insert(args, "--flags " .. shellQuote(flags)) + end + table.insert(args, shellQuote(name)) + table.insert(args, shellQuote(url)) + if trim(form.icon) ~= "" then + table.insert(args, shellQuote(trim(form.icon))) + end + + -- The script's output is a single error line at most, so 2>&1 is safe + -- for the status label. env_file (optional) may export HTTPS_PROXY etc. + -- for the icon download. + local cmd = "{ " .. envPrefix() .. "bash " .. shellQuote(scriptPath("webapp-install.sh")) .. " " + .. table.concat(args, " ") .. "; } 2>&1" + + noctalia.runAsync(cmd, function(result) + busy = false + if result.timedOut then + status = { ok = false, text = tr("err_timeout") } + elseif (result.exitCode or 1) ~= 0 then + local out = trim(result.stdout) + if #out > 200 then + out = out:sub(-200) + end + status = { ok = false, text = out ~= "" and out or tr("err_failed") } + else + status = { ok = true, text = tr("ok_created", { name = name }) } + -- A clean form for the next app; bumping formRev resets the + -- inputs' identity, or the uncontrolled fields keep the old text. + form = { name = "", url = "", flags = "", icon = "" } + formRev += 1 + end + refreshApps() + end) +end + +-- ── Render ────────────────────────────────────────────────────────────────── + +local function field(key, labelKey, phKey) + return ui.column({ gap = 2, align = "stretch" }, { + ui.label({ text = tr(labelKey), fontSize = 11, color = "on_surface_variant" }), + ui.input({ + key = "fld-" .. key .. "-" .. formRev, + value = form[key], + placeholder = tr(phKey), + onChange = "onFld_" .. key, + }), + }) +end + +render = function() + local children = { + ui.row({ gap = 8, align = "center" }, { + ui.glyph({ glyph = "world-plus", size = 18, color = "primary" }), + ui.label({ text = tr("title"), fontSize = 16, fontWeight = "bold", color = "on_surface", flexGrow = 1 }), + ui.button({ + glyph = "close", variant = "ghost", tooltip = tr("tip_close"), + onClick = function() + panel.close() + end, + }), + }), + field("name", "field_name", "field_name_ph"), + field("url", "field_url", "field_url_ph"), + field("flags", "field_flags", "field_flags_ph"), + field("icon", "field_icon", "field_icon_ph"), + } + + if busy then + table.insert(children, ui.label({ text = tr("status_busy"), fontSize = 11, color = "secondary" })) + elseif status ~= nil then + table.insert(children, ui.label({ + text = status.text, + fontSize = 11, + color = status.ok and "primary" or "error", + maxLines = 3, + })) + end + + table.insert(children, ui.button({ + key = "create" .. (busy and "-off" or ""), + text = tr("btn_create"), + enabled = not busy, + onClick = function() + create() + end, + })) + + table.insert(children, ui.separator({})) + table.insert(children, ui.label({ text = tr("installed_title"), fontSize = 11, color = "on_surface_variant" })) + + if #apps == 0 then + table.insert(children, ui.label({ text = tr("installed_empty"), fontSize = 12, color = "on_surface_variant" })) + table.insert(children, ui.spacer({ flexGrow = 1 })) + else + local rows = {} + for _, name in ipairs(apps) do + table.insert(rows, ui.row({ key = "app-" .. name, gap = 8, align = "center" }, { + ui.label({ text = name, fontSize = 12, color = "on_surface", flexGrow = 1, maxLines = 1 }), + ui.button({ + key = "del-" .. name .. (deleting[name] and "-off" or ""), + glyph = "trash", + variant = "ghost", + enabled = deleting[name] ~= true, + tooltip = tr("tip_remove"), + onClick = function() + removeApp(name) + end, + }), + })) + end + table.insert(children, ui.scroll({ key = "apps", flexGrow = 1, gap = 4 }, rows)) + end + + panel.render(ui.column({ flexGrow = 1, gap = 10, align = "stretch" }, children)) +end + +function onOpen(_context) + -- A fresh form on every open: the panel is summoned to make a new web + -- app, so previous input is not worth keeping. + form = { name = "", url = "", flags = "", icon = "" } + busy = false + status = nil + formRev += 1 + render() + ensureLauncher() + refreshApps() +end diff --git a/webapp-maker/plugin.toml b/webapp-maker/plugin.toml new file mode 100644 index 00000000..923d5d97 --- /dev/null +++ b/webapp-maker/plugin.toml @@ -0,0 +1,26 @@ +id = "umedbazarov/webapp-maker" +name = "Webapp Maker" +version = "1.0.0" +plugin_api = 9 +author = "umedbazarov" +license = "MIT" +icon = "world-plus" +description = "Turn websites into desktop apps: a launcher entry with the site's icon, opening in its own browser app window." +dependencies = ["bash", "chmod", "cp", "curl", "file", "grep", "head", "mkdir", "rm", "sed", "setsid", "tr", "xdg-settings"] +tags = ["panel", "utility"] + +[[setting]] +key = "env_file" +type = "string" +label_key = "settings.env_file.label" +description_key = "settings.env_file.description" +default = "" +advanced = true + +[[panel]] +id = "panel" +entry = "panel.luau" +width = 440 +height = 560 +placement = "floating" +position = "center" diff --git a/webapp-maker/scripts/webapp-install.sh b/webapp-maker/scripts/webapp-install.sh new file mode 100755 index 00000000..cb30673c --- /dev/null +++ b/webapp-maker/scripts/webapp-install.sh @@ -0,0 +1,173 @@ +#!/bin/bash + +# Create a desktop launcher for a web app: fetch the site's icon, write a +# .desktop entry whose Exec opens the URL as an app window via the launcher +# script this plugin installed into its data directory. +# +# Usage: webapp-install.sh --launcher [--flags ""] [icon-url-or-file] +# +# Non-interactive by design: the Noctalia panel is the UI. Exit non-zero with +# a one-line message on stderr/stdout when something is wrong. + +set -e + +ICON_DIR="$HOME/.local/share/icons/hicolor/256x256/apps" +DESKTOP_DIR="$HOME/.local/share/applications" + +LAUNCHER="" +EXTRA_FLAGS="" +args=() +while (($#)); do + case "$1" in + --launcher) + LAUNCHER=${2:?--launcher needs a value} + shift 2 + ;; + --flags) + EXTRA_FLAGS=${2:?--flags needs a value} + shift 2 + ;; + *) + args+=("$1") + shift + ;; + esac +done +set -- "${args[@]}" + +APP_NAME="${1:-}" +APP_URL="${2:-}" +ICON_REF="${3:-}" + +if [[ -z $LAUNCHER || -z $APP_NAME || -z $APP_URL ]]; then + echo "usage: webapp-install.sh --launcher [--flags \"...\"] [icon]" >&2 + exit 1 +fi + +safe_icon_name() { + printf '%s\n' "$1" \ + | tr '[:upper:]' '[:lower:]' \ + | sed 's/[^[:alnum:]]\+/-/g; s/^-//; s/-$//' +} + +# The name becomes a filename. A slash would turn it into directory levels, +# so the launcher lands somewhere webapp-remove cannot address; a leading +# ../ leaves the applications directory altogether. Most often it is a URL +# typed into the name field. +if [[ $APP_NAME == */* ]]; then + echo "App name cannot contain '/': $APP_NAME" + exit 1 +fi + +# Chromium's --app= treats javascript:, file:, and data: as a document to +# run. Prefix schemeless input with https, then refuse anything not http(s). +if [[ ! $APP_URL =~ ^[a-zA-Z][a-zA-Z0-9+.-]*: ]]; then + APP_URL="https://$APP_URL" +fi +if [[ $APP_URL =~ [[:space:]] ]]; then + echo "Error: web app URL must not contain whitespace." >&2 + exit 1 +fi +if [[ ! ${APP_URL,,} =~ ^https?:// ]]; then + echo "Error: web app URL must be http or https." >&2 + exit 1 +fi + +download_icon() { + curl -fsSL --max-time 10 -o "$2" "$1" 2>/dev/null && + [[ -s $2 && $(file -b --mime-type "$2") == image/* ]] +} + +# Prefer the site's own high-res icon (apple-touch-icon is typically 180px+), +# then the well-known path, then a favicon service as a last resort. +fetch_site_icon() { + local site_url="$1" dest="$2" + local origin page icon_url + origin=$(sed -E 's|^(https?://[^/]+).*|\1|' <<<"$site_url") + + page=$(curl -fsSL --max-time 5 "$site_url" 2>/dev/null | head -c 100000 | tr '\n' ' ') + icon_url=$(grep -oiE "]*rel=[\"'][^\"']*apple-touch-icon[^\"']*[\"'][^>]*>" <<<"$page" | + grep -oiE "href=[\"'][^\"']+" | head -1 | sed -E "s/^href=[\"']//") + + case $icon_url in + http://* | https://*) ;; + //*) icon_url="https:$icon_url" ;; + /*) icon_url="$origin$icon_url" ;; + ?*) icon_url="$origin/$icon_url" ;; + esac + + { [[ -n $icon_url ]] && download_icon "$icon_url" "$dest"; } || + download_icon "$origin/apple-touch-icon.png" "$dest" || + download_icon "https://www.google.com/s2/favicons?domain=${site_url}&sz=256" "$dest" +} + +mkdir -p "$ICON_DIR" +ICON_VALUE=$(safe_icon_name "$APP_NAME") +if [[ -z $ICON_REF ]]; then + if ! fetch_site_icon "$APP_URL" "$ICON_DIR/$ICON_VALUE.png"; then + echo "Error: could not download an icon for $APP_URL." + exit 1 + fi +elif [[ $ICON_REF =~ ^https?:// ]]; then + if ! download_icon "$ICON_REF" "$ICON_DIR/$ICON_VALUE.png"; then + echo "Error: could not download the icon." + exit 1 + fi +elif [[ -f $ICON_REF ]]; then + cp "$ICON_REF" "$ICON_DIR/$ICON_VALUE.png" +else + # The name of an icon already installed in the system theme. + ICON_VALUE=$ICON_REF +fi +command -v gtk-update-icon-cache >/dev/null && gtk-update-icon-cache "$HOME/.local/share/icons/hicolor" >/dev/null 2>&1 || true + +desktop_string_escape() { + # Desktop Entry "string" value (freedesktop spec): a raw newline would + # start a new key line and let a value inject a second Exec=. Escape + # backslash first, then tab/CR/LF and a leading space. + local value="$1" + value=${value//\\/\\\\} + value=${value//$'\t'/\\t} + value=${value//$'\r'/\\r} + value=${value//$'\n'/\\n} + [[ $value == " "* ]] && value="\\s${value# }" + printf '%s' "$value" +} + +desktop_exec_arg() { + # One Exec argument, double-quoted per the freedesktop Exec spec: inside + # quotes " ` $ \ take a backslash and a literal % becomes %%. + local escaped + escaped=$(printf '%s' "$1" \ + | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' -e 's/`/\\`/g' -e 's/\$/\\$/g' -e 's/%/%%/g') + printf '"%s"' "$escaped" +} + +EXEC_COMMAND="$(desktop_exec_arg "$LAUNCHER") $(desktop_exec_arg "$APP_URL")" +# Flags split on whitespace; each becomes its own quoted Exec argument. +for flag in $EXTRA_FLAGS; do + EXEC_COMMAND+=" $(desktop_exec_arg "$flag")" +done + +mkdir -p "$DESKTOP_DIR" +DESKTOP_FILE="$DESKTOP_DIR/$APP_NAME.desktop" + +name_field=$(desktop_string_escape "$APP_NAME") +exec_field=$(desktop_string_escape "$EXEC_COMMAND") +icon_field=$(desktop_string_escape "$ICON_VALUE") + +cat >"$DESKTOP_FILE" </dev/null && update-desktop-database "$DESKTOP_DIR" >/dev/null 2>&1 || true +exit 0 diff --git a/webapp-maker/scripts/webapp-launch.sh b/webapp-maker/scripts/webapp-launch.sh new file mode 100755 index 00000000..5386edc3 --- /dev/null +++ b/webapp-maker/scripts/webapp-launch.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +# Launch a URL as a web-app window (no tabs, no URL bar). +# Only chromium-family browsers have an --app mode; when the default browser +# is not one of them (e.g. Firefox), the first installed chromium-family +# browser is used instead. Extra arguments are passed to the browser as-is. + +url=${1:?usage: webapp-launch [browser flags...]} +shift + +browser=$(xdg-settings get default-web-browser 2>/dev/null) +case $browser in +chromium* | chrome* | google-chrome* | brave* | microsoft-edge* | opera* | vivaldi* | helium*) ;; +*) browser="" ;; +esac + +exec_bin="" +if [[ -n $browser ]]; then + exec_bin=$(sed -n 's/^Exec=\([^ ]*\).*/\1/p' \ + "$HOME/.local/share/applications/$browser" "/usr/share/applications/$browser" 2>/dev/null | head -1) +fi +if [[ -z $exec_bin ]]; then + for candidate in chromium google-chrome-stable google-chrome brave vivaldi microsoft-edge-stable; do + if command -v "$candidate" >/dev/null; then + exec_bin=$candidate + break + fi + done +fi +if [[ -z $exec_bin ]]; then + command -v notify-send >/dev/null && notify-send "Web app" "No chromium-family browser found for app windows" + exit 1 +fi + +exec setsid "$exec_bin" --app="$url" "$@" diff --git a/webapp-maker/scripts/webapp-remove.sh b/webapp-maker/scripts/webapp-remove.sh new file mode 100755 index 00000000..4cf39b0c --- /dev/null +++ b/webapp-maker/scripts/webapp-remove.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +# Remove a web-app launcher created by webapp-install.sh: its .desktop entry +# and the icon it installed. Only launchers whose Exec runs webapp-launch are +# touched, so a name clash with a regular application cannot delete it. + +set -e + +name=${1:?usage: webapp-remove } + +ICON_DIR="$HOME/.local/share/icons/hicolor/256x256/apps" +DESKTOP_DIR="$HOME/.local/share/applications" + +desktop_file="$DESKTOP_DIR/$name.desktop" +if [[ ! -f $desktop_file ]] || ! grep -q '^Exec=.*webapp-launch' "$desktop_file"; then + echo "Not a web app: $name" >&2 + exit 1 +fi + +icon_name=$(printf '%s\n' "$name" | tr '[:upper:]' '[:lower:]' | sed 's/[^[:alnum:]]\+/-/g; s/^-//; s/-$//') +rm -f "$desktop_file" "$ICON_DIR/$icon_name.png" "$ICON_DIR/$name.png" + +command -v update-desktop-database >/dev/null && update-desktop-database "$DESKTOP_DIR" >/dev/null 2>&1 || true +exit 0 diff --git a/webapp-maker/thumbnail.webp b/webapp-maker/thumbnail.webp new file mode 100644 index 0000000000000000000000000000000000000000..bb8b30735776e2a6b39c8baf7cfdb799d44dfb8e GIT binary patch literal 59980 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 literal 0 HcmV?d00001 diff --git a/webapp-maker/translations/en.json b/webapp-maker/translations/en.json new file mode 100644 index 00000000..b3650248 --- /dev/null +++ b/webapp-maker/translations/en.json @@ -0,0 +1,30 @@ +{ + "btn_create": "Create", + "err_failed": "webapp-install failed, see the Noctalia log", + "err_remove_failed": "Removal failed, see the Noctalia log", + "err_required": "Name and URL are required", + "err_slash": "Name cannot contain \"/\"", + "err_timeout": "webapp-install timed out", + "field_flags": "Chromium launch flags (optional)", + "field_flags_ph": "--proxy-server=http://127.0.0.1:1080 --incognito …", + "field_icon": "Icon: URL or file path (empty = fetch from site)", + "field_icon_ph": "https://…/icon.png or /path/icon.png", + "field_name": "Name", + "field_name_ph": "My web app", + "field_url": "URL", + "field_url_ph": "example.com (https is added automatically)", + "installed_empty": "Nothing created yet", + "installed_title": "Installed", + "ok_created": "\"{name}\" created — it is in the launcher now", + "ok_removed": "\"{name}\" removed", + "settings": { + "env_file": { + "label": "Environment file", + "description": "Sourced before the install and launch commands — e.g. a file exporting HTTPS_PROXY so site icons download through a proxy. Empty = none." + } + }, + "status_busy": "Creating — fetching the icon…", + "tip_close": "Close", + "tip_remove": "Remove the launcher and icon", + "title": "New web app" +} diff --git a/webapp-maker/translations/ru.json b/webapp-maker/translations/ru.json new file mode 100644 index 00000000..b9db7979 --- /dev/null +++ b/webapp-maker/translations/ru.json @@ -0,0 +1,30 @@ +{ + "btn_create": "Создать", + "err_failed": "webapp-install завершился с ошибкой, подробности в логе Noctalia", + "err_remove_failed": "Не удалось удалить, подробности в логе Noctalia", + "err_required": "Название и URL обязательны", + "err_slash": "В названии нельзя «/»", + "err_timeout": "webapp-install не уложился в таймаут", + "field_flags": "Параметры запуска chromium (опционально)", + "field_flags_ph": "--proxy-server=http://127.0.0.1:1080 --incognito …", + "field_icon": "Иконка: URL или путь (пусто = с сайта)", + "field_icon_ph": "https://…/icon.png или /путь/icon.png", + "field_name": "Название", + "field_name_ph": "Мой webapp", + "field_url": "URL", + "field_url_ph": "example.com (https допишется сам)", + "installed_empty": "Пока ничего не создано", + "installed_title": "Установленные", + "ok_created": "«{name}» создано — уже в лаунчере", + "ok_removed": "«{name}» удалено", + "settings": { + "env_file": { + "label": "Файл окружения", + "description": "Сорсится перед командами создания/запуска — например, файл с export HTTPS_PROXY, чтобы иконки сайтов качались через прокси. Пусто = не нужен." + } + }, + "status_busy": "Создание — скачивается иконка…", + "tip_close": "Закрыть", + "tip_remove": "Удалить ярлык и иконку", + "title": "Новое веб-приложение" +} From 2add9939d93fecff3694d18b41559124fb587a7f Mon Sep 17 00:00:00 2001 From: UmedjonBA Date: Sat, 29 Aug 2026 22:52:44 +0300 Subject: [PATCH 2/3] webapp-maker: use panel-toggle in the README IPC command --- webapp-maker/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp-maker/README.md b/webapp-maker/README.md index 5d92f887..510d3694 100644 --- a/webapp-maker/README.md +++ b/webapp-maker/README.md @@ -32,7 +32,7 @@ The plugin has no bar widget. Open the panel from the plugin's row in Settings, or bind it in your compositor: ```sh -noctalia msg panel-open umedbazarov/webapp-maker:panel +noctalia msg panel-toggle umedbazarov/webapp-maker:panel ``` Fill in the form: From 2b280634bdab4650143913a50516e62f658090dd Mon Sep 17 00:00:00 2001 From: UmedjonBA Date: Sun, 30 Aug 2026 15:45:22 +0300 Subject: [PATCH 3/3] webapp-maker: fix the panel header icon never rendering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `ui.glyph` takes `name`, not `glyph` — with the wrong prop the runtime drops the icon silently, so the panel header showed its title with an empty space where the globe should be. (`ui.button` is the other way round and takes `glyph`, which is what the confusion came from.) Co-Authored-By: Claude Opus 5 --- webapp-maker/panel.luau | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp-maker/panel.luau b/webapp-maker/panel.luau index b5a4016e..47853e47 100644 --- a/webapp-maker/panel.luau +++ b/webapp-maker/panel.luau @@ -220,7 +220,7 @@ end render = function() local children = { ui.row({ gap = 8, align = "center" }, { - ui.glyph({ glyph = "world-plus", size = 18, color = "primary" }), + ui.glyph({ name = "world-plus", size = 18, color = "primary" }), ui.label({ text = tr("title"), fontSize = 16, fontWeight = "bold", color = "on_surface", flexGrow = 1 }), ui.button({ glyph = "close", variant = "ghost", tooltip = tr("tip_close"),