Skip to content

Commit 5017be5

Browse files
authored
Merge pull request #104 from Lycoon/dev
bump staging
2 parents f4cd376 + e391cca commit 5017be5

35 files changed

+469
-251
lines changed

.github/workflows/deploy-macos.yaml

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,29 +7,57 @@ on:
77
jobs:
88
build:
99
runs-on: macos-latest
10+
env:
11+
APP_PATH: src-tauri/target/universal-apple-darwin/release/bundle/macos/Scriptio.app
12+
PKG_PATH: Scriptio.pkg
1013
steps:
11-
- uses: actions/checkout@v6
14+
- uses: actions/checkout@v4
1215

13-
- name: Setup Node.js
14-
uses: actions/setup-node@v6
16+
- name: Import Apple certificates
17+
uses: apple-actions/import-codesign-certs@v3
1518
with:
16-
node-version: "25.2.1"
19+
p12-file-base64: ${{ secrets.APPLE_CERT_P12_COMBINED_BASE64 }}
20+
p12-password: ${{ secrets.APPLE_CERT_PASSWORD }}
1721

18-
- name: Setup Rust
19-
uses: dtolnay/rust-toolchain@stable
22+
- name: Download provisioning profile
23+
uses: apple-actions/download-provisioning-profiles@v3
2024
with:
21-
targets: aarch64-apple-darwin, x86_64-apple-darwin
25+
bundle-id: "ArkoLogic.Scriptio"
26+
profile-type: "MAC_APP_STORE"
27+
issuer-id: ${{ secrets.APPSTORE_ISSUER_ID }}
28+
api-key-id: ${{ secrets.APPSTORE_KEY_ID }}
29+
api-key-content: ${{ secrets.APPSTORE_API_KEY_P8 }}
30+
31+
- uses: actions/setup-node@v4
32+
with: { node-version: "22" }
33+
- uses: dtolnay/rust-toolchain@stable
34+
with: { targets: "aarch64-apple-darwin, x86_64-apple-darwin" }
2235

2336
- name: Install dependencies
2437
run: npm install
2538

26-
- name: Build MacOS bundle
27-
run: npm run build:macos
39+
- name: Build and sign .app with Tauri
40+
run: npm run tauri build -- --bundles app --target universal-apple-darwin
41+
env:
42+
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
2843

29-
- name: Upload to App Store Connect
44+
- name: Embed provisioning profile
45+
run: |
46+
PROFILE=$(ls "$HOME/Library/MobileDevice/Provisioning Profiles/"*.provisionprofile | head -n 1)
47+
cp "$PROFILE" "$APP_PATH/Contents/embedded.provisionprofile"
48+
49+
- name: Build signed .pkg installer
3050
run: |
31-
xcrun altool --upload-package \
32-
--file "Scriptio.pkg" \
33-
--type osx \
34-
--apiKey "${{ secrets.APPSTORE_KEY_ID }}" \
35-
--apiIssuer "${{ secrets.APPSTORE_ISSUER_ID }}"
51+
xcrun productbuild \
52+
--component "$APP_PATH" /Applications \
53+
--sign "${{ secrets.APPLE_INSTALLER_IDENTITY }}" \
54+
"$PKG_PATH"
55+
56+
- name: Upload to App Store Connect
57+
uses: apple-actions/upload-testflight-build@v1
58+
with:
59+
app-path: ${{ env.PKG_PATH }}
60+
issuer-id: ${{ secrets.APPSTORE_ISSUER_ID }}
61+
api-key-id: ${{ secrets.APPSTORE_KEY_ID }}
62+
api-key-content: ${{ secrets.APPSTORE_API_KEY_P8 }}
63+
app-id: ${{ secrets.APPLE_APP_ID }}

components/dashboard/account/DashboardAuth.tsx

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -92,30 +92,27 @@ const DashboardAuth = () => {
9292
<div className={`${styles.message} ${styles.info}`}>
9393
{tAuth("checkInbox", { email })}
9494
</div>
95+
<button
96+
type="button"
97+
className={styles.authSwitchLink}
98+
style={{ alignSelf: "flex-end" }}
99+
onClick={() => {
100+
setSubmitted(false);
101+
setPollingDesktop(false);
102+
setMessage(null);
103+
}}
104+
>
105+
{tAuth("useDifferentEmail")}
106+
</button>
95107
{pollingDesktop && (
96108
<p className={styles.authInfoText}>{tAuth("waitingForClick")}</p>
97109
)}
98-
<div className={styles.authLinks}>
99-
<button
100-
type="button"
101-
className={styles.authSwitchLink}
102-
onClick={() => {
103-
setSubmitted(false);
104-
setPollingDesktop(false);
105-
setMessage(null);
106-
}}
107-
>
108-
{tAuth("useDifferentEmail")}
109-
</button>
110-
</div>
111110
</div>
112111
);
113112
}
114113

115114
return (
116115
<form className={`${sharedStyles.settingsForm} ${styles.authForm}`} onSubmit={handleSubmit}>
117-
<p className={styles.authInfoText}>{tAuth("intro")}</p>
118-
119116
<div className={sharedStyles.formGroup}>
120117
<label htmlFor="auth-email" className={form.label}>
121118
{tAuth("emailLabel")}

components/dashboard/account/OAuthButtons.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ const OAuthButtons = ({ callbackUrl = "/" }: Props) => {
3939

4040
const nonce = generateBridgeNonce();
4141
const apiBase = process.env.NEXT_PUBLIC_API_URL || window.location.origin;
42-
const bridgeUrl = `${apiBase}/desktop-auth/start?provider=${provider}&nonce=${encodeURIComponent(nonce)}`;
42+
const bridgeUrl = `${apiBase}/desktop-oauth/start?provider=${provider}&nonce=${encodeURIComponent(nonce)}`;
4343
await openUrl(bridgeUrl);
4444

4545
const token = await pollBridgeToken(nonce);

components/editor/DocumentEditorPanel.tsx

Lines changed: 76 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,8 @@ const DocumentEditorPanel = ({
8585
// Resolve the comments Y.Map for this document
8686
const projectState = repository?.getState();
8787
const commentsMap = useMemo(
88-
() => (projectState && config.features.comments ? config.getCommentsMap(projectState) : null),
88+
() =>
89+
projectState && config.features.comments ? config.getCommentsMap(projectState) : null,
8990
// Re-derive only when projectState identity changes (Yjs doc swap on project change)
9091
// eslint-disable-next-line react-hooks/exhaustive-deps
9192
[projectState],
@@ -118,7 +119,9 @@ const DocumentEditorPanel = ({
118119
// Register the editor instance with the parent wrapper
119120
useEffect(() => {
120121
onEditorCreated?.(editor);
121-
return () => { onEditorCreated?.(null); };
122+
return () => {
123+
onEditorCreated?.(null);
124+
};
122125
}, [editor, onEditorCreated]);
123126

124127
// Ready state
@@ -158,7 +161,15 @@ const DocumentEditorPanel = ({
158161
editorElement.style.setProperty("--contd-label", `"${contdLabel}"`);
159162
editorElement.style.setProperty("--more-label", `"${moreLabel}"`);
160163

161-
const elementKeys = ["action", "scene", "character", "dialogue", "parenthetical", "transition", "section"] as const;
164+
const elementKeys = [
165+
"action",
166+
"scene",
167+
"character",
168+
"dialogue",
169+
"parenthetical",
170+
"transition",
171+
"section",
172+
] as const;
162173
for (const key of elementKeys) {
163174
const m = elementMargins[key] ?? DEFAULT_ELEMENT_MARGINS[key];
164175
// Element CSS vars = page margin + element offset (total from page edge)
@@ -170,8 +181,14 @@ const DocumentEditorPanel = ({
170181
editorElement.style.setProperty(`--${key}-align`, s.align ?? "left");
171182
editorElement.style.setProperty(`--${key}-weight`, s.bold ? "bold" : "normal");
172183
editorElement.style.setProperty(`--${key}-style`, s.italic ? "italic" : "normal");
173-
editorElement.style.setProperty(`--${key}-decoration`, s.underline ? "underline" : "none");
174-
editorElement.style.setProperty(`--${key}-transform`, s.uppercase ? "uppercase" : "none");
184+
editorElement.style.setProperty(
185+
`--${key}-decoration`,
186+
s.underline ? "underline" : "none",
187+
);
188+
editorElement.style.setProperty(
189+
`--${key}-transform`,
190+
s.uppercase ? "uppercase" : "none",
191+
);
175192
}
176193

177194
// Compute startNewPage types from element styles
@@ -197,13 +214,25 @@ const DocumentEditorPanel = ({
197214
right: pageMargins.right * 96,
198215
})
199216
.run();
200-
201217
}
202218

203219
if (isVisible) {
204220
editor.commands.focus();
205221
}
206-
}, [editor, isVisible, config.type, pageFormat, pageMargins, displaySceneNumbers, sceneHeadingSpacing, sceneNumberOnRight, contdLabel, moreLabel, elementMargins, elementStyles]);
222+
}, [
223+
editor,
224+
isVisible,
225+
config.type,
226+
pageFormat,
227+
pageMargins,
228+
displaySceneNumbers,
229+
sceneHeadingSpacing,
230+
sceneNumberOnRight,
231+
contdLabel,
232+
moreLabel,
233+
elementMargins,
234+
elementStyles,
235+
]);
207236

208237
// ---- Pagination update (title page only) ----
209238
useEffect(() => {
@@ -228,9 +257,15 @@ const DocumentEditorPanel = ({
228257
const updateContextMenuRef = useRef(updateContextMenu);
229258
const updateSuggestionsRef = useRef(updateSuggestions);
230259

231-
useEffect(() => { selectedElementRef.current = selectedElement; }, [selectedElement]);
232-
useEffect(() => { updateContextMenuRef.current = updateContextMenu; }, [updateContextMenu]);
233-
useEffect(() => { updateSuggestionsRef.current = updateSuggestions; }, [updateSuggestions]);
260+
useEffect(() => {
261+
selectedElementRef.current = selectedElement;
262+
}, [selectedElement]);
263+
useEffect(() => {
264+
updateContextMenuRef.current = updateContextMenu;
265+
}, [updateContextMenu]);
266+
useEffect(() => {
267+
updateSuggestionsRef.current = updateSuggestions;
268+
}, [updateSuggestions]);
234269

235270
const setActiveElement = useCallback(
236271
(element: ScreenplayElement, applyStyle = true) => {
@@ -241,7 +276,9 @@ const DocumentEditorPanel = ({
241276
);
242277

243278
const setActiveElementRef = useRef(setActiveElement);
244-
useEffect(() => { setActiveElementRef.current = setActiveElement; }, [setActiveElement]);
279+
useEffect(() => {
280+
setActiveElementRef.current = setActiveElement;
281+
}, [setActiveElement]);
245282

246283
useEffect(() => {
247284
if (!editor || config.type !== "screenplay") return;
@@ -258,7 +295,8 @@ const DocumentEditorPanel = ({
258295
if (event.key === "Backspace") {
259296
// Inside a dual_dialogue_column: let the column node handle it.
260297
for (let d = selection.$anchor.depth; d >= 1; d--) {
261-
if (selection.$anchor.node(d).type.name === DUAL_DIALOGUE_COLUMN) return false;
298+
if (selection.$anchor.node(d).type.name === DUAL_DIALOGUE_COLUMN)
299+
return false;
262300
}
263301
if (nodeSize === 1 && nodePos === 1) {
264302
const tr = view.state.tr.delete(selection.from - 1, selection.from);
@@ -269,7 +307,10 @@ const DocumentEditorPanel = ({
269307
}
270308

271309
if (event.code === "Space") {
272-
if (currNode === ScreenplayElement.Action && node.textContent.match(/^\b(int|ext)\./gi)) {
310+
if (
311+
currNode === ScreenplayElement.Action &&
312+
node.textContent.match(/^\b(int|ext)\./gi)
313+
) {
273314
setActiveElementRef.current(ScreenplayElement.Scene);
274315
}
275316
return false;
@@ -290,7 +331,11 @@ const DocumentEditorPanel = ({
290331
if ($anchor.node(d).type.name === DUAL_DIALOGUE_COLUMN) return false;
291332
}
292333

293-
if (currNode === ScreenplayElement.Dialogue && nodePos > 0 && nodePos < nodeSize) {
334+
if (
335+
currNode === ScreenplayElement.Dialogue &&
336+
nodePos > 0 &&
337+
nodePos < nodeSize
338+
) {
294339
const doc = view.state.doc;
295340
const $anchor = selection.$anchor;
296341

@@ -302,7 +347,11 @@ const DocumentEditorPanel = ({
302347
charName = child.textContent;
303348
break;
304349
}
305-
if (child.attrs.class !== ScreenplayElement.Parenthetical && child.attrs.class !== ScreenplayElement.Dialogue) break;
350+
if (
351+
child.attrs.class !== ScreenplayElement.Parenthetical &&
352+
child.attrs.class !== ScreenplayElement.Dialogue
353+
)
354+
break;
306355
}
307356

308357
const schema = view.state.schema;
@@ -321,7 +370,9 @@ const DocumentEditorPanel = ({
321370
tr.delete($anchor.pos, $anchor.end(1));
322371
const insertPos = tr.mapping.map($anchor.after(1));
323372
tr.insert(insertPos, [charNode, newDialogue]);
324-
tr.setSelection(TextSelection.create(tr.doc, insertPos + charNode.nodeSize + 1));
373+
tr.setSelection(
374+
TextSelection.create(tr.doc, insertPos + charNode.nodeSize + 1),
375+
);
325376
tr.scrollIntoView();
326377
view.dispatch(tr);
327378
return true;
@@ -390,7 +441,7 @@ const DocumentEditorPanel = ({
390441

391442
addEventListener("keydown", pressedKeyEvent);
392443
return () => removeEventListener("keydown", pressedKeyEvent);
393-
}, [isVisible, config.type]);
444+
}, [isVisible, config.type, editor]);
394445

395446
// ---- Context menu ----
396447
const onEditorContextMenu = useCallback(
@@ -464,7 +515,8 @@ const DocumentEditorPanel = ({
464515
setIsScrolled(scrollTop > 0);
465516
};
466517

467-
const focusType = focusedTypeOverride ?? (config.type === "screenplay" ? "screenplay" : "title");
518+
const focusType =
519+
focusedTypeOverride ?? (config.type === "screenplay" ? "screenplay" : "title");
468520

469521
const isLocalAccess = isTauri() || isLocalOnly;
470522
if (!isLocalAccess && (!membership || isLoading)) return <Loading />;
@@ -477,8 +529,12 @@ const DocumentEditorPanel = ({
477529
onMouseDown={handleContainerMouseDown}
478530
onFocus={() => setFocusedEditorType(focusType)}
479531
>
480-
<div className={`${styles.editor_wrapper} ${isEndlessScroll ? styles.endless_scroll : ""}`}>
481-
<div className={join(styles.editor_shadow, isScrolled ? styles.show_shadow : "")} />
532+
<div
533+
className={`${styles.editor_wrapper} ${isEndlessScroll ? styles.endless_scroll : ""}`}
534+
>
535+
<div
536+
className={join(styles.editor_shadow, isScrolled ? styles.show_shadow : "")}
537+
/>
482538
<div onContextMenu={onEditorContextMenu}>
483539
<EditorContent editor={editor} spellCheck={false} />
484540
</div>

components/editor/sidebar/ShelfSidebarItem.module.css

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,54 @@
1313
flex-direction: row;
1414
align-items: center;
1515
gap: 8px;
16-
padding-inline: 20px;
16+
padding-left: 12px;
17+
padding-right: 20px;
1718
padding-block: 10px;
1819
}
1920

20-
.header:hover,
21-
.header_active {
21+
.header:hover {
2222
background-color: var(--editor-sidebar-hover);
2323
}
2424

25+
.chevron {
26+
flex-shrink: 0;
27+
color: var(--secondary-text);
28+
transition: transform 0.2s ease;
29+
}
30+
31+
.chevron_expanded {
32+
transform: rotate(90deg);
33+
}
34+
2535
.type_icon {
2636
flex-shrink: 0;
2737
color: var(--secondary-text);
2838
}
2939

40+
.goto_btn {
41+
display: flex;
42+
align-items: center;
43+
justify-content: center;
44+
padding: 3px;
45+
border-radius: 4px;
46+
border: none;
47+
background: none;
48+
color: var(--secondary-text);
49+
cursor: pointer;
50+
flex-shrink: 0;
51+
opacity: 0;
52+
transition: opacity 0.15s;
53+
}
54+
55+
.header:hover .goto_btn {
56+
opacity: 1;
57+
}
58+
59+
.goto_btn:hover {
60+
background-color: var(--editor-style-bg-hover);
61+
color: var(--primary-text);
62+
}
63+
3064
.title {
3165
flex: 1;
3266
min-width: 0;
@@ -57,8 +91,8 @@
5791
align-items: center;
5892
gap: 8px;
5993
padding-right: 20px;
60-
padding-left: 20px;
61-
padding-block: 10px;
94+
padding-left: 36px;
95+
padding-block: 8px;
6296
font-size: 12px;
6397
color: var(--secondary-text);
6498
cursor: pointer;

0 commit comments

Comments
 (0)