Add standalone desktop launch modes
This commit is contained in:
+2
-13
@@ -6,21 +6,10 @@ import { QWord } from "./features/qword/QWord";
|
||||
import { QExcell } from "./features/qexcell/QExcell";
|
||||
import { initialState } from "./data/sampleData";
|
||||
import { usePersistentState } from "./hooks/usePersistentState";
|
||||
import { activeAppFromLocation } from "./appRouting";
|
||||
import type { MailMessage, QOfficeState, SlideDeck, WordDocument, Workbook } from "./types";
|
||||
|
||||
const STORAGE_KEY = "qoffice-state-v1";
|
||||
const appPaths = {
|
||||
"/": "word",
|
||||
"/qword": "word",
|
||||
"/qexcell": "sheets",
|
||||
"/qpowerpoint": "slides",
|
||||
"/qoutlook": "mail"
|
||||
} as const;
|
||||
|
||||
function activeAppFromPath(pathname: string) {
|
||||
const normalizedPath = pathname.toLowerCase().replace(/\/$/, "") || "/";
|
||||
return appPaths[normalizedPath as keyof typeof appPaths] ?? "word";
|
||||
}
|
||||
|
||||
function migrateQOfficeState(state: QOfficeState): QOfficeState {
|
||||
const launchChecklistAttachments = initialState.mail.messages.find((message) => message.id === "mail-1")?.attachments;
|
||||
@@ -103,7 +92,7 @@ function migrateQOfficeState(state: QOfficeState): QOfficeState {
|
||||
|
||||
export function App() {
|
||||
const [state, setState] = usePersistentState<QOfficeState>(STORAGE_KEY, initialState, migrateQOfficeState);
|
||||
const activeApp = activeAppFromPath(window.location.pathname);
|
||||
const activeApp = activeAppFromLocation(window.location);
|
||||
|
||||
const status = useMemo(() => {
|
||||
const updatedAt =
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { activeAppFromLocation } from "./appRouting";
|
||||
|
||||
describe("activeAppFromLocation", () => {
|
||||
it.each([
|
||||
["/", "", "", "word"],
|
||||
["/qword", "", "", "word"],
|
||||
["/qexcell", "", "", "sheets"],
|
||||
["/qpowerpoint", "", "", "slides"],
|
||||
["/qoutlook", "", "", "mail"],
|
||||
["/index.html", "#/qexcell", "", "sheets"],
|
||||
["/index.html", "#qpowerpoint", "", "slides"],
|
||||
["/index.html", "", "?app=qoutlook", "mail"],
|
||||
["/index.html", "", "?module=pptx", "slides"],
|
||||
["/unknown", "", "", "word"]
|
||||
])("определяет приложение для pathname=%s hash=%s search=%s", (pathname, hash, search, expected) => {
|
||||
expect(activeAppFromLocation({ pathname, hash, search })).toBe(expected);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,67 @@
|
||||
import type { AppId } from "./types";
|
||||
|
||||
const routeAppIds = {
|
||||
"/": "word",
|
||||
"/qword": "word",
|
||||
"/qexcell": "sheets",
|
||||
"/qpowerpoint": "slides",
|
||||
"/qoutlook": "mail"
|
||||
} as const satisfies Record<string, AppId>;
|
||||
|
||||
const appAliases = {
|
||||
word: "word",
|
||||
qword: "word",
|
||||
docx: "word",
|
||||
sheets: "sheets",
|
||||
sheet: "sheets",
|
||||
excel: "sheets",
|
||||
excell: "sheets",
|
||||
qexcell: "sheets",
|
||||
xlsx: "sheets",
|
||||
slides: "slides",
|
||||
slide: "slides",
|
||||
powerpoint: "slides",
|
||||
qpowerpoint: "slides",
|
||||
pptx: "slides",
|
||||
mail: "mail",
|
||||
outlook: "mail",
|
||||
qoutlook: "mail",
|
||||
eml: "mail",
|
||||
msg: "mail"
|
||||
} as const satisfies Record<string, AppId>;
|
||||
|
||||
export interface AppLocationParts {
|
||||
pathname: string;
|
||||
hash?: string;
|
||||
search?: string;
|
||||
}
|
||||
|
||||
export function activeAppFromLocation(location: AppLocationParts): AppId {
|
||||
const queryApp = appFromSearch(location.search);
|
||||
if (queryApp) {
|
||||
return queryApp;
|
||||
}
|
||||
|
||||
const hashPath = normalizedPath(location.hash?.replace(/^#/, "") ?? "");
|
||||
if (hashPath && hashPath !== "/") {
|
||||
return routeAppIds[hashPath as keyof typeof routeAppIds] ?? appFromAlias(hashPath);
|
||||
}
|
||||
|
||||
const path = normalizedPath(location.pathname);
|
||||
return routeAppIds[path as keyof typeof routeAppIds] ?? appFromAlias(path) ?? "word";
|
||||
}
|
||||
|
||||
function appFromSearch(search?: string) {
|
||||
const params = new URLSearchParams(search ?? "");
|
||||
return appFromAlias(params.get("app") ?? params.get("module") ?? "");
|
||||
}
|
||||
|
||||
function appFromAlias(value: string) {
|
||||
const normalized = value.trim().toLowerCase().replace(/^\/+|\/+$/g, "");
|
||||
return appAliases[normalized as keyof typeof appAliases];
|
||||
}
|
||||
|
||||
function normalizedPath(pathname: string) {
|
||||
const normalized = pathname.trim().toLowerCase().replace(/\/+$/g, "") || "/";
|
||||
return normalized.startsWith("/") ? normalized : `/${normalized}`;
|
||||
}
|
||||
Reference in New Issue
Block a user