chore: space folders (#8707)
* chore: change the space folders structure * fix: format
This commit is contained in:
parent
be8836642a
commit
7fb6696c67
154 changed files with 30 additions and 197 deletions
143
apps/space/lib/b-progress/AppProgressBar.tsx
Normal file
143
apps/space/lib/b-progress/AppProgressBar.tsx
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
/**
|
||||
* Copyright (c) 2023-present Plane Software, Inc. and contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
import { useEffect, useRef } from "react";
|
||||
import { BProgress } from "@bprogress/core";
|
||||
import { useNavigation } from "react-router";
|
||||
import "@bprogress/core/css";
|
||||
|
||||
/**
|
||||
* Progress bar configuration options
|
||||
*/
|
||||
interface ProgressConfig {
|
||||
/** Whether to show the loading spinner */
|
||||
showSpinner: boolean;
|
||||
/** Minimum progress percentage (0-1) */
|
||||
minimum: number;
|
||||
/** Animation speed in milliseconds */
|
||||
speed: number;
|
||||
/** Auto-increment speed in milliseconds */
|
||||
trickleSpeed: number;
|
||||
/** CSS easing function */
|
||||
easing: string;
|
||||
/** Enable auto-increment */
|
||||
trickle: boolean;
|
||||
/** Delay before showing progress bar in milliseconds */
|
||||
delay: number;
|
||||
/** Whether to disable the progress bar */
|
||||
isDisabled?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration for the progress bar
|
||||
*/
|
||||
const PROGRESS_CONFIG: Readonly<ProgressConfig> = {
|
||||
showSpinner: false,
|
||||
minimum: 0.1,
|
||||
speed: 400,
|
||||
trickleSpeed: 800,
|
||||
easing: "ease",
|
||||
trickle: true,
|
||||
delay: 0,
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* Navigation Progress Bar Component
|
||||
*
|
||||
* Automatically displays a progress bar at the top of the page during React Router navigation.
|
||||
* Integrates with React Router's useNavigation hook to monitor route changes.
|
||||
*
|
||||
* Note: Progress bar is disabled in production builds.
|
||||
*
|
||||
* @returns null - This component doesn't render any visible elements
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* function App() {
|
||||
* return (
|
||||
* <>
|
||||
* <AppProgressBar />
|
||||
* <Outlet />
|
||||
* </>
|
||||
* );
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export function AppProgressBar(): null {
|
||||
const navigation = useNavigation();
|
||||
const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
const startedRef = useRef<boolean>(false);
|
||||
|
||||
// Initialize BProgress once on mount
|
||||
useEffect(() => {
|
||||
// Skip initialization in production builds
|
||||
if (PROGRESS_CONFIG.isDisabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Configure BProgress with our settings
|
||||
BProgress.configure({
|
||||
showSpinner: PROGRESS_CONFIG.showSpinner,
|
||||
minimum: PROGRESS_CONFIG.minimum,
|
||||
speed: PROGRESS_CONFIG.speed,
|
||||
trickleSpeed: PROGRESS_CONFIG.trickleSpeed,
|
||||
easing: PROGRESS_CONFIG.easing,
|
||||
trickle: PROGRESS_CONFIG.trickle,
|
||||
});
|
||||
|
||||
// Render the progress bar element in the DOM
|
||||
BProgress.render(true);
|
||||
|
||||
// Cleanup on unmount
|
||||
return () => {
|
||||
if (BProgress.isStarted()) {
|
||||
BProgress.done();
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Handle navigation state changes
|
||||
useEffect(() => {
|
||||
// Skip navigation tracking in production builds
|
||||
if (PROGRESS_CONFIG.isDisabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (navigation.state === "idle") {
|
||||
// Navigation complete - clear any pending timer
|
||||
if (timerRef.current !== null) {
|
||||
clearTimeout(timerRef.current);
|
||||
timerRef.current = null;
|
||||
}
|
||||
|
||||
// Complete progress if it was started
|
||||
if (startedRef.current) {
|
||||
BProgress.done();
|
||||
startedRef.current = false;
|
||||
}
|
||||
} else {
|
||||
// Navigation in progress (loading or submitting)
|
||||
// Only start if not already started and no timer pending
|
||||
if (timerRef.current === null && !startedRef.current) {
|
||||
timerRef.current = setTimeout((): void => {
|
||||
if (!BProgress.isStarted()) {
|
||||
BProgress.start();
|
||||
startedRef.current = true;
|
||||
}
|
||||
timerRef.current = null;
|
||||
}, PROGRESS_CONFIG.delay);
|
||||
}
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (timerRef.current !== null) {
|
||||
clearTimeout(timerRef.current);
|
||||
}
|
||||
};
|
||||
}, [navigation.state]);
|
||||
|
||||
return null;
|
||||
}
|
||||
7
apps/space/lib/b-progress/index.tsx
Normal file
7
apps/space/lib/b-progress/index.tsx
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
/**
|
||||
* Copyright (c) 2023-present Plane Software, Inc. and contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
export * from "./AppProgressBar";
|
||||
74
apps/space/lib/instance-provider.tsx
Normal file
74
apps/space/lib/instance-provider.tsx
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
/**
|
||||
* Copyright (c) 2023-present Plane Software, Inc. and contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
import { observer } from "mobx-react";
|
||||
import { Link } from "react-router";
|
||||
import { useTheme } from "next-themes";
|
||||
import useSWR from "swr";
|
||||
// plane imports
|
||||
import { SPACE_BASE_PATH } from "@plane/constants";
|
||||
import { PlaneLockup } from "@plane/propel/icons";
|
||||
// assets
|
||||
import PlaneBackgroundPatternDark from "@/app/assets/auth/background-pattern-dark.svg?url";
|
||||
import PlaneBackgroundPattern from "@/app/assets/auth/background-pattern.svg?url";
|
||||
// components
|
||||
import { LogoSpinner } from "@/components/common/logo-spinner";
|
||||
import { InstanceFailureView } from "@/components/instance/instance-failure-view";
|
||||
// hooks
|
||||
import { useInstance } from "@/hooks/store/use-instance";
|
||||
import { useUser } from "@/hooks/store/use-user";
|
||||
|
||||
export const InstanceProvider = observer(function InstanceProvider({ children }: { children: React.ReactNode }) {
|
||||
const { fetchInstanceInfo, instance, error } = useInstance();
|
||||
const { fetchCurrentUser } = useUser();
|
||||
const { resolvedTheme } = useTheme();
|
||||
|
||||
const patternBackground = resolvedTheme === "dark" ? PlaneBackgroundPatternDark : PlaneBackgroundPattern;
|
||||
|
||||
useSWR("INSTANCE_INFO", () => fetchInstanceInfo(), {
|
||||
revalidateOnFocus: false,
|
||||
revalidateIfStale: false,
|
||||
errorRetryCount: 0,
|
||||
});
|
||||
useSWR("CURRENT_USER", () => fetchCurrentUser(), {
|
||||
shouldRetryOnError: false,
|
||||
revalidateOnFocus: true,
|
||||
revalidateIfStale: true,
|
||||
});
|
||||
|
||||
if (!instance && !error)
|
||||
return (
|
||||
<div className="flex h-screen w-full items-center justify-center">
|
||||
<LogoSpinner />
|
||||
</div>
|
||||
);
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<div className="relative">
|
||||
<div className="flex h-screen w-full flex-col overflow-hidden overflow-y-auto">
|
||||
<div className="z-50 container mx-auto flex h-[110px] flex-shrink-0 items-center justify-between gap-5 px-5 lg:px-0">
|
||||
<div className="flex items-center gap-x-2 py-10">
|
||||
<Link to={`${SPACE_BASE_PATH}/`}>
|
||||
<PlaneLockup className="h-7 w-auto text-primary" />
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div className="absolute inset-0 z-0">
|
||||
<img src={patternBackground} className="h-full w-screen object-cover" alt="Plane background pattern" />
|
||||
</div>
|
||||
<div className="relative z-10 flex-grow">
|
||||
<div className="relative mx-auto flex h-full w-full items-center justify-center overflow-y-auto px-6 py-10">
|
||||
<InstanceFailureView />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return children;
|
||||
});
|
||||
39
apps/space/lib/store-provider.tsx
Normal file
39
apps/space/lib/store-provider.tsx
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/**
|
||||
* Copyright (c) 2023-present Plane Software, Inc. and contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
import { createContext } from "react";
|
||||
// plane web store
|
||||
import { RootStore } from "@/store/root.store";
|
||||
|
||||
let rootStore = new RootStore();
|
||||
|
||||
export const StoreContext = createContext(rootStore);
|
||||
|
||||
function initializeStore() {
|
||||
const singletonRootStore = rootStore ?? new RootStore();
|
||||
// For SSG and SSR always create a new store
|
||||
if (typeof window === "undefined") return singletonRootStore;
|
||||
// Create the store once in the client
|
||||
if (!rootStore) rootStore = singletonRootStore;
|
||||
return singletonRootStore;
|
||||
}
|
||||
|
||||
export type StoreProviderProps = {
|
||||
children: React.ReactNode;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
initialState?: any;
|
||||
};
|
||||
|
||||
export function StoreProvider({ children, initialState = undefined }: StoreProviderProps) {
|
||||
const store = initializeStore();
|
||||
// If your page has Next.js data fetching methods that use a Mobx store, it will
|
||||
// get hydrated here, check `pages/ssg.js` and `pages/ssr.js` for more details
|
||||
if (initialState) {
|
||||
store.hydrate(initialState);
|
||||
}
|
||||
|
||||
return <StoreContext.Provider value={store}>{children}</StoreContext.Provider>;
|
||||
}
|
||||
22
apps/space/lib/toast-provider.tsx
Normal file
22
apps/space/lib/toast-provider.tsx
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/**
|
||||
* Copyright (c) 2023-present Plane Software, Inc. and contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
import { useTheme } from "next-themes";
|
||||
// plane imports
|
||||
import { Toast } from "@plane/propel/toast";
|
||||
import { resolveGeneralTheme } from "@plane/utils";
|
||||
|
||||
export function ToastProvider({ children }: { children: React.ReactNode }) {
|
||||
// themes
|
||||
const { resolvedTheme } = useTheme();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Toast theme={resolveGeneralTheme(resolvedTheme)} />
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue