mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-09-14 12:24:33 +08:00
Compare commits
8
Commits
6ad046d5b6
...
5f9dbf5e2d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5f9dbf5e2d | ||
|
|
70e84ddf56 | ||
|
|
e0826e34a3 | ||
|
|
b92e3e9efb | ||
|
|
24345f777c | ||
|
|
695b29172f | ||
|
|
aac1b49f77 | ||
|
|
8eaa48a277 |
@@ -1,3 +1,14 @@
|
|||||||
|
--- a/pgyvpn/Makefile
|
||||||
|
+++ b/pgyvpn/Makefile
|
||||||
|
@@ -67,7 +67,6 @@ ifeq ($(ARCH),x86_64)
|
||||||
|
OPENSSL_COMPAT_TARGET:=linux-x86_64
|
||||||
|
endif
|
||||||
|
|
||||||
|
-PKG_FLAGS:=nonshared
|
||||||
|
PKG_MAINTAINER:=Oray <developer@oray.com>
|
||||||
|
|
||||||
|
include $(INCLUDE_DIR)/package.mk
|
||||||
|
|
||||||
--- a/luci-app-easytier/Makefile
|
--- a/luci-app-easytier/Makefile
|
||||||
+++ b/luci-app-easytier/Makefile
|
+++ b/luci-app-easytier/Makefile
|
||||||
@@ -10,7 +10,7 @@ PKG_VERSION:=2.3.0
|
@@ -10,7 +10,7 @@ PKG_VERSION:=2.3.0
|
||||||
@@ -33,17 +44,6 @@
|
|||||||
|
|
||||||
include $(INCLUDE_DIR)/package.mk
|
include $(INCLUDE_DIR)/package.mk
|
||||||
|
|
||||||
--- a/pgyvpn/Makefile
|
|
||||||
+++ b/pgyvpn/Makefile
|
|
||||||
@@ -36,7 +36,6 @@ PKG_SOURCE:=pgyvpnsvr
|
|
||||||
PKG_SOURCE_URL:=https://mirrors.oray.com/orayos/packages/$(PKG_NAME)/$(PKG_ARCH_PGYYPN)/$(PKG_VERSION)/bin
|
|
||||||
PKG_HASH:=skip
|
|
||||||
|
|
||||||
-PKG_FLAGS:=nonshared
|
|
||||||
PKG_MAINTAINER:=Oray <developer@oray.com>
|
|
||||||
|
|
||||||
include $(INCLUDE_DIR)/package.mk
|
|
||||||
|
|
||||||
--- a/luci-app-rclone/Makefile
|
--- a/luci-app-rclone/Makefile
|
||||||
+++ b/luci-app-rclone/Makefile
|
+++ b/luci-app-rclone/Makefile
|
||||||
@@ -9,7 +9,7 @@ PKG_VERSION:=1.4.1
|
@@ -9,7 +9,7 @@ PKG_VERSION:=1.4.1
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
--- a/pgyvpn/Makefile
|
|
||||||
+++ b/pgyvpn/Makefile
|
|
||||||
@@ -78,7 +78,7 @@ define Package/pgyvpn/install
|
|
||||||
$(INSTALL_DIR) $(1)/usr/sbin
|
|
||||||
$(INSTALL_DIR) $(1)/usr/share/pgyvpn
|
|
||||||
|
|
||||||
- $(CP) $(PKG_BUILD_DIR)/{pgyvpn_oraysl,pgyvpnsvr} $(1)/usr/sbin
|
|
||||||
+ $(CP) $(PKG_BUILD_DIR)/pgyvpn_oraysl $(1)/usr/sbin
|
|
||||||
$(INSTALL_BIN) ./files/etc/init.d/* $(1)/etc/init.d
|
|
||||||
$(INSTALL_CONF) ./files/etc/config/* $(1)/etc/config
|
|
||||||
$(INSTALL_BIN) ./files/etc/hotplug.d/iface/* $(1)/etc/hotplug.d/iface
|
|
||||||
+2
-2
@@ -6,11 +6,11 @@ include $(TOPDIR)/rules.mk
|
|||||||
|
|
||||||
PKG_NAME:=3proxy
|
PKG_NAME:=3proxy
|
||||||
PKG_VERSION:=0.9.5
|
PKG_VERSION:=0.9.5
|
||||||
PKG_RELEASE:=3
|
PKG_RELEASE:=4
|
||||||
|
|
||||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||||
PKG_SOURCE_URL:=https://codeload.github.com/3proxy/3proxy/tar.gz/$(PKG_VERSION)?
|
PKG_SOURCE_URL:=https://codeload.github.com/3proxy/3proxy/tar.gz/$(PKG_VERSION)?
|
||||||
PKG_HASH:=6f6da51d9bba93231e12acd707bb6cf86a1ab9491dc6dd0c79750cb3641541a3
|
PKG_HASH:=skip
|
||||||
|
|
||||||
PKG_CPE_ID:=cpe:/a:3proxy:3proxy
|
PKG_CPE_ID:=cpe:/a:3proxy:3proxy
|
||||||
PKG_LICENSE:=3proxy Apache-2.0 GPL-2.0-or-later LGPL-2.1-or-later
|
PKG_LICENSE:=3proxy Apache-2.0 GPL-2.0-or-later LGPL-2.1-or-later
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
include $(TOPDIR)/rules.mk
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
PKG_NAME:=filebrowser
|
PKG_NAME:=filebrowser
|
||||||
PKG_VERSION:=1.5.5-stable
|
PKG_VERSION:=1.5.6-stable
|
||||||
PKG_RELEASE=1
|
PKG_RELEASE=1
|
||||||
|
|
||||||
ifeq ($(ARCH),aarch64)
|
ifeq ($(ARCH),aarch64)
|
||||||
|
|||||||
@@ -1,156 +1,13 @@
|
|||||||
server:
|
server:
|
||||||
minSearchLength: 3 # minimum length of search query to begin searching (default: 3)
|
|
||||||
disableUpdateCheck: false # disables backend update check service
|
|
||||||
numImageProcessors: 4 # number of concurrent image processing jobs used to create previews, default is number of cpu cores available.
|
|
||||||
socket: "" # socket to listen on
|
|
||||||
tlsKey: "" # path to TLS key
|
|
||||||
tlsCert: "" # path to TLS cert
|
|
||||||
disablePreviews: false # disable all previews thumbnails, simple icons will be used
|
|
||||||
disablePreviewResize: false # disable resizing of previews for faster loading over slow connections
|
|
||||||
disableTypeDetectionByHeader: false # disable type detection by header, useful if filesystem is slow.
|
|
||||||
port: 8989
|
port: 8989
|
||||||
baseURL: "/"
|
database: "/etc/filebrowser/database.db"
|
||||||
logging:
|
sources:
|
||||||
- levels: "" # separated list of log levels to enable. (eg. "info|warning|error|debug")
|
- path: "/" # Do not use a root "/" directory or include the "/var" folder
|
||||||
apiLevels: "" # separated list of log levels to enable for the API. (eg. "info|warning|error")
|
|
||||||
output: "stdout" # output location. (eg. "stdout" or "path/to/file.log")
|
|
||||||
noColors: false # disable colors in the output
|
|
||||||
json: false # output in json format
|
|
||||||
utc: false # use UTC time in the output instead of local time
|
|
||||||
debugMedia: false # output ffmpeg stdout for media integration -- careful can produces lots of output!
|
|
||||||
database: "/etc/filebrowser/database.db" # path to the database file
|
|
||||||
sources: # validate:required,dive
|
|
||||||
- path: "/"
|
|
||||||
name: "Root" # display name
|
|
||||||
config:
|
config:
|
||||||
denyByDefault: false # deny access unless an "allow" access rule was specifically created.
|
defaultEnabled: true
|
||||||
private: false # designate as source as private -- currently just means no sharing permitted.
|
|
||||||
disabled: false # disable the source, this is useful so you don't need to remove it from the config file
|
|
||||||
indexingIntervalMinutes: 0 # optional manual overide interval in minutes to re-index the source
|
|
||||||
disableIndexing: false # disable the indexing of this source
|
|
||||||
maxWatchers: 0 # number of concurrent watchers to use for this source, currently not supported
|
|
||||||
neverWatchPaths: []
|
|
||||||
exclude: # exclude files and folders from indexing, if include is not set
|
|
||||||
hidden: false # exclude hidden files and folders.
|
|
||||||
ignoreZeroSizeFolders: false # ignore folders with 0 size
|
|
||||||
filePaths: []
|
|
||||||
folderPaths: []
|
|
||||||
fileNames: []
|
|
||||||
folderNames: []
|
|
||||||
fileEndsWith: []
|
|
||||||
folderEndsWith: []
|
|
||||||
fileStartsWith: []
|
|
||||||
folderStartsWith: []
|
|
||||||
include: # include files and folders from indexing, if exclude is not set
|
|
||||||
rootFolders: []
|
|
||||||
rootFiles: []
|
|
||||||
defaultUserScope: "/" # default "/" should match folders under path
|
|
||||||
defaultEnabled: false # should be added as a default source for new users?
|
|
||||||
createUserDir: false # create a user directory for each user
|
|
||||||
externalUrl: "" # used by share links if set (eg. http://mydomain.com)
|
|
||||||
internalUrl: "" # used by integrations if set, this is the base domain that an integration service will use to communicate with filebrowser (eg. http://localhost:8080)
|
|
||||||
cacheDir: "tmp" # path to the cache directory, used for thumbnails and other cached files
|
|
||||||
maxArchiveSize: 50 # max pre-archive combined size of files/folder that are allowed to be archived (in GB)
|
|
||||||
auth:
|
auth:
|
||||||
tokenExpirationHours: 2 # time in hours each web UI session token is valid for. Default is 2 hours.
|
adminUsername: admin
|
||||||
methods:
|
adminPassword: "admin"
|
||||||
proxy: # validate:omitempty
|
|
||||||
enabled: false
|
|
||||||
createUser: false # create user if not exists
|
|
||||||
header: "" # required header to use for authentication. Security Warning: FileBrowser blindly accepts the header value as username.
|
|
||||||
logoutRedirectUrl: "" # if provider logout url is provided, filebrowser will also redirect to logout url. Custom logout query params are respected.
|
|
||||||
noauth: false # if set to true, overrides all other auth methods and disables authentication
|
|
||||||
password: # validate:omitempty
|
|
||||||
enabled: true
|
|
||||||
minLength: 3 # minimum pasword length required, default is 5. validate:omitempty
|
|
||||||
signup: false # allow signups on login page if enabled -- not secure. validate:omitempty
|
|
||||||
recaptcha: # recaptcha config, only used if signup is enabled validate:omitempty
|
|
||||||
host: "" # validate:required
|
|
||||||
key: "" # validate:required
|
|
||||||
secret: "" # validate:required
|
|
||||||
enforcedOtp: false # if set to true, TOTP is enforced for all password users users. Otherwise, users can choose to enable TOTP.
|
|
||||||
oidc: # validate:omitempty
|
|
||||||
enabled: false # whether to enable OIDC authentication
|
|
||||||
clientId: "**hidden**" # secret: client id of the OIDC application
|
|
||||||
clientSecret: "**hidden**" # secret: client secret of the OIDC application
|
|
||||||
issuerUrl: "" # authorization URL of the OIDC provider
|
|
||||||
scopes: "openid email profile" # scopes to request from the OIDC provider
|
|
||||||
userIdentifier: "preferred_username" # the field value to use as the username. Default is "preferred_username", can also be "email" or "username", or "phone"
|
|
||||||
disableVerifyTLS: false # disable TLS verification for the OIDC provider. This is insecure and should only be used for testing.
|
|
||||||
logoutRedirectUrl: "" # if provider logout url is provided, filebrowser will also redirect to logout url. Custom logout query params are respected.
|
|
||||||
createUser: false # create user if not exists
|
|
||||||
adminGroup: "" # if set, users in this group will be granted admin privileges.
|
|
||||||
groupsClaim: "groups" # the JSON field name to read groups from. Default is "groups"
|
|
||||||
key: "**hidden**" # secret: the key used to sign the JWT tokens. If not set, a random key will be generated.
|
|
||||||
adminUsername: "admin" # secret: the username of the admin user. If not set, the default is "admin".
|
|
||||||
adminPassword: "admin" # secret: the password of the admin user. If not set, the default is "admin".
|
|
||||||
totpSecret: "**hidden**" # secret: secret used to encrypt TOTP secrets
|
|
||||||
frontend:
|
|
||||||
name: "FileBrowser Quantum" # display name
|
|
||||||
disableDefaultLinks: false # disable default links in the sidebar
|
|
||||||
disableUsedPercentage: false # disable used percentage for the sources in the sidebar
|
|
||||||
externalLinks:
|
|
||||||
- text: "Help" # the text to display on the link validate:required
|
|
||||||
title: "" # the title to display on hover
|
|
||||||
url: "https://github.com/gtsteffaniak/filebrowser" # the url to link to validate:required
|
|
||||||
disableNavButtons: false # disable the nav buttons in the sidebar
|
|
||||||
styling:
|
|
||||||
customCSS: "" # if a valid path to a css file is provided, it will be applied for all users. (eg. "reduce-rounded-corners.css")
|
|
||||||
lightBackground: "#f5f5f5" # specify a valid CSS color property value to use as the background color in light mode
|
|
||||||
darkBackground: "#141D24" # Specify a valid CSS color property value to use as the background color in dark mode
|
|
||||||
customThemes: # A list of custom css files that each user can select to override the default styling. if "default" is key name then it will be the default option.
|
|
||||||
default:
|
|
||||||
description: "The default theme" # The description of the theme to display in the UI.
|
|
||||||
css: "" # The css file path and filename to use for the theme.
|
|
||||||
alternative:
|
|
||||||
description: "Reduce rounded corners" # The description of the theme to display in the UI.
|
|
||||||
css: "reduce-rounded-corners.css" # The css file path and filename to use for the theme.
|
|
||||||
favicon: "" # path to a favicon to use for the frontend
|
|
||||||
description: "FileBrowser Quantum is a file manager for the web which can be used to manage files on your server" # description that shows up in html head meta description
|
|
||||||
userDefaults:
|
userDefaults:
|
||||||
editorQuickSave: false # show quick save button in editor
|
ui:
|
||||||
hideSidebarFileActions: false # hide the file actions in the sidebar
|
locale: "cn"
|
||||||
disableQuickToggles: false # disable the quick toggles in the sidebar
|
|
||||||
disableSearchOptions: false # disable the search options in the search bar
|
|
||||||
stickySidebar: true # keep sidebar open when navigating
|
|
||||||
darkMode: true # should dark mode be enabled
|
|
||||||
locale: "zhCN" # language to use: eg. de, en, or fr
|
|
||||||
viewMode: "normal" # view mode to use: eg. normal, list, grid, or compact
|
|
||||||
singleClick: false # open directory on single click, also enables middle click to open in new tab
|
|
||||||
showHidden: false # show hidden files in the UI. On windows this includes files starting with a dot and windows hidden files
|
|
||||||
dateFormat: false # when false, the date is relative, when true, the date is an exact timestamp
|
|
||||||
gallerySize: 3 # 0-9 - the size of the gallery thumbnails
|
|
||||||
themeColor: "var(--blue)" # theme color to use: eg. #ff0000, or var(--red), var(--purple), etc
|
|
||||||
quickDownload: false # show icon to download in one click
|
|
||||||
disablePreviewExt: "" # space separated list of file extensions to disable preview for
|
|
||||||
disableViewingExt: "" # space separated list of file extensions to disable viewing for
|
|
||||||
lockPassword: false # disable the user from changing their password
|
|
||||||
disableSettings: false # disable the user from viewing the settings page
|
|
||||||
preview:
|
|
||||||
disableHideSidebar: false
|
|
||||||
highQuality: false
|
|
||||||
image: false
|
|
||||||
video: false
|
|
||||||
motionVideoPreview: false
|
|
||||||
office: false
|
|
||||||
popup: false
|
|
||||||
autoplayMedia: false
|
|
||||||
defaultMediaPlayer: false
|
|
||||||
folder: false
|
|
||||||
permissions:
|
|
||||||
api: false
|
|
||||||
admin: false
|
|
||||||
modify: false
|
|
||||||
share: false
|
|
||||||
realtime: false
|
|
||||||
loginMethod: "password" # login method to use: eg. password, proxy, oidc
|
|
||||||
disableUpdateNotifications: false # disable update notifications banner for admin users
|
|
||||||
deleteWithoutConfirming: false # delete files without confirmation
|
|
||||||
fileLoading: # upload and download settings
|
|
||||||
maxConcurrentUpload: 10
|
|
||||||
uploadChunkSizeMb: 10
|
|
||||||
clearAll: false
|
|
||||||
disableOnlyOfficeExt: "" # list of file extensions to disable onlyoffice editor for
|
|
||||||
customTheme: "" # Name of theme to use chosen from custom themes config.
|
|
||||||
showSelectMultiple: false # show select multiple files on desktop
|
|
||||||
debugOffice: false # debug onlyoffice editor
|
|
||||||
|
|||||||
@@ -2,6 +2,4 @@ config filebrowser 'config'
|
|||||||
option enabled '0'
|
option enabled '0'
|
||||||
option listen_port '8989'
|
option listen_port '8989'
|
||||||
option root_path '/'
|
option root_path '/'
|
||||||
option base_url '/'
|
|
||||||
option disable_exec '1'
|
|
||||||
|
|
||||||
|
|||||||
@@ -18,9 +18,11 @@ start() {
|
|||||||
local listen_port root_path base_url
|
local listen_port root_path base_url
|
||||||
config_get listen_port "config" "listen_port" "8989"
|
config_get listen_port "config" "listen_port" "8989"
|
||||||
config_get root_path "config" "root_path" "/"
|
config_get root_path "config" "root_path" "/"
|
||||||
config_get base_url "config" "base_url" "/"
|
|
||||||
|
|
||||||
echo "Starting filebrowser..."
|
echo "Starting filebrowser..."
|
||||||
|
sed -e "s/ port:.*/ port: $listen_port/" \
|
||||||
|
-e "s, - path:.*, - path: \"$root_path\"," \
|
||||||
|
-i "$CONF_PATH"
|
||||||
start-stop-daemon -S -q -b -m -p "$PID_FILE" -x "$PROG" -- -c "$CONF_PATH"
|
start-stop-daemon -S -q -b -m -p "$PID_FILE" -x "$PROG" -- -c "$CONF_PATH"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,17 +49,24 @@ return view.extend({
|
|||||||
s = m.section(form.TypedSection);
|
s = m.section(form.TypedSection);
|
||||||
s.anonymous = true;
|
s.anonymous = true;
|
||||||
s.render = function() {
|
s.render = function() {
|
||||||
poll.add(function() {
|
poll.add(function() {
|
||||||
return Promise.resolve().then(function() {
|
return fs.stat('/var/run/filebrowser.pid').then(function(stat) {
|
||||||
let view = document.getElementById('service_status');
|
let view = document.getElementById('service_status');
|
||||||
view.innerHTML = renderStatus(data.isRunning, webport);
|
if (view) {
|
||||||
});
|
view.innerHTML = renderStatus(stat, webport);
|
||||||
});
|
}
|
||||||
|
}).catch(function() {
|
||||||
|
let view = document.getElementById('service_status');
|
||||||
|
if (view) {
|
||||||
|
view.innerHTML = renderStatus(null, webport);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
return E('div', { class: 'cbi-section', id: 'status_bar' }, [
|
return E('div', { class: 'cbi-section', id: 'status_bar' }, [
|
||||||
E('p', { id: 'service_status' }, _('Collecting data...'))
|
E('p', { id: 'service_status' }, _('Collecting data...'))
|
||||||
]);
|
]);
|
||||||
}
|
};
|
||||||
|
|
||||||
s = m.section(form.NamedSection, 'config', 'filebrowser');
|
s = m.section(form.NamedSection, 'config', 'filebrowser');
|
||||||
|
|
||||||
@@ -76,10 +83,6 @@ return view.extend({
|
|||||||
o.default = '/';
|
o.default = '/';
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
|
|
||||||
o = s.option(form.Value, 'base_url', _('Base url'));
|
|
||||||
o.default = '/';
|
|
||||||
o.rmempty = false;
|
|
||||||
|
|
||||||
return m.render();
|
return m.render();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -8,11 +8,6 @@ include $(TOPDIR)/rules.mk
|
|||||||
|
|
||||||
LUCI_TITLE:=LuCI page for IPK upload
|
LUCI_TITLE:=LuCI page for IPK upload
|
||||||
LUCI_DEPENDS:=+luci-lib-fs
|
LUCI_DEPENDS:=+luci-lib-fs
|
||||||
LUCI_PKGARCH:=all
|
|
||||||
|
|
||||||
PKG_NAME:=luci-app-filetransfer
|
|
||||||
PKG_VERSION:=1
|
|
||||||
PKG_RELEASE:=1
|
|
||||||
|
|
||||||
include $(TOPDIR)/feeds/luci/luci.mk
|
include $(TOPDIR)/feeds/luci/luci.mk
|
||||||
|
|
||||||
|
|||||||
@@ -9,5 +9,7 @@ module("luci.controller.filetransfer", package.seeall)
|
|||||||
|
|
||||||
function index()
|
function index()
|
||||||
|
|
||||||
entry({"admin", "system", "filetransfer"}, form("filetransfer"), _("FileTransfer"), 89).dependent = true
|
local page = entry({"admin", "system", "filetransfer"}, form("filetransfer"), _("FileTransfer"), 89)
|
||||||
|
page.dependent = true
|
||||||
|
page.acl_depends = { "luci-app-filetransfer" }
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -91,16 +91,6 @@ elseif luci.http.formvalue("download") then
|
|||||||
Download()
|
Download()
|
||||||
end
|
end
|
||||||
|
|
||||||
local function getSizeStr(size)
|
|
||||||
local i = 0
|
|
||||||
local byteUnits = {' kB', ' MB', ' GB', ' TB'}
|
|
||||||
repeat
|
|
||||||
size = size / 1024
|
|
||||||
i = i + 1
|
|
||||||
until(size <= 1024)
|
|
||||||
return string.format("%.1f", size) .. byteUnits[i]
|
|
||||||
end
|
|
||||||
|
|
||||||
local inits, attr = {}
|
local inits, attr = {}
|
||||||
for i, f in ipairs(fs.glob("/tmp/upload/*")) do
|
for i, f in ipairs(fs.glob("/tmp/upload/*")) do
|
||||||
attr = fs.stat(f)
|
attr = fs.stat(f)
|
||||||
@@ -109,7 +99,7 @@ for i, f in ipairs(fs.glob("/tmp/upload/*")) do
|
|||||||
inits[i].name = fs.basename(f)
|
inits[i].name = fs.basename(f)
|
||||||
inits[i].mtime = os.date("%Y-%m-%d %H:%M:%S", attr.mtime)
|
inits[i].mtime = os.date("%Y-%m-%d %H:%M:%S", attr.mtime)
|
||||||
inits[i].modestr = attr.modestr
|
inits[i].modestr = attr.modestr
|
||||||
inits[i].size = getSizeStr(attr.size)
|
inits[i].size = tostring(attr.size)
|
||||||
inits[i].remove = 0
|
inits[i].remove = 0
|
||||||
inits[i].install = false
|
inits[i].install = false
|
||||||
end
|
end
|
||||||
@@ -122,9 +112,8 @@ form.submit = false
|
|||||||
tb = form:section(Table, inits)
|
tb = form:section(Table, inits)
|
||||||
nm = tb:option(DummyValue, "name", translate("File name"))
|
nm = tb:option(DummyValue, "name", translate("File name"))
|
||||||
mt = tb:option(DummyValue, "mtime", translate("Modify time"))
|
mt = tb:option(DummyValue, "mtime", translate("Modify time"))
|
||||||
ms = tb:option(DummyValue, "modestr", translate("Attributes"))
|
ms = tb:option(DummyValue, "modestr", translate("Mode string"))
|
||||||
sz = tb:option(DummyValue, "size", translate("Size"))
|
sz = tb:option(DummyValue, "size", translate("Size"))
|
||||||
|
|
||||||
btnrm = tb:option(Button, "remove", translate("Remove"))
|
btnrm = tb:option(Button, "remove", translate("Remove"))
|
||||||
btnrm.render = function(self, section, scope)
|
btnrm.render = function(self, section, scope)
|
||||||
self.inputstyle = "remove"
|
self.inputstyle = "remove"
|
||||||
|
|||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
zh_Hans
|
||||||
@@ -1 +0,0 @@
|
|||||||
zh-cn
|
|
||||||
+5
-15
@@ -1,15 +1,5 @@
|
|||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr "Content-Type: text/plain; charset=UTF-8"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
|
||||||
"Project-Id-Version: \n"
|
|
||||||
"POT-Creation-Date: \n"
|
|
||||||
"PO-Revision-Date: \n"
|
|
||||||
"Last-Translator: dingpengyu <dingpengyu06@gmail.com>\n"
|
|
||||||
"Language-Team: \n"
|
|
||||||
"MIME-Version: 1.0\n"
|
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
|
||||||
"Language: zh_CN\n"
|
|
||||||
"X-Generator: Poedit 2.3.1\n"
|
|
||||||
|
|
||||||
msgid "Choose local file:"
|
msgid "Choose local file:"
|
||||||
msgstr "选择本地文件:"
|
msgstr "选择本地文件:"
|
||||||
@@ -38,17 +28,17 @@ msgstr "文件传输"
|
|||||||
msgid "Install"
|
msgid "Install"
|
||||||
msgstr "安装"
|
msgstr "安装"
|
||||||
|
|
||||||
msgid "Attributes"
|
msgid "Mode string"
|
||||||
msgstr "属性"
|
msgstr "模式字符串"
|
||||||
|
|
||||||
msgid "Modify time"
|
msgid "Modify time"
|
||||||
msgstr "修改时间"
|
msgstr "修改时间"
|
||||||
|
|
||||||
msgid "No specify upload file."
|
msgid "No specify upload file."
|
||||||
msgstr "未指定上传文件。"
|
msgstr "未指定上传文件"
|
||||||
|
|
||||||
msgid "Path on Route:"
|
msgid "Path on Route:"
|
||||||
msgstr "路由根目录:"
|
msgstr "路由上目录"
|
||||||
|
|
||||||
msgid "Remove"
|
msgid "Remove"
|
||||||
msgstr "移除"
|
msgstr "移除"
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
sed -i 's/cbi.submit\"] = true/cbi.submit\"] = \"1\"/g' /usr/lib/lua/luci/dispatcher.lua
|
|
||||||
|
|
||||||
rm -f /tmp/luci-indexcache
|
|
||||||
exit 0
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"luci-app-filetransfer": {
|
||||||
|
"description": "Grant UCI access for luci-app-filetransfer",
|
||||||
|
"read": {
|
||||||
|
"uci": [ "filetransfer" ]
|
||||||
|
},
|
||||||
|
"write": {
|
||||||
|
"uci": [ "filetransfer" ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,7 +17,7 @@ LUCI_NAME:=luci-theme-footstrap
|
|||||||
FOOTSTRAP_VERSION?=
|
FOOTSTRAP_VERSION?=
|
||||||
ifneq ($(FOOTSTRAP_VERSION),)
|
ifneq ($(FOOTSTRAP_VERSION),)
|
||||||
PKG_VERSION:=$(FOOTSTRAP_VERSION)
|
PKG_VERSION:=$(FOOTSTRAP_VERSION)
|
||||||
PKG_RELEASE:=56
|
PKG_RELEASE:=59
|
||||||
endif
|
endif
|
||||||
|
|
||||||
LUCI_TITLE:=Footstrap Theme
|
LUCI_TITLE:=Footstrap Theme
|
||||||
|
|||||||
@@ -296,7 +296,14 @@ function build() {
|
|||||||
const node = w.render();
|
const node = w.render();
|
||||||
node.setAttribute('aria-label', label);
|
node.setAttribute('aria-label', label);
|
||||||
const push = () => apply(parseInt(w.getValue(), 10));
|
const push = () => apply(parseInt(w.getValue(), 10));
|
||||||
node.addEventListener('widget-update', push);
|
/* `live: false` for an axis whose value moves THIS CONTROL. Content width widens the column
|
||||||
|
* the Appearance page is drawn in, so applying mid-drag slides the handle out from under
|
||||||
|
* the pointer, the pointer catches up, and one small drag runs the value to the maximum —
|
||||||
|
* reported from a router, and not a thing any other slider here can do: rounding and the
|
||||||
|
* tint sliders repaint around a control that stays where it is. On release the page still
|
||||||
|
* follows, and a keyboard user is unaffected either way: an arrow key on a range input
|
||||||
|
* fires `change` as well as `input`, so the value applies at once. */
|
||||||
|
if (o.live !== false) node.addEventListener('widget-update', push);
|
||||||
node.addEventListener('widget-change', push);
|
node.addEventListener('widget-change', push);
|
||||||
return node;
|
return node;
|
||||||
};
|
};
|
||||||
@@ -343,7 +350,10 @@ function build() {
|
|||||||
* so it is a proper noun and stays untranslated, like the two above it */
|
* so it is a proper noun and stays untranslated, like the two above it */
|
||||||
bootstrap: 'Bootstrap',
|
bootstrap: 'Bootstrap',
|
||||||
/* names the OTHER package again, luci-theme-openwrt-2020, whose colourway this is */
|
/* names the OTHER package again, luci-theme-openwrt-2020, whose colourway this is */
|
||||||
'2020': 'OpenWrt 2020'
|
'2020': 'OpenWrt 2020',
|
||||||
|
/* names the OpenWrt forum (forum.openwrt.org), whose Discourse colourway this is —
|
||||||
|
* a proper noun like the three above it, not the English common noun "forum" */
|
||||||
|
forum: 'Forum'
|
||||||
}, bump(repaint(axes.applyPalette)), label)),
|
}, bump(repaint(axes.applyPalette)), label)),
|
||||||
|
|
||||||
group(_('Density', 'footstrap'), (label) => selectCtl(prefs.currentDensity(), {
|
group(_('Density', 'footstrap'), (label) => selectCtl(prefs.currentDensity(), {
|
||||||
@@ -352,6 +362,16 @@ function build() {
|
|||||||
large: _('Large', 'footstrap')
|
large: _('Large', 'footstrap')
|
||||||
}, bump(prefs.applyDensity), label)),
|
}, bump(prefs.applyDensity), label)),
|
||||||
|
|
||||||
|
/* issue #44: the content column's own cap, separate from Density (which moves type and
|
||||||
|
* air, not the column's ceiling). The slider STARTS at the 1280px the theme has always
|
||||||
|
* shipped and only ever widens — there is no reason to offer a column narrower than the
|
||||||
|
* one every page was designed against, and keeping 1280 as the left end also keeps
|
||||||
|
* --fs-content-min (500px, what the sidebar-to-bar fold is measured against) out of reach
|
||||||
|
* by construction rather than by a rule someone has to remember. */
|
||||||
|
group(_('Content width', 'footstrap'),
|
||||||
|
(label) => sliderCtl(axes.currentContentWidth(), 1280, 3840,
|
||||||
|
bump(axes.applyContentWidth), label, { step: 40, live: false })),
|
||||||
|
|
||||||
group(_('Rounding', 'footstrap'),
|
group(_('Rounding', 'footstrap'),
|
||||||
(label) => sliderCtl(axes.currentRadius(), 0, 20, bump(axes.applyRadius), label)),
|
(label) => sliderCtl(axes.currentRadius(), 0, 20, bump(axes.applyRadius), label)),
|
||||||
|
|
||||||
@@ -575,7 +595,13 @@ function build() {
|
|||||||
* the scoped uci ACL). It does not change this browser — localStorage keeps overriding — so the
|
* the scoped uci ACL). It does not change this browser — localStorage keeps overriding — so the
|
||||||
* saved default only shows on a fresh browser. The two Reset buttons below are the escape
|
* saved default only shows on a fresh browser. The two Reset buttons below are the escape
|
||||||
* hatches, and they do not land in the same place. */
|
* hatches, and they do not land in the same place. */
|
||||||
const saveBtn = E('button', { 'class': 'btn cbi-button-action', 'type': 'button' }, [ _('Save to router', 'footstrap') ]);
|
/* the button/status label said three times below, inside this one build() call — hoisting the
|
||||||
|
* RESULT, not the msgid, so update-po.sh still sees the literal `_()` argument elsewhere
|
||||||
|
* (measured: 22 B x3 -> 27 B, 39 B saved) */
|
||||||
|
const SAVE_TO_ROUTER = _('Save to router', 'footstrap');
|
||||||
|
/* said twice below, same build() call (measured: 24 B x2 -> 30 B, 18 B saved) */
|
||||||
|
const RESET_TO_ROUTER = _('Reset to router', 'footstrap');
|
||||||
|
const saveBtn = E('button', { 'class': 'btn cbi-button-action', 'type': 'button' }, [ SAVE_TO_ROUTER ]);
|
||||||
/* Two resets, because two things sit underneath a browser's tweaks (fs-prefs.js): "Reset to
|
/* Two resets, because two things sit underneath a browser's tweaks (fs-prefs.js): "Reset to
|
||||||
* router" clears them and lets every axis fall back to whatever the router holds, while "Reset
|
* router" clears them and lets every axis fall back to whatever the router holds, while "Reset
|
||||||
* to built-in" writes the theme's built-ins explicitly — the only way to say "as the theme
|
* to built-in" writes the theme's built-ins explicitly — the only way to say "as the theme
|
||||||
@@ -585,7 +611,7 @@ function build() {
|
|||||||
* "Save as default" and the theme's in "Reset to default", while the router's look also
|
* "Save as default" and the theme's in "Reset to default", while the router's look also
|
||||||
* answered to "saved" — three names for two states, asked about on the forum (topic 251930,
|
* answered to "saved" — three names for two states, asked about on the forum (topic 251930,
|
||||||
* post 92). The row now reads as one save and two resets, over `router` and `built-in`. */
|
* post 92). The row now reads as one save and two resets, over `router` and `built-in`. */
|
||||||
const resetSavedBtn = E('button', { 'class': 'btn', 'type': 'button' }, [ _('Reset to router', 'footstrap') ]);
|
const resetSavedBtn = E('button', { 'class': 'btn', 'type': 'button' }, [ RESET_TO_ROUTER ]);
|
||||||
/* the stock destructive class, so the button discarding every local tweak is the red one
|
/* the stock destructive class, so the button discarding every local tweak is the red one
|
||||||
* (theme/55-buttons.css). "Reset to router" stays neutral: it steps back to the shared state
|
* (theme/55-buttons.css). "Reset to router" stays neutral: it steps back to the shared state
|
||||||
* rather than discarding. */
|
* rather than discarding. */
|
||||||
@@ -607,14 +633,14 @@ function build() {
|
|||||||
function refreshSave() {
|
function refreshSave() {
|
||||||
if (prefs.storageBroken()) {
|
if (prefs.storageBroken()) {
|
||||||
saveBtn.disabled = false;
|
saveBtn.disabled = false;
|
||||||
saveBtn.textContent = _('Save to router', 'footstrap');
|
saveBtn.textContent = SAVE_TO_ROUTER;
|
||||||
saveErr.textContent = _('This browser is not storing preferences (site data is blocked), so a change here lasts until you reload. Saving as default still works and applies to every browser.', 'footstrap');
|
saveErr.textContent = _('This browser is not storing preferences (site data is blocked), so a change here lasts until you reload. Saving as default still works and applies to every browser.', 'footstrap');
|
||||||
saveErr.hidden = false;
|
saveErr.hidden = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const saved = axes.matchesSavedDefault();
|
const saved = axes.matchesSavedDefault();
|
||||||
saveBtn.disabled = saved;
|
saveBtn.disabled = saved;
|
||||||
saveBtn.textContent = saved ? _('Saved to router', 'footstrap') : _('Save to router', 'footstrap');
|
saveBtn.textContent = saved ? _('Saved to router', 'footstrap') : SAVE_TO_ROUTER;
|
||||||
}
|
}
|
||||||
saveBtn.addEventListener('click', () => {
|
saveBtn.addEventListener('click', () => {
|
||||||
saveBtn.disabled = true;
|
saveBtn.disabled = true;
|
||||||
@@ -655,7 +681,7 @@ function build() {
|
|||||||
location.reload();
|
location.reload();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
twoClick(resetSavedBtn, _('Reset to router', 'footstrap'), axes.resetToSaved);
|
twoClick(resetSavedBtn, RESET_TO_ROUTER, axes.resetToSaved);
|
||||||
twoClick(resetBtn, _('Reset to built-in', 'footstrap'), axes.resetToBuiltin);
|
twoClick(resetBtn, _('Reset to built-in', 'footstrap'), axes.resetToBuiltin);
|
||||||
refreshSave(); /* correct label and enabled state before the first paint */
|
refreshSave(); /* correct label and enabled state before the first paint */
|
||||||
|
|
||||||
|
|||||||
@@ -43,17 +43,22 @@ const _uciCommit = rpc.declare({ object: 'uci', method: 'commit', params: [ 'con
|
|||||||
* Router-side, like the login photo and for the same reason — a file cannot live in localStorage,
|
* Router-side, like the login photo and for the same reason — a file cannot live in localStorage,
|
||||||
* and a pattern is something a router wears. The path is a fixed server-side constant matched
|
* and a pattern is something a router wears. The path is a fixed server-side constant matched
|
||||||
* exactly by the rpcd ACL, so nothing user-controlled reaches a path. It lives under /etc so a
|
* exactly by the rpcd ACL, so nothing user-controlled reaches a path. It lives under /etc so a
|
||||||
* package upgrade cannot delete it (keep.d carries it across a sysupgrade), and the served name
|
* package upgrade cannot delete it (keep.d carries it across a sysupgrade). It keeps the .svg name
|
||||||
* ends in .svg because uhttpd types a file by extension.
|
* for its own sake — the CGI handler that now serves it (root/www/cgi-bin) sets Content-Type
|
||||||
|
* itself and does not rely on uhttpd's by-extension typing the way the login photo's /www symlink
|
||||||
|
* still does.
|
||||||
*
|
*
|
||||||
* How it is made to fit is 15-wallpaper.css's mask, not anything done to the bytes: the file
|
* How it is made to fit is 15-wallpaper.css's mask, not anything done to the bytes: the file
|
||||||
* supplies the alpha and the theme the colour, so one upload reads correctly in both modes and
|
* supplies the alpha and the theme the colour, so one upload reads correctly in both modes and
|
||||||
* under every palette.
|
* under every palette.
|
||||||
*
|
*
|
||||||
* What is refused: an SVG is a document, not a picture, and while a masked or background image
|
* What is refused: an SVG is a document, not a picture, and while a masked or background image
|
||||||
* never executes script, the same file fetched from its own URL would. Uploading already needs an
|
* never executes script, the same file fetched from its own URL would (OpenWrt forum thread
|
||||||
* authenticated admin session with uci write rights, so this is defence in depth — but the check is
|
* 251930) — which is what the server-side handler (root/www/cgi-bin) now closes with response
|
||||||
* cheap and the failure mode is somebody else's browser. */
|
* headers a browser will not execute. THIS check runs in the uploading admin's OWN browser and is
|
||||||
|
* not a defence at all: a `curl` POST to the same cgi-io path skips it entirely, and the rpcd ACL
|
||||||
|
* authorises that POST regardless of what wrote it. It exists only so an admin who uploads a bad
|
||||||
|
* file by mistake is told so before it lands, and the cost of running it is cheap. */
|
||||||
const PAT_PATH = '/etc/footstrap/pattern.svg'; /* cgi-upload target; the ACL grants exactly this */
|
const PAT_PATH = '/etc/footstrap/pattern.svg'; /* cgi-upload target; the ACL grants exactly this */
|
||||||
const PAT_MAX = 512 * 1024; /* a tile that has to reach a router's flash and then every page load */
|
const PAT_MAX = 512 * 1024; /* a tile that has to reach a router's flash and then every page load */
|
||||||
/* What makes an uploaded SVG unacceptable, decided on the PARSED document and not on its text: a
|
/* What makes an uploaded SVG unacceptable, decided on the PARSED document and not on its text: a
|
||||||
@@ -65,19 +70,30 @@ const PAT_MAX = 512 * 1024; /* a tile that has to reach a router's flash
|
|||||||
* no subresource is fetched, no handler is bound. So the questions are exact ones about nodes:
|
* no subresource is fetched, no handler is bound. So the questions are exact ones about nodes:
|
||||||
*
|
*
|
||||||
* - is it an SVG at all (a parsererror, or a root that is not <svg>, is not an image)
|
* - is it an SVG at all (a parsererror, or a root that is not <svg>, is not an image)
|
||||||
* - does it carry an element that executes or embeds (script, foreignObject, iframe, …)
|
* - does it carry an element that executes or embeds (script, foreignObject, iframe, style, …)
|
||||||
* - does it carry a real event-handler attribute — `^on[a-z]+$`
|
* - does it carry a real event-handler attribute — `^on[a-z]+$`
|
||||||
* - does any value start a `javascript:` url
|
* - does any value start a `javascript:` url
|
||||||
* - does any href point off this router; `#fragment` and `data:` stay allowed, being how a tile
|
* - does any href point off this router — a leading `//`, or a `data:`/`blob:`/`about:` payload
|
||||||
* refers to its own <defs> and embeds a bitmap
|
* - does any element carry a `style` attribute
|
||||||
*
|
*
|
||||||
* The check is for the way the file can be reached that a mask does not cover: its own URL, opened
|
* The check is for the way the file can be reached that a mask does not cover: its own URL, opened
|
||||||
* directly, same-origin with the session.
|
* directly, same-origin with the session.
|
||||||
*
|
*
|
||||||
* `animate`/`set` are listed for a second reason as well: they can retarget an attribute at run
|
* `animate`/`set` are listed for a second reason as well: they can retarget an attribute at run
|
||||||
* time (`<set attributename="href" to="javascript:…">`), and a tile that animates repaints a
|
* time (`<set attributename="href" to="javascript:…">`), and a tile that animates repaints a
|
||||||
* full-viewport layer behind every page. */
|
* full-viewport layer behind every page.
|
||||||
const PAT_BAD_TAGS = [ 'script', 'foreignobject', 'iframe', 'embed', 'object', 'audio', 'video', 'animate', 'set' ];
|
*
|
||||||
|
* `style` is refused both as an ELEMENT and as an ATTRIBUTE: a `<style>@import
|
||||||
|
* url("//attacker/x.css")</style>` reaches off-router with no script and no href at all, and a
|
||||||
|
* `style="…url(…)…"` attribute does the same per-element. `data:`/`blob:`/`about:` were allowed
|
||||||
|
* through `href`/`xlink:href` before this pass, on the theory that a tile only ever uses `data:` to
|
||||||
|
* embed its own bitmap — closed anyway, because the same scheme admits `data:text/html` and
|
||||||
|
* `data:image/svg+xml`, and telling those apart from a `data:image/png` bitmap means parsing the
|
||||||
|
* URI's own MIME token, which is exactly the kind of grammar-guessing this file avoids everywhere
|
||||||
|
* else. The cost is real: an admin embedding a bitmap inside the tile now needs a second uploaded
|
||||||
|
* asset referenced by a same-origin URL instead of a `data:` href — the tile itself is unaffected,
|
||||||
|
* since 15-wallpaper.css never used one. */
|
||||||
|
const PAT_BAD_TAGS = [ 'script', 'foreignobject', 'iframe', 'embed', 'object', 'audio', 'video', 'animate', 'set', 'style' ];
|
||||||
const SVG_NS = 'http://www.w3.org/2000/svg';
|
const SVG_NS = 'http://www.w3.org/2000/svg';
|
||||||
|
|
||||||
/* null if the parsed document is fine, otherwise the sentence to show. */
|
/* null if the parsed document is fine, otherwise the sentence to show. */
|
||||||
@@ -118,8 +134,17 @@ function _svgObjection(text) {
|
|||||||
* refuse files that do nothing. */
|
* refuse files that do nothing. */
|
||||||
if ((/^on[a-z]+$/).test(n)) return refused;
|
if ((/^on[a-z]+$/).test(n)) return refused;
|
||||||
if ((/^javascript:/i).test(v)) return refused;
|
if ((/^javascript:/i).test(v)) return refused;
|
||||||
/* off-router reference. A leading `//` is protocol-relative and just as external. */
|
/* a `style=""` attribute reaches the same `url()` grammar as a `<style>` element,
|
||||||
if ((/(?:^|:)href$/).test(n) && (/^(?:[a-z][a-z0-9+.-]*:)?\/\//i).test(v)) return refused;
|
* per-element instead of per-document — refused for the same reason that tag is. */
|
||||||
|
if (n === 'style') return refused;
|
||||||
|
if ((/(?:^|:)href$/).test(n)) {
|
||||||
|
/* off-router reference. A leading `//` is protocol-relative and just as external. */
|
||||||
|
if ((/^(?:[a-z][a-z0-9+.-]*:)?\/\//i).test(v)) return refused;
|
||||||
|
/* `data:`/`blob:`/`about:` can carry a second document (text/html, image/svg+xml)
|
||||||
|
* behind an href that looks like a same-document reference — see the comment above
|
||||||
|
* PAT_BAD_TAGS for why this is a blanket refusal and not a MIME-token check. */
|
||||||
|
if ((/^(?:data|blob|about):/i).test(v)) return refused;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
'require baseclass';
|
'require baseclass';
|
||||||
'require rpc';
|
'require rpc';
|
||||||
'require fs-prefs as prefs';
|
'require fs-prefs as prefs';
|
||||||
|
'require fs-fit as fit';
|
||||||
|
|
||||||
/* fs-axes — the nineteen Appearance axes and the Save-as-default machinery.
|
/* fs-axes — the nineteen Appearance axes and the Save-as-default machinery.
|
||||||
*
|
*
|
||||||
@@ -79,8 +80,14 @@ function colorAxis(key, attr, hueProp, colorProp) {
|
|||||||
* in how the number formats onto the property, which is the one varying argument. The prefs.sd() field
|
* in how the number formats onto the property, which is the one varying argument. The prefs.sd() field
|
||||||
* name is passed explicitly because one instance needs a rename rather than a spelling
|
* name is passed explicitly because one instance needs a rename rather than a spelling
|
||||||
* ('fs-radius' -> rounding), and a factory right for four keys out of five is the trap enumAxis and
|
* ('fs-radius' -> rounding), and a factory right for four keys out of five is the trap enumAxis and
|
||||||
* colorAxis name above. */
|
* colorAxis name above.
|
||||||
function propAxis(key, sdKey, prop, min, max, dfl, fmt) {
|
*
|
||||||
|
* `after`, like listAxis's, is optional and runs once the property is set: every propAxis instance
|
||||||
|
* but Content width only repaints a rule that reads the token, so none of the other five pass it.
|
||||||
|
* Content width moves --fs-content-max, which shellGeometry() (fs-chrome.js) reads to decide
|
||||||
|
* data-narrow, so its applier must re-run the fit or the chrome goes on deciding against the width
|
||||||
|
* the column had a moment ago. */
|
||||||
|
function propAxis(key, sdKey, prop, min, max, dfl, fmt, after) {
|
||||||
const inRange = (n) => (typeof n === 'number' && n >= min && n <= max);
|
const inRange = (n) => (typeof n === 'number' && n >= min && n <= max);
|
||||||
const def = () => { const d = prefs.sd(sdKey); return inRange(d) ? d : dfl; };
|
const def = () => { const d = prefs.sd(sdKey); return inRange(d) ? d : dfl; };
|
||||||
return {
|
return {
|
||||||
@@ -96,6 +103,7 @@ function propAxis(key, sdKey, prop, min, max, dfl, fmt) {
|
|||||||
prefs.lsSet(key, String(v));
|
prefs.lsSet(key, String(v));
|
||||||
if (v === dfl) root.style.removeProperty(prop);
|
if (v === dfl) root.style.removeProperty(prop);
|
||||||
else root.style.setProperty(prop, fmt(v));
|
else root.style.setProperty(prop, fmt(v));
|
||||||
|
if (after) after();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -111,7 +119,7 @@ function propAxis(key, sdKey, prop, min, max, dfl, fmt) {
|
|||||||
* Legacy names ('rvht'/'roman'/'github') are migrated by head.ut before paint, so they never reach
|
* Legacy names ('rvht'/'roman'/'github') are migrated by head.ut before paint, so they never reach
|
||||||
* currentPalette() on a loaded page; the stray fallthrough covers them anyway. */
|
* currentPalette() on a loaded page; the stray fallthrough covers them anyway. */
|
||||||
|
|
||||||
const PALETTES = [ 'hicontrast', 'bootstrap', '2020' ]; /* the non-default values; 'footstrap' = bare :root */
|
const PALETTES = [ 'hicontrast', 'bootstrap', '2020', 'forum' ]; /* the non-default values; 'footstrap' = bare :root */
|
||||||
const PALETTE = prefs.listAxis('fs-palette', 'data-palette', PALETTES, 'footstrap');
|
const PALETTE = prefs.listAxis('fs-palette', 'data-palette', PALETTES, 'footstrap');
|
||||||
const currentPalette = PALETTE.current, applyPalette = PALETTE.apply;
|
const currentPalette = PALETTE.current, applyPalette = PALETTE.apply;
|
||||||
|
|
||||||
@@ -209,6 +217,19 @@ const currentDanger = DANGER.current, applyDanger = DANGER.apply;
|
|||||||
const RADIUS = propAxis('fs-radius', 'rounding', '--fs-radius-base', 0, 20, FS_RADIUS_DEFAULT, (v) => (v + 'px'));
|
const RADIUS = propAxis('fs-radius', 'rounding', '--fs-radius-base', 0, 20, FS_RADIUS_DEFAULT, (v) => (v + 'px'));
|
||||||
const currentRadius = RADIUS.current, applyRadius = RADIUS.apply, radiusDefault = RADIUS.def;
|
const currentRadius = RADIUS.current, applyRadius = RADIUS.apply, radiusDefault = RADIUS.def;
|
||||||
|
|
||||||
|
/* Content width (issue #44): how far the reader lets the column grow past --fs-content-max's own
|
||||||
|
* 1280px. A propAxis like Rounding, pointed at that one token — the range comment lives in
|
||||||
|
* 02-tokens.css, next to the token it bounds, and is not restated here.
|
||||||
|
*
|
||||||
|
* The one propAxis instance that moves chrome geometry: shellGeometry() (fs-chrome.js) reads
|
||||||
|
* --fs-content-max on every fit, so dragging the slider must re-run it through the SAME
|
||||||
|
* fit.schedule() every other geometry-affecting axis calls, or the sidebar goes on folding at the
|
||||||
|
* width the column had before the drag. */
|
||||||
|
const FS_CWIDTH_DEFAULT = 1280;
|
||||||
|
const CWIDTH = propAxis('fs-content-width', 'content_width', '--fs-content-max', 1280, 3840,
|
||||||
|
FS_CWIDTH_DEFAULT, (v) => (v + 'px'), () => fit.schedule());
|
||||||
|
const currentContentWidth = CWIDTH.current, applyContentWidth = CWIDTH.apply, contentWidthDefault = CWIDTH.def;
|
||||||
|
|
||||||
/* Layout axis: horizontal top bar (the default) vs vertical sidebar. One template, one renderer —
|
/* Layout axis: horizontal top bar (the default) vs vertical sidebar. One template, one renderer —
|
||||||
* CSS morphs the chrome off :root[data-layout] and toggling re-renders nothing; menu-footstrap.js
|
* CSS morphs the chrome off :root[data-layout] and toggling re-renders nothing; menu-footstrap.js
|
||||||
* observes the attribute and folds the accordion into dropdowns or restores it.
|
* observes the attribute and folds the accordion into dropdowns or restores it.
|
||||||
@@ -222,7 +243,7 @@ const AXIS_KEYS = [
|
|||||||
'fs-accent', 'fs-good', 'fs-warn', 'fs-danger', 'fs-card', 'fs-control',
|
'fs-accent', 'fs-good', 'fs-warn', 'fs-danger', 'fs-card', 'fs-control',
|
||||||
'fs-bar', 'fs-line', 'fs-radius', 'fs-menu-autocollapse', 'fs-tint-strength',
|
'fs-bar', 'fs-line', 'fs-radius', 'fs-menu-autocollapse', 'fs-tint-strength',
|
||||||
'fs-density', 'fs-photo-dim', 'fs-pattern-size', 'fs-pattern-strength',
|
'fs-density', 'fs-photo-dim', 'fs-pattern-size', 'fs-pattern-strength',
|
||||||
'fs-pattern-ink'
|
'fs-pattern-ink', 'fs-content-width'
|
||||||
];
|
];
|
||||||
/* Tint strength: a multiplier on the tint chroma (03-palettes.css), 100% being the designed
|
/* Tint strength: a multiplier on the tint chroma (03-palettes.css), 100% being the designed
|
||||||
* strength and 200% the cap. 0 is not quite "no tint" — the relative colour that applies the tint
|
* strength and 200% the cap. 0 is not quite "no tint" — the relative colour that applies the tint
|
||||||
@@ -291,7 +312,8 @@ function snapshotAxes() {
|
|||||||
photo_dim: String(currentPhotoDim()),
|
photo_dim: String(currentPhotoDim()),
|
||||||
pattern_size: String(currentPatternSize()),
|
pattern_size: String(currentPatternSize()),
|
||||||
pattern_strength: String(currentPatternStrength()),
|
pattern_strength: String(currentPatternStrength()),
|
||||||
pattern_ink: currentPatternInk()
|
pattern_ink: currentPatternInk(),
|
||||||
|
content_width: String(currentContentWidth())
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
/* The resolved router default (the uci value if set, else the built-in) in snapshotAxes() string
|
/* The resolved router default (the uci value if set, else the built-in) in snapshotAxes() string
|
||||||
@@ -326,7 +348,8 @@ function _resolvedDefault() {
|
|||||||
photo_dim: String(photoDimDefault()),
|
photo_dim: String(photoDimDefault()),
|
||||||
pattern_size: String(patternSizeDefault()),
|
pattern_size: String(patternSizeDefault()),
|
||||||
pattern_strength: String(patternStrengthDefault()),
|
pattern_strength: String(patternStrengthDefault()),
|
||||||
pattern_ink: PINK.def()
|
pattern_ink: PINK.def(),
|
||||||
|
content_width: String(contentWidthDefault())
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
let _savedDefault = _resolvedDefault();
|
let _savedDefault = _resolvedDefault();
|
||||||
@@ -401,6 +424,7 @@ function resetToBuiltin() {
|
|||||||
applyPatternSize(FS_PSIZE_DEFAULT);
|
applyPatternSize(FS_PSIZE_DEFAULT);
|
||||||
applyPatternStrength(FS_PSTR_DEFAULT);
|
applyPatternStrength(FS_PSTR_DEFAULT);
|
||||||
applyPatternInk('theme');
|
applyPatternInk('theme');
|
||||||
|
applyContentWidth(FS_CWIDTH_DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---- the two uploaded wallpapers, browser side ----
|
/* ---- the two uploaded wallpapers, browser side ----
|
||||||
@@ -414,7 +438,12 @@ function resetToBuiltin() {
|
|||||||
* layer — one admin uploads once and every device sees it, pre-login included. So they are absent
|
* layer — one admin uploads once and every device sees it, pre-login included. So they are absent
|
||||||
|
|
||||||
* from AXIS_KEYS, snapshotAxes() and matchesSavedDefault(), and must not move the Save button. */
|
* from AXIS_KEYS, snapshotAxes() and matchesSavedDefault(), and must not move the Save button. */
|
||||||
const PAT_SERVE = '/luci-static/footstrap/pattern.svg'; /* the uhttpd symlink the uci-default makes */
|
/* NOT a /www symlink, unlike BG_SERVE below: an SVG served as a plain static file is a same-origin
|
||||||
|
* document that runs script opened directly (OpenWrt forum thread 251930). This CGI handler reads
|
||||||
|
* the fixed /etc/footstrap/pattern.svg path itself and answers with CSP 'none' + sandbox and
|
||||||
|
* nosniff, headers uhttpd cannot attach to a static file — see the uci-default and the handler for
|
||||||
|
* the rest of the reasoning. Painting stays exactly as before: a URL is a URL to a mask-image. */
|
||||||
|
const PAT_SERVE = '/cgi-bin/luci-theme-footstrap-pattern';
|
||||||
function currentPattern() {
|
function currentPattern() {
|
||||||
const t = prefs.sd('pattern');
|
const t = prefs.sd('pattern');
|
||||||
return (typeof t === 'string' && BG_TOKEN_RE.test(t)) ? t : '';
|
return (typeof t === 'string' && BG_TOKEN_RE.test(t)) ? t : '';
|
||||||
@@ -430,7 +459,10 @@ function applyPattern(tok) {
|
|||||||
prefs.setSD('pattern', tok || '');
|
prefs.setSD('pattern', tok || '');
|
||||||
}
|
}
|
||||||
|
|
||||||
const BG_SERVE = '/luci-static/footstrap/bg'; /* the uhttpd symlink the uci-default makes */
|
/* Still the plain uhttpd symlink the uci-default makes, unlike PAT_SERVE above: fs-assets.js
|
||||||
|
* re-encodes every login-bg upload to a JPEG on a canvas before it is sent, so the stored bytes
|
||||||
|
* are pixels only — there is no script grammar left in a raster for a direct hit to run. */
|
||||||
|
const BG_SERVE = '/luci-static/footstrap/bg';
|
||||||
/* the cache-bust token charset, an md5/sha hex string. One copy here; head.ut's ucode sanitiser
|
/* the cache-bust token charset, an md5/sha hex string. One copy here; head.ut's ucode sanitiser
|
||||||
* and the pre-paint inline script keep their own identical copies unavoidably, running before this
|
* and the pre-paint inline script keep their own identical copies unavoidably, running before this
|
||||||
* module — see the axes contract in head.ut. */
|
* module — see the axes contract in head.ut. */
|
||||||
@@ -473,6 +505,7 @@ return baseclass.extend({
|
|||||||
currentPatternSize, applyPatternSize,
|
currentPatternSize, applyPatternSize,
|
||||||
currentPatternStrength, applyPatternStrength,
|
currentPatternStrength, applyPatternStrength,
|
||||||
currentPatternInk, applyPatternInk,
|
currentPatternInk, applyPatternInk,
|
||||||
|
currentContentWidth, applyContentWidth, contentWidthDefault,
|
||||||
|
|
||||||
currentPattern, patternUrl, applyPattern,
|
currentPattern, patternUrl, applyPattern,
|
||||||
currentLoginBg, loginBgUrl, applyLoginBg,
|
currentLoginBg, loginBgUrl, applyLoginBg,
|
||||||
|
|||||||
@@ -134,13 +134,22 @@ function resolveLen(token, dflt) {
|
|||||||
* The defaults are stated once so the fallbacks and the sanity net below cannot restate the
|
* The defaults are stated once so the fallbacks and the sanity net below cannot restate the
|
||||||
* stylesheet's widths in two places. Reaching for them means the measurement failed. */
|
* stylesheet's widths in two places. Reaching for them means the measurement failed. */
|
||||||
const GEOM_DFLT = { contentMin: 500, sidebarW: 224, railW: 68, contentPad: 56, contentMax: 1280 };
|
const GEOM_DFLT = { contentMin: 500, sidebarW: 224, railW: 68, contentPad: 56, contentMax: 1280 };
|
||||||
|
/* the class name toggled below by fitShell's own escalation and by fitCluster's (measured: 16 B x3
|
||||||
|
* -> 25 B, 23 B saved) */
|
||||||
|
const CLASS_IND_COMPACT = 'fs-ind-compact';
|
||||||
|
|
||||||
let _geom = null, _geomDensity = null, _geomWarned = false;
|
let _geom = null, _geomDensity = null, _geomWarned = false;
|
||||||
function shellGeometry() {
|
function shellGeometry() {
|
||||||
const density = document.documentElement.getAttribute('data-density') || '';
|
const density = document.documentElement.getAttribute('data-density') || '';
|
||||||
|
/* contentMax moves with data-content-width (02-tokens.css), the other three widths do not, but
|
||||||
|
* they are one memo and the axis's own applier calls fit.schedule() same as Density's — folded
|
||||||
|
* into the same key rather than a second one, or a content-width change alone would hit the
|
||||||
|
* density-only key and go on answering the previous contentMax until density also changed */
|
||||||
|
const cwidth = document.documentElement.getAttribute('data-content-width') || '';
|
||||||
|
const key = density + '|' + cwidth;
|
||||||
/* the gutter is re-asked even on a memo hit: it moves with the width, not the density */
|
/* the gutter is re-asked even on a memo hit: it moves with the width, not the density */
|
||||||
if (_geom && _geomDensity === density) return _geom;
|
if (_geom && _geomDensity === key) return _geom;
|
||||||
_geomDensity = density;
|
_geomDensity = key;
|
||||||
const px = (name, dflt) => resolveLen(name, dflt);
|
const px = (name, dflt) => resolveLen(name, dflt);
|
||||||
const g = {
|
const g = {
|
||||||
contentMin: px('--fs-content-min', GEOM_DFLT.contentMin),
|
contentMin: px('--fs-content-min', GEOM_DFLT.contentMin),
|
||||||
@@ -277,7 +286,7 @@ function fitChrome() {
|
|||||||
const hadMinH = bar ? bar.style.minHeight : '';
|
const hadMinH = bar ? bar.style.minHeight : '';
|
||||||
if (pinned > 0) bar.style.minHeight = pinned + 'px';
|
if (pinned > 0) bar.style.minHeight = pinned + 'px';
|
||||||
|
|
||||||
if (bar) bar.classList.remove('fs-bar-stack', 'fs-ind-compact', 'fs-bar-actrow');
|
if (bar) bar.classList.remove('fs-bar-stack', CLASS_IND_COMPACT, 'fs-bar-actrow');
|
||||||
fitTabStrips();
|
fitTabStrips();
|
||||||
/* ---- does the main menu fit on the brand's row? ----
|
/* ---- does the main menu fit on the brand's row? ----
|
||||||
* It depends on how many sections THIS router has (stock 5, a loaded box 11), not on the
|
* It depends on how many sections THIS router has (stock 5, a loaded box 11), not on the
|
||||||
@@ -294,7 +303,7 @@ function fitChrome() {
|
|||||||
/* first step before stacking: collapse the poll pill (~90px) to an icon square and
|
/* first step before stacking: collapse the poll pill (~90px) to an icon square and
|
||||||
* re-measure — often enough to keep the menu on the brand's row
|
* re-measure — often enough to keep the menu on the brand's row
|
||||||
* (theme/50-toplayout.css) */
|
* (theme/50-toplayout.css) */
|
||||||
bar.classList.add('fs-ind-compact');
|
bar.classList.add(CLASS_IND_COMPACT);
|
||||||
fitTabStrips();
|
fitTabStrips();
|
||||||
if (!stripFitsOneRow(menu)) {
|
if (!stripFitsOneRow(menu)) {
|
||||||
bar.classList.add('fs-bar-stack');
|
bar.classList.add('fs-bar-stack');
|
||||||
@@ -345,7 +354,7 @@ function fitCluster(bar, menu) {
|
|||||||
if (clusterFitsBrandRow(bar, menu))
|
if (clusterFitsBrandRow(bar, menu))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bar.classList.add('fs-ind-compact');
|
bar.classList.add(CLASS_IND_COMPACT);
|
||||||
if (clusterFitsBrandRow(bar, menu))
|
if (clusterFitsBrandRow(bar, menu))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,8 @@
|
|||||||
/* section title -> grid role. _() with no msgctxt on purpose: these must resolve to exactly what
|
/* section title -> grid role. _() with no msgctxt on purpose: these must resolve to exactly what
|
||||||
* luci-mod-status resolves to, or the titles stop matching. Built once, not per poll tick. */
|
* luci-mod-status resolves to, or the titles stop matching. Built once, not per poll tick. */
|
||||||
const ROLES = { [_('System')]: 'sys', [_('Memory')]: 'mem', [_('Storage')]: 'sto' };
|
const ROLES = { [_('System')]: 'sys', [_('Memory')]: 'mem', [_('Storage')]: 'sto' };
|
||||||
|
/* the data-page value four call sites compare against; a string literal is not mangled, so a
|
||||||
|
* repeat is paid in full on flash every time (measured: 24 B x4 -> 37 B, 59 B saved) */
|
||||||
|
|
||||||
function sectionTitle(sec) {
|
function sectionTitle(sec) {
|
||||||
/* two title markups, one per release: 25.12 wraps the heading (`.cbi-title > h3`), 24.10 emits
|
/* two title markups, one per release: 25.12 wraps the heading (`.cbi-title > h3`), 24.10 emits
|
||||||
@@ -63,7 +65,9 @@ function arrange() {
|
|||||||
/* an SPA nav can leave the observer wired while another page renders into #view: detach as soon
|
/* an SPA nav can leave the observer wired while another page renders into #view: detach as soon
|
||||||
* as the route stops being the overview. body[data-page] carries the DISPATCH path from both
|
* as the route stops being the overview. body[data-page] carries the DISPATCH path from both
|
||||||
* the server template and the router, so /admin/status (firstchild -> overview) matches. */
|
* the server template and the router, so /admin/status (firstchild -> overview) matches. */
|
||||||
if ((document.body.getAttribute('data-page') || '') !== 'admin-status-overview') {
|
if ((document.body.getAttribute('data-page') || '') !== /* spelled out, not hoisted: tools/page-modules.mjs reads this value out of the module's
|
||||||
|
* SOURCE to check it against the map in menu-footstrap-common.js */
|
||||||
|
'admin-status-overview') {
|
||||||
stopWatch();
|
stopWatch();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,7 +80,13 @@ function currentMode() {
|
|||||||
* `data-darkmode` is the name the theme's own CSS keys off. The other two are outbound
|
* `data-darkmode` is the name the theme's own CSS keys off. The other two are outbound
|
||||||
* compatibility, like the `--*-color-*` export tier: nothing in `styles/` may read them, and
|
* compatibility, like the `--*-color-*` export tier: nothing in `styles/` may read them, and
|
||||||
* tools/axes.mjs fails the build if it does. */
|
* tools/axes.mjs fails the build if it does. */
|
||||||
|
/* the attribute name reused below by the writer, the guard's reader and both MutationObserver
|
||||||
|
* filters (measured: 15 B x4 -> 28 B, 32 B saved) */
|
||||||
function stampDark(root, dark) {
|
function stampDark(root, dark) {
|
||||||
|
/* the literal stays spelled out HERE: tools/axes.mjs reads the attribute names out of
|
||||||
|
* this function's SOURCE, so a hoisted const reads as no attribute at all and the gate
|
||||||
|
* reports the pre-paint and the live applier as drifted. The 45 B a const would save are
|
||||||
|
* not worth teaching a gate to resolve them. */
|
||||||
root.setAttribute('data-darkmode', dark ? 'true' : 'false');
|
root.setAttribute('data-darkmode', dark ? 'true' : 'false');
|
||||||
root.setAttribute('data-theme', dark ? 'dark' : 'light');
|
root.setAttribute('data-theme', dark ? 'dark' : 'light');
|
||||||
root.setAttribute('data-bs-theme', dark ? 'dark' : 'light');
|
root.setAttribute('data-bs-theme', dark ? 'dark' : 'light');
|
||||||
@@ -137,7 +143,7 @@ function guardDarkStamp() {
|
|||||||
check();
|
check();
|
||||||
new MutationObserver(check).observe(root, {
|
new MutationObserver(check).observe(root, {
|
||||||
attributes: true,
|
attributes: true,
|
||||||
attributeFilter: ['data-darkmode', 'data-theme', 'data-bs-theme']
|
attributeFilter: [ 'data-darkmode', 'data-theme', 'data-bs-theme' ]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
/* ---- the browser's own chrome follows the page ----
|
/* ---- the browser's own chrome follows the page ----
|
||||||
@@ -192,10 +198,10 @@ _mqDark.addEventListener('change', () => {
|
|||||||
|
|
||||||
/* ---- the four axis shapes, each written once ----
|
/* ---- the four axis shapes, each written once ----
|
||||||
*
|
*
|
||||||
* Fifteen axes are four shapes, so the shape lives in a factory and each instance is one line:
|
* Sixteen axes are four shapes, so the shape lives in a factory and each instance is one line:
|
||||||
* enumAxis (pattern ink), colorAxis (tint, accent, good, warn, danger), surfaceAxis (cards,
|
* enumAxis (pattern ink), colorAxis (tint, accent, good, warn, danger), surfaceAxis (cards,
|
||||||
* controls, bar, borders), propAxis (rounding, tint strength, photo dim, pattern size, pattern
|
* controls, bar, borders), propAxis (rounding, tint strength, photo dim, pattern size, pattern
|
||||||
* strength). Same contract throughout: `current()` is localStorage ?? def(), `def()` is the router
|
* strength, content width). Same contract throughout: `current()` is localStorage ?? def(), `def()` is the router
|
||||||
* default alone, `apply()` stores the choice explicitly. None use `this` — every export is a
|
* default alone, `apply()` stores the choice explicitly. None use `this` — every export is a
|
||||||
* detached method reference, so a `this` here would throw on the first call.
|
* detached method reference, so a `this` here would throw on the first call.
|
||||||
*
|
*
|
||||||
@@ -272,6 +278,11 @@ const DENSITIES = [ 'compact', 'large' ]; /* the two non-default values; 'normal
|
|||||||
const DENSITY = listAxis('fs-density', 'data-density', DENSITIES, 'normal', () => fit.schedule());
|
const DENSITY = listAxis('fs-density', 'data-density', DENSITIES, 'normal', () => fit.schedule());
|
||||||
const currentDensity = DENSITY.current, applyDensity = DENSITY.apply,
|
const currentDensity = DENSITY.current, applyDensity = DENSITY.apply,
|
||||||
densityDefault = DENSITY.def;
|
densityDefault = DENSITY.def;
|
||||||
|
|
||||||
|
/* Content width lives entirely in fs-axes.js now (a propAxis like Rounding, issue #44): unlike
|
||||||
|
* Density it sets no attribute, so nothing here or in fs-chrome.js needs to read one, and
|
||||||
|
* currentContentWidth()/applyContentWidth() have no caller outside the Appearance tab — the one
|
||||||
|
* thing that kept Density's shape in this cold-path file. */
|
||||||
/* Background-tint axis: the canvas the cards float on (--fs-bg), so a whole install reads as one
|
/* Background-tint axis: the canvas the cards float on (--fs-bg), so a whole install reads as one
|
||||||
* colour and a tab or a screenshot says which router it belongs to. Cards, chrome and the status
|
* colour and a tab or a screenshot says which router it belongs to. Cards, chrome and the status
|
||||||
* colours keep the palette's values — the cue colours the paper, not the UI. On a hue it is mixed
|
* colours keep the palette's values — the cue colours the paper, not the UI. On a hue it is mixed
|
||||||
|
|||||||
@@ -219,12 +219,18 @@ function build() {
|
|||||||
const btn = document.getElementById('fs-search-btn');
|
const btn = document.getElementById('fs-search-btn');
|
||||||
if (!btn) return null;
|
if (!btn) return null;
|
||||||
|
|
||||||
|
/* the list's id, said three times below as an id, a class and aria-controls (measured: 17 B x3
|
||||||
|
* -> 26 B, 25 B saved) */
|
||||||
|
const ID_SEARCH_LIST = 'fs-search-list';
|
||||||
|
/* the attribute name toggled below and stated once more as its own starting value (measured:
|
||||||
|
* 15 B x3 -> 27 B, 18 B saved) */
|
||||||
|
const ATTR_EXPANDED = 'aria-expanded';
|
||||||
const input = E('input', {
|
const input = E('input', {
|
||||||
'type': 'text',
|
'type': 'text',
|
||||||
'class': 'fs-search-input',
|
'class': 'fs-search-input',
|
||||||
'role': 'combobox',
|
'role': 'combobox',
|
||||||
'aria-controls': 'fs-search-list',
|
'aria-controls': ID_SEARCH_LIST,
|
||||||
'aria-expanded': 'true',
|
[ATTR_EXPANDED]: 'true',
|
||||||
'aria-autocomplete': 'list',
|
'aria-autocomplete': 'list',
|
||||||
'aria-label': _('Search pages', 'footstrap'),
|
'aria-label': _('Search pages', 'footstrap'),
|
||||||
'placeholder': _('Search pages…', 'footstrap'),
|
'placeholder': _('Search pages…', 'footstrap'),
|
||||||
@@ -232,7 +238,7 @@ function build() {
|
|||||||
'autocapitalize': 'off',
|
'autocapitalize': 'off',
|
||||||
'spellcheck': 'false'
|
'spellcheck': 'false'
|
||||||
});
|
});
|
||||||
const list = E('div', { 'id': 'fs-search-list', 'class': 'fs-search-list', 'role': 'listbox', 'aria-label': _('Pages', 'footstrap') });
|
const list = E('div', { 'id': ID_SEARCH_LIST, 'class': ID_SEARCH_LIST, 'role': 'listbox', 'aria-label': _('Pages', 'footstrap') });
|
||||||
const note = E('div', { 'class': 'fs-search-note' });
|
const note = E('div', { 'class': 'fs-search-note' });
|
||||||
const ico = E('span', { 'class': 'fs-search-ico' });
|
const ico = E('span', { 'class': 'fs-search-ico' });
|
||||||
ico.innerHTML = widgets.svgIcon('<circle cx="11" cy="11" r="7"/><path d="M16.5 16.5 21 21"/>');
|
ico.innerHTML = widgets.svgIcon('<circle cx="11" cy="11" r="7"/><path d="M16.5 16.5 21 21"/>');
|
||||||
@@ -329,7 +335,7 @@ function build() {
|
|||||||
function open() {
|
function open() {
|
||||||
if (!ov.hidden) return;
|
if (!ov.hidden) return;
|
||||||
ov.hidden = false;
|
ov.hidden = false;
|
||||||
btn.setAttribute('aria-expanded', 'true');
|
btn.setAttribute(ATTR_EXPANDED, 'true');
|
||||||
input.value = '';
|
input.value = '';
|
||||||
render('');
|
render('');
|
||||||
input.focus();
|
input.focus();
|
||||||
@@ -338,7 +344,7 @@ function build() {
|
|||||||
function close(returnFocus = true) {
|
function close(returnFocus = true) {
|
||||||
if (ov.hidden) return;
|
if (ov.hidden) return;
|
||||||
ov.hidden = true;
|
ov.hidden = true;
|
||||||
btn.setAttribute('aria-expanded', 'false');
|
btn.setAttribute(ATTR_EXPANDED, 'false');
|
||||||
if (returnFocus) btn.focus();
|
if (returnFocus) btn.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,12 +11,12 @@ msgstr ""
|
|||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Generator: Poedit 3.9\n"
|
"X-Generator: Poedit 3.9\n"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:401
|
#: htdocs/luci-static/resources/fs-appearance.js:414
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Accent"
|
msgid "Accent"
|
||||||
msgstr "Acento"
|
msgstr "Acento"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:481
|
#: htdocs/luci-static/resources/fs-appearance.js:494
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "As in file"
|
msgid "As in file"
|
||||||
msgstr "Como en el archivo"
|
msgstr "Como en el archivo"
|
||||||
@@ -30,12 +30,12 @@ msgctxt "footstrap"
|
|||||||
msgid "Auto"
|
msgid "Auto"
|
||||||
msgstr "Auto"
|
msgstr "Auto"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:365
|
#: htdocs/luci-static/resources/fs-appearance.js:378
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Auto-collapse"
|
msgid "Auto-collapse"
|
||||||
msgstr "Colapso automático"
|
msgstr "Colapso automático"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:806
|
#: htdocs/luci-static/resources/fs-appearance.js:819
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Background"
|
msgid "Background"
|
||||||
msgstr "Fondo"
|
msgstr "Fondo"
|
||||||
@@ -45,22 +45,22 @@ msgctxt "footstrap"
|
|||||||
msgid "Barely visible %s"
|
msgid "Barely visible %s"
|
||||||
msgstr "Apenas visible %s"
|
msgstr "Apenas visible %s"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:424
|
#: htdocs/luci-static/resources/fs-appearance.js:437
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Borders"
|
msgid "Borders"
|
||||||
msgstr "Bordes"
|
msgstr "Bordes"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:421
|
#: htdocs/luci-static/resources/fs-appearance.js:434
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Cards"
|
msgid "Cards"
|
||||||
msgstr "Tarjetas"
|
msgstr "Tarjetas"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:454
|
#: htdocs/luci-static/resources/fs-appearance.js:467
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Choose SVG"
|
msgid "Choose SVG"
|
||||||
msgstr "Elegir SVG"
|
msgstr "Elegir SVG"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:447
|
#: htdocs/luci-static/resources/fs-appearance.js:460
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Choose image"
|
msgid "Choose image"
|
||||||
msgstr "Elegir imagen"
|
msgstr "Elegir imagen"
|
||||||
@@ -70,33 +70,38 @@ msgctxt "footstrap"
|
|||||||
msgid "Clearly visible %s"
|
msgid "Clearly visible %s"
|
||||||
msgstr "Bien visible %s"
|
msgstr "Bien visible %s"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-chrome.js:447
|
#: htdocs/luci-static/resources/fs-chrome.js:453
|
||||||
#: ucode/template/themes/footstrap/header.ut:138
|
#: ucode/template/themes/footstrap/header.ut:138
|
||||||
msgid "Collapse menu"
|
msgid "Collapse menu"
|
||||||
msgstr "Contraer menú"
|
msgstr "Contraer menú"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:465
|
#: htdocs/luci-static/resources/fs-appearance.js:478
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:803
|
#: htdocs/luci-static/resources/fs-appearance.js:816
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Colours"
|
msgid "Colours"
|
||||||
msgstr "Colores"
|
msgstr "Colores"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:350
|
#: htdocs/luci-static/resources/fs-appearance.js:353
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
msgstr "Compacto"
|
msgstr "Compacto"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:648
|
#: htdocs/luci-static/resources/fs-appearance.js:661
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Confirm reset"
|
msgid "Confirm reset"
|
||||||
msgstr "Confirmar restablecimiento"
|
msgstr "Confirmar restablecimiento"
|
||||||
|
|
||||||
|
#: htdocs/luci-static/resources/fs-appearance.js:364
|
||||||
|
msgctxt "footstrap"
|
||||||
|
msgid "Content width"
|
||||||
|
msgstr "Ancho del contenido"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:193
|
#: htdocs/luci-static/resources/fs-appearance.js:193
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Contrast %s:1 (WCAG AA wants %s:1 here)"
|
msgid "Contrast %s:1 (WCAG AA wants %s:1 here)"
|
||||||
msgstr "Contraste %s:1 (WCAG AA exige aquí %s:1)"
|
msgstr "Contraste %s:1 (WCAG AA exige aquí %s:1)"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:422
|
#: htdocs/luci-static/resources/fs-appearance.js:435
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Controls"
|
msgid "Controls"
|
||||||
msgstr "Controles"
|
msgstr "Controles"
|
||||||
@@ -106,14 +111,14 @@ msgctxt "footstrap"
|
|||||||
msgid "Could not process the image."
|
msgid "Could not process the image."
|
||||||
msgstr "No se pudo procesar la imagen."
|
msgstr "No se pudo procesar la imagen."
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:628
|
#: htdocs/luci-static/resources/fs-appearance.js:641
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Could not save the default. Reload the page and try again."
|
msgid "Could not save the default. Reload the page and try again."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"No se pudo guardar la configuración predeterminada. Recargue la página e "
|
"No se pudo guardar la configuración predeterminada. Recargue la página e "
|
||||||
"inténtelo de nuevo."
|
"inténtelo de nuevo."
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:404
|
#: htdocs/luci-static/resources/fs-appearance.js:417
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Danger"
|
msgid "Danger"
|
||||||
msgstr "Peligro"
|
msgstr "Peligro"
|
||||||
@@ -123,12 +128,12 @@ msgctxt "footstrap"
|
|||||||
msgid "Dark"
|
msgid "Dark"
|
||||||
msgstr "Oscuro"
|
msgstr "Oscuro"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:349
|
#: htdocs/luci-static/resources/fs-appearance.js:352
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Density"
|
msgid "Density"
|
||||||
msgstr "Densidad"
|
msgstr "Densidad"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:462
|
#: htdocs/luci-static/resources/fs-appearance.js:475
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Dim"
|
msgid "Dim"
|
||||||
msgstr "Oscurecimiento"
|
msgstr "Oscurecimiento"
|
||||||
@@ -138,12 +143,12 @@ msgctxt "footstrap"
|
|||||||
msgid "Easy to read %s"
|
msgid "Easy to read %s"
|
||||||
msgstr "Se lee bien %s"
|
msgstr "Se lee bien %s"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-chrome.js:447
|
#: htdocs/luci-static/resources/fs-chrome.js:453
|
||||||
msgid "Expand menu"
|
msgid "Expand menu"
|
||||||
msgstr "Expandir menú"
|
msgstr "Expandir menú"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:486
|
#: htdocs/luci-static/resources/fs-appearance.js:499
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:564
|
#: htdocs/luci-static/resources/fs-appearance.js:577
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "File"
|
msgid "File"
|
||||||
msgstr "Archivo"
|
msgstr "Archivo"
|
||||||
@@ -153,10 +158,10 @@ msgid ""
|
|||||||
"Footstrap Appearance router-wide look (Save to router) and the login "
|
"Footstrap Appearance router-wide look (Save to router) and the login "
|
||||||
"background and pattern uploads"
|
"background and pattern uploads"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Aspecto de Footstrap para todo el router («Guardar en el router») y subida de "
|
"Aspecto de Footstrap para todo el router («Guardar en el router») y subida "
|
||||||
"la imagen de fondo y del patrón"
|
"de la imagen de fondo y del patrón"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:794
|
#: htdocs/luci-static/resources/fs-appearance.js:807
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid ""
|
msgid ""
|
||||||
"Footstrap theme settings apply at once and are stored permanently in this "
|
"Footstrap theme settings apply at once and are stored permanently in this "
|
||||||
@@ -173,7 +178,7 @@ msgstr "Ir a la actualización del firmware..."
|
|||||||
msgid "Go to password configuration..."
|
msgid "Go to password configuration..."
|
||||||
msgstr "Ir a la configuración de contraseñas..."
|
msgstr "Ir a la configuración de contraseñas..."
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:402
|
#: htdocs/luci-static/resources/fs-appearance.js:415
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Good"
|
msgid "Good"
|
||||||
msgstr "Correcto"
|
msgstr "Correcto"
|
||||||
@@ -183,7 +188,7 @@ msgctxt "footstrap"
|
|||||||
msgid "Hard to read %s — large text only"
|
msgid "Hard to read %s — large text only"
|
||||||
msgstr "Se lee mal %s: solo texto grande"
|
msgstr "Se lee mal %s: solo texto grande"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:802
|
#: htdocs/luci-static/resources/fs-appearance.js:815
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Interface"
|
msgid "Interface"
|
||||||
msgstr "Interfaz"
|
msgstr "Interfaz"
|
||||||
@@ -196,18 +201,18 @@ msgstr "¡Nombre de usuario y/o contraseña incorrectos! Inténtelo de nuevo."
|
|||||||
msgid "JavaScript required!"
|
msgid "JavaScript required!"
|
||||||
msgstr "¡Se requiere JavaScript!"
|
msgstr "¡Se requiere JavaScript!"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:364
|
#: htdocs/luci-static/resources/fs-appearance.js:377
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Keep open"
|
msgid "Keep open"
|
||||||
msgstr "Mantener abierto"
|
msgstr "Mantener abierto"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:352
|
#: htdocs/luci-static/resources/fs-appearance.js:355
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Large"
|
msgid "Large"
|
||||||
msgstr "Grande"
|
msgstr "Grande"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:328
|
#: htdocs/luci-static/resources/fs-appearance.js:328
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:723
|
#: htdocs/luci-static/resources/fs-appearance.js:736
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Layout"
|
msgid "Layout"
|
||||||
msgstr "Diseño"
|
msgstr "Diseño"
|
||||||
@@ -257,12 +262,12 @@ msgstr "No se encontraron páginas"
|
|||||||
msgid "No password set!"
|
msgid "No password set!"
|
||||||
msgstr "¡No se ha establecido ninguna contraseña!"
|
msgstr "¡No se ha establecido ninguna contraseña!"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:351
|
#: htdocs/luci-static/resources/fs-appearance.js:354
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Normal"
|
msgid "Normal"
|
||||||
msgstr "Normal"
|
msgstr "Normal"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:562
|
#: htdocs/luci-static/resources/fs-appearance.js:575
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Off"
|
msgid "Off"
|
||||||
msgstr "Apagado"
|
msgstr "Apagado"
|
||||||
@@ -282,8 +287,8 @@ msgstr "Paleta"
|
|||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr "Contraseña"
|
msgstr "Contraseña"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:472
|
#: htdocs/luci-static/resources/fs-appearance.js:485
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:563
|
#: htdocs/luci-static/resources/fs-appearance.js:576
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Pattern"
|
msgid "Pattern"
|
||||||
msgstr "Patrón"
|
msgstr "Patrón"
|
||||||
@@ -307,44 +312,44 @@ msgctxt "footstrap"
|
|||||||
msgid "Recently visited"
|
msgid "Recently visited"
|
||||||
msgstr "Visitado recientemente"
|
msgstr "Visitado recientemente"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:449
|
#: htdocs/luci-static/resources/fs-appearance.js:462
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:456
|
#: htdocs/luci-static/resources/fs-appearance.js:469
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Remove"
|
msgid "Remove"
|
||||||
msgstr "Eliminar"
|
msgstr "Eliminar"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:592
|
#: htdocs/luci-static/resources/fs-appearance.js:605
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:659
|
#: htdocs/luci-static/resources/fs-appearance.js:672
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Reset to built-in"
|
msgid "Reset to built-in"
|
||||||
msgstr "Restablecer al integrado"
|
msgstr "Restablecer al integrado"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:687
|
#: htdocs/luci-static/resources/fs-appearance.js:700
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Reset to built-in — go back to the look the theme ships with."
|
msgid "Reset to built-in — go back to the look the theme ships with."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"«Restablecer al integrado»: vuelve al aspecto con el que se distribuye el "
|
"«Restablecer al integrado»: vuelve al aspecto con el que se distribuye el "
|
||||||
"tema."
|
"tema."
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:588
|
#: htdocs/luci-static/resources/fs-appearance.js:601
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:658
|
#: htdocs/luci-static/resources/fs-appearance.js:671
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Reset to router"
|
msgid "Reset to router"
|
||||||
msgstr "Restablecer al del router"
|
msgstr "Restablecer al del router"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:685
|
#: htdocs/luci-static/resources/fs-appearance.js:698
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Reset to router — drop this browser's changes and follow the router."
|
msgid "Reset to router — drop this browser's changes and follow the router."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"«Restablecer al del router»: descarta los cambios de este navegador y sigue "
|
"«Restablecer al del router»: descarta los cambios de este navegador y sigue "
|
||||||
"al router."
|
"al router."
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:355
|
#: htdocs/luci-static/resources/fs-appearance.js:368
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Rounding"
|
msgid "Rounding"
|
||||||
msgstr "Redondeo"
|
msgstr "Redondeo"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:795
|
#: htdocs/luci-static/resources/fs-appearance.js:808
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid ""
|
msgid ""
|
||||||
"Save & Apply at the foot of the page belongs to the System form and does not "
|
"Save & Apply at the foot of the page belongs to the System form and does not "
|
||||||
@@ -353,38 +358,38 @@ msgstr ""
|
|||||||
"El botón «Guardar y aplicar» al pie de la página pertenece al formulario del "
|
"El botón «Guardar y aplicar» al pie de la página pertenece al formulario del "
|
||||||
"Sistema y no los guarda."
|
"Sistema y no los guarda."
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:578
|
#: htdocs/luci-static/resources/fs-appearance.js:591
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:610
|
#: htdocs/luci-static/resources/fs-appearance.js:623
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:617
|
#: htdocs/luci-static/resources/fs-appearance.js:630
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Save to router"
|
msgid "Save to router"
|
||||||
msgstr "Guardar en el router"
|
msgstr "Guardar en el router"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:683
|
#: htdocs/luci-static/resources/fs-appearance.js:696
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid ""
|
msgid ""
|
||||||
"Save to router — store this look on the router. Browsers with a look of "
|
"Save to router — store this look on the router. Browsers with a look of "
|
||||||
"their own keep it."
|
"their own keep it."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"«Guardar en el router»: guarda este aspecto en el router. Los navegadores con "
|
"«Guardar en el router»: guarda este aspecto en el router. Los navegadores "
|
||||||
"un aspecto propio lo conservan."
|
"con un aspecto propio lo conservan."
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:693
|
#: htdocs/luci-static/resources/fs-appearance.js:706
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Saved look"
|
msgid "Saved look"
|
||||||
msgstr "Aspecto guardado"
|
msgstr "Aspecto guardado"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:617
|
#: htdocs/luci-static/resources/fs-appearance.js:630
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Saved to router"
|
msgid "Saved to router"
|
||||||
msgstr "Guardado en el router"
|
msgstr "Guardado en el router"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:807
|
#: htdocs/luci-static/resources/fs-appearance.js:820
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Saving"
|
msgid "Saving"
|
||||||
msgstr "Guardado"
|
msgstr "Guardado"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:463
|
#: htdocs/luci-static/resources/fs-appearance.js:476
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Scale"
|
msgid "Scale"
|
||||||
msgstr "Escala"
|
msgstr "Escala"
|
||||||
@@ -410,7 +415,7 @@ msgctxt "footstrap"
|
|||||||
msgid "Sidebar"
|
msgid "Sidebar"
|
||||||
msgstr "Barra lateral"
|
msgstr "Barra lateral"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:423
|
#: htdocs/luci-static/resources/fs-appearance.js:436
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Sidebar and bar"
|
msgid "Sidebar and bar"
|
||||||
msgstr "Barra lateral y superior"
|
msgstr "Barra lateral y superior"
|
||||||
@@ -428,17 +433,17 @@ msgstr "Empiece a escribir para encontrar una página"
|
|||||||
msgid "Storage"
|
msgid "Storage"
|
||||||
msgstr "Almacenamiento"
|
msgstr "Almacenamiento"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:464
|
#: htdocs/luci-static/resources/fs-appearance.js:477
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Strength"
|
msgid "Strength"
|
||||||
msgstr "Intensidad"
|
msgstr "Intensidad"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:362
|
#: htdocs/luci-static/resources/fs-appearance.js:375
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Submenus"
|
msgid "Submenus"
|
||||||
msgstr "Submenús"
|
msgstr "Submenús"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:804
|
#: htdocs/luci-static/resources/fs-appearance.js:817
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Surfaces"
|
msgid "Surfaces"
|
||||||
msgstr "Superficies"
|
msgstr "Superficies"
|
||||||
@@ -494,7 +499,7 @@ msgid "The router refused to delete the file (ubus status %d)."
|
|||||||
msgstr "El router se negó a eliminar el archivo (estado ubus %d)."
|
msgstr "El router se negó a eliminar el archivo (estado ubus %d)."
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:333
|
#: htdocs/luci-static/resources/fs-appearance.js:333
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:480
|
#: htdocs/luci-static/resources/fs-appearance.js:493
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Theme"
|
msgid "Theme"
|
||||||
msgstr "Tema"
|
msgstr "Tema"
|
||||||
@@ -507,7 +512,7 @@ msgstr ""
|
|||||||
"Este enrutador no tiene contraseña. Configure una contraseña de "
|
"Este enrutador no tiene contraseña. Configure una contraseña de "
|
||||||
"administrador para proteger la interfaz web."
|
"administrador para proteger la interfaz web."
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:611
|
#: htdocs/luci-static/resources/fs-appearance.js:624
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid ""
|
msgid ""
|
||||||
"This browser is not storing preferences (site data is blocked), so a change "
|
"This browser is not storing preferences (site data is blocked), so a change "
|
||||||
@@ -518,17 +523,17 @@ msgstr ""
|
|||||||
"bloqueados), así que un cambio aquí dura hasta que recargues. Guardar como "
|
"bloqueados), así que un cambio aquí dura hasta que recargues. Guardar como "
|
||||||
"predeterminado sigue funcionando y se aplica a todos los navegadores."
|
"predeterminado sigue funcionando y se aplica a todos los navegadores."
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:725
|
#: htdocs/luci-static/resources/fs-appearance.js:738
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "This theme is not translated on this router yet."
|
msgid "This theme is not translated on this router yet."
|
||||||
msgstr "Este tema aún no está traducido en este router."
|
msgstr "Este tema aún no está traducido en este router."
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:374
|
#: htdocs/luci-static/resources/fs-appearance.js:387
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Tint (router identification)"
|
msgid "Tint (router identification)"
|
||||||
msgstr "Tinte (identificación del enrutador)"
|
msgstr "Tinte (identificación del enrutador)"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:387
|
#: htdocs/luci-static/resources/fs-appearance.js:400
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Tint strength"
|
msgid "Tint strength"
|
||||||
msgstr "Intensidad del tinte"
|
msgstr "Intensidad del tinte"
|
||||||
@@ -548,7 +553,7 @@ msgctxt "footstrap"
|
|||||||
msgid "Upload failed."
|
msgid "Upload failed."
|
||||||
msgstr "Error al cargar el archivo."
|
msgstr "Error al cargar el archivo."
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:531
|
#: htdocs/luci-static/resources/fs-appearance.js:544
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Uploading…"
|
msgid "Uploading…"
|
||||||
msgstr "Cargando…"
|
msgstr "Cargando…"
|
||||||
@@ -557,12 +562,12 @@ msgstr "Cargando…"
|
|||||||
msgid "Username"
|
msgid "Username"
|
||||||
msgstr "Nombre de usuario"
|
msgstr "Nombre de usuario"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:560
|
#: htdocs/luci-static/resources/fs-appearance.js:573
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Wallpaper"
|
msgid "Wallpaper"
|
||||||
msgstr "Fondo de pantalla"
|
msgstr "Fondo de pantalla"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:403
|
#: htdocs/luci-static/resources/fs-appearance.js:416
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Warning"
|
msgid "Warning"
|
||||||
msgstr "Advertencia"
|
msgstr "Advertencia"
|
||||||
@@ -573,7 +578,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Debe activar JavaScript en su navegador o LuCI no funcionará correctamente."
|
"Debe activar JavaScript en su navegador o LuCI no funcionará correctamente."
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:423
|
#: htdocs/luci-static/resources/fs-appearance.js:436
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "in the sidebar"
|
msgid "in the sidebar"
|
||||||
msgstr "en la barra lateral"
|
msgstr "en la barra lateral"
|
||||||
@@ -583,12 +588,12 @@ msgctxt "footstrap"
|
|||||||
msgid "on a card"
|
msgid "on a card"
|
||||||
msgstr "en una tarjeta"
|
msgstr "en una tarjeta"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:422
|
#: htdocs/luci-static/resources/fs-appearance.js:435
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "on a control"
|
msgid "on a control"
|
||||||
msgstr "en un control"
|
msgstr "en un control"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:379
|
#: htdocs/luci-static/resources/fs-appearance.js:392
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "on the canvas"
|
msgid "on the canvas"
|
||||||
msgstr "en el lienzo"
|
msgstr "en el lienzo"
|
||||||
@@ -599,6 +604,14 @@ msgid ""
|
|||||||
"the uploaded file could not be removed either; it is still on the router."
|
"the uploaded file could not be removed either; it is still on the router."
|
||||||
msgstr "tampoco se pudo eliminar el archivo subido; sigue en el router."
|
msgstr "tampoco se pudo eliminar el archivo subido; sigue en el router."
|
||||||
|
|
||||||
|
#~ msgctxt "footstrap"
|
||||||
|
#~ msgid "Full"
|
||||||
|
#~ msgstr "Completa"
|
||||||
|
|
||||||
|
#~ msgctxt "footstrap"
|
||||||
|
#~ msgid "Wide"
|
||||||
|
#~ msgstr "Ancha"
|
||||||
|
|
||||||
#~ msgctxt "footstrap"
|
#~ msgctxt "footstrap"
|
||||||
#~ msgid "Defaults"
|
#~ msgid "Defaults"
|
||||||
#~ msgstr "Predeterminados"
|
#~ msgstr "Predeterminados"
|
||||||
|
|||||||
@@ -7,12 +7,12 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
|
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
|
||||||
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
|
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:401
|
#: htdocs/luci-static/resources/fs-appearance.js:414
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Accent"
|
msgid "Accent"
|
||||||
msgstr "Акцент"
|
msgstr "Акцент"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:481
|
#: htdocs/luci-static/resources/fs-appearance.js:494
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "As in file"
|
msgid "As in file"
|
||||||
msgstr "Как в файле"
|
msgstr "Как в файле"
|
||||||
@@ -26,12 +26,12 @@ msgctxt "footstrap"
|
|||||||
msgid "Auto"
|
msgid "Auto"
|
||||||
msgstr "Авто"
|
msgstr "Авто"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:365
|
#: htdocs/luci-static/resources/fs-appearance.js:378
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Auto-collapse"
|
msgid "Auto-collapse"
|
||||||
msgstr "Сворачивать"
|
msgstr "Сворачивать"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:806
|
#: htdocs/luci-static/resources/fs-appearance.js:819
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Background"
|
msgid "Background"
|
||||||
msgstr "Фон"
|
msgstr "Фон"
|
||||||
@@ -41,22 +41,22 @@ msgctxt "footstrap"
|
|||||||
msgid "Barely visible %s"
|
msgid "Barely visible %s"
|
||||||
msgstr "Едва заметна %s"
|
msgstr "Едва заметна %s"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:424
|
#: htdocs/luci-static/resources/fs-appearance.js:437
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Borders"
|
msgid "Borders"
|
||||||
msgstr "Границы"
|
msgstr "Границы"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:421
|
#: htdocs/luci-static/resources/fs-appearance.js:434
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Cards"
|
msgid "Cards"
|
||||||
msgstr "Карточки"
|
msgstr "Карточки"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:454
|
#: htdocs/luci-static/resources/fs-appearance.js:467
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Choose SVG"
|
msgid "Choose SVG"
|
||||||
msgstr "Выбрать SVG"
|
msgstr "Выбрать SVG"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:447
|
#: htdocs/luci-static/resources/fs-appearance.js:460
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Choose image"
|
msgid "Choose image"
|
||||||
msgstr "Выбрать изображение"
|
msgstr "Выбрать изображение"
|
||||||
@@ -66,33 +66,38 @@ msgctxt "footstrap"
|
|||||||
msgid "Clearly visible %s"
|
msgid "Clearly visible %s"
|
||||||
msgstr "Хорошо видна %s"
|
msgstr "Хорошо видна %s"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-chrome.js:447
|
#: htdocs/luci-static/resources/fs-chrome.js:453
|
||||||
#: ucode/template/themes/footstrap/header.ut:138
|
#: ucode/template/themes/footstrap/header.ut:138
|
||||||
msgid "Collapse menu"
|
msgid "Collapse menu"
|
||||||
msgstr "Свернуть меню"
|
msgstr "Свернуть меню"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:465
|
#: htdocs/luci-static/resources/fs-appearance.js:478
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:803
|
#: htdocs/luci-static/resources/fs-appearance.js:816
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Colours"
|
msgid "Colours"
|
||||||
msgstr "Цвета"
|
msgstr "Цвета"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:350
|
#: htdocs/luci-static/resources/fs-appearance.js:353
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
msgstr "Компактно"
|
msgstr "Компактно"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:648
|
#: htdocs/luci-static/resources/fs-appearance.js:661
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Confirm reset"
|
msgid "Confirm reset"
|
||||||
msgstr "Подтвердить сброс"
|
msgstr "Подтвердить сброс"
|
||||||
|
|
||||||
|
#: htdocs/luci-static/resources/fs-appearance.js:364
|
||||||
|
msgctxt "footstrap"
|
||||||
|
msgid "Content width"
|
||||||
|
msgstr "Ширина контента"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:193
|
#: htdocs/luci-static/resources/fs-appearance.js:193
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Contrast %s:1 (WCAG AA wants %s:1 here)"
|
msgid "Contrast %s:1 (WCAG AA wants %s:1 here)"
|
||||||
msgstr "Контраст %s:1 (WCAG AA требует здесь %s:1)"
|
msgstr "Контраст %s:1 (WCAG AA требует здесь %s:1)"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:422
|
#: htdocs/luci-static/resources/fs-appearance.js:435
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Controls"
|
msgid "Controls"
|
||||||
msgstr "Элементы форм"
|
msgstr "Элементы форм"
|
||||||
@@ -102,12 +107,12 @@ msgctxt "footstrap"
|
|||||||
msgid "Could not process the image."
|
msgid "Could not process the image."
|
||||||
msgstr "Не удалось обработать изображение."
|
msgstr "Не удалось обработать изображение."
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:628
|
#: htdocs/luci-static/resources/fs-appearance.js:641
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Could not save the default. Reload the page and try again."
|
msgid "Could not save the default. Reload the page and try again."
|
||||||
msgstr "Не удалось сохранить умолчание. Обновите страницу и повторите."
|
msgstr "Не удалось сохранить умолчание. Обновите страницу и повторите."
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:404
|
#: htdocs/luci-static/resources/fs-appearance.js:417
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Danger"
|
msgid "Danger"
|
||||||
msgstr "Опасность"
|
msgstr "Опасность"
|
||||||
@@ -117,12 +122,12 @@ msgctxt "footstrap"
|
|||||||
msgid "Dark"
|
msgid "Dark"
|
||||||
msgstr "Тёмная"
|
msgstr "Тёмная"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:349
|
#: htdocs/luci-static/resources/fs-appearance.js:352
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Density"
|
msgid "Density"
|
||||||
msgstr "Плотность"
|
msgstr "Плотность"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:462
|
#: htdocs/luci-static/resources/fs-appearance.js:475
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Dim"
|
msgid "Dim"
|
||||||
msgstr "Затемнение"
|
msgstr "Затемнение"
|
||||||
@@ -132,12 +137,12 @@ msgctxt "footstrap"
|
|||||||
msgid "Easy to read %s"
|
msgid "Easy to read %s"
|
||||||
msgstr "Хорошо читается %s"
|
msgstr "Хорошо читается %s"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-chrome.js:447
|
#: htdocs/luci-static/resources/fs-chrome.js:453
|
||||||
msgid "Expand menu"
|
msgid "Expand menu"
|
||||||
msgstr "Развернуть меню"
|
msgstr "Развернуть меню"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:486
|
#: htdocs/luci-static/resources/fs-appearance.js:499
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:564
|
#: htdocs/luci-static/resources/fs-appearance.js:577
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "File"
|
msgid "File"
|
||||||
msgstr "Файл"
|
msgstr "Файл"
|
||||||
@@ -150,7 +155,7 @@ msgstr ""
|
|||||||
"Общий для роутера вид Footstrap («Сохранить на роутер»), а также загрузка "
|
"Общий для роутера вид Footstrap («Сохранить на роутер»), а также загрузка "
|
||||||
"фонового изображения и узора"
|
"фонового изображения и узора"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:794
|
#: htdocs/luci-static/resources/fs-appearance.js:807
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid ""
|
msgid ""
|
||||||
"Footstrap theme settings apply at once and are stored permanently in this "
|
"Footstrap theme settings apply at once and are stored permanently in this "
|
||||||
@@ -167,7 +172,7 @@ msgstr "Перейти к обновлению прошивки..."
|
|||||||
msgid "Go to password configuration..."
|
msgid "Go to password configuration..."
|
||||||
msgstr "Перейти к настройке пароля..."
|
msgstr "Перейти к настройке пароля..."
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:402
|
#: htdocs/luci-static/resources/fs-appearance.js:415
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Good"
|
msgid "Good"
|
||||||
msgstr "Норма"
|
msgstr "Норма"
|
||||||
@@ -177,7 +182,7 @@ msgctxt "footstrap"
|
|||||||
msgid "Hard to read %s — large text only"
|
msgid "Hard to read %s — large text only"
|
||||||
msgstr "Плохо читается %s — только крупный текст"
|
msgstr "Плохо читается %s — только крупный текст"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:802
|
#: htdocs/luci-static/resources/fs-appearance.js:815
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Interface"
|
msgid "Interface"
|
||||||
msgstr "Интерфейс"
|
msgstr "Интерфейс"
|
||||||
@@ -190,18 +195,18 @@ msgstr "Неверное имя пользователя и/или пароль!
|
|||||||
msgid "JavaScript required!"
|
msgid "JavaScript required!"
|
||||||
msgstr "Требуется JavaScript!"
|
msgstr "Требуется JavaScript!"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:364
|
#: htdocs/luci-static/resources/fs-appearance.js:377
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Keep open"
|
msgid "Keep open"
|
||||||
msgstr "Не сворачивать"
|
msgstr "Не сворачивать"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:352
|
#: htdocs/luci-static/resources/fs-appearance.js:355
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Large"
|
msgid "Large"
|
||||||
msgstr "Крупно"
|
msgstr "Крупно"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:328
|
#: htdocs/luci-static/resources/fs-appearance.js:328
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:723
|
#: htdocs/luci-static/resources/fs-appearance.js:736
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Layout"
|
msgid "Layout"
|
||||||
msgstr "Раскладка"
|
msgstr "Раскладка"
|
||||||
@@ -250,12 +255,12 @@ msgstr "Страницы не найдены"
|
|||||||
msgid "No password set!"
|
msgid "No password set!"
|
||||||
msgstr "Пароль не установлен!"
|
msgstr "Пароль не установлен!"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:351
|
#: htdocs/luci-static/resources/fs-appearance.js:354
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Normal"
|
msgid "Normal"
|
||||||
msgstr "Обычно"
|
msgstr "Обычно"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:562
|
#: htdocs/luci-static/resources/fs-appearance.js:575
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Off"
|
msgid "Off"
|
||||||
msgstr "Выкл."
|
msgstr "Выкл."
|
||||||
@@ -275,8 +280,8 @@ msgstr "Палитра"
|
|||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr "Пароль"
|
msgstr "Пароль"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:472
|
#: htdocs/luci-static/resources/fs-appearance.js:485
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:563
|
#: htdocs/luci-static/resources/fs-appearance.js:576
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Pattern"
|
msgid "Pattern"
|
||||||
msgstr "Узор"
|
msgstr "Узор"
|
||||||
@@ -300,43 +305,42 @@ msgctxt "footstrap"
|
|||||||
msgid "Recently visited"
|
msgid "Recently visited"
|
||||||
msgstr "Недавние"
|
msgstr "Недавние"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:449
|
#: htdocs/luci-static/resources/fs-appearance.js:462
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:456
|
#: htdocs/luci-static/resources/fs-appearance.js:469
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Remove"
|
msgid "Remove"
|
||||||
msgstr "Убрать"
|
msgstr "Убрать"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:592
|
#: htdocs/luci-static/resources/fs-appearance.js:605
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:659
|
#: htdocs/luci-static/resources/fs-appearance.js:672
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Reset to built-in"
|
msgid "Reset to built-in"
|
||||||
msgstr "Сбросить к встроенному"
|
msgstr "Сбросить к встроенному"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:687
|
#: htdocs/luci-static/resources/fs-appearance.js:700
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Reset to built-in — go back to the look the theme ships with."
|
msgid "Reset to built-in — go back to the look the theme ships with."
|
||||||
msgstr ""
|
msgstr "«Сбросить к встроенному» — вернуть вид, с которым поставляется тема."
|
||||||
"«Сбросить к встроенному» — вернуть вид, с которым поставляется тема."
|
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:588
|
#: htdocs/luci-static/resources/fs-appearance.js:601
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:658
|
#: htdocs/luci-static/resources/fs-appearance.js:671
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Reset to router"
|
msgid "Reset to router"
|
||||||
msgstr "Сбросить к виду роутера"
|
msgstr "Сбросить к виду роутера"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:685
|
#: htdocs/luci-static/resources/fs-appearance.js:698
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Reset to router — drop this browser's changes and follow the router."
|
msgid "Reset to router — drop this browser's changes and follow the router."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"«Сбросить к виду роутера» — отменить правки этого браузера и следовать "
|
"«Сбросить к виду роутера» — отменить правки этого браузера и следовать "
|
||||||
"роутеру."
|
"роутеру."
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:355
|
#: htdocs/luci-static/resources/fs-appearance.js:368
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Rounding"
|
msgid "Rounding"
|
||||||
msgstr "Скругление"
|
msgstr "Скругление"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:795
|
#: htdocs/luci-static/resources/fs-appearance.js:808
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid ""
|
msgid ""
|
||||||
"Save & Apply at the foot of the page belongs to the System form and does not "
|
"Save & Apply at the foot of the page belongs to the System form and does not "
|
||||||
@@ -345,14 +349,14 @@ msgstr ""
|
|||||||
"Кнопка «Сохранить и применить» внизу страницы принадлежит форме «Система» и "
|
"Кнопка «Сохранить и применить» внизу страницы принадлежит форме «Система» и "
|
||||||
"их не сохраняет."
|
"их не сохраняет."
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:578
|
#: htdocs/luci-static/resources/fs-appearance.js:591
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:610
|
#: htdocs/luci-static/resources/fs-appearance.js:623
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:617
|
#: htdocs/luci-static/resources/fs-appearance.js:630
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Save to router"
|
msgid "Save to router"
|
||||||
msgstr "Сохранить на роутер"
|
msgstr "Сохранить на роутер"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:683
|
#: htdocs/luci-static/resources/fs-appearance.js:696
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid ""
|
msgid ""
|
||||||
"Save to router — store this look on the router. Browsers with a look of "
|
"Save to router — store this look on the router. Browsers with a look of "
|
||||||
@@ -361,22 +365,22 @@ msgstr ""
|
|||||||
"«Сохранить на роутер» — записать этот вид на роутер. Браузеры со своим видом "
|
"«Сохранить на роутер» — записать этот вид на роутер. Браузеры со своим видом "
|
||||||
"его сохранят."
|
"его сохранят."
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:693
|
#: htdocs/luci-static/resources/fs-appearance.js:706
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Saved look"
|
msgid "Saved look"
|
||||||
msgstr "Сохранённый вид"
|
msgstr "Сохранённый вид"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:617
|
#: htdocs/luci-static/resources/fs-appearance.js:630
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Saved to router"
|
msgid "Saved to router"
|
||||||
msgstr "Сохранено на роутере"
|
msgstr "Сохранено на роутере"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:807
|
#: htdocs/luci-static/resources/fs-appearance.js:820
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Saving"
|
msgid "Saving"
|
||||||
msgstr "Сохранение"
|
msgstr "Сохранение"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:463
|
#: htdocs/luci-static/resources/fs-appearance.js:476
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Scale"
|
msgid "Scale"
|
||||||
msgstr "Масштаб"
|
msgstr "Масштаб"
|
||||||
@@ -402,7 +406,7 @@ msgctxt "footstrap"
|
|||||||
msgid "Sidebar"
|
msgid "Sidebar"
|
||||||
msgstr "Сбоку"
|
msgstr "Сбоку"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:423
|
#: htdocs/luci-static/resources/fs-appearance.js:436
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Sidebar and bar"
|
msgid "Sidebar and bar"
|
||||||
msgstr "Боковая панель и шапка"
|
msgstr "Боковая панель и шапка"
|
||||||
@@ -420,17 +424,17 @@ msgstr "Начните вводить название страницы"
|
|||||||
msgid "Storage"
|
msgid "Storage"
|
||||||
msgstr "Накопитель"
|
msgstr "Накопитель"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:464
|
#: htdocs/luci-static/resources/fs-appearance.js:477
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Strength"
|
msgid "Strength"
|
||||||
msgstr "Насыщенность"
|
msgstr "Насыщенность"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:362
|
#: htdocs/luci-static/resources/fs-appearance.js:375
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Submenus"
|
msgid "Submenus"
|
||||||
msgstr "Подменю"
|
msgstr "Подменю"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:804
|
#: htdocs/luci-static/resources/fs-appearance.js:817
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Surfaces"
|
msgid "Surfaces"
|
||||||
msgstr "Поверхности"
|
msgstr "Поверхности"
|
||||||
@@ -486,7 +490,7 @@ msgid "The router refused to delete the file (ubus status %d)."
|
|||||||
msgstr "Роутер отказался удалить файл (статус ubus %d)."
|
msgstr "Роутер отказался удалить файл (статус ubus %d)."
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:333
|
#: htdocs/luci-static/resources/fs-appearance.js:333
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:480
|
#: htdocs/luci-static/resources/fs-appearance.js:493
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Theme"
|
msgid "Theme"
|
||||||
msgstr "Тема"
|
msgstr "Тема"
|
||||||
@@ -499,7 +503,7 @@ msgstr ""
|
|||||||
"На этом роутере не задан пароль. Установите пароль root, чтобы защитить веб-"
|
"На этом роутере не задан пароль. Установите пароль root, чтобы защитить веб-"
|
||||||
"интерфейс."
|
"интерфейс."
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:611
|
#: htdocs/luci-static/resources/fs-appearance.js:624
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid ""
|
msgid ""
|
||||||
"This browser is not storing preferences (site data is blocked), so a change "
|
"This browser is not storing preferences (site data is blocked), so a change "
|
||||||
@@ -510,17 +514,17 @@ msgstr ""
|
|||||||
"изменение здесь действует до перезагрузки страницы. «Сохранить как "
|
"изменение здесь действует до перезагрузки страницы. «Сохранить как "
|
||||||
"умолчание» по-прежнему работает и применяется ко всем браузерам."
|
"умолчание» по-прежнему работает и применяется ко всем браузерам."
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:725
|
#: htdocs/luci-static/resources/fs-appearance.js:738
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "This theme is not translated on this router yet."
|
msgid "This theme is not translated on this router yet."
|
||||||
msgstr "Тема ещё не переведена на этом роутере."
|
msgstr "Тема ещё не переведена на этом роутере."
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:374
|
#: htdocs/luci-static/resources/fs-appearance.js:387
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Tint (router identification)"
|
msgid "Tint (router identification)"
|
||||||
msgstr "Оттенок (опознание роутера)"
|
msgstr "Оттенок (опознание роутера)"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:387
|
#: htdocs/luci-static/resources/fs-appearance.js:400
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Tint strength"
|
msgid "Tint strength"
|
||||||
msgstr "Насыщенность оттенка"
|
msgstr "Насыщенность оттенка"
|
||||||
@@ -540,7 +544,7 @@ msgctxt "footstrap"
|
|||||||
msgid "Upload failed."
|
msgid "Upload failed."
|
||||||
msgstr "Не удалось загрузить."
|
msgstr "Не удалось загрузить."
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:531
|
#: htdocs/luci-static/resources/fs-appearance.js:544
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Uploading…"
|
msgid "Uploading…"
|
||||||
msgstr "Загрузка…"
|
msgstr "Загрузка…"
|
||||||
@@ -549,12 +553,12 @@ msgstr "Загрузка…"
|
|||||||
msgid "Username"
|
msgid "Username"
|
||||||
msgstr "Имя пользователя"
|
msgstr "Имя пользователя"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:560
|
#: htdocs/luci-static/resources/fs-appearance.js:573
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Wallpaper"
|
msgid "Wallpaper"
|
||||||
msgstr "Обои"
|
msgstr "Обои"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:403
|
#: htdocs/luci-static/resources/fs-appearance.js:416
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Warning"
|
msgid "Warning"
|
||||||
msgstr "Предупреждение"
|
msgstr "Предупреждение"
|
||||||
@@ -565,7 +569,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Включите JavaScript в браузере, иначе LuCI не будет работать корректно."
|
"Включите JavaScript в браузере, иначе LuCI не будет работать корректно."
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:423
|
#: htdocs/luci-static/resources/fs-appearance.js:436
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "in the sidebar"
|
msgid "in the sidebar"
|
||||||
msgstr "в боковой панели"
|
msgstr "в боковой панели"
|
||||||
@@ -575,12 +579,12 @@ msgctxt "footstrap"
|
|||||||
msgid "on a card"
|
msgid "on a card"
|
||||||
msgstr "на карточке"
|
msgstr "на карточке"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:422
|
#: htdocs/luci-static/resources/fs-appearance.js:435
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "on a control"
|
msgid "on a control"
|
||||||
msgstr "на элементе формы"
|
msgstr "на элементе формы"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:379
|
#: htdocs/luci-static/resources/fs-appearance.js:392
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "on the canvas"
|
msgid "on the canvas"
|
||||||
msgstr "на холсте"
|
msgstr "на холсте"
|
||||||
@@ -591,6 +595,14 @@ msgid ""
|
|||||||
"the uploaded file could not be removed either; it is still on the router."
|
"the uploaded file could not be removed either; it is still on the router."
|
||||||
msgstr "загруженный файл тоже не удалось удалить — он остался на роутере."
|
msgstr "загруженный файл тоже не удалось удалить — он остался на роутере."
|
||||||
|
|
||||||
|
#~ msgctxt "footstrap"
|
||||||
|
#~ msgid "Full"
|
||||||
|
#~ msgstr "Во всю ширину"
|
||||||
|
|
||||||
|
#~ msgctxt "footstrap"
|
||||||
|
#~ msgid "Wide"
|
||||||
|
#~ msgstr "Широкая"
|
||||||
|
|
||||||
#~ msgctxt "footstrap"
|
#~ msgctxt "footstrap"
|
||||||
#~ msgid "Defaults"
|
#~ msgid "Defaults"
|
||||||
#~ msgstr "Умолчания"
|
#~ msgstr "Умолчания"
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
msgid ""
|
msgid ""
|
||||||
msgstr "Content-Type: text/plain; charset=UTF-8"
|
msgstr "Content-Type: text/plain; charset=UTF-8"
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:401
|
#: htdocs/luci-static/resources/fs-appearance.js:414
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Accent"
|
msgid "Accent"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:481
|
#: htdocs/luci-static/resources/fs-appearance.js:494
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "As in file"
|
msgid "As in file"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -20,12 +20,12 @@ msgctxt "footstrap"
|
|||||||
msgid "Auto"
|
msgid "Auto"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:365
|
#: htdocs/luci-static/resources/fs-appearance.js:378
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Auto-collapse"
|
msgid "Auto-collapse"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:806
|
#: htdocs/luci-static/resources/fs-appearance.js:819
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Background"
|
msgid "Background"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -35,22 +35,22 @@ msgctxt "footstrap"
|
|||||||
msgid "Barely visible %s"
|
msgid "Barely visible %s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:424
|
#: htdocs/luci-static/resources/fs-appearance.js:437
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Borders"
|
msgid "Borders"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:421
|
#: htdocs/luci-static/resources/fs-appearance.js:434
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Cards"
|
msgid "Cards"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:454
|
#: htdocs/luci-static/resources/fs-appearance.js:467
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Choose SVG"
|
msgid "Choose SVG"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:447
|
#: htdocs/luci-static/resources/fs-appearance.js:460
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Choose image"
|
msgid "Choose image"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -60,33 +60,38 @@ msgctxt "footstrap"
|
|||||||
msgid "Clearly visible %s"
|
msgid "Clearly visible %s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-chrome.js:447
|
#: htdocs/luci-static/resources/fs-chrome.js:453
|
||||||
#: ucode/template/themes/footstrap/header.ut:138
|
#: ucode/template/themes/footstrap/header.ut:138
|
||||||
msgid "Collapse menu"
|
msgid "Collapse menu"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:465
|
#: htdocs/luci-static/resources/fs-appearance.js:478
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:803
|
#: htdocs/luci-static/resources/fs-appearance.js:816
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Colours"
|
msgid "Colours"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:350
|
#: htdocs/luci-static/resources/fs-appearance.js:353
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:648
|
#: htdocs/luci-static/resources/fs-appearance.js:661
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Confirm reset"
|
msgid "Confirm reset"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: htdocs/luci-static/resources/fs-appearance.js:364
|
||||||
|
msgctxt "footstrap"
|
||||||
|
msgid "Content width"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:193
|
#: htdocs/luci-static/resources/fs-appearance.js:193
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Contrast %s:1 (WCAG AA wants %s:1 here)"
|
msgid "Contrast %s:1 (WCAG AA wants %s:1 here)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:422
|
#: htdocs/luci-static/resources/fs-appearance.js:435
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Controls"
|
msgid "Controls"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -96,12 +101,12 @@ msgctxt "footstrap"
|
|||||||
msgid "Could not process the image."
|
msgid "Could not process the image."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:628
|
#: htdocs/luci-static/resources/fs-appearance.js:641
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Could not save the default. Reload the page and try again."
|
msgid "Could not save the default. Reload the page and try again."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:404
|
#: htdocs/luci-static/resources/fs-appearance.js:417
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Danger"
|
msgid "Danger"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -111,12 +116,12 @@ msgctxt "footstrap"
|
|||||||
msgid "Dark"
|
msgid "Dark"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:349
|
#: htdocs/luci-static/resources/fs-appearance.js:352
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Density"
|
msgid "Density"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:462
|
#: htdocs/luci-static/resources/fs-appearance.js:475
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Dim"
|
msgid "Dim"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -126,12 +131,12 @@ msgctxt "footstrap"
|
|||||||
msgid "Easy to read %s"
|
msgid "Easy to read %s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-chrome.js:447
|
#: htdocs/luci-static/resources/fs-chrome.js:453
|
||||||
msgid "Expand menu"
|
msgid "Expand menu"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:486
|
#: htdocs/luci-static/resources/fs-appearance.js:499
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:564
|
#: htdocs/luci-static/resources/fs-appearance.js:577
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "File"
|
msgid "File"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -142,7 +147,7 @@ msgid ""
|
|||||||
"background and pattern uploads"
|
"background and pattern uploads"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:794
|
#: htdocs/luci-static/resources/fs-appearance.js:807
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid ""
|
msgid ""
|
||||||
"Footstrap theme settings apply at once and are stored permanently in this "
|
"Footstrap theme settings apply at once and are stored permanently in this "
|
||||||
@@ -157,7 +162,7 @@ msgstr ""
|
|||||||
msgid "Go to password configuration..."
|
msgid "Go to password configuration..."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:402
|
#: htdocs/luci-static/resources/fs-appearance.js:415
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Good"
|
msgid "Good"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -167,7 +172,7 @@ msgctxt "footstrap"
|
|||||||
msgid "Hard to read %s — large text only"
|
msgid "Hard to read %s — large text only"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:802
|
#: htdocs/luci-static/resources/fs-appearance.js:815
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Interface"
|
msgid "Interface"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -180,18 +185,18 @@ msgstr ""
|
|||||||
msgid "JavaScript required!"
|
msgid "JavaScript required!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:364
|
#: htdocs/luci-static/resources/fs-appearance.js:377
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Keep open"
|
msgid "Keep open"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:352
|
#: htdocs/luci-static/resources/fs-appearance.js:355
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Large"
|
msgid "Large"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:328
|
#: htdocs/luci-static/resources/fs-appearance.js:328
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:723
|
#: htdocs/luci-static/resources/fs-appearance.js:736
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Layout"
|
msgid "Layout"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -238,12 +243,12 @@ msgstr ""
|
|||||||
msgid "No password set!"
|
msgid "No password set!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:351
|
#: htdocs/luci-static/resources/fs-appearance.js:354
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Normal"
|
msgid "Normal"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:562
|
#: htdocs/luci-static/resources/fs-appearance.js:575
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Off"
|
msgid "Off"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -263,8 +268,8 @@ msgstr ""
|
|||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:472
|
#: htdocs/luci-static/resources/fs-appearance.js:485
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:563
|
#: htdocs/luci-static/resources/fs-appearance.js:576
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Pattern"
|
msgid "Pattern"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -288,76 +293,76 @@ msgctxt "footstrap"
|
|||||||
msgid "Recently visited"
|
msgid "Recently visited"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:449
|
#: htdocs/luci-static/resources/fs-appearance.js:462
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:456
|
#: htdocs/luci-static/resources/fs-appearance.js:469
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Remove"
|
msgid "Remove"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:592
|
#: htdocs/luci-static/resources/fs-appearance.js:605
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:659
|
#: htdocs/luci-static/resources/fs-appearance.js:672
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Reset to built-in"
|
msgid "Reset to built-in"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:687
|
#: htdocs/luci-static/resources/fs-appearance.js:700
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Reset to built-in — go back to the look the theme ships with."
|
msgid "Reset to built-in — go back to the look the theme ships with."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:588
|
#: htdocs/luci-static/resources/fs-appearance.js:601
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:658
|
#: htdocs/luci-static/resources/fs-appearance.js:671
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Reset to router"
|
msgid "Reset to router"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:685
|
#: htdocs/luci-static/resources/fs-appearance.js:698
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Reset to router — drop this browser's changes and follow the router."
|
msgid "Reset to router — drop this browser's changes and follow the router."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:355
|
#: htdocs/luci-static/resources/fs-appearance.js:368
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Rounding"
|
msgid "Rounding"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:795
|
#: htdocs/luci-static/resources/fs-appearance.js:808
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid ""
|
msgid ""
|
||||||
"Save & Apply at the foot of the page belongs to the System form and does not "
|
"Save & Apply at the foot of the page belongs to the System form and does not "
|
||||||
"store them."
|
"store them."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:578
|
#: htdocs/luci-static/resources/fs-appearance.js:591
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:610
|
#: htdocs/luci-static/resources/fs-appearance.js:623
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:617
|
#: htdocs/luci-static/resources/fs-appearance.js:630
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Save to router"
|
msgid "Save to router"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:683
|
#: htdocs/luci-static/resources/fs-appearance.js:696
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid ""
|
msgid ""
|
||||||
"Save to router — store this look on the router. Browsers with a look of "
|
"Save to router — store this look on the router. Browsers with a look of "
|
||||||
"their own keep it."
|
"their own keep it."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:693
|
#: htdocs/luci-static/resources/fs-appearance.js:706
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Saved look"
|
msgid "Saved look"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:617
|
#: htdocs/luci-static/resources/fs-appearance.js:630
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Saved to router"
|
msgid "Saved to router"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:807
|
#: htdocs/luci-static/resources/fs-appearance.js:820
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Saving"
|
msgid "Saving"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:463
|
#: htdocs/luci-static/resources/fs-appearance.js:476
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Scale"
|
msgid "Scale"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -383,7 +388,7 @@ msgctxt "footstrap"
|
|||||||
msgid "Sidebar"
|
msgid "Sidebar"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:423
|
#: htdocs/luci-static/resources/fs-appearance.js:436
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Sidebar and bar"
|
msgid "Sidebar and bar"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -401,17 +406,17 @@ msgstr ""
|
|||||||
msgid "Storage"
|
msgid "Storage"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:464
|
#: htdocs/luci-static/resources/fs-appearance.js:477
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Strength"
|
msgid "Strength"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:362
|
#: htdocs/luci-static/resources/fs-appearance.js:375
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Submenus"
|
msgid "Submenus"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:804
|
#: htdocs/luci-static/resources/fs-appearance.js:817
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Surfaces"
|
msgid "Surfaces"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -466,7 +471,7 @@ msgid "The router refused to delete the file (ubus status %d)."
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:333
|
#: htdocs/luci-static/resources/fs-appearance.js:333
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:480
|
#: htdocs/luci-static/resources/fs-appearance.js:493
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Theme"
|
msgid "Theme"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -477,7 +482,7 @@ msgid ""
|
|||||||
"protect the web interface."
|
"protect the web interface."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:611
|
#: htdocs/luci-static/resources/fs-appearance.js:624
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid ""
|
msgid ""
|
||||||
"This browser is not storing preferences (site data is blocked), so a change "
|
"This browser is not storing preferences (site data is blocked), so a change "
|
||||||
@@ -485,17 +490,17 @@ msgid ""
|
|||||||
"every browser."
|
"every browser."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:725
|
#: htdocs/luci-static/resources/fs-appearance.js:738
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "This theme is not translated on this router yet."
|
msgid "This theme is not translated on this router yet."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:374
|
#: htdocs/luci-static/resources/fs-appearance.js:387
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Tint (router identification)"
|
msgid "Tint (router identification)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:387
|
#: htdocs/luci-static/resources/fs-appearance.js:400
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Tint strength"
|
msgid "Tint strength"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -515,7 +520,7 @@ msgctxt "footstrap"
|
|||||||
msgid "Upload failed."
|
msgid "Upload failed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:531
|
#: htdocs/luci-static/resources/fs-appearance.js:544
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Uploading…"
|
msgid "Uploading…"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -524,12 +529,12 @@ msgstr ""
|
|||||||
msgid "Username"
|
msgid "Username"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:560
|
#: htdocs/luci-static/resources/fs-appearance.js:573
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Wallpaper"
|
msgid "Wallpaper"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:403
|
#: htdocs/luci-static/resources/fs-appearance.js:416
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "Warning"
|
msgid "Warning"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -539,7 +544,7 @@ msgid ""
|
|||||||
"You must enable JavaScript in your browser or LuCI will not work properly."
|
"You must enable JavaScript in your browser or LuCI will not work properly."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:423
|
#: htdocs/luci-static/resources/fs-appearance.js:436
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "in the sidebar"
|
msgid "in the sidebar"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -549,12 +554,12 @@ msgctxt "footstrap"
|
|||||||
msgid "on a card"
|
msgid "on a card"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:422
|
#: htdocs/luci-static/resources/fs-appearance.js:435
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "on a control"
|
msgid "on a control"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: htdocs/luci-static/resources/fs-appearance.js:379
|
#: htdocs/luci-static/resources/fs-appearance.js:392
|
||||||
msgctxt "footstrap"
|
msgctxt "footstrap"
|
||||||
msgid "on the canvas"
|
msgid "on the canvas"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
# Registration, plus the three symlinks that expose what the admin uploads. Nothing here migrates a
|
# Registration, plus the two symlinks that expose what the admin uploads (a third, the pattern, is
|
||||||
# router off an older footstrap: OpenWrt expects a sysupgrade rather than a package upgrade.
|
# deliberately NOT one — see below). Nothing here migrates a router off an older footstrap: OpenWrt
|
||||||
|
# expects a sysupgrade rather than a package upgrade — the one exception is the stale pattern
|
||||||
|
# symlink itself, removed below because leaving it would keep a reported security hole open.
|
||||||
|
|
||||||
changed=0
|
changed=0
|
||||||
|
|
||||||
@@ -23,13 +25,22 @@ fi
|
|||||||
[ "$changed" = 1 ] && uci commit luci
|
[ "$changed" = 1 ] && uci commit luci
|
||||||
|
|
||||||
# uhttpd serves /www only, so the admin's uploads live in /etc — where a sysupgrade keeps them
|
# uhttpd serves /www only, so the admin's uploads live in /etc — where a sysupgrade keeps them
|
||||||
# (lib/upgrade/keep.d) — and are reached through symlinks. The pattern keeps its .svg name: uhttpd
|
# (lib/upgrade/keep.d) — and are reached through symlinks, EXCEPT the pattern (below).
|
||||||
# types a response by extension, and an SVG sent as octet-stream paints nowhere.
|
#
|
||||||
|
# The pattern is deliberately NOT symlinked into /www: an SVG is a document, and served as one
|
||||||
|
# through a plain same-origin URL it runs as a script with the admin's session (OpenWrt forum
|
||||||
|
# thread 251930). It is instead read by cgi-bin/luci-theme-footstrap-pattern, which answers with
|
||||||
|
# CSP 'none' + sandbox and nosniff — headers uhttpd cannot attach to a static file. The login
|
||||||
|
# background stays a plain symlink: fs-assets.js re-encodes every upload to a JPEG on a canvas
|
||||||
|
# first, so there is no script grammar left in the bytes for a direct hit to run.
|
||||||
mkdir -p /etc/footstrap
|
mkdir -p /etc/footstrap
|
||||||
if [ -d /www/luci-static/footstrap ]; then
|
if [ -d /www/luci-static/footstrap ]; then
|
||||||
ln -sf /etc/footstrap/login-bg /www/luci-static/footstrap/bg
|
ln -sf /etc/footstrap/login-bg /www/luci-static/footstrap/bg
|
||||||
ln -sf /etc/footstrap/pattern.svg /www/luci-static/footstrap/pattern.svg
|
|
||||||
ln -sfn /etc/footstrap/fonts /www/luci-static/footstrap/fonts
|
ln -sfn /etc/footstrap/fonts /www/luci-static/footstrap/fonts
|
||||||
fi
|
fi
|
||||||
|
# Clean up a pre-0.15 install's stale pattern symlink — see the header comment above for why this
|
||||||
|
# is the one migration this script makes. `-L` only: never remove a real file some other install
|
||||||
|
# step could have left at that path.
|
||||||
|
[ -L /www/luci-static/footstrap/pattern.svg ] && rm -f /www/luci-static/footstrap/pattern.svg
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Serves the admin-uploaded wallpaper pattern with headers a browser will not execute: opened
|
||||||
|
# directly, the /www symlink this replaces was a same-origin document with an authenticated LuCI
|
||||||
|
# session reachable from it (OpenWrt forum thread 251930, confirmed on a stand — a marker SVG set
|
||||||
|
# document.title, read location.origin as the router's, and reached document.cookie, pre-login
|
||||||
|
# too, since /www needs no session). The theme's own rendering never hits this: 15-wallpaper.css
|
||||||
|
# paints the same file through mask-image or a tiled background-image, and neither ever runs
|
||||||
|
# script inside it — the exposure was only the direct URL, which is what CSP 'none' + sandbox and
|
||||||
|
# nosniff below close, without touching how the mask/background paints it.
|
||||||
|
#
|
||||||
|
# Deliberately unauthenticated, on purpose and not an oversight: the pattern paints before login
|
||||||
|
# too (head.ut's pre-paint, from window.__fsSD). That is safe here ONLY because this script takes
|
||||||
|
# NO input at all — FILE below is a shell constant, never $QUERY_STRING, $PATH_INFO or anything
|
||||||
|
# else request-supplied — so there is nothing to traverse and nothing else this handler can be
|
||||||
|
# made to read.
|
||||||
|
#
|
||||||
|
# The login background (/etc/footstrap/login-bg) stays a plain /www symlink and does NOT get this
|
||||||
|
# treatment: fs-assets.js re-encodes every upload to a JPEG on a canvas before it is sent, so the
|
||||||
|
# stored bytes are pixels only and there is no script grammar left in the file for a direct hit to
|
||||||
|
# run — see docs/package.md.
|
||||||
|
|
||||||
|
FILE=/etc/footstrap/pattern.svg
|
||||||
|
|
||||||
|
if [ ! -r "$FILE" ]; then
|
||||||
|
printf 'Status: 404 Not Found\r\n'
|
||||||
|
printf 'Content-Type: text/plain\r\n'
|
||||||
|
printf '\r\n'
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf 'Status: 200 OK\r\n'
|
||||||
|
printf 'Content-Type: image/svg+xml\r\n'
|
||||||
|
# Cacheable forever, because the URL is not stable: fs-axes.js appends `?v=<token>` and the token
|
||||||
|
# changes with every upload, so a new file is a new URL. Without this the /www symlink's ETag and
|
||||||
|
# Last-Modified were gone and the tile was re-fetched on EVERY page load - a background image on a
|
||||||
|
# router that serves it off flash with no gzip, which is the cost this handler must not add.
|
||||||
|
printf 'Cache-Control: public, max-age=31536000, immutable\r\n'
|
||||||
|
printf 'X-Content-Type-Options: nosniff\r\n'
|
||||||
|
printf "Content-Security-Policy: default-src 'none'; sandbox\r\n"
|
||||||
|
printf '\r\n'
|
||||||
|
cat "$FILE"
|
||||||
|
|
||||||
|
exit 0
|
||||||
@@ -169,6 +169,29 @@
|
|||||||
--fs-bar-bg: color-mix(in srgb, var(--fs-panel) 88%, transparent);
|
--fs-bar-bg: color-mix(in srgb, var(--fs-panel) 88%, transparent);
|
||||||
/* height of that bar, and the scroll-margin every anchor target needs to clear it
|
/* height of that bar, and the scroll-margin every anchor target needs to clear it
|
||||||
* (base/10-reset.css): if the two drift, an in-page jump lands under the bar */
|
* (base/10-reset.css): if the two drift, an in-page jump lands under the bar */
|
||||||
|
/* The chrome's own controls — the square buttons (search, appearance, log out) and the poll
|
||||||
|
* pill — ride the bar rather than cutting panel-coloured holes in it: the bar is one surface,
|
||||||
|
* and a control on it is carried by its hairline, not by a second fill. `transparent`, not a
|
||||||
|
* copy of --fs-bar-bg, so the strip's own translucency is not applied twice.
|
||||||
|
*
|
||||||
|
* This gives up what `.label`'s comment in theme/35-alerts.css leans on — that a coloured
|
||||||
|
* variant sits on --fs-panel2, where the palette guarantees >=4.5:1 by construction. On the
|
||||||
|
* bar the backdrop is now whatever the strip lands on, so the ratio is a MEASURED fact per
|
||||||
|
* palette rather than a guaranteed one; the numbers live in the changelog entry. A palette that
|
||||||
|
* needs the old behaviour sets this back to var(--fs-panel2). */
|
||||||
|
--fs-bar-ctl-bg: transparent;
|
||||||
|
/* The select's chevron, drawn rather than fetched. It used to be an inline SVG data-URI, and
|
||||||
|
* a URI cannot read var() — the stroke colour had to be written INTO the string, so the
|
||||||
|
* declaration was repeated once per palette and once per mode: ten copies of one glyph, ~2.4 KB
|
||||||
|
* of the shipped sheet, and ten chances for a palette to be recoloured while its chevron was
|
||||||
|
* not. Two gradient bands cost one declaration and take their colour from the palette's own
|
||||||
|
* --fs-dim at paint time, so a new palette gets a correct chevron for free. The 45% / 55% stops
|
||||||
|
* are the band's thickness; the two layers are positioned by the rules that use this, since
|
||||||
|
* only they know the field's inset. What is given up is the round line cap the SVG had, which
|
||||||
|
* at 12px is not visible — compared side by side before the swap. */
|
||||||
|
--fs-select-chevron:
|
||||||
|
linear-gradient(-45deg, transparent 45%, var(--fs-dim) 45% 55%, transparent 55%),
|
||||||
|
linear-gradient(45deg, transparent 45%, var(--fs-dim) 45% 55%, transparent 55%);
|
||||||
--fs-bar-h: calc(46px * var(--fs-density-box));
|
--fs-bar-h: calc(46px * var(--fs-density-box));
|
||||||
/* the square icon button in the bar and rail: the logo box, the .fs-themerow controls,
|
/* the square icon button in the bar and rail: the logo box, the .fs-themerow controls,
|
||||||
* Log out and the collapsed poll pill are one size, so the right cluster reads as a row
|
* Log out and the collapsed poll pill are one size, so the right cluster reads as a row
|
||||||
@@ -509,6 +532,32 @@
|
|||||||
--fs-density-space: 1;
|
--fs-density-space: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ---- the content-width axis ----
|
||||||
|
*
|
||||||
|
* No :root[data-content-width] blocks here (issue #44 moved this from a three-step picker to a
|
||||||
|
* slider): the value is a real px length written straight onto --fs-content-max as an inline
|
||||||
|
* style by fs-axes.js's propAxis, the same shape Rounding uses, and read back exactly as before
|
||||||
|
* by `.fs-content`, the modal width calc and the top layout's centring padding
|
||||||
|
* (theme/20-shell.css, theme/50-toplayout.css) — deliberately including the modal, which follows
|
||||||
|
* the column on purpose rather than keeping its own separate cap the reader would have to
|
||||||
|
* reconcile against.
|
||||||
|
*
|
||||||
|
* The range is 1280-3840, and neither end is derived from this file: 1280 (--fs-content-max
|
||||||
|
* above) is the value the theme has always drawn, so the slider's left end IS today's look and
|
||||||
|
* the axis can never go narrower than the default — a difference from every other numeric axis,
|
||||||
|
* none of which has a floor that also has to be the default. --fs-content-min (500px) was the
|
||||||
|
* rule this axis had to stay clear of; with 1280 as the floor it is now a property of the range
|
||||||
|
* instead, 780px below the nearest point the slider can reach. 3840 stands in for "uncapped": no
|
||||||
|
* CSS viewport width in ordinary use reaches it, since even a physical 4K panel reports a scaled
|
||||||
|
* CSS width well under it — and `columnWidth()`'s `Math.min(state.outerW - cut, g.contentMax)`
|
||||||
|
* needs a real px length either way, `none`/`100%` failing both the `calc()` in
|
||||||
|
* 50-toplayout.css and `px()`'s getComputedStyle probe in fs-chrome.js.
|
||||||
|
*
|
||||||
|
* Step 128px: 2,560px of travel at 20 stops, matching Rounding/Photo dim/Pattern strength's stop
|
||||||
|
* count rather than Pattern scale's near-pixel drag — a stop here should move a table's column
|
||||||
|
* count, not shave a pixel off a margin, and 128 is the largest round number that divides the
|
||||||
|
* range into stops that few. */
|
||||||
|
|
||||||
:root[data-darkmode="true"] {
|
:root[data-darkmode="true"] {
|
||||||
/* palette colours are in 03-palettes.css; only mode-level, palette-independent
|
/* palette colours are in 03-palettes.css; only mode-level, palette-independent
|
||||||
* tokens live here */
|
* tokens live here */
|
||||||
|
|||||||
@@ -2,8 +2,9 @@
|
|||||||
/* ---- colourways (palettes) ----
|
/* ---- colourways (palettes) ----
|
||||||
*
|
*
|
||||||
* Every colour is a variable and every palette is one self-contained block per mode, so a new
|
* Every colour is a variable and every palette is one self-contained block per mode, so a new
|
||||||
* colourway is copy-one-pair-and-recolour. Four ship: footstrap (GitHub Primer, the default),
|
* colourway is copy-one-pair-and-recolour. Five ship: footstrap (GitHub Primer, the default),
|
||||||
* hicontrast, bootstrap (the stock LuCI theme's colours) and 2020.
|
* hicontrast, bootstrap (the stock LuCI theme's colours), 2020 (the OpenWrt 2020 theme's
|
||||||
|
* colourway) and forum (the OpenWrt forum's Discourse colourway).
|
||||||
*
|
*
|
||||||
* TO ADD A COLOURWAY "sunset":
|
* TO ADD A COLOURWAY "sunset":
|
||||||
* 1. Copy the two hicontrast blocks below, rename data-palette to "sunset".
|
* 1. Copy the two hicontrast blocks below, rename data-palette to "sunset".
|
||||||
@@ -262,7 +263,6 @@
|
|||||||
* label. */
|
* label. */
|
||||||
--fs-dim: #33383d;
|
--fs-dim: #33383d;
|
||||||
--fs-faint: #3d4348;
|
--fs-faint: #3d4348;
|
||||||
--fs-select-chevron: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="%2333383d" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg>');
|
|
||||||
--fs-accent-base: #0969da;
|
--fs-accent-base: #0969da;
|
||||||
/* a tint OF --fs-accent, mixed FROM it: a restated literal goes stale the moment the accent
|
/* a tint OF --fs-accent, mixed FROM it: a restated literal goes stale the moment the accent
|
||||||
* is recoloured or the accent-hue axis rotates it */
|
* is recoloured or the accent-hue axis rotates it */
|
||||||
@@ -287,7 +287,6 @@
|
|||||||
--fs-text: #adbac7;
|
--fs-text: #adbac7;
|
||||||
--fs-dim: #8f9cab;
|
--fs-dim: #8f9cab;
|
||||||
--fs-faint: #959ca5;
|
--fs-faint: #959ca5;
|
||||||
--fs-select-chevron: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="%238f9cab" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg>');
|
|
||||||
--fs-accent-base: #569df5;
|
--fs-accent-base: #569df5;
|
||||||
--fs-accent-soft: color-mix(in srgb, var(--fs-accent) 15%, transparent);
|
--fs-accent-soft: color-mix(in srgb, var(--fs-accent) 15%, transparent);
|
||||||
--fs-track: #373e47;
|
--fs-track: #373e47;
|
||||||
@@ -320,7 +319,6 @@
|
|||||||
* 12.0:1 against the default palette's 11.8 and 10.0 */
|
* 12.0:1 against the default palette's 11.8 and 10.0 */
|
||||||
--fs-dim: #272f3d;
|
--fs-dim: #272f3d;
|
||||||
--fs-faint: #2e3745;
|
--fs-faint: #2e3745;
|
||||||
--fs-select-chevron: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="%23272f3d" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg>');
|
|
||||||
--fs-accent-base: #0b6fbd;
|
--fs-accent-base: #0b6fbd;
|
||||||
--fs-accent-soft: color-mix(in srgb, var(--fs-accent) 10%, transparent);
|
--fs-accent-soft: color-mix(in srgb, var(--fs-accent) 10%, transparent);
|
||||||
--fs-track: #eaeef4;
|
--fs-track: #eaeef4;
|
||||||
@@ -342,7 +340,6 @@
|
|||||||
--fs-text: #e8edf5;
|
--fs-text: #e8edf5;
|
||||||
--fs-dim: #9ba6b8;
|
--fs-dim: #9ba6b8;
|
||||||
--fs-faint: #8f9aad;
|
--fs-faint: #8f9aad;
|
||||||
--fs-select-chevron: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="%239ba6b8" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg>');
|
|
||||||
--fs-accent-base: #3ba7ff;
|
--fs-accent-base: #3ba7ff;
|
||||||
--fs-accent-soft: color-mix(in srgb, var(--fs-accent) 14%, transparent);
|
--fs-accent-soft: color-mix(in srgb, var(--fs-accent) 14%, transparent);
|
||||||
--fs-track: #1b2230;
|
--fs-track: #1b2230;
|
||||||
@@ -396,7 +393,6 @@
|
|||||||
--fs-text: #232323;
|
--fs-text: #232323;
|
||||||
--fs-dim: #383838;
|
--fs-dim: #383838;
|
||||||
--fs-faint: #424242;
|
--fs-faint: #424242;
|
||||||
--fs-select-chevron: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="%23383838" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg>');
|
|
||||||
/* --primary-color-medium; -high (#1976d2) measured 4.22:1 on --fs-panel2 */
|
/* --primary-color-medium; -high (#1976d2) measured 4.22:1 on --fs-panel2 */
|
||||||
--fs-accent-base: #1564c0;
|
--fs-accent-base: #1564c0;
|
||||||
--fs-accent-soft: color-mix(in srgb, var(--fs-accent) 10%, transparent);
|
--fs-accent-soft: color-mix(in srgb, var(--fs-accent) 10%, transparent);
|
||||||
@@ -430,7 +426,6 @@
|
|||||||
* than collapsing --text-color-medium and -low onto one colour. */
|
* than collapsing --text-color-medium and -low onto one colour. */
|
||||||
--fs-dim: #a6a6a6;
|
--fs-dim: #a6a6a6;
|
||||||
--fs-faint: #9a9a9a;
|
--fs-faint: #9a9a9a;
|
||||||
--fs-select-chevron: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="%23a6a6a6" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg>');
|
|
||||||
--fs-accent-base: #53a4c2;
|
--fs-accent-base: #53a4c2;
|
||||||
--fs-accent-soft: color-mix(in srgb, var(--fs-accent) 15%, transparent);
|
--fs-accent-soft: color-mix(in srgb, var(--fs-accent) 15%, transparent);
|
||||||
--fs-track: #333333;
|
--fs-track: #333333;
|
||||||
@@ -470,7 +465,6 @@
|
|||||||
--fs-text: #10202b;
|
--fs-text: #10202b;
|
||||||
--fs-dim: #2c4150;
|
--fs-dim: #2c4150;
|
||||||
--fs-faint: #3d5566;
|
--fs-faint: #3d5566;
|
||||||
--fs-select-chevron: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="%232c4150" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg>');
|
|
||||||
/* #00B5E2 held at hue, taken down until it reads: 5.89:1 on white against its own 2.09:1 */
|
/* #00B5E2 held at hue, taken down until it reads: 5.89:1 on white against its own 2.09:1 */
|
||||||
--fs-accent-base: #036c92;
|
--fs-accent-base: #036c92;
|
||||||
--fs-accent-soft: color-mix(in srgb, var(--fs-accent) 10%, transparent);
|
--fs-accent-soft: color-mix(in srgb, var(--fs-accent) 10%, transparent);
|
||||||
@@ -493,7 +487,6 @@
|
|||||||
--fs-text: #e6f1f7;
|
--fs-text: #e6f1f7;
|
||||||
--fs-dim: #b8cfdd;
|
--fs-dim: #b8cfdd;
|
||||||
--fs-faint: #9dbccd;
|
--fs-faint: #9dbccd;
|
||||||
--fs-select-chevron: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="%23b8cfdd" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg>');
|
|
||||||
/* the CI cyan, one step up so it clears AA on the lightest of the three surfaces too */
|
/* the CI cyan, one step up so it clears AA on the lightest of the three surfaces too */
|
||||||
--fs-accent-base: #35c6ea;
|
--fs-accent-base: #35c6ea;
|
||||||
--fs-accent-soft: color-mix(in srgb, var(--fs-accent) 15%, transparent);
|
--fs-accent-soft: color-mix(in srgb, var(--fs-accent) 15%, transparent);
|
||||||
@@ -507,4 +500,91 @@
|
|||||||
--fs-on-warn: #002b49;
|
--fs-on-warn: #002b49;
|
||||||
--fs-on-danger: #002b49;
|
--fs-on-danger: #002b49;
|
||||||
}
|
}
|
||||||
|
/* ---- forum — the OpenWrt forum's Discourse colourway (opt-in) ----
|
||||||
|
*
|
||||||
|
* Sampled from forum.openwrt.org's own `getComputedStyle(document.documentElement)`, one read
|
||||||
|
* per colour scheme: LIGHT --primary #222 (ink) / --secondary #fff (page) / --tertiary #0088cc
|
||||||
|
* (accent) / --quaternary and --danger both #e45735 / --success #009900 / --highlight #ffff4d;
|
||||||
|
* DARK --primary #ddd / --secondary #222 / --tertiary #0f82af / --danger #e45735 (unchanged
|
||||||
|
* from light) / --success #1ca551 / --highlight #a87137. Discourse names quaternary and
|
||||||
|
* danger as one colour in light and two in dark (#c14924); footstrap has no fifth semantic
|
||||||
|
* slot, so the dark quaternary is not carried — --fs-danger reads the site's own --danger.
|
||||||
|
*
|
||||||
|
* The header bar's navy (rgb(0,43,73) = #002b49) is not here: it is the forum's masthead, not
|
||||||
|
* its dark canvas — --secondary is #222 in BOTH the forum's own light and dark schemes (ink
|
||||||
|
* and page swap places, the page itself never turns navy). 2020's dark canvas is navy because
|
||||||
|
* that theme has no dark scheme of its own to sample; forum does, and it says #222. The chrome
|
||||||
|
* reads --fs-panel regardless (2020's own note, above), so the bar could not carry it anyway.
|
||||||
|
*
|
||||||
|
* None of the six sampled colours clears 4.5:1 as TEXT on the surface its own scheme pairs it
|
||||||
|
* with — Discourse checks contrast for its own use (a filled pill, an icon), not for the
|
||||||
|
* export tier every app prints text in — so every one of them is moved the way 2020's cyan
|
||||||
|
* was: hue and saturation held, lightness walked until the ratio clears. --fs-highlight has no
|
||||||
|
* footstrap analogue (it marks a search hit, not a status) and the sampled #ffff4d is a
|
||||||
|
* background wash — 1.07:1 on white — so it fills the one status slot forum's own scheme has
|
||||||
|
* no colour for, --fs-warn, exactly as its LIGHTNESS says: the brightest of the four before the
|
||||||
|
* move, still the one furthest from AA after it. */
|
||||||
|
:root[data-palette="forum"] {
|
||||||
|
/* LIGHT — the forum's own page, exactly: white canvas, near-black ink */
|
||||||
|
--fs-bg-base: #ffffff;
|
||||||
|
--fs-panel-base: #ffffff;
|
||||||
|
--fs-panel2-base: #f0f0f0;
|
||||||
|
--fs-border-base: #dddddd;
|
||||||
|
--fs-text: #222222;
|
||||||
|
--fs-dim: #3d3d3d;
|
||||||
|
--fs-faint: #4a4a4a;
|
||||||
|
/* --tertiary #0088cc measures 3.89:1 on white; #0074ad held the hue at 5.12:1 there but
|
||||||
|
* only 4.49:1 on --fs-panel2, under the 4.5:1 floor the export tier holds every surface to;
|
||||||
|
* #0073ac holds it at 5.19:1 on white and 4.55:1 on --fs-panel2 */
|
||||||
|
--fs-accent-base: #0073ac;
|
||||||
|
--fs-accent-soft: color-mix(in srgb, var(--fs-accent) 10%, transparent);
|
||||||
|
--fs-track: #eeeeee;
|
||||||
|
/* --success #009900 measured 3.78:1, #008000 5.14:1; --quaternary/--danger #e45735
|
||||||
|
* measured 3.68:1, #c63c1b 5.17:1; --highlight #ffff4d measured 1.07:1 as text, #717100
|
||||||
|
* 5.17:1 — see the block comment above for why highlight fills warn */
|
||||||
|
--fs-good-base: #008000;
|
||||||
|
--fs-warn-base: #717100;
|
||||||
|
--fs-danger-base: #c63c1b;
|
||||||
|
/* white on the fills above: 5.19/5.14/5.17/5.17 */
|
||||||
|
--fs-on-accent: #fff;
|
||||||
|
--fs-on-good: #fff;
|
||||||
|
--fs-on-warn: #fff;
|
||||||
|
--fs-on-danger: #fff;
|
||||||
|
}
|
||||||
|
:root[data-palette="forum"][data-darkmode="true"] {
|
||||||
|
/* DARK — the forum's own dark scheme: #222 canvas, #ddd ink, both exactly as sampled */
|
||||||
|
--fs-bg-base: #222222;
|
||||||
|
--fs-panel-base: #262626;
|
||||||
|
--fs-panel2-base: #2e2e2e;
|
||||||
|
--fs-border-base: #3a3a3a;
|
||||||
|
--fs-text: #dddddd;
|
||||||
|
--fs-dim: #a3a3a3;
|
||||||
|
--fs-faint: #969696;
|
||||||
|
/* --tertiary #0f82af measured 3.66:1 on --fs-bg and 3.12:1 on --fs-panel2, both under the
|
||||||
|
* 4.5:1 the export tier wants for a colour printed as text; #13a8e3 holds the hue at
|
||||||
|
* 5.86:1 on --fs-bg and 5.00:1 on --fs-panel2 */
|
||||||
|
--fs-accent-base: #13a8e3;
|
||||||
|
--fs-accent-soft: color-mix(in srgb, var(--fs-accent) 15%, transparent);
|
||||||
|
--fs-track: #333333;
|
||||||
|
/* --success #1ca551 measured 4.24:1 on --fs-panel2, #1fb65a 5.11:1; --danger #e45735
|
||||||
|
* measured 3.69:1, #eb8066 5.05:1; --highlight #a87137 measured 3.29:1, #c99259 5.00:1 —
|
||||||
|
* same reasoning as the light block for why highlight fills warn */
|
||||||
|
--fs-good-base: #1fb65a;
|
||||||
|
--fs-warn-base: #c99259;
|
||||||
|
--fs-danger-base: #eb8066;
|
||||||
|
/* dark ink: these fills are light, and #222222 (= --fs-bg-base) gives 5.86/5.98/5.86/5.92 */
|
||||||
|
--fs-on-accent: #222222;
|
||||||
|
--fs-on-good: #222222;
|
||||||
|
--fs-on-warn: #222222;
|
||||||
|
--fs-on-danger: #222222;
|
||||||
|
/* The masthead, and the one place the forum's navy belongs. rgb(0,43,73) is what
|
||||||
|
forum.openwrt.org paints its header with in its DARK scheme — measured live; its light
|
||||||
|
scheme has a white header (--header_background #ffffff, ink #333333), which is what this
|
||||||
|
palette's light half already gives, so the navy is declared here and only here.
|
||||||
|
color-mix, not a flat fill: --fs-bar-bg is 88% of the panel over the page on purpose (a
|
||||||
|
bar is a thin strip the page ghosts through, 02-tokens.css), and a flat colour would drop
|
||||||
|
that. Over this palette's #222 canvas the strip lands near #06294a, where the bar's own
|
||||||
|
ink (#dddddd) measures 9.9:1 and its dimmed ink (#a3a3a3) 5.4:1. */
|
||||||
|
--fs-bar-bg: color-mix(in srgb, #002b49 88%, transparent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -190,6 +190,7 @@
|
|||||||
display: flex; flex-wrap: wrap; gap: var(--fs-space-1-5);
|
display: flex; flex-wrap: wrap; gap: var(--fs-space-1-5);
|
||||||
order: 2; margin-inline-start: auto; padding: 0;
|
order: 2; margin-inline-start: auto; padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fs-themerow {
|
.fs-themerow {
|
||||||
display: flex; align-items: center; justify-content: center;
|
display: flex; align-items: center; justify-content: center;
|
||||||
flex: 0 0 auto; order: 2; margin-inline-start: auto;
|
flex: 0 0 auto; order: 2; margin-inline-start: auto;
|
||||||
@@ -197,7 +198,7 @@
|
|||||||
* them instead of pushing one cluster to the bar's far edge */
|
* them instead of pushing one cluster to the bar's far edge */
|
||||||
width: var(--fs-btn-size); height: var(--fs-btn-size); padding: 0;
|
width: var(--fs-btn-size); height: var(--fs-btn-size); padding: 0;
|
||||||
border: var(--fs-hairline); border-radius: var(--fs-radius);
|
border: var(--fs-hairline); border-radius: var(--fs-radius);
|
||||||
background: var(--fs-panel2); color: var(--fs-dim);
|
background: var(--fs-bar-ctl-bg); color: var(--fs-dim);
|
||||||
font: inherit; font-weight: var(--fs-weight); font-size: var(--fs-type); line-height: 1.1;
|
font: inherit; font-weight: var(--fs-weight); font-size: var(--fs-type); line-height: 1.1;
|
||||||
text-align: start; cursor: pointer;
|
text-align: start; cursor: pointer;
|
||||||
transition: background var(--fs-dur), border-color var(--fs-dur), color var(--fs-dur);
|
transition: background var(--fs-dur), border-color var(--fs-dur), color var(--fs-dur);
|
||||||
@@ -262,7 +263,7 @@
|
|||||||
flex: 0 0 auto; order: 2; justify-content: center;
|
flex: 0 0 auto; order: 2; justify-content: center;
|
||||||
width: var(--fs-btn-size); height: var(--fs-btn-size); padding: 0;
|
width: var(--fs-btn-size); height: var(--fs-btn-size); padding: 0;
|
||||||
border: var(--fs-hairline); border-radius: var(--fs-radius);
|
border: var(--fs-hairline); border-radius: var(--fs-radius);
|
||||||
background: var(--fs-panel2);
|
background: var(--fs-bar-ctl-bg);
|
||||||
}
|
}
|
||||||
/* on a square button the BORDER carries the state — the fill and the ink come from the
|
/* on a square button the BORDER carries the state — the fill and the ink come from the
|
||||||
* shared hover/active groups in 10-chrome.css */
|
* shared hover/active groups in 10-chrome.css */
|
||||||
@@ -769,7 +770,11 @@
|
|||||||
min-height: var(--fs-btn-size);
|
min-height: var(--fs-btn-size);
|
||||||
text-transform: none;
|
text-transform: none;
|
||||||
font-weight: var(--fs-weight); font-size: var(--fs-type);
|
font-weight: var(--fs-weight); font-size: var(--fs-type);
|
||||||
background: var(--fs-panel2); background-image: none;
|
/* the bar's control surface, not the panel: this pill sits in the same row as the square
|
||||||
|
* buttons and wears what they wear. Verified on the live DOM rather than by reading —
|
||||||
|
* ui.js emits the indicator as a bare `<span data-indicator=…>` with NO class, so a rule
|
||||||
|
* written against `.label` (as one here briefly was) matches nothing at all. */
|
||||||
|
background: var(--fs-bar-ctl-bg); background-image: none;
|
||||||
border: var(--fs-hairline);
|
border: var(--fs-hairline);
|
||||||
color: var(--fs-dim);
|
color: var(--fs-dim);
|
||||||
border-radius: var(--fs-radius); padding: 0 var(--fs-space-3); box-shadow: none;
|
border-radius: var(--fs-radius); padding: 0 var(--fs-space-3); box-shadow: none;
|
||||||
|
|||||||
@@ -313,17 +313,9 @@
|
|||||||
}
|
}
|
||||||
/* keyboard/click focus rings on the DRAWN box — the theme's one ring token, replacing
|
/* keyboard/click focus rings on the DRAWN box — the theme's one ring token, replacing
|
||||||
* base's old generic glow; :focus (not :focus-visible) keeps the pre-absorption behaviour
|
* base's old generic glow; :focus (not :focus-visible) keeps the pre-absorption behaviour
|
||||||
* of ringing a clicked box */
|
* of ringing a clicked box. Both states (plain and invalid) are declared once, further
|
||||||
input[type="checkbox"]:focus::before,
|
* down this file, in the selector lists every other same-body ring joins — see the two
|
||||||
input[type="radio"]:focus::before {
|
* `--fs-focus-ring`/`--fs-focus-ring-invalid` rules below the text-input group. */
|
||||||
border-color: var(--fs-accent);
|
|
||||||
box-shadow: var(--fs-focus-ring);
|
|
||||||
}
|
|
||||||
input[type="checkbox"].cbi-input-invalid:focus::before,
|
|
||||||
input[type="radio"].cbi-input-invalid:focus::before {
|
|
||||||
border-color: var(--fs-danger);
|
|
||||||
box-shadow: var(--fs-focus-ring-invalid);
|
|
||||||
}
|
|
||||||
input[type="checkbox"]::after,
|
input[type="checkbox"]::after,
|
||||||
input[type="radio"]::after {
|
input[type="radio"]::after {
|
||||||
/* the mark is inset from the DRAWING, and the drawing is centred in the target, so the mark
|
/* the mark is inset from the DRAWING, and the drawing is centred in the target, so the mark
|
||||||
@@ -401,7 +393,10 @@
|
|||||||
background-image: var(--fs-select-chevron);
|
background-image: var(--fs-select-chevron);
|
||||||
/* right inset from the scale, not a literal 12 — the .cbi-select shell below states the same
|
/* right inset from the scale, not a literal 12 — the .cbi-select shell below states the same
|
||||||
* position and two spellings of one number is how they would drift apart */
|
* position and two spellings of one number is how they would drift apart */
|
||||||
background-repeat: no-repeat; background-position: right var(--fs-space-3) center; background-size: 12px;
|
/* two 6px bands forming the V, the far one a band-width further in; --fs-space-3 stays the
|
||||||
|
* single spelling of the inset, as the note above says */
|
||||||
|
background-repeat: no-repeat; background-size: 6px 6px;
|
||||||
|
background-position: right calc(var(--fs-space-3) - 1px) center, right calc(var(--fs-space-3) + 5px) center;
|
||||||
padding: var(--fs-space-2) var(--fs-space-8) var(--fs-space-2) var(--fs-space-3);
|
padding: var(--fs-space-2) var(--fs-space-8) var(--fs-space-2) var(--fs-space-3);
|
||||||
border: var(--fs-hairline); border-radius: var(--fs-radius);
|
border: var(--fs-hairline); border-radius: var(--fs-radius);
|
||||||
color: var(--fs-text); font-family: var(--fs-font-sans); font-size: var(--fs-type);
|
color: var(--fs-text); font-family: var(--fs-font-sans); font-size: var(--fs-type);
|
||||||
@@ -420,7 +415,7 @@
|
|||||||
* listbox in dark mode. `height: inherit` absorbed from base with the width above — without
|
* listbox in dark mode. `height: inherit` absorbed from base with the width above — without
|
||||||
* it the fixed box would cap a multi-row listbox at one line. */
|
* it the fixed box would cap a multi-row listbox at one line. */
|
||||||
select[multiple] { background-color: var(--fs-panel2); color: var(--fs-text); height: inherit; }
|
select[multiple] { background-color: var(--fs-panel2); color: var(--fs-text); height: inherit; }
|
||||||
select:focus { border-color: var(--fs-accent); box-shadow: var(--fs-focus-ring); outline: none; }
|
/* :focus joins the shared accent ring in the text-input group below. */
|
||||||
/* absorbed from base's reset: 100% (= inherit) keeps the option on its select's size, and
|
/* absorbed from base's reset: 100% (= inherit) keeps the option on its select's size, and
|
||||||
* only <option> needs the 2em leading — the other controls carry line-height: normal above */
|
* only <option> needs the 2em leading — the other controls carry line-height: normal above */
|
||||||
option { font-size: 100%; line-height: 2em; }
|
option { font-size: 100%; line-height: 2em; }
|
||||||
@@ -491,8 +486,8 @@
|
|||||||
background-color: var(--fs-panel2);
|
background-color: var(--fs-panel2);
|
||||||
background-image: var(--fs-select-chevron);
|
background-image: var(--fs-select-chevron);
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: right var(--fs-space-3) center;
|
background-size: 6px 6px;
|
||||||
background-size: 12px;
|
background-position: right calc(var(--fs-space-3) - 1px) center, right calc(var(--fs-space-3) + 5px) center;
|
||||||
transition: var(--fs-field-transition);
|
transition: var(--fs-field-transition);
|
||||||
}
|
}
|
||||||
/* The disabled cue used to live ENTIRELY on the ▾ plate: base/30-forms.css dims
|
/* The disabled cue used to live ENTIRELY on the ▾ plate: base/30-forms.css dims
|
||||||
@@ -502,15 +497,8 @@
|
|||||||
opacity: var(--fs-disabled-opacity);
|
opacity: var(--fs-disabled-opacity);
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
.cbi-select.focus {
|
/* .focus and .cbi-input-invalid.focus join the shared accent/danger ring rules further down
|
||||||
border-color: var(--fs-accent);
|
* this file — same two bodies as every other :focus/:focus-within ring on this token. */
|
||||||
box-shadow: var(--fs-focus-ring);
|
|
||||||
}
|
|
||||||
/* the alarm must survive focus: .focus above would repaint an invalid shell accent */
|
|
||||||
.cbi-select.cbi-input-invalid.focus {
|
|
||||||
border-color: var(--fs-danger);
|
|
||||||
box-shadow: var(--fs-focus-ring-invalid);
|
|
||||||
}
|
|
||||||
/* the native <select> inside the shell: invisible, filling it, clearing the ▾ plate on the
|
/* the native <select> inside the shell: invisible, filling it, clearing the ▾ plate on the
|
||||||
* right. The inset is a scale step; the right margin is the plate's width, so it stays
|
* right. The inset is a scale step; the right margin is the plate's width, so it stays
|
||||||
* em-relative to the glyph it clears. Every themed-select declaration above (chevron,
|
* em-relative to the glyph it clears. Every themed-select declaration above (chevron,
|
||||||
@@ -621,26 +609,57 @@
|
|||||||
/* bare `input:focus` absorbed from base's generic glow onto the same ring: it is the fallback
|
/* bare `input:focus` absorbed from base's generic glow onto the same ring: it is the fallback
|
||||||
* for the types the list does not name and for a typeless <input>; on checkbox/radio it lands
|
* for the types the list does not name and for a typeless <input>; on checkbox/radio it lands
|
||||||
* on the invisible element box UNDER the drawn ::before ring above — coincident boxes, one
|
* on the invisible element box UNDER the drawn ::before ring above — coincident boxes, one
|
||||||
* visible ring, as the old glow behaved */
|
* visible ring, as the old glow behaved. `select:focus` and the keyboard-removable dynlist
|
||||||
|
* chip (ui.js gives it a tabindex) join here rather than repeating the same three
|
||||||
|
* declarations under their own selector: one shared body instead of three, 149 B off
|
||||||
|
* cascade.css. */
|
||||||
.cbi-input-text:focus, .cbi-input-password:focus, .cbi-input-textarea:focus,
|
.cbi-input-text:focus, .cbi-input-password:focus, .cbi-input-textarea:focus,
|
||||||
.cbi-section-create-name:focus,
|
.cbi-section-create-name:focus,
|
||||||
input:focus,
|
input:focus,
|
||||||
input[type="text"]:focus, input[type="password"]:focus, input[type="number"]:focus,
|
input[type="text"]:focus, input[type="password"]:focus, input[type="number"]:focus,
|
||||||
input[type="email"]:focus, input[type="url"]:focus, input[type="search"]:focus,
|
input[type="email"]:focus, input[type="url"]:focus, input[type="search"]:focus,
|
||||||
input[type="tel"]:focus, input[type="date"]:focus, input[type="time"]:focus,
|
input[type="tel"]:focus, input[type="date"]:focus, input[type="time"]:focus,
|
||||||
textarea:focus {
|
textarea:focus,
|
||||||
|
select:focus,
|
||||||
|
.cbi-dynlist > .item:focus {
|
||||||
border-color: var(--fs-accent);
|
border-color: var(--fs-accent);
|
||||||
box-shadow: var(--fs-focus-ring);
|
box-shadow: var(--fs-focus-ring);
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
/* The plain accent ring above, restated for four components whose selector cannot join that
|
||||||
|
* list without changing what it matches (a pseudo-element, a legacy shell class, two
|
||||||
|
* `:focus-within` containers) — same two declarations, one shared body instead of four, 186 B
|
||||||
|
* off cascade.css. `:is()` around the `:has()` compound keeps the list forgiving: unwrapped, a
|
||||||
|
* `:has()` compound sharing a selector list with plain ones fails the WHOLE rule below the
|
||||||
|
* floor (Firefox < 121; docs/css.md "Two shapes fail it"), instead of just losing that one
|
||||||
|
* selector. */
|
||||||
|
input[type="checkbox"]:focus::before, input[type="radio"]:focus::before,
|
||||||
|
.cbi-select.focus,
|
||||||
|
.cbi-dynlist > .add-item:focus-within,
|
||||||
|
.control-group:is(:has(> .cbi-input-password)):focus-within {
|
||||||
|
border-color: var(--fs-accent);
|
||||||
|
box-shadow: var(--fs-focus-ring);
|
||||||
|
}
|
||||||
|
|
||||||
/* Invalid state keeps the danger cue. `.cbi-value-error input` is the Lua-CBI path and belongs
|
/* Invalid state keeps the danger cue. `.cbi-value-error input` is the Lua-CBI path and belongs
|
||||||
* HERE, not in base: base does declare a red border-color for it, but the rule above sets the
|
* HERE, not in base: base does declare a red border-color for it, but the rule above sets the
|
||||||
* `border` SHORTHAND, and a shorthand in a later layer wipes the longhand out regardless of
|
* `border` SHORTHAND, and a shorthand in a later layer wipes the longhand out regardless of
|
||||||
* specificity — so every third-party app on luci-compat rendered the field in --fs-border grey
|
* specificity — so every third-party app on luci-compat rendered the field in --fs-border grey
|
||||||
* and had lost its field-error cue while the modern .cbi-input-invalid path worked. */
|
* and had lost its field-error cue while the modern .cbi-input-invalid path worked.
|
||||||
|
*
|
||||||
|
* `.cbi-input-invalid:focus` is not redundant with the rule it sits beside: the generic
|
||||||
|
* `input:focus` above is (0,1,1) and would repaint a focused invalid field accent, and
|
||||||
|
* `.cbi-input-invalid:focus` at (0,2,0) is what stops it — the TYPED `:focus` rules above are
|
||||||
|
* (0,2,1) and still outrank this, so a typed invalid field focuses accent, exactly as before
|
||||||
|
* the absorption. The checkbox/radio `::before` ring and the legacy `.cbi-select` shell need
|
||||||
|
* the identical danger body for the same reason on their own elements — one shared rule
|
||||||
|
* instead of four, 186 B off cascade.css. */
|
||||||
|
input[type="checkbox"].cbi-input-invalid:focus::before,
|
||||||
|
input[type="radio"].cbi-input-invalid:focus::before,
|
||||||
|
.cbi-select.cbi-input-invalid.focus,
|
||||||
.cbi-input-invalid, input.cbi-input-invalid, textarea.cbi-input-invalid,
|
.cbi-input-invalid, input.cbi-input-invalid, textarea.cbi-input-invalid,
|
||||||
.cbi-value-error input, .cbi-value-error textarea {
|
.cbi-value-error input, .cbi-value-error textarea,
|
||||||
|
.cbi-input-invalid:focus {
|
||||||
border-color: var(--fs-danger);
|
border-color: var(--fs-danger);
|
||||||
box-shadow: var(--fs-focus-ring-invalid);
|
box-shadow: var(--fs-focus-ring-invalid);
|
||||||
}
|
}
|
||||||
@@ -649,13 +668,6 @@
|
|||||||
* the input, so half of one state lived in a layer the theme cannot reach. */
|
* the input, so half of one state lived in a layer the theme cannot reach. */
|
||||||
.cbi-input-invalid.cbi-dropdown:not(.btn):not(.cbi-button),
|
.cbi-input-invalid.cbi-dropdown:not(.btn):not(.cbi-button),
|
||||||
.cbi-input-invalid.cbi-dropdown:not([open]) > ul > li { border-color: var(--fs-danger); }
|
.cbi-input-invalid.cbi-dropdown:not([open]) > ul > li { border-color: var(--fs-danger); }
|
||||||
/* the alarm must survive focus: the generic `input:focus` above is (0,1,1) and would repaint
|
|
||||||
* a focused invalid field accent; (0,2,0) outranks it. The TYPED :focus rules (0,2,1) still
|
|
||||||
* outrank this — a typed invalid field focuses accent, exactly as before the absorption. */
|
|
||||||
.cbi-input-invalid:focus {
|
|
||||||
border-color: var(--fs-danger);
|
|
||||||
box-shadow: var(--fs-focus-ring-invalid);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* readonly keeps its faded border — moved from base with the generic box (its border-color
|
/* readonly keeps its faded border — moved from base with the generic box (its border-color
|
||||||
* longhand would lose to the box's `border` shorthand by layer). The doubled [readonly] is
|
* longhand would lose to the box's `border` shorthand by layer). The doubled [readonly] is
|
||||||
@@ -692,12 +704,8 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
transition: var(--fs-field-transition);
|
transition: var(--fs-field-transition);
|
||||||
}
|
}
|
||||||
/* a chip is keyboard-removable (ui.js gives it a tabindex), so it needs the ring */
|
/* a chip is keyboard-removable (ui.js gives it a tabindex): :focus joins the shared accent
|
||||||
.cbi-dynlist > .item:focus {
|
* ring in the text-input group above. */
|
||||||
border-color: var(--fs-accent);
|
|
||||||
box-shadow: var(--fs-focus-ring);
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
/* The chip's × plate is a BUTTON in base's paint group (`.item::after, .btn, .cbi-button`) —
|
/* The chip's × plate is a BUTTON in base's paint group (`.item::after, .btn, .cbi-button`) —
|
||||||
* absorbed with it, bare as base had it (coverage: an .item outside a dynlist keeps its
|
* absorbed with it, bare as base had it (coverage: an .item outside a dynlist keeps its
|
||||||
* plate). The machinery — content/position/edges/align — stays in base with the widget. */
|
* plate). The machinery — content/position/edges/align — stays in base with the widget. */
|
||||||
@@ -730,7 +738,7 @@
|
|||||||
border-radius: var(--fs-radius-sm); overflow: hidden;
|
border-radius: var(--fs-radius-sm); overflow: hidden;
|
||||||
transition: var(--fs-field-transition);
|
transition: var(--fs-field-transition);
|
||||||
}
|
}
|
||||||
.cbi-dynlist > .add-item:focus-within { border-color: var(--fs-accent); box-shadow: var(--fs-focus-ring); }
|
/* :focus-within joins the shared accent ring in the text-input group above. */
|
||||||
.cbi-dynlist > .add-item > input,
|
.cbi-dynlist > .add-item > input,
|
||||||
/* `width: auto` keeps the flex basis in charge: this input sits INSIDE .cbi-value-field, so the
|
/* `width: auto` keeps the flex basis in charge: this input sits INSIDE .cbi-value-field, so the
|
||||||
* elastic width above would otherwise hand it 100% of the field on top of `flex: 1 1 auto`. */
|
* elastic width above would otherwise hand it 100% of the field on top of `flex: 1 1 auto`. */
|
||||||
@@ -756,10 +764,8 @@
|
|||||||
background: transparent; box-shadow: none;
|
background: transparent; box-shadow: none;
|
||||||
min-height: var(--fs-ctl-h);
|
min-height: var(--fs-ctl-h);
|
||||||
}
|
}
|
||||||
.control-group:has(> .cbi-input-password):focus-within {
|
/* :focus-within (wrapped in :is() for the shared list) joins the accent ring in the
|
||||||
border-color: var(--fs-accent);
|
* text-input group above. */
|
||||||
box-shadow: var(--fs-focus-ring);
|
|
||||||
}
|
|
||||||
/* base pulls .cbi-section-create up 3px to hug a table border, which glues the "Add" button
|
/* base pulls .cbi-section-create up 3px to hug a table border, which glues the "Add" button
|
||||||
* to the last row — give it a real gap instead. */
|
* to the last row — give it a real gap instead. */
|
||||||
.cbi-section-create, .cbi-section-create.cbi-tblsection-create { margin-top: var(--fs-space-3); }
|
.cbi-section-create, .cbi-section-create.cbi-tblsection-create { margin-top: var(--fs-space-3); }
|
||||||
|
|||||||
@@ -45,7 +45,7 @@
|
|||||||
'tint', 'accent', 'good', 'warn', 'danger',
|
'tint', 'accent', 'good', 'warn', 'danger',
|
||||||
'card', 'control', 'bar', 'line',
|
'card', 'control', 'bar', 'line',
|
||||||
'rounding', 'autocollapse', 'tint_strength', 'photo_dim',
|
'rounding', 'autocollapse', 'tint_strength', 'photo_dim',
|
||||||
'pattern_size', 'pattern_strength', 'pattern_ink',
|
'pattern_size', 'pattern_strength', 'pattern_ink', 'content_width',
|
||||||
/* the two uploaded images' cache-bust tokens (head.ut whitelists both to hex); the files
|
/* the two uploaded images' cache-bust tokens (head.ut whitelists both to hex); the files
|
||||||
themselves are served. Not axes — they have no browser layer — but they reach the client
|
themselves are served. Not axes — they have no browser layer — but they reach the client
|
||||||
the same way. */
|
the same way. */
|
||||||
|
|||||||
@@ -16,11 +16,15 @@
|
|||||||
before the include, so a `?? {}` here would only hide that contract from a second caller. */
|
before the include, so a `?? {}` here would only hide that contract from a second caller. */
|
||||||
let _sd_lay = index([ 'sidebar', 'top' ], fs_defaults.layout) >= 0 ? fs_defaults.layout : '';
|
let _sd_lay = index([ 'sidebar', 'top' ], fs_defaults.layout) >= 0 ? fs_defaults.layout : '';
|
||||||
let _sd_dark = index([ 'auto', 'light', 'dark' ], fs_defaults.darkmode) >= 0 ? fs_defaults.darkmode : '';
|
let _sd_dark = index([ 'auto', 'light', 'dark' ], fs_defaults.darkmode) >= 0 ? fs_defaults.darkmode : '';
|
||||||
let _sd_pal = index([ 'footstrap', 'hicontrast', 'bootstrap', '2020' ], fs_defaults.palette) >= 0 ? fs_defaults.palette : '';
|
let _sd_pal = index([ 'footstrap', 'hicontrast', 'bootstrap', '2020', 'forum' ], fs_defaults.palette) >= 0 ? fs_defaults.palette : '';
|
||||||
let _sd_wall = index([ 'off', 'pattern', 'file' ], fs_defaults.wallpaper) >= 0 ? fs_defaults.wallpaper : '';
|
let _sd_wall = index([ 'off', 'pattern', 'file' ], fs_defaults.wallpaper) >= 0 ? fs_defaults.wallpaper : '';
|
||||||
let _sd_pink = index([ 'theme', 'original' ], fs_defaults.pattern_ink) >= 0 ? fs_defaults.pattern_ink : '';
|
let _sd_pink = index([ 'theme', 'original' ], fs_defaults.pattern_ink) >= 0 ? fs_defaults.pattern_ink : '';
|
||||||
let _sd_ac = index([ 'on', 'off' ], fs_defaults.autocollapse) >= 0 ? fs_defaults.autocollapse : '';
|
let _sd_ac = index([ 'on', 'off' ], fs_defaults.autocollapse) >= 0 ? fs_defaults.autocollapse : '';
|
||||||
let _sd_dens = index([ 'compact', 'normal', 'large' ], fs_defaults.density) >= 0 ? fs_defaults.density : '';
|
let _sd_dens = index([ 'compact', 'normal', 'large' ], fs_defaults.density) >= 0 ? fs_defaults.density : '';
|
||||||
|
/* issue #44: how far the content column may grow past --fs-content-max's 1280px default.
|
||||||
|
header.ut's FS_AXES carries 'content_width', so a saved router default reaches this. */
|
||||||
|
let _cw = int(fs_defaults.content_width);
|
||||||
|
let _sd_cwidth = (fs_defaults.content_width != '' && _cw >= 1280 && _cw <= 3840) ? _cw : -1;
|
||||||
/* The five colour axes each hold one of three things: '' or '0' for off, '1'..'360' for a hue,
|
/* The five colour axes each hold one of three things: '' or '0' for off, '1'..'360' for a hue,
|
||||||
or '#rrggbb'. Both live forms reach the client as a string, and the pre-paint re-reads which
|
or '#rrggbb'. Both live forms reach the client as a string, and the pre-paint re-reads which
|
||||||
it is the way fs-prefs.js's normColor() does, so this passes through exactly those two shapes
|
it is the way fs-prefs.js's normColor() does, so this passes through exactly those two shapes
|
||||||
@@ -147,7 +151,7 @@
|
|||||||
current*(), so the Appearance controls show the effective default when this browser has no
|
current*(), so the Appearance controls show the effective default when this browser has no
|
||||||
localStorage. See the sanitiser above for the unset encodings. #}
|
localStorage. See the sanitiser above for the unset encodings. #}
|
||||||
<script>window.__fsPlugins={{ sprintf('%J', fs_plugins) }};</script>
|
<script>window.__fsPlugins={{ sprintf('%J', fs_plugins) }};</script>
|
||||||
<script>window.__fsSD={layout:"{{ _sd_lay }}",darkmode:"{{ _sd_dark }}",palette:"{{ _sd_pal }}",wallpaper:"{{ _sd_wall }}",tint:"{{ _sd_tint }}",accent:"{{ _sd_acc }}",good:"{{ _sd_good }}",warn:"{{ _sd_warn }}",danger:"{{ _sd_dang }}",card:"{{ _sd_card }}",control:"{{ _sd_ctrl }}",bar:"{{ _sd_bar }}",line:"{{ _sd_line }}",rounding:{{ _sd_round }},autocollapse:"{{ _sd_ac }}",login_bg:"{{ _sd_lbg }}",tint_strength:{{ _sd_tstr }},photo_dim:{{ _sd_pdim }},density:"{{ _sd_dens }}",pattern:"{{ _sd_pat }}",pattern_size:{{ _sd_psize }},pattern_strength:{{ _sd_pstr }},pattern_ink:"{{ _sd_pink }}"};</script>
|
<script>window.__fsSD={layout:"{{ _sd_lay }}",darkmode:"{{ _sd_dark }}",palette:"{{ _sd_pal }}",wallpaper:"{{ _sd_wall }}",tint:"{{ _sd_tint }}",accent:"{{ _sd_acc }}",good:"{{ _sd_good }}",warn:"{{ _sd_warn }}",danger:"{{ _sd_dang }}",card:"{{ _sd_card }}",control:"{{ _sd_ctrl }}",bar:"{{ _sd_bar }}",line:"{{ _sd_line }}",rounding:{{ _sd_round }},autocollapse:"{{ _sd_ac }}",login_bg:"{{ _sd_lbg }}",tint_strength:{{ _sd_tstr }},photo_dim:{{ _sd_pdim }},density:"{{ _sd_dens }}",pattern:"{{ _sd_pat }}",pattern_size:{{ _sd_psize }},pattern_strength:{{ _sd_pstr }},pattern_ink:"{{ _sd_pink }}",content_width:{{ _sd_cwidth }}};</script>
|
||||||
<script>
|
<script>
|
||||||
/* Each IIFE below pre-paints one Appearance axis before the first frame, duplicating a
|
/* Each IIFE below pre-paints one Appearance axis before the first frame, duplicating a
|
||||||
live applier in fs-prefs.js. They cannot share code — this runs before the module
|
live applier in fs-prefs.js. They cannot share code — this runs before the module
|
||||||
@@ -218,7 +222,7 @@
|
|||||||
is the same one fs-prefs.js validates against — a name in one and not the
|
is the same one fs-prefs.js validates against — a name in one and not the
|
||||||
other paints here and is taken away by the first live change. */
|
other paints here and is taken away by the first live change. */
|
||||||
if (p === null) p = sd.palette || null;
|
if (p === null) p = sd.palette || null;
|
||||||
if (p === 'hicontrast' || p === 'bootstrap' || p === '2020') root.setAttribute('data-palette', p);
|
if (p === 'hicontrast' || p === 'bootstrap' || p === '2020' || p === 'forum') root.setAttribute('data-palette', p);
|
||||||
else root.removeAttribute('data-palette');
|
else root.removeAttribute('data-palette');
|
||||||
|
|
||||||
/* Wallpaper: off | pattern (the uploaded SVG, tiled and recoloured) | file (the
|
/* Wallpaper: off | pattern (the uploaded SVG, tiled and recoloured) | file (the
|
||||||
@@ -227,7 +231,11 @@
|
|||||||
sd.pattern is whitelisted to hex above, so nothing user-controlled reaches
|
sd.pattern is whitelisted to hex above, so nothing user-controlled reaches
|
||||||
the url(). */
|
the url(). */
|
||||||
const pu = sd.pattern;
|
const pu = sd.pattern;
|
||||||
if (pu) root.style.setProperty('--fs-pattern-url', 'url("/luci-static/footstrap/pattern.svg?v=' + pu + '")');
|
/* /cgi-bin, not a /www symlink: a plain static SVG is a same-origin document
|
||||||
|
that runs script opened directly (OpenWrt forum thread 251930); this path
|
||||||
|
is the CGI handler that answers with CSP 'none' + sandbox instead — see
|
||||||
|
fs-axes.js's PAT_SERVE, which this string must keep matching. */
|
||||||
|
if (pu) root.style.setProperty('--fs-pattern-url', 'url("/cgi-bin/luci-theme-footstrap-pattern?v=' + pu + '")');
|
||||||
const psRaw = lsGet('fs-pattern-size');
|
const psRaw = lsGet('fs-pattern-size');
|
||||||
const ps = (psRaw !== null) ? parseInt(psRaw, 10) : sd.pattern_size;
|
const ps = (psRaw !== null) ? parseInt(psRaw, 10) : sd.pattern_size;
|
||||||
if (ps >= 40 && ps <= 1600 && ps !== 440) root.style.setProperty('--fs-pattern-size', ps + 'px');
|
if (ps >= 40 && ps <= 1600 && ps !== 440) root.style.setProperty('--fs-pattern-size', ps + 'px');
|
||||||
@@ -252,6 +260,17 @@
|
|||||||
if (dn === 'compact' || dn === 'large') root.setAttribute('data-density', dn);
|
if (dn === 'compact' || dn === 'large') root.setAttribute('data-density', dn);
|
||||||
else root.removeAttribute('data-density');
|
else root.removeAttribute('data-density');
|
||||||
|
|
||||||
|
/* Content width (issue #44): how far the column may grow past the 1280px
|
||||||
|
default, as a px length rather than a step name — the slider is continuous.
|
||||||
|
Written only when it differs from the default, so an untouched theme paints
|
||||||
|
from the bare :root exactly as it did before this axis existed.
|
||||||
|
sd.content_width is -1 when unset. */
|
||||||
|
const cwRaw = lsGet('fs-content-width');
|
||||||
|
let cw = parseInt(cwRaw, 10);
|
||||||
|
if (cwRaw === null) cw = (sd.content_width >= 1280 ? sd.content_width : 1280);
|
||||||
|
if (cw >= 1280 && cw <= 3840 && cw !== 1280)
|
||||||
|
root.style.setProperty('--fs-content-max', cw + 'px');
|
||||||
|
|
||||||
/* Rounding 0-20px (02-tokens derives the control and chip radii from it). The
|
/* Rounding 0-20px (02-tokens derives the control and chip radii from it). The
|
||||||
default is a literal, this running before the stylesheet, so axes.mjs is the
|
default is a literal, this running before the stylesheet, so axes.mjs is the
|
||||||
only thing checking the two agree. sd.rounding is -1 when unset. */
|
only thing checking the two agree. sd.rounding is -1 when unset. */
|
||||||
|
|||||||
+2
-2
@@ -10,12 +10,12 @@ include $(INCLUDE_DIR)/kernel.mk
|
|||||||
|
|
||||||
PKG_NAME:=natflow
|
PKG_NAME:=natflow
|
||||||
PKG_VERSION:=20260531
|
PKG_VERSION:=20260531
|
||||||
PKG_RELEASE:=78
|
PKG_RELEASE:=79
|
||||||
|
|
||||||
PKG_SOURCE:=$(PKG_VERSION).tar.xz
|
PKG_SOURCE:=$(PKG_VERSION).tar.xz
|
||||||
PKG_SOURCE_URL:=https://github.com/ptpt52/natflow.git
|
PKG_SOURCE_URL:=https://github.com/ptpt52/natflow.git
|
||||||
PKG_SOURCE_PROTO:=git
|
PKG_SOURCE_PROTO:=git
|
||||||
PKG_SOURCE_VERSION:=da0eb608568f2ff10ce80ee3337db87c8e49611b
|
PKG_SOURCE_VERSION:=e059e88e4c1ddc202d122098424d8b9f1d859356
|
||||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
|
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
|
||||||
PKG_MAINTAINER:=Chen Minqiang <ptpt52@gmail.com>
|
PKG_MAINTAINER:=Chen Minqiang <ptpt52@gmail.com>
|
||||||
PKG_LICENSE:=GPL-2.0
|
PKG_LICENSE:=GPL-2.0
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ include $(TOPDIR)/rules.mk
|
|||||||
include $(INCLUDE_DIR)/kernel.mk
|
include $(INCLUDE_DIR)/kernel.mk
|
||||||
|
|
||||||
PKG_NAME:=tcp-brutal
|
PKG_NAME:=tcp-brutal
|
||||||
PKG_VERSION:=1.0.3
|
PKG_VERSION:=2.0.0
|
||||||
PKG_RELEASE:=1
|
PKG_RELEASE:=2
|
||||||
|
|
||||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||||
PKG_SOURCE_URL:=https://codeload.github.com/apernet/tcp-brutal/tar.gz/v$(PKG_VERSION)?
|
PKG_SOURCE_URL:=https://codeload.github.com/apernet/tcp-brutal/tar.gz/v$(PKG_VERSION)?
|
||||||
|
|||||||
+54
-4
@@ -37,12 +37,36 @@ endif
|
|||||||
|
|
||||||
PKG_NAME:=pgyvpn
|
PKG_NAME:=pgyvpn
|
||||||
PKG_VERSION:=3.1.0
|
PKG_VERSION:=3.1.0
|
||||||
PKG_RELEASE:=1
|
PKG_RELEASE:=4
|
||||||
|
|
||||||
PKG_SOURCE:=pgyvpnsvr
|
PKG_SOURCE:=pgyvpnsvr
|
||||||
PKG_SOURCE_URL:=https://mirrors.oray.com/orayos/packages/$(PKG_NAME)/$(PKG_ARCH_PGYYPN)/$(PKG_VERSION)/bin
|
PKG_SOURCE_URL:=https://mirrors.oray.com/orayos/packages/$(PKG_NAME)/$(PKG_ARCH_PGYYPN)/$(PKG_VERSION)/bin
|
||||||
PKG_HASH:=skip
|
PKG_HASH:=skip
|
||||||
|
|
||||||
|
OPENSSL_COMPAT_VERSION:=1.1.1w
|
||||||
|
OPENSSL_COMPAT_SOURCE:=openssl-$(OPENSSL_COMPAT_VERSION).tar.gz
|
||||||
|
OPENSSL_COMPAT_HASH:=cf3098950cb4d853ad95c0841f1f9c6d3dc102dccfcacd521d93925208b76ac8
|
||||||
|
|
||||||
|
OPENSSL_COMPAT_TARGET:=linux-generic32
|
||||||
|
ifeq ($(ARCH),arm)
|
||||||
|
OPENSSL_COMPAT_TARGET:=linux-armv4
|
||||||
|
endif
|
||||||
|
ifeq ($(ARCH),aarch64)
|
||||||
|
OPENSSL_COMPAT_TARGET:=linux-aarch64
|
||||||
|
endif
|
||||||
|
ifeq ($(ARCH),mips)
|
||||||
|
OPENSSL_COMPAT_TARGET:=linux-mips32
|
||||||
|
endif
|
||||||
|
ifeq ($(ARCH),mipsel)
|
||||||
|
OPENSSL_COMPAT_TARGET:=linux-mips32
|
||||||
|
endif
|
||||||
|
ifeq ($(ARCH),i386)
|
||||||
|
OPENSSL_COMPAT_TARGET:=linux-x86
|
||||||
|
endif
|
||||||
|
ifeq ($(ARCH),x86_64)
|
||||||
|
OPENSSL_COMPAT_TARGET:=linux-x86_64
|
||||||
|
endif
|
||||||
|
|
||||||
PKG_MAINTAINER:=Oray <developer@oray.com>
|
PKG_MAINTAINER:=Oray <developer@oray.com>
|
||||||
|
|
||||||
include $(INCLUDE_DIR)/package.mk
|
include $(INCLUDE_DIR)/package.mk
|
||||||
@@ -52,7 +76,7 @@ define Package/pgyvpn
|
|||||||
CATEGORY:=Network
|
CATEGORY:=Network
|
||||||
SUBMENU:=VPN
|
SUBMENU:=VPN
|
||||||
DEPENDS:=@(arm||aarch64||mips||mipsel||i386||x86_64) \
|
DEPENDS:=@(arm||aarch64||mips||mipsel||i386||x86_64) \
|
||||||
+iptables +libc +libopenssl +librt \
|
+iptables +libc +librt \
|
||||||
+libpthread +libstdcpp +kmod-tun
|
+libpthread +libstdcpp +kmod-tun
|
||||||
TITLE:=PuGongYing VPN, Fast networking
|
TITLE:=PuGongYing VPN, Fast networking
|
||||||
URL:=https://pgy.oray.com/
|
URL:=https://pgy.oray.com/
|
||||||
@@ -68,16 +92,39 @@ define Download/extra
|
|||||||
URL:=$(PKG_SOURCE_URL)
|
URL:=$(PKG_SOURCE_URL)
|
||||||
HASH:=skip
|
HASH:=skip
|
||||||
endef
|
endef
|
||||||
|
|
||||||
|
define Download/openssl-compat
|
||||||
|
FILE:=$(OPENSSL_COMPAT_SOURCE)
|
||||||
|
URL:=https://www.openssl.org/source/old/1.1.1
|
||||||
|
HASH:=skip
|
||||||
|
endef
|
||||||
$(eval $(call Download,extra))
|
$(eval $(call Download,extra))
|
||||||
|
$(eval $(call Download,openssl-compat))
|
||||||
|
|
||||||
define Build/Prepare
|
define Build/Prepare
|
||||||
mkdir -p $(PKG_BUILD_DIR)
|
mkdir -p $(PKG_BUILD_DIR)
|
||||||
|
$(TAR) -C $(PKG_BUILD_DIR) -xf $(DL_DIR)/$(OPENSSL_COMPAT_SOURCE)
|
||||||
mv $(DL_DIR)/{pgyvpn_oraysl,pgyvpnsvr} $(PKG_BUILD_DIR)
|
mv $(DL_DIR)/{pgyvpn_oraysl,pgyvpnsvr} $(PKG_BUILD_DIR)
|
||||||
chmod +x $(PKG_BUILD_DIR)/{pgyvpn_oraysl,pgyvpnsvr}
|
chmod +x $(PKG_BUILD_DIR)/{pgyvpn_oraysl,pgyvpnsvr}
|
||||||
endef
|
endef
|
||||||
|
|
||||||
|
define Build/Configure
|
||||||
|
( cd $(PKG_BUILD_DIR)/openssl-$(OPENSSL_COMPAT_VERSION) && \
|
||||||
|
CC="$(TARGET_CC)" \
|
||||||
|
./Configure $(OPENSSL_COMPAT_TARGET) \
|
||||||
|
--prefix=/usr \
|
||||||
|
--libdir=lib \
|
||||||
|
--cross-compile-prefix="$(TARGET_CROSS)" \
|
||||||
|
shared no-tests no-engine no-async no-comp no-asm \
|
||||||
|
$(TARGET_CFLAGS) $(TARGET_CPPFLAGS) $(TARGET_LDFLAGS) \
|
||||||
|
)
|
||||||
|
endef
|
||||||
|
|
||||||
define Build/Compile
|
define Build/Compile
|
||||||
true
|
+$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR)/openssl-$(OPENSSL_COMPAT_VERSION) \
|
||||||
|
CC="$(TARGET_CC)" \
|
||||||
|
SOURCE_DATE_EPOCH=$(SOURCE_DATE_EPOCH) \
|
||||||
|
build_libs
|
||||||
endef
|
endef
|
||||||
|
|
||||||
define Package/pgyvpn/install
|
define Package/pgyvpn/install
|
||||||
@@ -86,8 +133,11 @@ define Package/pgyvpn/install
|
|||||||
$(INSTALL_DIR) $(1)/etc/hotplug.d/iface
|
$(INSTALL_DIR) $(1)/etc/hotplug.d/iface
|
||||||
$(INSTALL_DIR) $(1)/usr/sbin
|
$(INSTALL_DIR) $(1)/usr/sbin
|
||||||
$(INSTALL_DIR) $(1)/usr/share/pgyvpn
|
$(INSTALL_DIR) $(1)/usr/share/pgyvpn
|
||||||
|
$(INSTALL_DIR) $(1)/usr/lib
|
||||||
|
|
||||||
$(CP) $(PKG_BUILD_DIR)/pgyvpn_oraysl $(1)/usr/sbin
|
$(CP) $(PKG_BUILD_DIR)/{pgyvpn_oraysl,pgyvpnsvr} $(1)/usr/sbin
|
||||||
|
$(INSTALL_DATA) $(PKG_BUILD_DIR)/openssl-$(OPENSSL_COMPAT_VERSION)/libssl.so.1.1 $(1)/usr/lib
|
||||||
|
$(INSTALL_DATA) $(PKG_BUILD_DIR)/openssl-$(OPENSSL_COMPAT_VERSION)/libcrypto.so.1.1 $(1)/usr/lib
|
||||||
$(INSTALL_BIN) ./files/etc/init.d/* $(1)/etc/init.d
|
$(INSTALL_BIN) ./files/etc/init.d/* $(1)/etc/init.d
|
||||||
$(INSTALL_CONF) ./files/etc/config/* $(1)/etc/config
|
$(INSTALL_CONF) ./files/etc/config/* $(1)/etc/config
|
||||||
$(INSTALL_BIN) ./files/etc/hotplug.d/iface/* $(1)/etc/hotplug.d/iface
|
$(INSTALL_BIN) ./files/etc/hotplug.d/iface/* $(1)/etc/hotplug.d/iface
|
||||||
|
|||||||
Reference in New Issue
Block a user