Compare commits
10
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2dd4b49b29
|
||
|
|
da1e7a180c
|
||
|
|
57eae9f643
|
||
|
|
0da26e0fed
|
||
|
|
6ffba3be02
|
||
|
|
187f2eaa25
|
||
|
|
3fadd008f4
|
||
|
|
410049d161
|
||
|
|
5301187413
|
||
|
|
fe275ac17c
|
@@ -1,3 +1,6 @@
|
|||||||
[submodule "docs/reference/outline-openapi"]
|
[submodule "docs/reference/outline-openapi"]
|
||||||
path = docs/reference/outline-openapi
|
path = docs/reference/outline-openapi
|
||||||
url = https://github.com/outline/openapi.git
|
url = https://github.com/outline/openapi.git
|
||||||
|
[submodule "Vendor/swift-markdown-engine"]
|
||||||
|
path = Vendor/swift-markdown-engine
|
||||||
|
url = https://github.com/nodes-app/swift-markdown-engine.git
|
||||||
|
|||||||
@@ -7,10 +7,10 @@
|
|||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
|
FA7596B230366A1D0000167E /* MarkdownEngine in Frameworks */ = {isa = PBXBuildFile; productRef = FA7596B130366A1D0000167E /* MarkdownEngine */; };
|
||||||
|
FA7596B430366A1D0000167E /* MarkdownEngineCodeBlocks in Frameworks */ = {isa = PBXBuildFile; productRef = FA7596B330366A1D0000167E /* MarkdownEngineCodeBlocks */; };
|
||||||
|
FA7596B630366A1D0000167E /* MarkdownEngineLatex in Frameworks */ = {isa = PBXBuildFile; productRef = FA7596B530366A1D0000167E /* MarkdownEngineLatex */; };
|
||||||
FAF99C44302CF1BD00C9949F /* OutlineKit in Frameworks */ = {isa = PBXBuildFile; productRef = FAF99C43302CF1BD00C9949F /* OutlineKit */; };
|
FAF99C44302CF1BD00C9949F /* OutlineKit in Frameworks */ = {isa = PBXBuildFile; productRef = FAF99C43302CF1BD00C9949F /* OutlineKit */; };
|
||||||
FAF99CAF302D120500C9949F /* MarkdownEngine in Frameworks */ = {isa = PBXBuildFile; productRef = FAF99CAE302D120500C9949F /* MarkdownEngine */; };
|
|
||||||
FAF99CB1302D120500C9949F /* MarkdownEngineCodeBlocks in Frameworks */ = {isa = PBXBuildFile; productRef = FAF99CB0302D120500C9949F /* MarkdownEngineCodeBlocks */; };
|
|
||||||
FAF99CB3302D120500C9949F /* MarkdownEngineLatex in Frameworks */ = {isa = PBXBuildFile; productRef = FAF99CB2302D120500C9949F /* MarkdownEngineLatex */; };
|
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
@@ -59,9 +59,9 @@
|
|||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
files = (
|
files = (
|
||||||
FAF99C44302CF1BD00C9949F /* OutlineKit in Frameworks */,
|
FAF99C44302CF1BD00C9949F /* OutlineKit in Frameworks */,
|
||||||
FAF99CB1302D120500C9949F /* MarkdownEngineCodeBlocks in Frameworks */,
|
FA7596B430366A1D0000167E /* MarkdownEngineCodeBlocks in Frameworks */,
|
||||||
FAF99CB3302D120500C9949F /* MarkdownEngineLatex in Frameworks */,
|
FA7596B630366A1D0000167E /* MarkdownEngineLatex in Frameworks */,
|
||||||
FAF99CAF302D120500C9949F /* MarkdownEngine in Frameworks */,
|
FA7596B230366A1D0000167E /* MarkdownEngine in Frameworks */,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
FAF99C24302CE96200C9949F /* Frameworks */ = {
|
FAF99C24302CE96200C9949F /* Frameworks */ = {
|
||||||
@@ -116,9 +116,9 @@
|
|||||||
name = Outpost;
|
name = Outpost;
|
||||||
packageProductDependencies = (
|
packageProductDependencies = (
|
||||||
FAF99C43302CF1BD00C9949F /* OutlineKit */,
|
FAF99C43302CF1BD00C9949F /* OutlineKit */,
|
||||||
FAF99CAE302D120500C9949F /* MarkdownEngine */,
|
FA7596B130366A1D0000167E /* MarkdownEngine */,
|
||||||
FAF99CB0302D120500C9949F /* MarkdownEngineCodeBlocks */,
|
FA7596B330366A1D0000167E /* MarkdownEngineCodeBlocks */,
|
||||||
FAF99CB2302D120500C9949F /* MarkdownEngineLatex */,
|
FA7596B530366A1D0000167E /* MarkdownEngineLatex */,
|
||||||
);
|
);
|
||||||
productName = Outpost;
|
productName = Outpost;
|
||||||
productReference = FAF99C18302CE96100C9949F /* Outpost.app */;
|
productReference = FAF99C18302CE96100C9949F /* Outpost.app */;
|
||||||
@@ -200,7 +200,7 @@
|
|||||||
minimizedProjectReferenceProxies = 1;
|
minimizedProjectReferenceProxies = 1;
|
||||||
packageReferences = (
|
packageReferences = (
|
||||||
FAF99C42302CF1BD00C9949F /* XCLocalSwiftPackageReference "OutlineKit" */,
|
FAF99C42302CF1BD00C9949F /* XCLocalSwiftPackageReference "OutlineKit" */,
|
||||||
FAF99CAD302D120500C9949F /* XCRemoteSwiftPackageReference "swift-markdown-engine" */,
|
FA7596B030366A1D0000167E /* XCLocalSwiftPackageReference "Vendor/swift-markdown-engine" */,
|
||||||
);
|
);
|
||||||
preferredProjectObjectVersion = 77;
|
preferredProjectObjectVersion = 77;
|
||||||
productRefGroup = FAF99C19302CE96100C9949F /* Products */;
|
productRefGroup = FAF99C19302CE96100C9949F /* Products */;
|
||||||
@@ -622,43 +622,33 @@
|
|||||||
/* End XCConfigurationList section */
|
/* End XCConfigurationList section */
|
||||||
|
|
||||||
/* Begin XCLocalSwiftPackageReference section */
|
/* Begin XCLocalSwiftPackageReference section */
|
||||||
|
FA7596B030366A1D0000167E /* XCLocalSwiftPackageReference "Vendor/swift-markdown-engine" */ = {
|
||||||
|
isa = XCLocalSwiftPackageReference;
|
||||||
|
relativePath = "Vendor/swift-markdown-engine";
|
||||||
|
};
|
||||||
FAF99C42302CF1BD00C9949F /* XCLocalSwiftPackageReference "OutlineKit" */ = {
|
FAF99C42302CF1BD00C9949F /* XCLocalSwiftPackageReference "OutlineKit" */ = {
|
||||||
isa = XCLocalSwiftPackageReference;
|
isa = XCLocalSwiftPackageReference;
|
||||||
relativePath = OutlineKit;
|
relativePath = OutlineKit;
|
||||||
};
|
};
|
||||||
/* End XCLocalSwiftPackageReference section */
|
/* End XCLocalSwiftPackageReference section */
|
||||||
|
|
||||||
/* Begin XCRemoteSwiftPackageReference section */
|
|
||||||
FAF99CAD302D120500C9949F /* XCRemoteSwiftPackageReference "swift-markdown-engine" */ = {
|
|
||||||
isa = XCRemoteSwiftPackageReference;
|
|
||||||
repositoryURL = "https://github.com/nodes-app/swift-markdown-engine";
|
|
||||||
requirement = {
|
|
||||||
kind = upToNextMajorVersion;
|
|
||||||
minimumVersion = 0.12.0;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
/* End XCRemoteSwiftPackageReference section */
|
|
||||||
|
|
||||||
/* Begin XCSwiftPackageProductDependency section */
|
/* Begin XCSwiftPackageProductDependency section */
|
||||||
|
FA7596B130366A1D0000167E /* MarkdownEngine */ = {
|
||||||
|
isa = XCSwiftPackageProductDependency;
|
||||||
|
productName = MarkdownEngine;
|
||||||
|
};
|
||||||
|
FA7596B330366A1D0000167E /* MarkdownEngineCodeBlocks */ = {
|
||||||
|
isa = XCSwiftPackageProductDependency;
|
||||||
|
productName = MarkdownEngineCodeBlocks;
|
||||||
|
};
|
||||||
|
FA7596B530366A1D0000167E /* MarkdownEngineLatex */ = {
|
||||||
|
isa = XCSwiftPackageProductDependency;
|
||||||
|
productName = MarkdownEngineLatex;
|
||||||
|
};
|
||||||
FAF99C43302CF1BD00C9949F /* OutlineKit */ = {
|
FAF99C43302CF1BD00C9949F /* OutlineKit */ = {
|
||||||
isa = XCSwiftPackageProductDependency;
|
isa = XCSwiftPackageProductDependency;
|
||||||
productName = OutlineKit;
|
productName = OutlineKit;
|
||||||
};
|
};
|
||||||
FAF99CAE302D120500C9949F /* MarkdownEngine */ = {
|
|
||||||
isa = XCSwiftPackageProductDependency;
|
|
||||||
package = FAF99CAD302D120500C9949F /* XCRemoteSwiftPackageReference "swift-markdown-engine" */;
|
|
||||||
productName = MarkdownEngine;
|
|
||||||
};
|
|
||||||
FAF99CB0302D120500C9949F /* MarkdownEngineCodeBlocks */ = {
|
|
||||||
isa = XCSwiftPackageProductDependency;
|
|
||||||
package = FAF99CAD302D120500C9949F /* XCRemoteSwiftPackageReference "swift-markdown-engine" */;
|
|
||||||
productName = MarkdownEngineCodeBlocks;
|
|
||||||
};
|
|
||||||
FAF99CB2302D120500C9949F /* MarkdownEngineLatex */ = {
|
|
||||||
isa = XCSwiftPackageProductDependency;
|
|
||||||
package = FAF99CAD302D120500C9949F /* XCRemoteSwiftPackageReference "swift-markdown-engine" */;
|
|
||||||
productName = MarkdownEngineLatex;
|
|
||||||
};
|
|
||||||
/* End XCSwiftPackageProductDependency section */
|
/* End XCSwiftPackageProductDependency section */
|
||||||
};
|
};
|
||||||
rootObject = FAF99C10302CE96100C9949F /* Project object */;
|
rootObject = FAF99C10302CE96100C9949F /* Project object */;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"originHash" : "f233fa96f0c6bdcdbf87f726af38f25704f6d46a156a27dfac47541baa63bf97",
|
"originHash" : "4127e8224149bef00a33500e8db49748a735e1c07626f2255faea52554afef5e",
|
||||||
"pins" : [
|
"pins" : [
|
||||||
{
|
{
|
||||||
"identity" : "highlighterswift",
|
"identity" : "highlighterswift",
|
||||||
@@ -10,15 +10,6 @@
|
|||||||
"version" : "3.1.0"
|
"version" : "3.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"identity" : "swift-markdown-engine",
|
|
||||||
"kind" : "remoteSourceControl",
|
|
||||||
"location" : "https://github.com/nodes-app/swift-markdown-engine",
|
|
||||||
"state" : {
|
|
||||||
"revision" : "e5f7607fc4021181056ef7a09dbb7573dc0237d9",
|
|
||||||
"version" : "0.12.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"identity" : "swiftmath",
|
"identity" : "swiftmath",
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
|
|||||||
@@ -2,13 +2,11 @@
|
|||||||
import AppKit
|
import AppKit
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
/// Bare content (icon, name, version, links) with no window chrome — reused
|
/// Bare content (icon, name, version, links) with no window chrome — the
|
||||||
/// by both the standalone "About Outpost" window (`AboutView`, the standard
|
/// macOS "About Outpost" app-menu command now opens Settings' own About
|
||||||
/// macOS app-menu affordance) and the Settings page's own About section, so
|
/// section directly (no separate popup window), so this is its only caller.
|
||||||
/// the two can't drift out of sync.
|
|
||||||
struct AboutInfoView: View {
|
struct AboutInfoView: View {
|
||||||
private let repositoryURL = URL(string: "https://git.psmattas.com/psmattas/Outpost")!
|
private let repositoryURL = URL(string: "https://git.psmattas.com/psmattas/Outpost")!
|
||||||
private let releasesURL = URL(string: "https://git.psmattas.com/psmattas/Outpost/releases")!
|
|
||||||
|
|
||||||
var appName: String {
|
var appName: String {
|
||||||
Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as? String ?? "Outpost"
|
Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as? String ?? "Outpost"
|
||||||
@@ -45,35 +43,15 @@ struct AboutInfoView: View {
|
|||||||
.fixedSize(horizontal: false, vertical: true)
|
.fixedSize(horizontal: false, vertical: true)
|
||||||
.frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity)
|
||||||
|
|
||||||
VStack(spacing: 10) {
|
|
||||||
Link(destination: repositoryURL) {
|
Link(destination: repositoryURL) {
|
||||||
Label("View Source on Git", systemImage: "link")
|
Label("View Source on Git", systemImage: "link")
|
||||||
}
|
}
|
||||||
.font(.callout)
|
.font(.callout)
|
||||||
|
|
||||||
Button("Check for Updates…") {
|
|
||||||
checkForUpdates()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Text("© \(copyrightYear) Puranjay Savar Mattas")
|
Text("© \(copyrightYear) Puranjay Savar Mattas")
|
||||||
.font(.caption2)
|
.font(.caption2)
|
||||||
.foregroundStyle(.tertiary)
|
.foregroundStyle(.tertiary)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// No Sparkle-style in-app updater yet — this just opens the releases page
|
|
||||||
// on the self-hosted Gitea instance so the user can check/download manually.
|
|
||||||
private func checkForUpdates() {
|
|
||||||
NSWorkspace.shared.open(releasesURL)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct AboutView: View {
|
|
||||||
var body: some View {
|
|
||||||
AboutInfoView()
|
|
||||||
.padding(32)
|
|
||||||
.frame(width: 320)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ struct OutpostApp: App {
|
|||||||
@AppStorage("outpost.appearance") private var appearance: AppAppearance = .system
|
@AppStorage("outpost.appearance") private var appearance: AppAppearance = .system
|
||||||
|
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
@Environment(\.openWindow) private var openWindow
|
|
||||||
@State private var isShowingLogoutConfirmation = false
|
@State private var isShowingLogoutConfirmation = false
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -40,7 +39,8 @@ struct OutpostApp: App {
|
|||||||
.commands {
|
.commands {
|
||||||
CommandGroup(replacing: .appInfo) {
|
CommandGroup(replacing: .appInfo) {
|
||||||
Button("About Outpost") {
|
Button("About Outpost") {
|
||||||
openWindow(id: "about")
|
navigation.selectedSettingsSection = .about
|
||||||
|
navigation.isShowingSettings = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// No `Settings {}` scene anymore — Settings renders inside the
|
// No `Settings {}` scene anymore — Settings renders inside the
|
||||||
@@ -64,12 +64,6 @@ struct OutpostApp: App {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
Window("About Outpost", id: "about") {
|
|
||||||
AboutView()
|
|
||||||
.disablesFullScreen()
|
|
||||||
}
|
|
||||||
.windowResizability(.contentSize)
|
|
||||||
|
|
||||||
Window("Keyboard Shortcuts", id: "keyboard-shortcuts") {
|
Window("Keyboard Shortcuts", id: "keyboard-shortcuts") {
|
||||||
KeyboardShortcutsView()
|
KeyboardShortcutsView()
|
||||||
.disablesFullScreen()
|
.disablesFullScreen()
|
||||||
|
|||||||
@@ -1,27 +1,29 @@
|
|||||||
# Outpost
|
<p align="center">
|
||||||
|
<img src="Outpost/Assets.xcassets/AppLogo.imageset/outpost-ios-1024.png" width="120" alt="Outpost logo">
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h1 align="center">Outpost</h1>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://testflight.apple.com/join/y1mYcYAM">
|
||||||
|
<img src="https://img.shields.io/badge/Download-TestFlight-0D96F6?style=for-the-badge&logo=apple&logoColor=white" alt="Download on TestFlight">
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
A native Apple ecosystem client for [Outline](https://github.com/outline/outline) — built for iOS, iPadOS, and macOS from a single SwiftUI codebase, aiming for full editing parity with Outline's web app, including realtime collaborative editing.
|
A native Apple ecosystem client for [Outline](https://github.com/outline/outline) — built for iOS, iPadOS, and macOS from a single SwiftUI codebase, aiming for full editing parity with Outline's web app, including realtime collaborative editing.
|
||||||
|
|
||||||
|
> **Early alpha — macOS only for now.** Expect missing features and rough edges. iOS/iPadOS support is planned but not in the current build. See the [releases page](https://git.psmattas.com/psmattas/Outpost/releases) for changelogs, and [open an issue](https://git.psmattas.com/psmattas/Outpost/issues) if you hit anything.
|
||||||
|
|
||||||
## Why
|
## Why
|
||||||
|
|
||||||
Outline's web app is great, but there's no native Apple client with full editing parity. This project connects to a self-hosted Outline instance over its REST API and realtime collaboration socket to provide a proper native experience across the Apple ecosystem.
|
Outline's web app is great, but there's no native Apple client with full editing parity. This project connects to a self-hosted Outline instance over its REST API and realtime collaboration socket to provide a proper native experience across the Apple ecosystem.
|
||||||
|
|
||||||
## Status
|
|
||||||
|
|
||||||
Early development. See `CLAUDE.md` for the current architecture and phased build plan.
|
|
||||||
|
|
||||||
- [ ] Phase 1 — Auth, browse, search, REST-only editing
|
|
||||||
- [ ] Phase 2 — Realtime collaborative editing (Yjs/Hocuspocus)
|
|
||||||
- [ ] Phase 3 — Offline cache, tables, embeds, comments, macOS polish
|
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- Xcode 16+
|
- Xcode 27+ (currently developed against an Xcode 27 beta — this is a hard minimum, not a suggestion)
|
||||||
- iOS 17+ / iPadOS 17+ / macOS 14+
|
- macOS 27+. iOS/iPadOS support is planned but not in the current build (see the alpha note above) — same 27+ minimum will apply once it lands
|
||||||
- A self-hosted (or hosted) Outline instance with API access
|
- A self-hosted (or hosted) Outline instance with API access
|
||||||
|
|
||||||
> They will be updated. These are old requirements.
|
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
|
|
||||||
1. Clone the repo and open the `.xcodeproj` in Xcode.
|
1. Clone the repo and open the `.xcodeproj` in Xcode.
|
||||||
@@ -42,6 +44,16 @@ Parts of this codebase are AI-assisted (built with the help of AI coding tools).
|
|||||||
|
|
||||||
This project is a client only — it does not include, vendor, or redistribute any of Outline's (BSL 1.1 licensed) server source. See [`LICENSE`](./LICENSE) for this repository's own license.
|
This project is a client only — it does not include, vendor, or redistribute any of Outline's (BSL 1.1 licensed) server source. See [`LICENSE`](./LICENSE) for this repository's own license.
|
||||||
|
|
||||||
|
## Privacy
|
||||||
|
|
||||||
|
Outpost collects nothing about you — no analytics, no telemetry, no crash reporting of its own, no age or demographic data, nothing. The only thing stored locally is your Outline server URL and API token (in the device Keychain) and, optionally, a local offline cache of what you've viewed. Everything else goes straight from your device to whatever Outline server you configure — there's no backend in between, and the developer has no access to your data or your server.
|
||||||
|
|
||||||
|
Full policy, terms of service, and data-processing statement are on the [wiki](https://git.psmattas.com/psmattas/Outpost/wiki):
|
||||||
|
|
||||||
|
- [Privacy Policy](https://git.psmattas.com/psmattas/Outpost/wiki/Privacy-Policy.-)
|
||||||
|
- [Terms of Service](https://git.psmattas.com/psmattas/Outpost/wiki/Terms-of-Service.-)
|
||||||
|
- [Data Processing Statement](https://git.psmattas.com/psmattas/Outpost/wiki/Data-Processing-Statement.-)
|
||||||
|
|
||||||
## Not affiliated with Outline
|
## Not affiliated with Outline
|
||||||
|
|
||||||
This is an independent, unofficial client. Not affiliated with or endorsed by General Outline, Inc.
|
This is an independent, unofficial client. Not affiliated with or endorsed by General Outline, Inc.
|
||||||
|
|||||||
+1
Submodule Vendor/swift-markdown-engine added at 05c1720f44
Reference in New Issue
Block a user