Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,6 @@ playground.xcworkspace

# Icon?
Icon?

# Project
project.pbxproj
8 changes: 4 additions & 4 deletions freewrite.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -398,11 +398,11 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
CODE_SIGN_ENTITLEMENTS = freewrite/freewrite.entitlements;
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"freewrite/Preview Content\"";
DEVELOPMENT_TEAM = 2UDAY4J48G;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
Expand Down Expand Up @@ -440,11 +440,11 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
CODE_SIGN_ENTITLEMENTS = freewrite/freewrite.entitlements;
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"freewrite/Preview Content\"";
DEVELOPMENT_TEAM = 2UDAY4J48G;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
Expand Down
79 changes: 65 additions & 14 deletions freewrite/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ struct ContentView: View {
@State private var colorScheme: ColorScheme = .light // Add state for color scheme
@State private var isHoveringThemeToggle = false // Add state for theme toggle hover
@State private var didCopyPrompt: Bool = false // Add state for copy prompt feedback
@State private var strictMode = false // Add state for strict mode
@State private var isHoveringStrictMode = false // Add state for strict mode hover
let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
let entryHeight: CGFloat = 40

Expand Down Expand Up @@ -157,6 +159,19 @@ struct ContentView: View {
_colorScheme = State(initialValue: savedScheme == "dark" ? .dark : .light)
}

// Setup key event monitor for strict mode
private func setupStrictModeKeyMonitor() {
NSEvent.addLocalMonitorForEvents(matching: .keyDown) { event in
// Check if strict mode is enabled and the key is backspace (keyCode 51)
if strictMode && event.keyCode == 51 {
// Block the backspace key by returning nil
return nil
}
// Allow all other key events to pass through
return event
}
}

// Modify getDocumentsDirectory to use cached value
private func getDocumentsDirectory() -> URL {
return documentsDirectory
Expand Down Expand Up @@ -382,8 +397,9 @@ struct ContentView: View {
return colorScheme == .light ? Color.primary : Color.white
}

@State private var viewHeight: CGFloat = 0

var body: some View {
let buttonBackground = colorScheme == .light ? Color.white : Color.black
let navHeight: CGFloat = 68
let textColor = colorScheme == .light ? Color.gray : Color.gray.opacity(0.8)
let textHoverColor = colorScheme == .light ? Color.black : Color.white
Expand All @@ -394,24 +410,27 @@ struct ContentView: View {
Color(colorScheme == .light ? .white : .black)
.ignoresSafeArea()

TextEditor(text: Binding(
get: { text },
set: { newValue in
// Ensure the text always starts with two newlines
if !newValue.hasPrefix("\n\n") {
text = "\n\n" + newValue.trimmingCharacters(in: .newlines)
} else {
text = newValue

TextEditor(text: Binding(
get: { text },
set: { newValue in
// Ensure the text always starts with two newlines
if !newValue.hasPrefix("\n\n") {
text = "\n\n" + newValue.trimmingCharacters(in: .newlines)
} else {
text = newValue
}
}
}
))
))
.background(Color(colorScheme == .light ? .white : .black))
.font(.custom(selectedFont, size: fontSize))
.foregroundColor(colorScheme == .light ? Color(red: 0.20, green: 0.20, blue: 0.20) : Color(red: 0.9, green: 0.9, blue: 0.9))
.scrollContentBackground(.hidden)
.scrollIndicators(.never)
.lineSpacing(lineHeight)
.frame(maxWidth: 650)


.id("\(selectedFont)-\(fontSize)-\(colorScheme)")
.padding(.bottom, bottomNavOpacity > 0 ? navHeight : 0)
.ignoresSafeArea()
Expand All @@ -426,13 +445,20 @@ struct ContentView: View {
Text(placeholderText)
.font(.custom(selectedFont, size: fontSize))
.foregroundColor(colorScheme == .light ? .gray.opacity(0.5) : .gray.opacity(0.6))
// .padding(.top, 8)
// .padding(.leading, 8)
// .padding(.top, 8)
// .padding(.leading, 8)
.allowsHitTesting(false)
.offset(x: 5, y: placeholderOffset)
}
}, alignment: .topLeading
)
.onGeometryChange(for: CGFloat.self) { proxy in
proxy.size.height
} action: { height in
viewHeight = height
}
.contentMargins(.bottom, viewHeight / 4)


VStack {
Spacer()
Expand Down Expand Up @@ -803,6 +829,30 @@ struct ContentView: View {
}
}

Text("•")
.foregroundColor(.gray)

// Strict mode toggle button
Button(action: {
strictMode.toggle()
}) {
Image(systemName: strictMode ? "lock.fill" : "lock.open")
.foregroundColor(strictMode ?
(isHoveringStrictMode ? textHoverColor : .red) :
(isHoveringStrictMode ? textHoverColor : textColor))
}
.buttonStyle(.plain)
.onHover { hovering in
isHoveringStrictMode = hovering
isHoveringBottomNav = hovering
if hovering {
NSCursor.pointingHand.push()
} else {
NSCursor.pop()
}
}
.help(strictMode ? "Strict mode enabled - backspace disabled" : "Enable strict mode")

Text("•")
.foregroundColor(.gray)

Expand Down Expand Up @@ -1027,6 +1077,7 @@ struct ContentView: View {
.onAppear {
showingSidebar = false // Hide sidebar by default
loadExistingEntries()
setupStrictModeKeyMonitor()
}
.onChange(of: text) { _ in
// Save current entry when text changes
Expand Down Expand Up @@ -1399,4 +1450,4 @@ extension NSView {

#Preview {
ContentView()
}
}
2 changes: 1 addition & 1 deletion freewrite/default.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ That’s it.

Some basic rules:

- Again, no backspaces
- Again, no backspaces (click on the padlock to toggle strict mode and really enforce this)
- No fixing spelling
- Little 5–10s breaks are fine, but try to not stop typing
- No need to stay on the topic you started with — let your mind wander
Expand Down