diff --git a/package.json b/package.json index 3407add..5c5d9ce 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,8 @@ "scripts": { "build": "parcel build source/manifest.json --no-source-maps --no-optimize --dist-dir distribution --no-cache --detailed-report 0", "lint": "xo", + "pack:safari": "xcodebuild -project 'safari/GhostText.xcodeproj'", + "start:safari": "open 'safari/build/Release/GhostText.app'", "test": "xo && npm run build", "watch": "parcel watch source/manifest.json --dist-dir distribution --no-cache --no-hmr" }, diff --git a/promo/demo-screen-safari.png b/promo/demo-screen-safari.png new file mode 100644 index 0000000..4ff964a Binary files /dev/null and b/promo/demo-screen-safari.png differ diff --git a/promo/demo-screen.png b/promo/demo-screen.png new file mode 100644 index 0000000..0bc4f4f Binary files /dev/null and b/promo/demo-screen.png differ diff --git a/promo/demo-screen.sketch b/promo/demo-screen.sketch new file mode 100644 index 0000000..182f1f1 Binary files /dev/null and b/promo/demo-screen.sketch differ diff --git a/promo/graphics.sketch b/promo/graphics.sketch new file mode 100644 index 0000000..7c8b2f6 Binary files /dev/null and b/promo/graphics.sketch differ diff --git a/readme.md b/readme.md index d4d1fd8..7722af6 100644 --- a/readme.md +++ b/readme.md @@ -1,7 +1,8 @@ # GhostText -[link-cws]: https://chrome.google.com/webstore/detail/ghosttext/godiecgffnchndlihlpaajjcplehddca 'Version published on Chrome Web Store' -[link-amo]: https://addons.mozilla.org/en-US/firefox/addon/ghosttext/ 'Version published on Mozilla Add-ons' +[link-chrome]: https://chrome.google.com/webstore/detail/ghosttext/godiecgffnchndlihlpaajjcplehddca 'Version published on Chrome Web Store' +[link-firefox]: https://addons.mozilla.org/en-US/firefox/addon/ghosttext/ 'Version published on Mozilla Add-ons' +[link-safari]: https://apps.apple.com/app/ghosttext/id1552641506 'Version published on the Mac App Store' Demo screencast @@ -30,8 +31,9 @@ Use your text editor to write in your browser. Everything you type in the editor 2. Install your browser extension: - - [**Chrome**][link-cws] [][link-cws] - - [**Firefox**][link-amo] [][link-amo] + - [**Chrome**][link-chrome] [][link-chrome] + - [**Firefox**][link-firefox] [][link-firefox] + - [**Safari**][link-safari] [][link-safari] ## Usage diff --git a/safari/.gitignore b/safari/.gitignore new file mode 100644 index 0000000..5fcea4d --- /dev/null +++ b/safari/.gitignore @@ -0,0 +1,7 @@ +xcuserdata/ +*.xcworkspace +build/ +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots/**/*.png +fastlane/test_output diff --git a/safari/AppIcon.sketch b/safari/AppIcon.sketch new file mode 100644 index 0000000..48db284 Binary files /dev/null and b/safari/AppIcon.sketch differ diff --git a/safari/GhostText Extension/GhostText_Extension.entitlements b/safari/GhostText Extension/GhostText_Extension.entitlements new file mode 100644 index 0000000..13cb114 --- /dev/null +++ b/safari/GhostText Extension/GhostText_Extension.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/safari/GhostText Extension/Info.plist b/safari/GhostText Extension/Info.plist new file mode 100644 index 0000000..8f6c468 --- /dev/null +++ b/safari/GhostText Extension/Info.plist @@ -0,0 +1,33 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + GhostText Extension + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSExtension + + NSExtensionPointIdentifier + com.apple.Safari.web-extension + NSExtensionPrincipalClass + $(PRODUCT_MODULE_NAME).SafariWebExtensionHandler + + + diff --git a/safari/GhostText Extension/SafariWebExtensionHandler.swift b/safari/GhostText Extension/SafariWebExtensionHandler.swift new file mode 100644 index 0000000..aa824c5 --- /dev/null +++ b/safari/GhostText Extension/SafariWebExtensionHandler.swift @@ -0,0 +1,21 @@ +import SafariServices +import os.log + +let SFExtensionMessageKey = "message" + +final class SafariWebExtensionHandler: NSObject, NSExtensionRequestHandling { + func beginRequest(with context: NSExtensionContext) { + let item = context.inputItems[0] as! NSExtensionItem + let message = item.userInfo?[SFExtensionMessageKey] + os_log(.default, "Received message from browser.runtime.sendNativeMessage: %@", message as! CVarArg) + + let response = NSExtensionItem() + response.userInfo = [ + SFExtensionMessageKey: [ + "Response to": message + ] + ] + + context.completeRequest(returningItems: [response], completionHandler: nil) + } +} diff --git a/safari/GhostText.xcodeproj/project.pbxproj b/safari/GhostText.xcodeproj/project.pbxproj new file mode 100644 index 0000000..fab7db9 --- /dev/null +++ b/safari/GhostText.xcodeproj/project.pbxproj @@ -0,0 +1,530 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 1F92803125CA3273008B74DB /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F92803025CA3273008B74DB /* AppDelegate.swift */; }; + 1F92803425CA3273008B74DB /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 1F92803225CA3273008B74DB /* Main.storyboard */; }; + 1F92803625CA3273008B74DB /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F92803525CA3273008B74DB /* ViewController.swift */; }; + 1F92803825CA3274008B74DB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1F92803725CA3274008B74DB /* Assets.xcassets */; }; + 1F92803F25CA3274008B74DB /* GhostText Extension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 1F92803E25CA3274008B74DB /* GhostText Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + 1F92804425CA3274008B74DB /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1F92804325CA3274008B74DB /* Cocoa.framework */; }; + 1F92804725CA3274008B74DB /* SafariWebExtensionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F92804625CA3274008B74DB /* SafariWebExtensionHandler.swift */; }; + 1F92806325CA3274008B74DB /* background.js in Resources */ = {isa = PBXBuildFile; fileRef = 1F92805525CA3274008B74DB /* background.js */; }; + 1F92806425CA3274008B74DB /* icons in Resources */ = {isa = PBXBuildFile; fileRef = 1F92805625CA3274008B74DB /* icons */; }; + 1F92806525CA3274008B74DB /* ghost-text.css in Resources */ = {isa = PBXBuildFile; fileRef = 1F92805725CA3274008B74DB /* ghost-text.css */; }; + 1F92806725CA3274008B74DB /* ghost-text.js in Resources */ = {isa = PBXBuildFile; fileRef = 1F92805A25CA3274008B74DB /* ghost-text.js */; }; + 1F92806825CA3274008B74DB /* manifest.json in Resources */ = {isa = PBXBuildFile; fileRef = 1F92805D25CA3274008B74DB /* manifest.json */; }; + 1F92806A25CA3274008B74DB /* options.html in Resources */ = {isa = PBXBuildFile; fileRef = 1F92805F25CA3274008B74DB /* options.html */; }; + 1F92806B25CA3274008B74DB /* options.js in Resources */ = {isa = PBXBuildFile; fileRef = 1F92806125CA3274008B74DB /* options.js */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 1F92804025CA3274008B74DB /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 1F92802425CA3272008B74DB /* Project object */; + proxyType = 1; + remoteGlobalIDString = 1F92803D25CA3274008B74DB; + remoteInfo = "GhostText Extension"; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 1F92804F25CA3274008B74DB /* Embed App Extensions */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 13; + files = ( + 1F92803F25CA3274008B74DB /* GhostText Extension.appex in Embed App Extensions */, + ); + name = "Embed App Extensions"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1F92802C25CA3273008B74DB /* GhostText.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = GhostText.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 1F92802F25CA3273008B74DB /* GhostText.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = GhostText.entitlements; sourceTree = ""; }; + 1F92803025CA3273008B74DB /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 1F92803325CA3273008B74DB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 1F92803525CA3273008B74DB /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + 1F92803725CA3274008B74DB /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 1F92803925CA3274008B74DB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 1F92803E25CA3274008B74DB /* GhostText Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "GhostText Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; }; + 1F92804325CA3274008B74DB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 1F92804625CA3274008B74DB /* SafariWebExtensionHandler.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = SafariWebExtensionHandler.swift; sourceTree = ""; usesTabs = 0; }; + 1F92804825CA3274008B74DB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 1F92804925CA3274008B74DB /* GhostText_Extension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = GhostText_Extension.entitlements; sourceTree = ""; }; + 1F92805525CA3274008B74DB /* background.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = background.js; path = ../../distribution/background.js; sourceTree = ""; }; + 1F92805625CA3274008B74DB /* icons */ = {isa = PBXFileReference; lastKnownFileType = folder; name = icons; path = ../../distribution/icons; sourceTree = ""; }; + 1F92805725CA3274008B74DB /* ghost-text.css */ = {isa = PBXFileReference; lastKnownFileType = text.css; name = "ghost-text.css"; path = "../../distribution/ghost-text.css"; sourceTree = ""; }; + 1F92805A25CA3274008B74DB /* ghost-text.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = "ghost-text.js"; path = "../../distribution/ghost-text.js"; sourceTree = ""; }; + 1F92805D25CA3274008B74DB /* manifest.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; name = manifest.json; path = ../../distribution/manifest.json; sourceTree = ""; }; + 1F92805F25CA3274008B74DB /* options.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = options.html; path = ../../distribution/options.html; sourceTree = ""; }; + 1F92806125CA3274008B74DB /* options.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = options.js; path = ../../distribution/options.js; sourceTree = ""; }; + 1FA6620525CA421D00076F52 /* Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Shared.xcconfig; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 1F92802925CA3273008B74DB /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1F92803B25CA3274008B74DB /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 1F92804425CA3274008B74DB /* Cocoa.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 1F92802325CA3272008B74DB = { + isa = PBXGroup; + children = ( + 1FA6620525CA421D00076F52 /* Shared.xcconfig */, + 1F92802E25CA3273008B74DB /* GhostText */, + 1F92804525CA3274008B74DB /* GhostText Extension */, + 1F92804225CA3274008B74DB /* Frameworks */, + 1F92802D25CA3273008B74DB /* Products */, + ); + sourceTree = ""; + }; + 1F92802D25CA3273008B74DB /* Products */ = { + isa = PBXGroup; + children = ( + 1F92802C25CA3273008B74DB /* GhostText.app */, + 1F92803E25CA3274008B74DB /* GhostText Extension.appex */, + ); + name = Products; + sourceTree = ""; + }; + 1F92802E25CA3273008B74DB /* GhostText */ = { + isa = PBXGroup; + children = ( + 1F92802F25CA3273008B74DB /* GhostText.entitlements */, + 1F92803025CA3273008B74DB /* AppDelegate.swift */, + 1F92803225CA3273008B74DB /* Main.storyboard */, + 1F92803525CA3273008B74DB /* ViewController.swift */, + 1F92803725CA3274008B74DB /* Assets.xcassets */, + 1F92803925CA3274008B74DB /* Info.plist */, + ); + path = GhostText; + sourceTree = ""; + }; + 1F92804225CA3274008B74DB /* Frameworks */ = { + isa = PBXGroup; + children = ( + 1F92804325CA3274008B74DB /* Cocoa.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 1F92804525CA3274008B74DB /* GhostText Extension */ = { + isa = PBXGroup; + children = ( + 1F92805325CA3274008B74DB /* Resources */, + 1F92804625CA3274008B74DB /* SafariWebExtensionHandler.swift */, + 1F92804825CA3274008B74DB /* Info.plist */, + 1F92804925CA3274008B74DB /* GhostText_Extension.entitlements */, + ); + path = "GhostText Extension"; + sourceTree = ""; + }; + 1F92805325CA3274008B74DB /* Resources */ = { + isa = PBXGroup; + children = ( + 1F92805525CA3274008B74DB /* background.js */, + 1F92805625CA3274008B74DB /* icons */, + 1F92805725CA3274008B74DB /* ghost-text.css */, + 1F92805A25CA3274008B74DB /* ghost-text.js */, + 1F92805D25CA3274008B74DB /* manifest.json */, + 1F92805F25CA3274008B74DB /* options.html */, + 1F92806125CA3274008B74DB /* options.js */, + ); + name = Resources; + path = "GhostText Extension"; + sourceTree = SOURCE_ROOT; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 1F92802B25CA3273008B74DB /* GhostText */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1F92805025CA3274008B74DB /* Build configuration list for PBXNativeTarget "GhostText" */; + buildPhases = ( + 1F92802825CA3273008B74DB /* Sources */, + 1F92802925CA3273008B74DB /* Frameworks */, + 1F92802A25CA3273008B74DB /* Resources */, + 1F92804F25CA3274008B74DB /* Embed App Extensions */, + ); + buildRules = ( + ); + dependencies = ( + 1F92804125CA3274008B74DB /* PBXTargetDependency */, + ); + name = GhostText; + productName = GhostText; + productReference = 1F92802C25CA3273008B74DB /* GhostText.app */; + productType = "com.apple.product-type.application"; + }; + 1F92803D25CA3274008B74DB /* GhostText Extension */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1F92804C25CA3274008B74DB /* Build configuration list for PBXNativeTarget "GhostText Extension" */; + buildPhases = ( + 1F92803A25CA3274008B74DB /* Sources */, + 1F92803B25CA3274008B74DB /* Frameworks */, + 1F92803C25CA3274008B74DB /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "GhostText Extension"; + productName = "GhostText Extension"; + productReference = 1F92803E25CA3274008B74DB /* GhostText Extension.appex */; + productType = "com.apple.product-type.app-extension"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 1F92802425CA3272008B74DB /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1220; + LastUpgradeCheck = 1240; + TargetAttributes = { + 1F92802B25CA3273008B74DB = { + CreatedOnToolsVersion = 12.2; + }; + 1F92803D25CA3274008B74DB = { + CreatedOnToolsVersion = 12.2; + }; + }; + }; + buildConfigurationList = 1F92802725CA3272008B74DB /* Build configuration list for PBXProject "GhostText" */; + compatibilityVersion = "Xcode 12.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 1F92802325CA3272008B74DB; + productRefGroup = 1F92802D25CA3273008B74DB /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 1F92802B25CA3273008B74DB /* GhostText */, + 1F92803D25CA3274008B74DB /* GhostText Extension */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 1F92802A25CA3273008B74DB /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1F92803825CA3274008B74DB /* Assets.xcassets in Resources */, + 1F92803425CA3273008B74DB /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1F92803C25CA3274008B74DB /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1F92806725CA3274008B74DB /* ghost-text.js in Resources */, + 1F92806425CA3274008B74DB /* icons in Resources */, + 1F92806A25CA3274008B74DB /* options.html in Resources */, + 1F92806B25CA3274008B74DB /* options.js in Resources */, + 1F92806525CA3274008B74DB /* ghost-text.css in Resources */, + 1F92806825CA3274008B74DB /* manifest.json in Resources */, + 1F92806325CA3274008B74DB /* background.js in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 1F92802825CA3273008B74DB /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1F92803625CA3273008B74DB /* ViewController.swift in Sources */, + 1F92803125CA3273008B74DB /* AppDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1F92803A25CA3274008B74DB /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1F92804725CA3274008B74DB /* SafariWebExtensionHandler.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 1F92804125CA3274008B74DB /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 1F92803D25CA3274008B74DB /* GhostText Extension */; + targetProxy = 1F92804025CA3274008B74DB /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 1F92803225CA3273008B74DB /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 1F92803325CA3273008B74DB /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 1F92804A25CA3274008B74DB /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 1FA6620525CA421D00076F52 /* Shared.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + 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; + GCC_C_LANGUAGE_STANDARD = gnu11; + 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; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 1F92804B25CA3274008B74DB /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 1FA6620525CA421D00076F52 /* Shared.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + 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; + GCC_C_LANGUAGE_STANDARD = gnu11; + 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; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 1F92804D25CA3274008B74DB /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_ENTITLEMENTS = "GhostText Extension/GhostText_Extension.entitlements"; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Automatic; + INFOPLIST_FILE = "GhostText Extension/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@executable_path/../../../../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.fregante.GhostText.Extension; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 1F92804E25CA3274008B74DB /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_ENTITLEMENTS = "GhostText Extension/GhostText_Extension.entitlements"; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Automatic; + INFOPLIST_FILE = "GhostText Extension/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@executable_path/../../../../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.fregante.GhostText.Extension; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 1F92805125CA3274008B74DB /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = GhostText/GhostText.entitlements; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = GhostText/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.fregante.GhostText; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 1F92805225CA3274008B74DB /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = GhostText/GhostText.entitlements; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = GhostText/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.fregante.GhostText; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1F92802725CA3272008B74DB /* Build configuration list for PBXProject "GhostText" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1F92804A25CA3274008B74DB /* Debug */, + 1F92804B25CA3274008B74DB /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1F92804C25CA3274008B74DB /* Build configuration list for PBXNativeTarget "GhostText Extension" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1F92804D25CA3274008B74DB /* Debug */, + 1F92804E25CA3274008B74DB /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1F92805025CA3274008B74DB /* Build configuration list for PBXNativeTarget "GhostText" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1F92805125CA3274008B74DB /* Debug */, + 1F92805225CA3274008B74DB /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 1F92802425CA3272008B74DB /* Project object */; +} diff --git a/safari/GhostText/AppDelegate.swift b/safari/GhostText/AppDelegate.swift new file mode 100644 index 0000000..41bd841 --- /dev/null +++ b/safari/GhostText/AppDelegate.swift @@ -0,0 +1,6 @@ +import Cocoa + +@main +final class AppDelegate: NSObject, NSApplicationDelegate { + func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { true } +} diff --git a/safari/GhostText/Assets.xcassets/AccentColor.colorset/Contents.json b/safari/GhostText/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000..eb87897 --- /dev/null +++ b/safari/GhostText/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/safari/GhostText/Assets.xcassets/AppIcon.appiconset/Contents.json b/safari/GhostText/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..ba334e3 --- /dev/null +++ b/safari/GhostText/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images": [ + { + "filename": "icon16.png", + "idiom": "mac", + "scale": "1x", + "size": "16x16" + }, + { + "filename": "icon32.png", + "idiom": "mac", + "scale": "2x", + "size": "16x16" + }, + { + "filename": "icon32.png", + "idiom": "mac", + "scale": "1x", + "size": "32x32" + }, + { + "filename": "icon64.png", + "idiom": "mac", + "scale": "2x", + "size": "32x32" + }, + { + "filename": "icon128.png", + "idiom": "mac", + "scale": "1x", + "size": "128x128" + }, + { + "filename": "icon256.png", + "idiom": "mac", + "scale": "2x", + "size": "128x128" + }, + { + "filename": "icon256.png", + "idiom": "mac", + "scale": "1x", + "size": "256x256" + }, + { + "filename": "icon512.png", + "idiom": "mac", + "scale": "2x", + "size": "256x256" + }, + { + "filename": "icon512.png", + "idiom": "mac", + "scale": "1x", + "size": "512x512" + }, + { + "filename": "icon1024.png", + "idiom": "mac", + "scale": "2x", + "size": "512x512" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} diff --git a/safari/GhostText/Assets.xcassets/AppIcon.appiconset/icon1024.png b/safari/GhostText/Assets.xcassets/AppIcon.appiconset/icon1024.png new file mode 100644 index 0000000..c6631e9 Binary files /dev/null and b/safari/GhostText/Assets.xcassets/AppIcon.appiconset/icon1024.png differ diff --git a/safari/GhostText/Assets.xcassets/AppIcon.appiconset/icon128.png b/safari/GhostText/Assets.xcassets/AppIcon.appiconset/icon128.png new file mode 100644 index 0000000..f234eb7 Binary files /dev/null and b/safari/GhostText/Assets.xcassets/AppIcon.appiconset/icon128.png differ diff --git a/safari/GhostText/Assets.xcassets/AppIcon.appiconset/icon16.png b/safari/GhostText/Assets.xcassets/AppIcon.appiconset/icon16.png new file mode 100644 index 0000000..9f34e30 Binary files /dev/null and b/safari/GhostText/Assets.xcassets/AppIcon.appiconset/icon16.png differ diff --git a/safari/GhostText/Assets.xcassets/AppIcon.appiconset/icon256.png b/safari/GhostText/Assets.xcassets/AppIcon.appiconset/icon256.png new file mode 100644 index 0000000..06ca942 Binary files /dev/null and b/safari/GhostText/Assets.xcassets/AppIcon.appiconset/icon256.png differ diff --git a/safari/GhostText/Assets.xcassets/AppIcon.appiconset/icon32.png b/safari/GhostText/Assets.xcassets/AppIcon.appiconset/icon32.png new file mode 100644 index 0000000..d273d1c Binary files /dev/null and b/safari/GhostText/Assets.xcassets/AppIcon.appiconset/icon32.png differ diff --git a/safari/GhostText/Assets.xcassets/AppIcon.appiconset/icon512.png b/safari/GhostText/Assets.xcassets/AppIcon.appiconset/icon512.png new file mode 100644 index 0000000..aa7abe8 Binary files /dev/null and b/safari/GhostText/Assets.xcassets/AppIcon.appiconset/icon512.png differ diff --git a/safari/GhostText/Assets.xcassets/AppIcon.appiconset/icon64.png b/safari/GhostText/Assets.xcassets/AppIcon.appiconset/icon64.png new file mode 100644 index 0000000..1638d40 Binary files /dev/null and b/safari/GhostText/Assets.xcassets/AppIcon.appiconset/icon64.png differ diff --git a/safari/GhostText/Assets.xcassets/Contents.json b/safari/GhostText/Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/safari/GhostText/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/safari/GhostText/Base.lproj/Main.storyboard b/safari/GhostText/Base.lproj/Main.storyboard new file mode 100644 index 0000000..49a2b60 --- /dev/null +++ b/safari/GhostText/Base.lproj/Main.storyboard @@ -0,0 +1,167 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/safari/GhostText/GhostText.entitlements b/safari/GhostText/GhostText.entitlements new file mode 100644 index 0000000..13cb114 --- /dev/null +++ b/safari/GhostText/GhostText.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/safari/GhostText/Info.plist b/safari/GhostText/Info.plist new file mode 100644 index 0000000..8642e57 --- /dev/null +++ b/safari/GhostText/Info.plist @@ -0,0 +1,30 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + LSApplicationCategoryType + public.app-category.developer-tools + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSMainStoryboardFile + Main + NSPrincipalClass + NSApplication + + diff --git a/safari/GhostText/ViewController.swift b/safari/GhostText/ViewController.swift new file mode 100644 index 0000000..1135c20 --- /dev/null +++ b/safari/GhostText/ViewController.swift @@ -0,0 +1,44 @@ +import Cocoa +import SafariServices.SFSafariApplication +import SafariServices.SFSafariExtensionManager + +let appName = "GhostText" +let extensionBundleIdentifier = "com.fregante.GhostText.Extension" + +final class ViewController: NSViewController { + @IBOutlet private var appNameLabel: NSTextField! + + override func viewDidLoad() { + super.viewDidLoad() + + appNameLabel.stringValue = appName + + 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 { [self] in + if (state.isEnabled) { + appNameLabel.stringValue = "\(appName)'s extension is currently on." + } else { + appNameLabel.stringValue = "\(appName)'s extension is currently off. You can turn it on in Safari Extensions preferences." + } + } + } + } + + @IBAction private func openSafariExtensionPreferences(_ sender: AnyObject?) { + SFSafariApplication.showPreferencesForExtension(withIdentifier: extensionBundleIdentifier) { error in + guard error == nil else { + // Insert code to inform the user that something went wrong. + return + } + + DispatchQueue.main.async { + NSApplication.shared.terminate(nil) + } + } + } +} diff --git a/safari/Shared.xcconfig b/safari/Shared.xcconfig new file mode 100644 index 0000000..22fdded --- /dev/null +++ b/safari/Shared.xcconfig @@ -0,0 +1,2 @@ +MARKETING_VERSION = 21.2.4 +CURRENT_PROJECT_VERSION = 2 diff --git a/safari/app-store-description.txt b/safari/app-store-description.txt new file mode 100644 index 0000000..2ef6264 --- /dev/null +++ b/safari/app-store-description.txt @@ -0,0 +1,5 @@ +Use your text editor to write in your browser. Everything you type in the editor will be instantly updated in the browser (and vice versa). + +It supports Sublime Text, VS Code, Emacs, Acme, Vim/Neovim. Each editor also requires its own GhostText extension. Search and install from their extension stores (or GhostText’s GitHub repository) + +When you're on a page with a supported field (a plain text area, a contenteditable block, CodeMirror, Ace editor, …), click the GhostText button that appears in Safari. The extension will connect the field to your editor, as long as it's open and has its own GhostText extension. diff --git a/safari/app-store-keywords.txt b/safari/app-store-keywords.txt new file mode 100644 index 0000000..2f75240 --- /dev/null +++ b/safari/app-store-keywords.txt @@ -0,0 +1 @@ +safari, extension, sublime text, vscode, editor, ide, text, write, code diff --git a/source/background.js b/source/background.js index c6830b6..14d03a9 100644 --- a/source/background.js +++ b/source/background.js @@ -104,7 +104,7 @@ function handleMessages({code, count}, {tab}) { if (code === 'connection-count') { let text = ''; if (count === 1) { - text = /os x/i.test(navigator.userAgent) ? '✓' : 'ON'; + text = '\u2713'; // ✓ checkmark. Safari encoding issue https://developer.apple.com/forums/thread/660798 } else if (count > 1) { text = String(count); } diff --git a/source/icons/icon128.png b/source/icons/icon128.png new file mode 100644 index 0000000..255fc95 Binary files /dev/null and b/source/icons/icon128.png differ diff --git a/source/icons/icon16.png b/source/icons/icon16.png new file mode 100644 index 0000000..fd543cc Binary files /dev/null and b/source/icons/icon16.png differ diff --git a/source/icons/icon256.png b/source/icons/icon256.png new file mode 100644 index 0000000..1556058 Binary files /dev/null and b/source/icons/icon256.png differ diff --git a/source/icons/icon32.png b/source/icons/icon32.png new file mode 100644 index 0000000..a547309 Binary files /dev/null and b/source/icons/icon32.png differ diff --git a/source/icons/icon48.png b/source/icons/icon48.png new file mode 100644 index 0000000..b11f34d Binary files /dev/null and b/source/icons/icon48.png differ diff --git a/source/icons/icon64.png b/source/icons/icon64.png new file mode 100644 index 0000000..17414ba Binary files /dev/null and b/source/icons/icon64.png differ diff --git a/source/images/icon_128.png b/source/images/icon_128.png deleted file mode 100644 index 06b1d43..0000000 Binary files a/source/images/icon_128.png and /dev/null differ diff --git a/source/images/icon_19.png b/source/images/icon_19.png deleted file mode 100644 index 0a25c69..0000000 Binary files a/source/images/icon_19.png and /dev/null differ diff --git a/source/images/icon_48.png b/source/images/icon_48.png deleted file mode 100644 index f42df32..0000000 Binary files a/source/images/icon_48.png and /dev/null differ diff --git a/source/manifest.json b/source/manifest.json index de8d32c..660faa6 100644 --- a/source/manifest.json +++ b/source/manifest.json @@ -1,16 +1,17 @@ { "manifest_version": 2, "name": "GhostText", - "description": "Use your text editor to write in your browser. Everything you type in the editor will be instantly updated in the browser.", + "description": "Write in the browser with your text editor.", "version": "0.0.0", "minimum_chrome_version": "86", "author": "Federico Brigante", "icons": { - "16": "images/icon_19.png", - "19": "images/icon_19.png", - "38": "images/icon_48.png", - "48": "images/icon_48.png", - "128": "images/icon_128.png" + "16": "icons/icon16.png", + "32": "icons/icon32.png", + "48": "icons/icon48.png", + "64": "icons/icon64.png", + "128": "icons/icon128.png", + "256": "icons/icon256.png" }, "permissions": [ "activeTab", @@ -31,8 +32,12 @@ "browser_action": { "default_title": "GhostText", "default_icon": { - "19": "images/icon_19.png", - "38": "images/icon_48.png" + "16": "icons/icon16.png", + "32": "icons/icon32.png", + "48": "icons/icon48.png", + "64": "icons/icon64.png", + "128": "icons/icon128.png", + "256": "icons/icon256.png" } }, "commands": { @@ -44,12 +49,23 @@ } } }, - "content_scripts": [{ - "matches": ["http://localhost:4001/*"], - "js": ["ghost-text.js"], - "css": ["ghost-text.css"] - }], + "content_scripts": [ + { + "matches": [ + "http://localhost:4001/*" + ], + "js": [ + "ghost-text.js", + "options.js" + ], + "css": [ + "ghost-text.css" + ] + } + ], "background": { - "scripts": ["background.js"] + "scripts": [ + "background.js" + ] } }