diff --git a/.github/workflows/deployment.yaml b/.github/workflows/deployment.yaml
index 1d6cdf02..f9b2e529 100644
--- a/.github/workflows/deployment.yaml
+++ b/.github/workflows/deployment.yaml
@@ -9,7 +9,7 @@ jobs:
strategy:
matrix: # https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs
platform: [mac, ios]
- runs-on: macos-latest # https://github.com/actions/runner-images
+ runs-on: macos-26 # https://github.com/actions/runner-images
steps:
- uses: actions/checkout@v4 # https://github.com/actions/checkout
with:
@@ -37,8 +37,10 @@ jobs:
if: ${{ github.event.release.prerelease }}
- run: npm run build:${{ matrix.platform }}-safari-15
if: ${{ ! github.event.release.prerelease }}
- - name: Set xcode version
- run: sudo xcode-select -s "/Applications/Xcode_16.2.app" # https://github.com/actions/runner-images/blob/main/images/macos/macos-14-arm64-Readme.md#xcode
+ # - name: Set xcode version
+ # run: sudo xcode-select -s "/Applications/Xcode_26.1.1.app" # https://github.com/actions/runner-images/blob/main/images/macos/macos-26-arm64-Readme.md#xcode
+ # - run: xcodebuild -downloadPlatform iOS # Temporary fix for Xcode_26_beta
+ # if: matrix.platform == 'ios'
- name: Run fastlane
id: fastlane
working-directory: ./fastlane
diff --git a/README.md b/README.md
index b000d558..09cdc78a 100644
--- a/README.md
+++ b/README.md
@@ -54,14 +54,15 @@ After installing the iOS App, you need two main steps to make the extension work
> [!NOTE]
>
-> The App cannot detect whether you have enabled the extension in Safari, therefore, the App prompt will not change after you enable the extension. Currently the App interface is only used to set or change the userscripts directory.
+> The iOS App cannot detect whether you have enabled the extension in Safari, therefore, the App prompt will not change after you enable the extension. Currently the App interface is only used to set or change the userscripts directory.
>
-> You could select an iCloud folder for syncing scripts between macOS and iOS, but please note that there may be delays in synchronization, and you may encounter files be evictioned due to iCloud optimization, please refer to [#424](https://github.com/quoid/userscripts/issues/424).
+> You could select an iCloud folder for syncing scripts between macOS and iOS, but please note that there may be delays in synchronization, and you may encounter files be evictioned due to iCloud optimization, please refer to [#424](https://github.com/quoid/userscripts/issues/424). (**Since macOS 15 / iOS 18, please set "keep downloaded" for the folder to avoid eviction**)
There are two main ways to install a user script from the iOS version:
-- Visit any `.user.js` URL in Safari, then open the extension `popup` and you will see an installation prompt
-- You can also save `.user.js` files directly to the Userscripts directory you set above
+- Visit a `.user.js` URL in Safari, then open the extension `popup` and you will see an installation prompt
+ - The URL should end with `.user.js` in `/PATH` part, not the `?QUERY` or `#HASH` parts
+- You could also save files with the extension `.user.js` directly to the Userscripts directory you set above
> [!TIP]
>
@@ -177,10 +178,13 @@ Userscripts Safari currently supports the following userscript metadata:
- when paired with `@updateURL`, this will allow the user to update a userscript from a remote source, if the version on their machine is `<` version at the update URL
- `@version` does nothing by itself, it needs to be paired with` @updateURL` for remote updating to function properly
- `@updateURL`
- - the remote url to check version against
+ - the remote url to check version against, the url `/PATH` should end with `.meta.js` and contains the Metadata block
- if the version of the file located at the update URL is `>` the version on the local machine, the file will be updated
- `@updateURL` does nothing by itself, it needs to be paired with `@version` for remote updating to function properly
+ - Read this [link](https://stackoverflow.com/questions/38023717/) for more details
+ - _Note: The extension does not correctly implement the entire update process, tracking in issue [#248](https://github.com/quoid/userscripts/issues/248)_
- `@downloadURL`
+ - the url `/PATH` should end with `.user.js`, that is, it cannot be in `?QUERY` or `#HASH` parts
- optional download location for a remotely updateable file (\*i.e. a file that has both `@version` and `@updateURL`)
- when paired with `@version` and `@updateURL`, if the local version is `<` the version of the file that `@updateURL` points to, the extension will attempt to update the file's code with the contents of the file located at the `@downloadURL`
- `@downloadURL` does nothing by itself, it needs `@version` and `@updateURL` to present in order to function properly
@@ -382,6 +386,6 @@ Userscripts does not collect any data from its users nor monitor activities or a
## License
-Copyright (c) 2018-2024 Justin Wasack
+Copyright © 2018-2025 Justin Wasack
Licensed under the [GNU General Public License v3.0](/LICENSE) license for all open source applications. A commercial license is required for all other applications.
diff --git a/docs/contributing.md b/docs/contributing.md
index 7d09d9d4..3cb92e9d 100644
--- a/docs/contributing.md
+++ b/docs/contributing.md
@@ -117,4 +117,4 @@ If you are not a member of the project, first you need to fork the master branch
# About
-[Userscripts](https://github.com/quoid/userscripts) @ 2018-2023
+[Userscripts](https://github.com/quoid/userscripts)
diff --git a/docs/dev.md b/docs/dev.md
index 2bfa7681..262aac05 100644
--- a/docs/dev.md
+++ b/docs/dev.md
@@ -79,4 +79,4 @@ Note that all existing `.xcconfig` files already include `.dev.xcconfig` files o
# About
-[Userscripts](https://github.com/quoid/userscripts) @ 2018-2024
+[Userscripts](https://github.com/quoid/userscripts)
diff --git a/docs/structure.md b/docs/structure.md
index d493c3b7..1a0cd320 100644
--- a/docs/structure.md
+++ b/docs/structure.md
@@ -38,4 +38,4 @@ Build the project from here to extension bundled app
# About
-[Userscripts](https://github.com/quoid/userscripts) @ 2018-2023
+[Userscripts](https://github.com/quoid/userscripts)
diff --git a/fastlane/Gemfile.lock b/fastlane/Gemfile.lock
index 989cb342..c6013a88 100644
--- a/fastlane/Gemfile.lock
+++ b/fastlane/Gemfile.lock
@@ -1,39 +1,40 @@
GEM
remote: https://rubygems.org/
specs:
- CFPropertyList (3.0.7)
- base64
- nkf
- rexml
- addressable (2.8.7)
- public_suffix (>= 2.0.2, < 7.0)
+ CFPropertyList (3.0.8)
+ abbrev (0.1.2)
+ addressable (2.8.8)
+ public_suffix (>= 2.0.2, < 8.0)
artifactory (3.0.17)
atomos (0.1.3)
- aws-eventstream (1.3.2)
- aws-partitions (1.1106.0)
- aws-sdk-core (3.224.0)
+ aws-eventstream (1.4.0)
+ aws-partitions (1.1188.0)
+ aws-sdk-core (3.239.2)
aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.992.0)
aws-sigv4 (~> 1.9)
base64
+ bigdecimal
jmespath (~> 1, >= 1.6.1)
logger
- aws-sdk-kms (1.101.0)
- aws-sdk-core (~> 3, >= 3.216.0)
+ aws-sdk-kms (1.118.0)
+ aws-sdk-core (~> 3, >= 3.239.1)
aws-sigv4 (~> 1.5)
- aws-sdk-s3 (1.186.1)
- aws-sdk-core (~> 3, >= 3.216.0)
+ aws-sdk-s3 (1.205.0)
+ aws-sdk-core (~> 3, >= 3.234.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.5)
- aws-sigv4 (1.11.0)
+ aws-sigv4 (1.12.1)
aws-eventstream (~> 1, >= 1.0.2)
babosa (1.0.4)
base64 (0.2.0)
+ bigdecimal (3.3.1)
claide (1.1.0)
colored (1.2)
colored2 (3.1.2)
commander (4.6.0)
highline (~> 2.0.0)
+ csv (3.3.5)
declarative (0.0.20)
digest-crc (0.7.0)
rake (>= 12.0.0, < 14.0.0)
@@ -53,14 +54,14 @@ GEM
faraday-rack (~> 1.0)
faraday-retry (~> 1.0)
ruby2_keywords (>= 0.0.4)
- faraday-cookie_jar (0.0.7)
+ faraday-cookie_jar (0.0.8)
faraday (>= 0.8.0)
- http-cookie (~> 1.0.0)
+ http-cookie (>= 1.0.0)
faraday-em_http (1.0.0)
- faraday-em_synchrony (1.0.0)
+ faraday-em_synchrony (1.0.1)
faraday-excon (1.1.0)
faraday-httpclient (1.0.1)
- faraday-multipart (1.1.0)
+ faraday-multipart (1.1.1)
multipart-post (~> 2.0)
faraday-net_http (1.0.2)
faraday-net_http_persistent (1.2.0)
@@ -70,15 +71,18 @@ GEM
faraday_middleware (1.2.1)
faraday (~> 1.0)
fastimage (2.4.0)
- fastlane (2.227.2)
+ fastlane (2.229.1)
CFPropertyList (>= 2.3, < 4.0.0)
+ abbrev (~> 0.1.2)
addressable (>= 2.8, < 3.0.0)
artifactory (~> 3.0)
aws-sdk-s3 (~> 1.0)
babosa (>= 1.0.3, < 2.0.0)
+ base64 (~> 0.2.0)
bundler (>= 1.12.0, < 3.0.0)
colored (~> 1.2)
commander (~> 4.6)
+ csv (~> 3.3)
dotenv (>= 2.1.1, < 3.0.0)
emoji_regex (>= 0.1, < 4.0)
excon (>= 0.71.0, < 1.0.0)
@@ -98,7 +102,9 @@ GEM
jwt (>= 2.1.0, < 3)
mini_magick (>= 4.9.4, < 5.0.0)
multipart-post (>= 2.0.0, < 3.0.0)
+ mutex_m (~> 0.3.0)
naturally (~> 2.2)
+ nkf (~> 0.2.0)
optparse (>= 0.1.1, < 1.0.0)
plist (>= 3.1.0, < 4.0.0)
rubyzip (>= 2.0.0, < 3.0.0)
@@ -157,37 +163,37 @@ GEM
httpclient (2.9.0)
mutex_m
jmespath (1.6.2)
- json (2.12.0)
- jwt (2.10.1)
+ json (2.16.0)
+ jwt (2.10.2)
base64
logger (1.7.0)
mini_magick (4.13.2)
mini_mime (1.1.5)
- multi_json (1.15.0)
+ multi_json (1.17.0)
multipart-post (2.4.1)
mutex_m (0.3.0)
nanaimo (0.4.0)
- naturally (2.2.1)
+ naturally (2.3.0)
nkf (0.2.0)
- optparse (0.6.0)
+ optparse (0.8.0)
os (1.1.4)
plist (3.7.2)
- public_suffix (6.0.2)
- rake (13.2.1)
+ public_suffix (7.0.0)
+ rake (13.3.1)
representable (3.2.0)
declarative (< 0.1.0)
trailblazer-option (>= 0.1.1, < 0.2.0)
uber (< 0.2.0)
retriable (3.1.2)
- rexml (3.4.1)
+ rexml (3.4.4)
rouge (3.28.0)
ruby2_keywords (0.0.5)
rubyzip (2.4.1)
security (0.1.5)
- signet (0.20.0)
+ signet (0.21.0)
addressable (~> 2.8)
faraday (>= 0.17.5, < 3.a)
- jwt (>= 1.5, < 3.0)
+ jwt (>= 1.5, < 4.0)
multi_json (~> 1.10)
simctl (1.6.10)
CFPropertyList
@@ -217,11 +223,11 @@ GEM
xcpretty (~> 0.2, >= 0.0.7)
PLATFORMS
- arm64-darwin-23
+ arm64-darwin-25
ruby
DEPENDENCIES
fastlane
BUNDLED WITH
- 2.6.9
+ 2.7.2
diff --git a/public/ext/shared/_locales/en/messages.json b/public/ext/shared/_locales/en/messages.json
index a39bfc24..c17c6cad 100644
--- a/public/ext/shared/_locales/en/messages.json
+++ b/public/ext/shared/_locales/en/messages.json
@@ -85,6 +85,24 @@
"settings_global_active_desc": {
"message": "Toggle on/off script injection for the pages you visit"
},
+ "settings_theme_mode": {
+ "message": "Theme mode"
+ },
+ "settings_theme_mode_desc": {
+ "message": "Toggle theme mode"
+ },
+ "settings_theme_mode_auto": {
+ "message": "Auto (System)"
+ },
+ "settings_theme_mode_dark": {
+ "message": "Dark"
+ },
+ "settings_theme_mode_light": {
+ "message": "Light"
+ },
+ "settings_theme_mode_custom": {
+ "message": "Custom"
+ },
"settings_global_exclude_match": {
"message": "Global Exclude Match patterns"
},
diff --git a/scripts/dev-safari.js b/scripts/dev-safari.js
index 34943850..c9236b9f 100644
--- a/scripts/dev-safari.js
+++ b/scripts/dev-safari.js
@@ -186,6 +186,7 @@ async function serverCheck(url) {
/** run development server */
const server = await createServer({
...sharedConfig,
+ publicDir: "public/ext/vendor/",
plugins: [svelte()],
server: {
host: true,
diff --git a/src/app/App.svelte b/src/app/App.svelte
index 7e6c5c5b..bbfe8df8 100644
--- a/src/app/App.svelte
+++ b/src/app/App.svelte
@@ -1,7 +1,7 @@
@@ -72,10 +108,30 @@
{/if}
{/if}
-
-
-
+
+ {#if !sidebarHidden}
+
+
+ {/if}
+
+{#if splitterActive}
+
+{/if}
{#each $notifications as item (item.id)}
notifications.remove(item.id)} {item} />
@@ -120,6 +176,34 @@
overflow: hidden;
}
+ .resize-mask {
+ background-color: transparent;
+ cursor: col-resize;
+ position: fixed;
+ inset: 0;
+ z-index: 20;
+ }
+
+ .splitter {
+ --splitter-width: 6px;
+ --splitter-offset: calc(var(--splitter-width) / 2);
+ --sidebar-fixed-width: max(var(--sidebar-min-width), var(--sidebar-width));
+
+ background-color: transparent;
+ cursor: col-resize;
+ position: fixed;
+ left: calc(var(--sidebar-fixed-width) - var(--splitter-offset));
+ width: var(--splitter-width);
+ height: 100svh;
+ z-index: 21;
+ transition: background-color 0.2s ease-in-out;
+
+ &:hover,
+ &.dragging {
+ background-color: var(--color-blue);
+ }
+ }
+
ul {
bottom: 1rem;
left: 50%;
diff --git a/src/ext/extension-page/Components/Editor/CodeMirror.svelte b/src/ext/extension-page/Components/Editor/CodeMirror.svelte
index f097189b..b2cbacda 100644
--- a/src/ext/extension-page/Components/Editor/CodeMirror.svelte
+++ b/src/ext/extension-page/Components/Editor/CodeMirror.svelte
@@ -150,11 +150,6 @@
"Cmd-S": () => saveHandler(),
"Cmd-F": () => activateSearch(),
Esc: () => (searchActive = false),
- Tab: (cm) => {
- // convert tabs to spaces and add invisible elements
- const s = Array(cm.getOption("indentUnit") + 1).join(" ");
- cm.replaceSelection(s);
- },
},
});
diff --git a/src/ext/extension-page/Components/Editor/Editor.svelte b/src/ext/extension-page/Components/Editor/Editor.svelte
index 0bdd3507..e0b7c719 100644
--- a/src/ext/extension-page/Components/Editor/Editor.svelte
+++ b/src/ext/extension-page/Components/Editor/Editor.svelte
@@ -13,6 +13,10 @@
import iconDownload from "@shared/img/icon-download.svg?raw";
import iconTrash from "@shared/img/icon-trash.svg?raw";
import iconSync from "@shared/img/icon-sync.svg?raw";
+ import iconSidebar from "@shared/img/icon-sidebar.svg?raw";
+
+ export let sidebarHidden;
+ export let sidebarSwitch;
// the data the populates editor elements
let canUpdate;
@@ -167,13 +171,22 @@
No Item Selected
{/if}