feat: add support for safari
@@ -10,6 +10,7 @@ lerna-debug.log*
|
|||||||
node_modules
|
node_modules
|
||||||
dist
|
dist
|
||||||
dist-ssr
|
dist-ssr
|
||||||
|
dist-safari
|
||||||
*.local
|
*.local
|
||||||
dist.crx
|
dist.crx
|
||||||
dist.pem
|
dist.pem
|
||||||
@@ -26,3 +27,8 @@ dist.pem
|
|||||||
*.sw?
|
*.sw?
|
||||||
|
|
||||||
linkwarden.zip
|
linkwarden.zip
|
||||||
|
|
||||||
|
# Safari / Xcode
|
||||||
|
**/build/
|
||||||
|
**/DerivedData/
|
||||||
|
*.xcuserdata
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
{
|
||||||
|
"manifest_version": 3,
|
||||||
|
"name": "Linkwarden",
|
||||||
|
"description": "The browser extension for Linkwarden.",
|
||||||
|
"homepage_url": "https://linkwarden.app/",
|
||||||
|
"version": "1.5.3",
|
||||||
|
"action": {
|
||||||
|
"default_popup": "index.html",
|
||||||
|
"default_icon": {
|
||||||
|
"16": "16.png",
|
||||||
|
"32": "32.png",
|
||||||
|
"48": "48.png",
|
||||||
|
"128": "128.png"
|
||||||
|
},
|
||||||
|
"default_title": "Linkwarden"
|
||||||
|
},
|
||||||
|
"options_ui": {
|
||||||
|
"page": "src/pages/Options/options.html",
|
||||||
|
"browser_style": false
|
||||||
|
},
|
||||||
|
"icons": { "16": "16.png", "32": "32.png", "48": "48.png", "128": "128.png" },
|
||||||
|
"permissions": [
|
||||||
|
"storage",
|
||||||
|
"scripting",
|
||||||
|
"activeTab",
|
||||||
|
"tabs",
|
||||||
|
"contextMenus"
|
||||||
|
],
|
||||||
|
"host_permissions": ["<all_urls>"],
|
||||||
|
"background": {
|
||||||
|
"scripts": ["background.js"],
|
||||||
|
"type": "module"
|
||||||
|
},
|
||||||
|
"content_security_policy": {
|
||||||
|
"extension_pages": "script-src 'self'; object-src 'self'; connect-src 'self' http: https:;"
|
||||||
|
},
|
||||||
|
"commands": {
|
||||||
|
"_execute_action": {
|
||||||
|
"suggested_key": { "default": "Ctrl+Shift+F", "mac": "Command+Shift+Y" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"browser_specific_settings": {
|
||||||
|
"safari": {
|
||||||
|
"strict_min_version": "15.4"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,6 +9,8 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "tsc && vite build && cp ./manifest.json dist/manifest.json",
|
"build": "tsc && vite build && cp ./manifest.json dist/manifest.json",
|
||||||
|
"build:safari": "tsc && vite build --outDir dist-safari && cp ./manifest.safari.json dist-safari/manifest.json && cp public/*.png dist-safari/",
|
||||||
|
"convert:safari": "xcrun safari-web-extension-converter dist-safari/ --project-location safari/ --app-name Linkwarden --bundle-identifier app.linkwarden.safari-extension --swift --macos-only --no-prompt --no-open",
|
||||||
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>NSExtension</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSExtensionPointIdentifier</key>
|
||||||
|
<string>com.apple.Safari.web-extension</string>
|
||||||
|
<key>NSExtensionPrincipalClass</key>
|
||||||
|
<string>$(PRODUCT_MODULE_NAME).SafariWebExtensionHandler</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
//
|
||||||
|
// SafariWebExtensionHandler.swift
|
||||||
|
// Linkwarden Extension
|
||||||
|
//
|
||||||
|
// Created by Daniel on 2026-04-23.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SafariServices
|
||||||
|
import os.log
|
||||||
|
|
||||||
|
class SafariWebExtensionHandler: NSObject, NSExtensionRequestHandling {
|
||||||
|
|
||||||
|
func beginRequest(with context: NSExtensionContext) {
|
||||||
|
let request = context.inputItems.first as? NSExtensionItem
|
||||||
|
|
||||||
|
let profile: UUID?
|
||||||
|
if #available(iOS 17.0, macOS 14.0, *) {
|
||||||
|
profile = request?.userInfo?[SFExtensionProfileKey] as? UUID
|
||||||
|
} else {
|
||||||
|
profile = request?.userInfo?["profile"] as? UUID
|
||||||
|
}
|
||||||
|
|
||||||
|
let message: Any?
|
||||||
|
if #available(iOS 15.0, macOS 11.0, *) {
|
||||||
|
message = request?.userInfo?[SFExtensionMessageKey]
|
||||||
|
} else {
|
||||||
|
message = request?.userInfo?["message"]
|
||||||
|
}
|
||||||
|
|
||||||
|
os_log(.default, "Received message from browser.runtime.sendNativeMessage: %@ (profile: %@)", String(describing: message), profile?.uuidString ?? "none")
|
||||||
|
|
||||||
|
let response = NSExtensionItem()
|
||||||
|
if #available(iOS 15.0, macOS 11.0, *) {
|
||||||
|
response.userInfo = [ SFExtensionMessageKey: [ "echo": message ] ]
|
||||||
|
} else {
|
||||||
|
response.userInfo = [ "message": [ "echo": message ] ]
|
||||||
|
}
|
||||||
|
|
||||||
|
context.completeRequest(returningItems: [ response ], completionHandler: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,647 @@
|
|||||||
|
// !$*UTF8*$!
|
||||||
|
{
|
||||||
|
archiveVersion = 1;
|
||||||
|
classes = {
|
||||||
|
};
|
||||||
|
objectVersion = 77;
|
||||||
|
objects = {
|
||||||
|
|
||||||
|
/* Begin PBXBuildFile section */
|
||||||
|
65E051CD2F9AFEE100628D48 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65E051CC2F9AFEE100628D48 /* AppDelegate.swift */; };
|
||||||
|
65E051D12F9AFEE200628D48 /* Main.html in Resources */ = {isa = PBXBuildFile; fileRef = 65E051CF2F9AFEE100628D48 /* Main.html */; };
|
||||||
|
65E051D32F9AFEE200628D48 /* Icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 65E051D22F9AFEE200628D48 /* Icon.png */; };
|
||||||
|
65E051D52F9AFEE200628D48 /* Style.css in Resources */ = {isa = PBXBuildFile; fileRef = 65E051D42F9AFEE200628D48 /* Style.css */; };
|
||||||
|
65E051D72F9AFEE200628D48 /* Script.js in Resources */ = {isa = PBXBuildFile; fileRef = 65E051D62F9AFEE200628D48 /* Script.js */; };
|
||||||
|
65E051D92F9AFEE200628D48 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65E051D82F9AFEE200628D48 /* ViewController.swift */; };
|
||||||
|
65E051DC2F9AFEE200628D48 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 65E051DA2F9AFEE200628D48 /* Main.storyboard */; };
|
||||||
|
65E051DE2F9AFEE300628D48 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 65E051DD2F9AFEE300628D48 /* Assets.xcassets */; };
|
||||||
|
65E051E52F9AFEE300628D48 /* Linkwarden Extension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 65E051E42F9AFEE300628D48 /* Linkwarden Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
|
65E051EA2F9AFEE300628D48 /* SafariWebExtensionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65E051E92F9AFEE300628D48 /* SafariWebExtensionHandler.swift */; };
|
||||||
|
65E052012F9AFEE300628D48 /* 48.png in Resources */ = {isa = PBXBuildFile; fileRef = 65E051F62F9AFEE300628D48 /* 48.png */; };
|
||||||
|
65E052022F9AFEE300628D48 /* index.html in Resources */ = {isa = PBXBuildFile; fileRef = 65E051F72F9AFEE300628D48 /* index.html */; };
|
||||||
|
65E052032F9AFEE300628D48 /* background.js in Resources */ = {isa = PBXBuildFile; fileRef = 65E051F82F9AFEE300628D48 /* background.js */; };
|
||||||
|
65E052042F9AFEE300628D48 /* 128.png in Resources */ = {isa = PBXBuildFile; fileRef = 65E051F92F9AFEE300628D48 /* 128.png */; };
|
||||||
|
65E052052F9AFEE300628D48 /* options.js in Resources */ = {isa = PBXBuildFile; fileRef = 65E051FA2F9AFEE300628D48 /* options.js */; };
|
||||||
|
65E052062F9AFEE300628D48 /* 16.png in Resources */ = {isa = PBXBuildFile; fileRef = 65E051FB2F9AFEE300628D48 /* 16.png */; };
|
||||||
|
65E052072F9AFEE300628D48 /* main.js in Resources */ = {isa = PBXBuildFile; fileRef = 65E051FC2F9AFEE300628D48 /* main.js */; };
|
||||||
|
65E052082F9AFEE300628D48 /* 32.png in Resources */ = {isa = PBXBuildFile; fileRef = 65E051FD2F9AFEE300628D48 /* 32.png */; };
|
||||||
|
65E052092F9AFEE300628D48 /* manifest.json in Resources */ = {isa = PBXBuildFile; fileRef = 65E051FE2F9AFEE300628D48 /* manifest.json */; };
|
||||||
|
65E0520A2F9AFEE300628D48 /* assets in Resources */ = {isa = PBXBuildFile; fileRef = 65E051FF2F9AFEE300628D48 /* assets */; };
|
||||||
|
65E0520B2F9AFEE300628D48 /* src in Resources */ = {isa = PBXBuildFile; fileRef = 65E052002F9AFEE300628D48 /* src */; };
|
||||||
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
|
/* Begin PBXContainerItemProxy section */
|
||||||
|
65E051E62F9AFEE300628D48 /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = 65E051C12F9AFEE100628D48 /* Project object */;
|
||||||
|
proxyType = 1;
|
||||||
|
remoteGlobalIDString = 65E051E32F9AFEE300628D48;
|
||||||
|
remoteInfo = "Linkwarden Extension";
|
||||||
|
};
|
||||||
|
/* End PBXContainerItemProxy section */
|
||||||
|
|
||||||
|
/* Begin PBXCopyFilesBuildPhase section */
|
||||||
|
65E051F12F9AFEE300628D48 /* Embed Foundation Extensions */ = {
|
||||||
|
isa = PBXCopyFilesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
dstPath = "";
|
||||||
|
dstSubfolderSpec = 13;
|
||||||
|
files = (
|
||||||
|
65E051E52F9AFEE300628D48 /* Linkwarden Extension.appex in Embed Foundation Extensions */,
|
||||||
|
);
|
||||||
|
name = "Embed Foundation Extensions";
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXCopyFilesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXFileReference section */
|
||||||
|
65E051C92F9AFEE100628D48 /* Linkwarden.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Linkwarden.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
65E051CC2F9AFEE100628D48 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||||
|
65E051D02F9AFEE100628D48 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = Base; path = Base.lproj/Main.html; sourceTree = "<group>"; };
|
||||||
|
65E051D22F9AFEE200628D48 /* Icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Icon.png; sourceTree = "<group>"; };
|
||||||
|
65E051D42F9AFEE200628D48 /* Style.css */ = {isa = PBXFileReference; lastKnownFileType = text.css; path = Style.css; sourceTree = "<group>"; };
|
||||||
|
65E051D62F9AFEE200628D48 /* Script.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = Script.js; sourceTree = "<group>"; };
|
||||||
|
65E051D82F9AFEE200628D48 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
|
||||||
|
65E051DB2F9AFEE200628D48 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||||
|
65E051DD2F9AFEE300628D48 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
|
65E051DF2F9AFEE300628D48 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
65E051E42F9AFEE300628D48 /* Linkwarden Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "Linkwarden Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
65E051E92F9AFEE300628D48 /* SafariWebExtensionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariWebExtensionHandler.swift; sourceTree = "<group>"; };
|
||||||
|
65E051EB2F9AFEE300628D48 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
65E051F62F9AFEE300628D48 /* 48.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = 48.png; path = "../../../dist-safari/48.png"; sourceTree = "<group>"; };
|
||||||
|
65E051F72F9AFEE300628D48 /* index.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = index.html; path = "../../../dist-safari/index.html"; sourceTree = "<group>"; };
|
||||||
|
65E051F82F9AFEE300628D48 /* background.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = background.js; path = "../../../dist-safari/background.js"; sourceTree = "<group>"; };
|
||||||
|
65E051F92F9AFEE300628D48 /* 128.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = 128.png; path = "../../../dist-safari/128.png"; sourceTree = "<group>"; };
|
||||||
|
65E051FA2F9AFEE300628D48 /* options.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = options.js; path = "../../../dist-safari/options.js"; sourceTree = "<group>"; };
|
||||||
|
65E051FB2F9AFEE300628D48 /* 16.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = 16.png; path = "../../../dist-safari/16.png"; sourceTree = "<group>"; };
|
||||||
|
65E051FC2F9AFEE300628D48 /* main.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = main.js; path = "../../../dist-safari/main.js"; sourceTree = "<group>"; };
|
||||||
|
65E051FD2F9AFEE300628D48 /* 32.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = 32.png; path = "../../../dist-safari/32.png"; sourceTree = "<group>"; };
|
||||||
|
65E051FE2F9AFEE300628D48 /* manifest.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; name = manifest.json; path = "../../../dist-safari/manifest.json"; sourceTree = "<group>"; };
|
||||||
|
65E051FF2F9AFEE300628D48 /* assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = assets; path = "../../../dist-safari/assets"; sourceTree = "<group>"; };
|
||||||
|
65E052002F9AFEE300628D48 /* src */ = {isa = PBXFileReference; lastKnownFileType = folder; name = src; path = "../../../dist-safari/src"; sourceTree = "<group>"; };
|
||||||
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
65E051C62F9AFEE100628D48 /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
65E051E12F9AFEE300628D48 /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXGroup section */
|
||||||
|
65E051C02F9AFEE100628D48 = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
65E051CB2F9AFEE100628D48 /* Linkwarden */,
|
||||||
|
65E051E82F9AFEE300628D48 /* Linkwarden Extension */,
|
||||||
|
65E051CA2F9AFEE100628D48 /* Products */,
|
||||||
|
);
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
65E051CA2F9AFEE100628D48 /* Products */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
65E051C92F9AFEE100628D48 /* Linkwarden.app */,
|
||||||
|
65E051E42F9AFEE300628D48 /* Linkwarden Extension.appex */,
|
||||||
|
);
|
||||||
|
name = Products;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
65E051CB2F9AFEE100628D48 /* Linkwarden */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
65E051CC2F9AFEE100628D48 /* AppDelegate.swift */,
|
||||||
|
65E051D82F9AFEE200628D48 /* ViewController.swift */,
|
||||||
|
65E051DA2F9AFEE200628D48 /* Main.storyboard */,
|
||||||
|
65E051DD2F9AFEE300628D48 /* Assets.xcassets */,
|
||||||
|
65E051DF2F9AFEE300628D48 /* Info.plist */,
|
||||||
|
65E051CE2F9AFEE100628D48 /* Resources */,
|
||||||
|
);
|
||||||
|
path = Linkwarden;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
65E051CE2F9AFEE100628D48 /* Resources */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
65E051CF2F9AFEE100628D48 /* Main.html */,
|
||||||
|
65E051D22F9AFEE200628D48 /* Icon.png */,
|
||||||
|
65E051D42F9AFEE200628D48 /* Style.css */,
|
||||||
|
65E051D62F9AFEE200628D48 /* Script.js */,
|
||||||
|
);
|
||||||
|
path = Resources;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
65E051E82F9AFEE300628D48 /* Linkwarden Extension */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
65E051F52F9AFEE300628D48 /* Resources */,
|
||||||
|
65E051E92F9AFEE300628D48 /* SafariWebExtensionHandler.swift */,
|
||||||
|
65E051EB2F9AFEE300628D48 /* Info.plist */,
|
||||||
|
);
|
||||||
|
path = "Linkwarden Extension";
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
65E051F52F9AFEE300628D48 /* Resources */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
65E051F62F9AFEE300628D48 /* 48.png */,
|
||||||
|
65E051F72F9AFEE300628D48 /* index.html */,
|
||||||
|
65E051F82F9AFEE300628D48 /* background.js */,
|
||||||
|
65E051F92F9AFEE300628D48 /* 128.png */,
|
||||||
|
65E051FA2F9AFEE300628D48 /* options.js */,
|
||||||
|
65E051FB2F9AFEE300628D48 /* 16.png */,
|
||||||
|
65E051FC2F9AFEE300628D48 /* main.js */,
|
||||||
|
65E051FD2F9AFEE300628D48 /* 32.png */,
|
||||||
|
65E051FE2F9AFEE300628D48 /* manifest.json */,
|
||||||
|
65E051FF2F9AFEE300628D48 /* assets */,
|
||||||
|
65E052002F9AFEE300628D48 /* src */,
|
||||||
|
);
|
||||||
|
name = Resources;
|
||||||
|
path = "Linkwarden Extension";
|
||||||
|
sourceTree = SOURCE_ROOT;
|
||||||
|
};
|
||||||
|
/* End PBXGroup section */
|
||||||
|
|
||||||
|
/* Begin PBXNativeTarget section */
|
||||||
|
65E051C82F9AFEE100628D48 /* Linkwarden */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = 65E051F22F9AFEE300628D48 /* Build configuration list for PBXNativeTarget "Linkwarden" */;
|
||||||
|
buildPhases = (
|
||||||
|
65E051C52F9AFEE100628D48 /* Sources */,
|
||||||
|
65E051C62F9AFEE100628D48 /* Frameworks */,
|
||||||
|
65E051C72F9AFEE100628D48 /* Resources */,
|
||||||
|
65E051F12F9AFEE300628D48 /* Embed Foundation Extensions */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
65E051E72F9AFEE300628D48 /* PBXTargetDependency */,
|
||||||
|
);
|
||||||
|
name = Linkwarden;
|
||||||
|
packageProductDependencies = (
|
||||||
|
);
|
||||||
|
productName = Linkwarden;
|
||||||
|
productReference = 65E051C92F9AFEE100628D48 /* Linkwarden.app */;
|
||||||
|
productType = "com.apple.product-type.application";
|
||||||
|
};
|
||||||
|
65E051E32F9AFEE300628D48 /* Linkwarden Extension */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = 65E051EE2F9AFEE300628D48 /* Build configuration list for PBXNativeTarget "Linkwarden Extension" */;
|
||||||
|
buildPhases = (
|
||||||
|
65E051E02F9AFEE300628D48 /* Sources */,
|
||||||
|
65E051E12F9AFEE300628D48 /* Frameworks */,
|
||||||
|
65E051E22F9AFEE300628D48 /* Resources */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
);
|
||||||
|
name = "Linkwarden Extension";
|
||||||
|
packageProductDependencies = (
|
||||||
|
);
|
||||||
|
productName = "Linkwarden Extension";
|
||||||
|
productReference = 65E051E42F9AFEE300628D48 /* Linkwarden Extension.appex */;
|
||||||
|
productType = "com.apple.product-type.app-extension";
|
||||||
|
};
|
||||||
|
/* End PBXNativeTarget section */
|
||||||
|
|
||||||
|
/* Begin PBXProject section */
|
||||||
|
65E051C12F9AFEE100628D48 /* Project object */ = {
|
||||||
|
isa = PBXProject;
|
||||||
|
attributes = {
|
||||||
|
BuildIndependentTargetsInParallel = 1;
|
||||||
|
LastSwiftUpdateCheck = 2610;
|
||||||
|
LastUpgradeCheck = 2610;
|
||||||
|
TargetAttributes = {
|
||||||
|
65E051C82F9AFEE100628D48 = {
|
||||||
|
CreatedOnToolsVersion = 26.1;
|
||||||
|
};
|
||||||
|
65E051E32F9AFEE300628D48 = {
|
||||||
|
CreatedOnToolsVersion = 26.1;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
buildConfigurationList = 65E051C42F9AFEE100628D48 /* Build configuration list for PBXProject "Linkwarden" */;
|
||||||
|
developmentRegion = en;
|
||||||
|
hasScannedForEncodings = 0;
|
||||||
|
knownRegions = (
|
||||||
|
en,
|
||||||
|
Base,
|
||||||
|
);
|
||||||
|
mainGroup = 65E051C02F9AFEE100628D48;
|
||||||
|
minimizedProjectReferenceProxies = 1;
|
||||||
|
preferredProjectObjectVersion = 77;
|
||||||
|
productRefGroup = 65E051CA2F9AFEE100628D48 /* Products */;
|
||||||
|
projectDirPath = "";
|
||||||
|
projectRoot = "";
|
||||||
|
targets = (
|
||||||
|
65E051C82F9AFEE100628D48 /* Linkwarden */,
|
||||||
|
65E051E32F9AFEE300628D48 /* Linkwarden Extension */,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
/* End PBXProject section */
|
||||||
|
|
||||||
|
/* Begin PBXResourcesBuildPhase section */
|
||||||
|
65E051C72F9AFEE100628D48 /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
65E051D32F9AFEE200628D48 /* Icon.png in Resources */,
|
||||||
|
65E051DC2F9AFEE200628D48 /* Main.storyboard in Resources */,
|
||||||
|
65E051D72F9AFEE200628D48 /* Script.js in Resources */,
|
||||||
|
65E051D12F9AFEE200628D48 /* Main.html in Resources */,
|
||||||
|
65E051DE2F9AFEE300628D48 /* Assets.xcassets in Resources */,
|
||||||
|
65E051D52F9AFEE200628D48 /* Style.css in Resources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
65E051E22F9AFEE300628D48 /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
65E052012F9AFEE300628D48 /* 48.png in Resources */,
|
||||||
|
65E052042F9AFEE300628D48 /* 128.png in Resources */,
|
||||||
|
65E052062F9AFEE300628D48 /* 16.png in Resources */,
|
||||||
|
65E052032F9AFEE300628D48 /* background.js in Resources */,
|
||||||
|
65E052092F9AFEE300628D48 /* manifest.json in Resources */,
|
||||||
|
65E0520A2F9AFEE300628D48 /* assets in Resources */,
|
||||||
|
65E052072F9AFEE300628D48 /* main.js in Resources */,
|
||||||
|
65E0520B2F9AFEE300628D48 /* src in Resources */,
|
||||||
|
65E052022F9AFEE300628D48 /* index.html in Resources */,
|
||||||
|
65E052082F9AFEE300628D48 /* 32.png in Resources */,
|
||||||
|
65E052052F9AFEE300628D48 /* options.js in Resources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
65E051C52F9AFEE100628D48 /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
65E051D92F9AFEE200628D48 /* ViewController.swift in Sources */,
|
||||||
|
65E051CD2F9AFEE100628D48 /* AppDelegate.swift in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
65E051E02F9AFEE300628D48 /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
65E051EA2F9AFEE300628D48 /* SafariWebExtensionHandler.swift in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXTargetDependency section */
|
||||||
|
65E051E72F9AFEE300628D48 /* PBXTargetDependency */ = {
|
||||||
|
isa = PBXTargetDependency;
|
||||||
|
target = 65E051E32F9AFEE300628D48 /* Linkwarden Extension */;
|
||||||
|
targetProxy = 65E051E62F9AFEE300628D48 /* PBXContainerItemProxy */;
|
||||||
|
};
|
||||||
|
/* End PBXTargetDependency section */
|
||||||
|
|
||||||
|
/* Begin PBXVariantGroup section */
|
||||||
|
65E051CF2F9AFEE100628D48 /* Main.html */ = {
|
||||||
|
isa = PBXVariantGroup;
|
||||||
|
children = (
|
||||||
|
65E051D02F9AFEE100628D48 /* Base */,
|
||||||
|
);
|
||||||
|
name = Main.html;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
65E051DA2F9AFEE200628D48 /* Main.storyboard */ = {
|
||||||
|
isa = PBXVariantGroup;
|
||||||
|
children = (
|
||||||
|
65E051DB2F9AFEE200628D48 /* Base */,
|
||||||
|
);
|
||||||
|
name = Main.storyboard;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXVariantGroup section */
|
||||||
|
|
||||||
|
/* Begin XCBuildConfiguration section */
|
||||||
|
65E051EC2F9AFEE300628D48 /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
ENABLE_TESTABILITY = YES;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
|
"DEBUG=1",
|
||||||
|
"$(inherited)",
|
||||||
|
);
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 26.1;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
|
SDKROOT = macosx;
|
||||||
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
65E051ED2F9AFEE300628D48 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 26.1;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
SDKROOT = macosx;
|
||||||
|
SWIFT_COMPILATION_MODE = wholemodule;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
65E051EF2F9AFEE300628D48 /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEVELOPMENT_TEAM = FZ44882Y36;
|
||||||
|
ENABLE_APP_SANDBOX = YES;
|
||||||
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
|
ENABLE_USER_SELECTED_FILES = readonly;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_FILE = "Linkwarden Extension/Info.plist";
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = "Linkwarden Extension";
|
||||||
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/../Frameworks",
|
||||||
|
"@executable_path/../../../../Frameworks",
|
||||||
|
);
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||||
|
MARKETING_VERSION = 1.5.3;
|
||||||
|
OTHER_LDFLAGS = (
|
||||||
|
"-framework",
|
||||||
|
SafariServices,
|
||||||
|
);
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = app.linkwarden.extension.safari;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||||
|
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
|
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
65E051F02F9AFEE300628D48 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEVELOPMENT_TEAM = FZ44882Y36;
|
||||||
|
ENABLE_APP_SANDBOX = YES;
|
||||||
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
|
ENABLE_USER_SELECTED_FILES = readonly;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_FILE = "Linkwarden Extension/Info.plist";
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = "Linkwarden Extension";
|
||||||
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
|
"INFOPLIST_KEY_NSHumanReadableCopyright[sdk=*]" = "Copyright © 2026 Linkwarden. All rights reserved.";
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/../Frameworks",
|
||||||
|
"@executable_path/../../../../Frameworks",
|
||||||
|
);
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||||
|
MARKETING_VERSION = 1.5.3;
|
||||||
|
OTHER_LDFLAGS = (
|
||||||
|
"-framework",
|
||||||
|
SafariServices,
|
||||||
|
);
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = app.linkwarden.extension.safari;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||||
|
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
|
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
65E051F32F9AFEE300628D48 /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
|
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEVELOPMENT_TEAM = FZ44882Y36;
|
||||||
|
ENABLE_APP_SANDBOX = YES;
|
||||||
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
|
ENABLE_OUTGOING_NETWORK_CONNECTIONS = YES;
|
||||||
|
ENABLE_USER_SELECTED_FILES = readonly;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_FILE = Linkwarden/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = Linkwarden;
|
||||||
|
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity";
|
||||||
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
|
INFOPLIST_KEY_NSMainStoryboardFile = Main;
|
||||||
|
INFOPLIST_KEY_NSPrincipalClass = NSApplication;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/../Frameworks",
|
||||||
|
);
|
||||||
|
MARKETING_VERSION = 1.5.3;
|
||||||
|
OTHER_LDFLAGS = (
|
||||||
|
"-framework",
|
||||||
|
SafariServices,
|
||||||
|
"-framework",
|
||||||
|
WebKit,
|
||||||
|
);
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = app.linkwarden.extension;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
REGISTER_APP_GROUPS = YES;
|
||||||
|
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||||
|
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||||
|
SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor;
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
|
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
65E051F42F9AFEE300628D48 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
|
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEVELOPMENT_TEAM = FZ44882Y36;
|
||||||
|
ENABLE_APP_SANDBOX = YES;
|
||||||
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
|
ENABLE_OUTGOING_NETWORK_CONNECTIONS = YES;
|
||||||
|
ENABLE_USER_SELECTED_FILES = readonly;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_FILE = Linkwarden/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = Linkwarden;
|
||||||
|
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity";
|
||||||
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
|
"INFOPLIST_KEY_NSHumanReadableCopyright[sdk=*]" = "Copyright © 2026 Linkwarden. All rights reserved.";
|
||||||
|
INFOPLIST_KEY_NSMainStoryboardFile = Main;
|
||||||
|
INFOPLIST_KEY_NSPrincipalClass = NSApplication;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/../Frameworks",
|
||||||
|
);
|
||||||
|
MARKETING_VERSION = 1.5.3;
|
||||||
|
OTHER_LDFLAGS = (
|
||||||
|
"-framework",
|
||||||
|
SafariServices,
|
||||||
|
"-framework",
|
||||||
|
WebKit,
|
||||||
|
);
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = app.linkwarden.extension;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
REGISTER_APP_GROUPS = YES;
|
||||||
|
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||||
|
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||||
|
SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor;
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
|
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
|
/* Begin XCConfigurationList section */
|
||||||
|
65E051C42F9AFEE100628D48 /* Build configuration list for PBXProject "Linkwarden" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
65E051EC2F9AFEE300628D48 /* Debug */,
|
||||||
|
65E051ED2F9AFEE300628D48 /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
65E051EE2F9AFEE300628D48 /* Build configuration list for PBXNativeTarget "Linkwarden Extension" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
65E051EF2F9AFEE300628D48 /* Debug */,
|
||||||
|
65E051F02F9AFEE300628D48 /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
65E051F22F9AFEE300628D48 /* Build configuration list for PBXNativeTarget "Linkwarden" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
65E051F32F9AFEE300628D48 /* Debug */,
|
||||||
|
65E051F42F9AFEE300628D48 /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
/* End XCConfigurationList section */
|
||||||
|
};
|
||||||
|
rootObject = 65E051C12F9AFEE100628D48 /* Project object */;
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Workspace
|
||||||
|
version = "1.0">
|
||||||
|
<FileRef
|
||||||
|
location = "self:">
|
||||||
|
</FileRef>
|
||||||
|
</Workspace>
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Scheme
|
||||||
|
LastUpgradeVersion = "2610"
|
||||||
|
version = "1.7">
|
||||||
|
<BuildAction
|
||||||
|
parallelizeBuildables = "YES"
|
||||||
|
buildImplicitDependencies = "YES"
|
||||||
|
buildArchitectures = "Automatic">
|
||||||
|
<BuildActionEntries>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "65E051C82F9AFEE100628D48"
|
||||||
|
BuildableName = "Linkwarden.app"
|
||||||
|
BlueprintName = "Linkwarden"
|
||||||
|
ReferencedContainer = "container:Linkwarden.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
</BuildActionEntries>
|
||||||
|
</BuildAction>
|
||||||
|
<TestAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
shouldAutocreateTestPlan = "YES">
|
||||||
|
</TestAction>
|
||||||
|
<LaunchAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
launchStyle = "0"
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
debugServiceExtension = "internal"
|
||||||
|
allowLocationSimulation = "YES">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "65E051C82F9AFEE100628D48"
|
||||||
|
BuildableName = "Linkwarden.app"
|
||||||
|
BlueprintName = "Linkwarden"
|
||||||
|
ReferencedContainer = "container:Linkwarden.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</LaunchAction>
|
||||||
|
<ProfileAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
savedToolIdentifier = ""
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
debugDocumentVersioning = "YES">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "65E051C82F9AFEE100628D48"
|
||||||
|
BuildableName = "Linkwarden.app"
|
||||||
|
BlueprintName = "Linkwarden"
|
||||||
|
ReferencedContainer = "container:Linkwarden.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</ProfileAction>
|
||||||
|
<AnalyzeAction
|
||||||
|
buildConfiguration = "Debug">
|
||||||
|
</AnalyzeAction>
|
||||||
|
<ArchiveAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
revealArchiveInOrganizer = "YES">
|
||||||
|
</ArchiveAction>
|
||||||
|
</Scheme>
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>SchemeUserState</key>
|
||||||
|
<dict>
|
||||||
|
<key>Linkwarden.xcscheme_^#shared#^_</key>
|
||||||
|
<dict>
|
||||||
|
<key>orderHint</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<key>SuppressBuildableAutocreation</key>
|
||||||
|
<dict>
|
||||||
|
<key>65E051C82F9AFEE100628D48</key>
|
||||||
|
<dict>
|
||||||
|
<key>primary</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
//
|
||||||
|
// AppDelegate.swift
|
||||||
|
// Linkwarden
|
||||||
|
//
|
||||||
|
// Created by Daniel on 2026-04-23.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Cocoa
|
||||||
|
|
||||||
|
@main
|
||||||
|
class AppDelegate: NSObject, NSApplicationDelegate {
|
||||||
|
|
||||||
|
func applicationDidFinishLaunching(_ notification: Notification) {
|
||||||
|
// Override point for customization after application launch.
|
||||||
|
}
|
||||||
|
|
||||||
|
func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "mac-icon-16@1x.png",
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "1x",
|
||||||
|
"size" : "16x16"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "mac-icon-16@2x.png",
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "16x16"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "mac-icon-32@1x.png",
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "1x",
|
||||||
|
"size" : "32x32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "mac-icon-32@2x.png",
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "32x32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "mac-icon-128@1x.png",
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "1x",
|
||||||
|
"size" : "128x128"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "mac-icon-128@2x.png",
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "128x128"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "mac-icon-256@1x.png",
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "1x",
|
||||||
|
"size" : "256x256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "mac-icon-256@2x.png",
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "256x256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "mac-icon-512@1x.png",
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "1x",
|
||||||
|
"size" : "512x512"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "mac-icon-512@2x.png",
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "512x512"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 769 B |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 107 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 107 KiB |
|
After Width: | Height: | Size: 280 KiB |
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="19085" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS">
|
||||||
|
<dependencies>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="19085"/>
|
||||||
|
<plugIn identifier="com.apple.WebKit2IBPlugin" version="19085"/>
|
||||||
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
|
</dependencies>
|
||||||
|
<scenes>
|
||||||
|
<!--Application-->
|
||||||
|
<scene sceneID="JPo-4y-FX3">
|
||||||
|
<objects>
|
||||||
|
<application id="hnw-xV-0zn" sceneMemberID="viewController">
|
||||||
|
<menu key="mainMenu" title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Linkwarden" id="1Xt-HY-uBw">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Linkwarden" systemMenu="apple" id="uQy-DD-JDr">
|
||||||
|
<items>
|
||||||
|
<menuItem title="About Linkwarden" id="5kV-Vb-QxS">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="orderFrontStandardAboutPanel:" target="Ady-hI-5gd" id="Exp-CZ-Vem"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
|
||||||
|
<menuItem title="Hide Linkwarden" keyEquivalent="h" id="Olw-nP-bQN">
|
||||||
|
<connections>
|
||||||
|
<action selector="hide:" target="Ady-hI-5gd" id="PnN-Uc-m68"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="hideOtherApplications:" target="Ady-hI-5gd" id="VT4-aY-XCT"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Show All" id="Kd2-mp-pUS">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="unhideAllApplications:" target="Ady-hI-5gd" id="Dhg-Le-xox"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
|
||||||
|
<menuItem title="Quit Linkwarden" keyEquivalent="q" id="4sb-4s-VLi">
|
||||||
|
<connections>
|
||||||
|
<action selector="terminate:" target="Ady-hI-5gd" id="Te7-pn-YzF"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Help" id="wpr-3q-Mcd">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Help" systemMenu="help" id="F2S-fz-NVQ">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Linkwarden Help" keyEquivalent="?" id="FKE-Sm-Kum">
|
||||||
|
<connections>
|
||||||
|
<action selector="showHelp:" target="Ady-hI-5gd" id="y7X-2Q-9no"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
<connections>
|
||||||
|
<outlet property="delegate" destination="Voe-Tx-rLC" id="PrD-fu-P6m"/>
|
||||||
|
</connections>
|
||||||
|
</application>
|
||||||
|
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModuleProvider="target"/>
|
||||||
|
<customObject id="YLy-65-1bz" customClass="NSFontManager"/>
|
||||||
|
<customObject id="Ady-hI-5gd" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
<point key="canvasLocation" x="76" y="-134"/>
|
||||||
|
</scene>
|
||||||
|
<!--Window Controller-->
|
||||||
|
<scene sceneID="R2V-B0-nI4">
|
||||||
|
<objects>
|
||||||
|
<windowController showSeguePresentationStyle="single" id="B8D-0N-5wS" sceneMemberID="viewController">
|
||||||
|
<window key="window" title="Linkwarden" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" restorable="NO" releasedWhenClosed="NO" animationBehavior="default" id="IQv-IB-iLA">
|
||||||
|
<windowStyleMask key="styleMask" titled="YES" closable="YES"/>
|
||||||
|
<windowCollectionBehavior key="collectionBehavior" fullScreenNone="YES"/>
|
||||||
|
<rect key="contentRect" x="196" y="240" width="425" height="325"/>
|
||||||
|
<rect key="screenRect" x="0.0" y="0.0" width="1680" height="1027"/>
|
||||||
|
<connections>
|
||||||
|
<outlet property="delegate" destination="B8D-0N-5wS" id="98r-iN-zZc"/>
|
||||||
|
</connections>
|
||||||
|
</window>
|
||||||
|
<connections>
|
||||||
|
<segue destination="XfG-lQ-9wD" kind="relationship" relationship="window.shadowedContentViewController" id="cq2-FE-JQM"/>
|
||||||
|
</connections>
|
||||||
|
</windowController>
|
||||||
|
<customObject id="Oky-zY-oP4" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
<point key="canvasLocation" x="75" y="250"/>
|
||||||
|
</scene>
|
||||||
|
<!--View Controller-->
|
||||||
|
<scene sceneID="hIz-AP-VOD">
|
||||||
|
<objects>
|
||||||
|
<viewController id="XfG-lQ-9wD" customClass="ViewController" customModuleProvider="target" sceneMemberID="viewController">
|
||||||
|
<view key="view" id="m2S-Jp-Qdl">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="425" height="325"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<subviews>
|
||||||
|
<wkWebView wantsLayer="YES" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="eOr-cG-IQY">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="425" height="325"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<wkWebViewConfiguration key="configuration">
|
||||||
|
<audiovisualMediaTypes key="mediaTypesRequiringUserActionForPlayback" none="YES"/>
|
||||||
|
<wkPreferences key="preferences"/>
|
||||||
|
</wkWebViewConfiguration>
|
||||||
|
</wkWebView>
|
||||||
|
</subviews>
|
||||||
|
</view>
|
||||||
|
<connections>
|
||||||
|
<outlet property="webView" destination="eOr-cG-IQY" id="GFe-mU-dBY"/>
|
||||||
|
</connections>
|
||||||
|
</viewController>
|
||||||
|
<customObject id="rPt-NT-nkU" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
<point key="canvasLocation" x="75" y="655"/>
|
||||||
|
</scene>
|
||||||
|
</scenes>
|
||||||
|
</document>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>SFSafariWebExtensionConverterVersion</key>
|
||||||
|
<string>26.1</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||||
|
<meta http-equiv="Content-Security-Policy" content="default-src 'self'">
|
||||||
|
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="../Style.css">
|
||||||
|
<script src="../Script.js" defer></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<img src="../Icon.png" width="128" height="128" alt="Linkwarden Icon">
|
||||||
|
<p class="state-unknown">You can turn on Linkwarden’s extension in Safari Extensions preferences.</p>
|
||||||
|
<p class="state-on">Linkwarden’s extension is currently on. You can turn it off in Safari Extensions preferences.</p>
|
||||||
|
<p class="state-off">Linkwarden’s extension is currently off. You can turn it on in Safari Extensions preferences.</p>
|
||||||
|
<button class="open-preferences">Quit and Open Safari Extensions Preferences…</button>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
After Width: | Height: | Size: 15 KiB |
@@ -0,0 +1,22 @@
|
|||||||
|
function show(enabled, useSettingsInsteadOfPreferences) {
|
||||||
|
if (useSettingsInsteadOfPreferences) {
|
||||||
|
document.getElementsByClassName('state-on')[0].innerText = "Linkwarden’s extension is currently on. You can turn it off in the Extensions section of Safari Settings.";
|
||||||
|
document.getElementsByClassName('state-off')[0].innerText = "Linkwarden’s extension is currently off. You can turn it on in the Extensions section of Safari Settings.";
|
||||||
|
document.getElementsByClassName('state-unknown')[0].innerText = "You can turn on Linkwarden’s extension in the Extensions section of Safari Settings.";
|
||||||
|
document.getElementsByClassName('open-preferences')[0].innerText = "Quit and Open Safari Settings…";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof enabled === "boolean") {
|
||||||
|
document.body.classList.toggle(`state-on`, enabled);
|
||||||
|
document.body.classList.toggle(`state-off`, !enabled);
|
||||||
|
} else {
|
||||||
|
document.body.classList.remove(`state-on`);
|
||||||
|
document.body.classList.remove(`state-off`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function openPreferences() {
|
||||||
|
webkit.messageHandlers.controller.postMessage("open-preferences");
|
||||||
|
}
|
||||||
|
|
||||||
|
document.querySelector("button.open-preferences").addEventListener("click", openPreferences);
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
* {
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-webkit-user-drag: none;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
color-scheme: light dark;
|
||||||
|
|
||||||
|
--spacing: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
gap: var(--spacing);
|
||||||
|
margin: 0 calc(var(--spacing) * 2);
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
font: -apple-system-short-body;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
body:not(.state-on, .state-off) :is(.state-on, .state-off) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.state-on :is(.state-off, .state-unknown) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.state-off :is(.state-on, .state-unknown) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
//
|
||||||
|
// ViewController.swift
|
||||||
|
// Linkwarden
|
||||||
|
//
|
||||||
|
// Created by Daniel on 2026-04-23.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Cocoa
|
||||||
|
import SafariServices
|
||||||
|
import WebKit
|
||||||
|
|
||||||
|
let extensionBundleIdentifier = "app.linkwarden.safari-extension.Extension"
|
||||||
|
|
||||||
|
class ViewController: NSViewController, WKNavigationDelegate, WKScriptMessageHandler {
|
||||||
|
|
||||||
|
@IBOutlet var webView: WKWebView!
|
||||||
|
|
||||||
|
override func viewDidLoad() {
|
||||||
|
super.viewDidLoad()
|
||||||
|
|
||||||
|
self.webView.navigationDelegate = self
|
||||||
|
|
||||||
|
self.webView.configuration.userContentController.add(self, name: "controller")
|
||||||
|
|
||||||
|
self.webView.loadFileURL(Bundle.main.url(forResource: "Main", withExtension: "html")!, allowingReadAccessTo: Bundle.main.resourceURL!)
|
||||||
|
}
|
||||||
|
|
||||||
|
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
|
||||||
|
SFSafariExtensionManager.getStateOfSafariExtension(withIdentifier: extensionBundleIdentifier) { (state, error) in
|
||||||
|
guard let state = state, error == nil else {
|
||||||
|
// Insert code to inform the user that something went wrong.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
if #available(macOS 13, *) {
|
||||||
|
webView.evaluateJavaScript("show(\(state.isEnabled), true)")
|
||||||
|
} else {
|
||||||
|
webView.evaluateJavaScript("show(\(state.isEnabled), false)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
|
||||||
|
if (message.body as! String != "open-preferences") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SFSafariApplication.showPreferencesForExtension(withIdentifier: extensionBundleIdentifier) { error in
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
NSApplication.shared.terminate(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -72,19 +72,58 @@ const drawImagesOnCanvas = async (
|
|||||||
};
|
};
|
||||||
|
|
||||||
async function executeScript(tabId: number, func: any, args: any[] = []) {
|
async function executeScript(tabId: number, func: any, args: any[] = []) {
|
||||||
if (typeof chrome.scripting !== 'undefined') {
|
if (
|
||||||
|
typeof chrome !== 'undefined' &&
|
||||||
|
typeof chrome.scripting !== 'undefined'
|
||||||
|
) {
|
||||||
const results = await chrome.scripting.executeScript({
|
const results = await chrome.scripting.executeScript({
|
||||||
target: { tabId },
|
target: { tabId },
|
||||||
func,
|
func,
|
||||||
args,
|
args,
|
||||||
});
|
});
|
||||||
return results[0]?.result;
|
return results[0]?.result;
|
||||||
} else {
|
|
||||||
const results = await browser.tabs.executeScript(tabId, {
|
|
||||||
code: `(${func})(${args.map((arg) => JSON.stringify(arg)).join(',')})`,
|
|
||||||
});
|
|
||||||
return results[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const results = await browser.tabs.executeScript(tabId, {
|
||||||
|
code: `(${func})(${args.map((arg) => JSON.stringify(arg)).join(',')})`,
|
||||||
|
});
|
||||||
|
return results[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
async function safeExecuteScript(tabId: number, func: any, args: any[] = []) {
|
||||||
|
try {
|
||||||
|
await executeScript(tabId, func, args);
|
||||||
|
} catch {
|
||||||
|
// Best effort cleanup for browsers that reject script execution.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function dataUrlToBlob(dataUrl: string): Blob {
|
||||||
|
const [meta = '', encodedData = ''] = dataUrl.split(',', 2);
|
||||||
|
const mimeType = meta.match(/^data:(.*?)(;base64)?$/)?.[1] ?? 'image/png';
|
||||||
|
|
||||||
|
if (meta.includes(';base64')) {
|
||||||
|
const binary = atob(encodedData);
|
||||||
|
const bytes = new Uint8Array(binary.length);
|
||||||
|
for (let index = 0; index < binary.length; index++) {
|
||||||
|
bytes[index] = binary.charCodeAt(index);
|
||||||
|
}
|
||||||
|
return new Blob([bytes], { type: mimeType });
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Blob([decodeURIComponent(encodedData)], { type: mimeType });
|
||||||
|
}
|
||||||
|
|
||||||
|
async function captureVisibleTabScreenshot(): Promise<Blob> {
|
||||||
|
const tabs = await browser.tabs.query({ active: true, currentWindow: true });
|
||||||
|
const tab = tabs[0];
|
||||||
|
if (!tab || !tab.id) {
|
||||||
|
throw new Error('Unable to get the current tab.');
|
||||||
|
}
|
||||||
|
const dataUrl = await browser.tabs.captureVisibleTab(tab.windowId!, {
|
||||||
|
format: 'png',
|
||||||
|
});
|
||||||
|
return dataUrlToBlob(dataUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function captureFullPageScreenshot(): Promise<Blob> {
|
async function captureFullPageScreenshot(): Promise<Blob> {
|
||||||
@@ -218,8 +257,7 @@ async function captureFullPageScreenshot(): Promise<Blob> {
|
|||||||
const dataUrl = await browser.tabs.captureVisibleTab(tab.windowId!, {
|
const dataUrl = await browser.tabs.captureVisibleTab(tab.windowId!, {
|
||||||
format: 'png',
|
format: 'png',
|
||||||
});
|
});
|
||||||
const blob = await fetch(dataUrl).then((res) => res.blob());
|
blobs.push(dataUrlToBlob(dataUrl));
|
||||||
blobs.push(blob);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const canvas = document.createElement('canvas');
|
const canvas = document.createElement('canvas');
|
||||||
@@ -235,11 +273,30 @@ async function captureFullPageScreenshot(): Promise<Blob> {
|
|||||||
dpr
|
dpr
|
||||||
);
|
);
|
||||||
|
|
||||||
await executeScript(tab.id, removeHideScrollbarClass);
|
await safeExecuteScript(tab.id, removeHideScrollbarClass);
|
||||||
await executeScript(tab.id, restoreFixedElements, [originalStyles]);
|
await safeExecuteScript(tab.id, restoreFixedElements, [originalStyles]);
|
||||||
await executeScript(tab.id, removeDisableSmoothScrollbarClass);
|
await safeExecuteScript(tab.id, removeDisableSmoothScrollbarClass);
|
||||||
|
|
||||||
return resultBlob;
|
return resultBlob;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default captureFullPageScreenshot;
|
async function captureScreenshot(): Promise<Blob> {
|
||||||
|
try {
|
||||||
|
return await captureFullPageScreenshot();
|
||||||
|
} catch (fullPageError) {
|
||||||
|
console.warn(
|
||||||
|
'Full-page screenshot failed, falling back to visible tab capture.',
|
||||||
|
fullPageError
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
return await captureVisibleTabScreenshot();
|
||||||
|
} catch (visibleTabError) {
|
||||||
|
console.error('Visible tab screenshot capture failed.', visibleTabError);
|
||||||
|
throw new Error(
|
||||||
|
'Screenshot capture is not available for this page.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default captureScreenshot;
|
||||||
|
|||||||
@@ -57,6 +57,24 @@ export function openOptions() {
|
|||||||
getBrowser().runtime.openOptionsPage();
|
getBrowser().runtime.openOptionsPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isSafari(): boolean {
|
||||||
|
try {
|
||||||
|
return /^safari-web-extension:/.test(getBrowser().runtime.getURL(''));
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hasAPI(api: string): boolean {
|
||||||
|
const b = getBrowser();
|
||||||
|
let obj: any = b;
|
||||||
|
for (const part of api.split('.')) {
|
||||||
|
if (!obj || typeof obj[part] === 'undefined') return false;
|
||||||
|
obj = obj[part];
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
export async function updateBadge(tabId: number | undefined) {
|
export async function updateBadge(tabId: number | undefined) {
|
||||||
if (!tabId) return;
|
if (!tabId) return;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import {
|
import {
|
||||||
getBrowser,
|
getBrowser,
|
||||||
getCurrentTabInfo,
|
getCurrentTabInfo,
|
||||||
|
hasAPI,
|
||||||
|
isSafari,
|
||||||
updateBadge,
|
updateBadge,
|
||||||
} from '../../@/lib/utils.ts';
|
} from '../../@/lib/utils.ts';
|
||||||
// import BookmarkTreeNode = chrome.bookmarks.BookmarkTreeNode;
|
// import BookmarkTreeNode = chrome.bookmarks.BookmarkTreeNode;
|
||||||
@@ -240,7 +242,7 @@ async function genericOnClick(
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
// Handle cases where sync is enabled or not
|
// Handle cases where sync is enabled or not
|
||||||
if (syncBookmarks) {
|
if (syncBookmarks && hasAPI('bookmarks.create')) {
|
||||||
browser.bookmarks.create({
|
browser.bookmarks.create({
|
||||||
parentId: '1',
|
parentId: '1',
|
||||||
title: tab.title,
|
title: tab.title,
|
||||||
@@ -277,15 +279,9 @@ async function genericOnClick(
|
|||||||
}
|
}
|
||||||
browser.runtime.onInstalled.addListener(async function () {
|
browser.runtime.onInstalled.addListener(async function () {
|
||||||
// Create one test item for each context type.
|
// Create one test item for each context type.
|
||||||
const contexts: ContextType[] = [
|
const contexts: ContextType[] = isSafari()
|
||||||
'page',
|
? ['page', 'selection', 'link']
|
||||||
'selection',
|
: ['page', 'selection', 'link', 'editable', 'image', 'video', 'audio'];
|
||||||
'link',
|
|
||||||
'editable',
|
|
||||||
'image',
|
|
||||||
'video',
|
|
||||||
'audio',
|
|
||||||
];
|
|
||||||
for (const context of contexts) {
|
for (const context of contexts) {
|
||||||
const title: string = 'Add link to Linkwarden';
|
const title: string = 'Add link to Linkwarden';
|
||||||
browser.contextMenus.create({
|
browser.contextMenus.create({
|
||||||
@@ -346,79 +342,81 @@ browser.tabs.onUpdated.addListener(async (tabId, changeInfo, tab) => {
|
|||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|
||||||
// Omnibox implementation
|
// Omnibox implementation (not available in Safari)
|
||||||
|
|
||||||
browser.omnibox.onInputStarted.addListener(async () => {
|
if (hasAPI('omnibox.onInputStarted')) {
|
||||||
const configured = await isConfigured();
|
browser.omnibox.onInputStarted.addListener(async () => {
|
||||||
const description = configured
|
|
||||||
? 'Search links in linkwarden'
|
|
||||||
: 'Please configure the extension first';
|
|
||||||
|
|
||||||
browser.omnibox.setDefaultSuggestion({
|
|
||||||
description: description,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
browser.omnibox.onInputChanged.addListener(
|
|
||||||
async (
|
|
||||||
text: string,
|
|
||||||
suggest: (arg0: { content: string; description: string }[]) => void
|
|
||||||
) => {
|
|
||||||
const configured = await isConfigured();
|
const configured = await isConfigured();
|
||||||
|
const description = configured
|
||||||
|
? 'Search links in linkwarden'
|
||||||
|
: 'Please configure the extension first';
|
||||||
|
|
||||||
if (!configured) {
|
browser.omnibox.setDefaultSuggestion({
|
||||||
return;
|
description: description,
|
||||||
}
|
|
||||||
|
|
||||||
const currentBookmarks = await getBookmarksMetadata();
|
|
||||||
|
|
||||||
const searchedBookmarks = currentBookmarks.filter((bookmark) => {
|
|
||||||
return bookmark.name?.includes(text) || bookmark.url.includes(text);
|
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
const bookmarkSuggestions = searchedBookmarks.map((bookmark) => {
|
browser.omnibox.onInputChanged.addListener(
|
||||||
return {
|
async (
|
||||||
content: bookmark.url,
|
text: string,
|
||||||
description: bookmark.name || bookmark.url,
|
suggest: (arg0: { content: string; description: string }[]) => void
|
||||||
};
|
) => {
|
||||||
});
|
const configured = await isConfigured();
|
||||||
suggest(bookmarkSuggestions);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// This part was taken https://github.com/sissbruecker/linkding-extension/blob/master/src/background.js Thanks to @sissbruecker
|
if (!configured) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
browser.omnibox.onInputEntered.addListener(
|
const currentBookmarks = await getBookmarksMetadata();
|
||||||
async (content: string, disposition: OnInputEnteredDisposition) => {
|
|
||||||
if (!(await isConfigured()) || !content) {
|
const searchedBookmarks = currentBookmarks.filter((bookmark) => {
|
||||||
return;
|
return bookmark.name?.includes(text) || bookmark.url.includes(text);
|
||||||
|
});
|
||||||
|
|
||||||
|
const bookmarkSuggestions = searchedBookmarks.map((bookmark) => {
|
||||||
|
return {
|
||||||
|
content: bookmark.url,
|
||||||
|
description: bookmark.name || bookmark.url,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
suggest(bookmarkSuggestions);
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const isUrl = /^http(s)?:\/\//.test(content);
|
// This part was taken https://github.com/sissbruecker/linkding-extension/blob/master/src/background.js Thanks to @sissbruecker
|
||||||
const url = isUrl ? content : `lk`;
|
|
||||||
|
|
||||||
// Edge doesn't allow updating the New Tab Page (tested with version 117).
|
browser.omnibox.onInputEntered.addListener(
|
||||||
// Trying to do so will throw: "Error: Cannot update NTP tab."
|
async (content: string, disposition: OnInputEnteredDisposition) => {
|
||||||
// As a workaround, open a new tab instead.
|
if (!(await isConfigured()) || !content) {
|
||||||
if (disposition === 'currentTab') {
|
return;
|
||||||
const tabInfo = await getCurrentTabInfo();
|
}
|
||||||
if (tabInfo.url === 'edge://newtab/') {
|
|
||||||
disposition = 'newForegroundTab';
|
const isUrl = /^http(s)?:\/\//.test(content);
|
||||||
|
const url = isUrl ? content : `lk`;
|
||||||
|
|
||||||
|
// Edge doesn't allow updating the New Tab Page (tested with version 117).
|
||||||
|
// Trying to do so will throw: "Error: Cannot update NTP tab."
|
||||||
|
// As a workaround, open a new tab instead.
|
||||||
|
if (disposition === 'currentTab') {
|
||||||
|
const tabInfo = await getCurrentTabInfo();
|
||||||
|
if (tabInfo.url === 'edge://newtab/') {
|
||||||
|
disposition = 'newForegroundTab';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (disposition) {
|
||||||
|
case 'currentTab':
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore
|
||||||
|
await browser.tabs.update({ url });
|
||||||
|
break;
|
||||||
|
case 'newForegroundTab':
|
||||||
|
await browser.tabs.create({ url });
|
||||||
|
break;
|
||||||
|
case 'newBackgroundTab':
|
||||||
|
await browser.tabs.create({ url, active: false });
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
);
|
||||||
switch (disposition) {
|
}
|
||||||
case 'currentTab':
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore
|
|
||||||
await browser.tabs.update({ url });
|
|
||||||
break;
|
|
||||||
case 'newForegroundTab':
|
|
||||||
await browser.tabs.create({ url });
|
|
||||||
break;
|
|
||||||
case 'newBackgroundTab':
|
|
||||||
await browser.tabs.create({ url, active: false });
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|||||||