mirror of
https://git.srhtnin.garden/sarah/SaraView.git
synced 2026-10-15 02:43:17 +02:00
Added guests.
This commit is contained in:
1 parent
6743dd7626
commit
9736a55e00
10 files changed
+200
-84
No files matched your search
+29
-4
@@ -53,6 +53,8 @@ function ParseLocationPath(Pathname) {
|
||||
return { RootName: RootName || null, Path: RestSegments.join("/"), IsDirectory };
|
||||
}
|
||||
|
||||
const GuestUser = { Username: null, IsAdmin: false, IsGuest: true, Colour: "Purple" };
|
||||
|
||||
export default function App() {
|
||||
const [AuthState, SetAuthState] = useState("Loading");
|
||||
const [CurrentUser, SetCurrentUser] = useState(null);
|
||||
@@ -84,8 +86,10 @@ export default function App() {
|
||||
});
|
||||
}, []);
|
||||
|
||||
const IsUsable = AuthState === "LoggedIn" || AuthState === "Guest";
|
||||
|
||||
useEffect(() => {
|
||||
if (AuthState !== "LoggedIn") return;
|
||||
if (!IsUsable) return;
|
||||
|
||||
FetchRoots().then((Fetched) => {
|
||||
SetRoots(Fetched);
|
||||
@@ -100,7 +104,7 @@ export default function App() {
|
||||
}, [AuthState]);
|
||||
|
||||
useEffect(() => {
|
||||
if (AuthState !== "LoggedIn" || !ActiveRoot) return;
|
||||
if (!IsUsable || !ActiveRoot) return;
|
||||
|
||||
const Url = BuildLocationPath(ActiveRoot, ViewPath, ViewIsDirectory);
|
||||
if (window.location.pathname !== Url) {
|
||||
@@ -109,7 +113,7 @@ export default function App() {
|
||||
}, [AuthState, ActiveRoot, ViewPath, ViewIsDirectory]);
|
||||
|
||||
useEffect(() => {
|
||||
if (AuthState !== "LoggedIn") return;
|
||||
if (!IsUsable) return;
|
||||
|
||||
function HandlePopState() {
|
||||
RestoreFromLocation(Roots);
|
||||
@@ -174,6 +178,16 @@ export default function App() {
|
||||
SetAuthState("LoggedOut");
|
||||
}
|
||||
|
||||
function HandleContinueAsGuest() {
|
||||
SetCurrentUser(GuestUser);
|
||||
SetAuthState("Guest");
|
||||
}
|
||||
|
||||
function HandleRequestLogin() {
|
||||
SetCurrentUser(null);
|
||||
SetAuthState("LoggedOut");
|
||||
}
|
||||
|
||||
function HandleProfileUpdated(UpdatedUser) {
|
||||
SetCurrentUser((Existing) => ({ ...Existing, ...UpdatedUser }));
|
||||
}
|
||||
@@ -272,9 +286,16 @@ export default function App() {
|
||||
}
|
||||
|
||||
if (AuthState === "LoggedOut") {
|
||||
return <LoginScreen IsBootstrap={false} OnAuthenticated={HandleAuthenticated} />;
|
||||
return (
|
||||
<LoginScreen
|
||||
IsBootstrap={false}
|
||||
OnAuthenticated={HandleAuthenticated}
|
||||
OnContinueAsGuest={HandleContinueAsGuest}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const IsGuest = AuthState === "Guest";
|
||||
const ShowTopBar = (Settings && Settings.ShowBreadcrumbs) || Roots.length > 1;
|
||||
const ConfirmBeforeDelete = Settings ? Settings.ConfirmBeforeDelete : true;
|
||||
|
||||
@@ -286,6 +307,7 @@ export default function App() {
|
||||
SelectedFile={ViewIsDirectory ? null : ViewPath}
|
||||
CurrentDirectoryPath={CurrentDirectoryPath}
|
||||
CurrentUser={CurrentUser}
|
||||
IsGuest={IsGuest}
|
||||
OnSelectFile={HandleSelectFile}
|
||||
OnSelectDirectory={OpenDirectoryNote}
|
||||
OnNavigateDirectory={HandleNavigateDirectory}
|
||||
@@ -293,6 +315,7 @@ export default function App() {
|
||||
OnEntryRenamed={HandleEntryRenamed}
|
||||
OnEntryDeleted={HandleEntryDeleted}
|
||||
OnOpenSettings={() => SetIsSettingsOpen(true)}
|
||||
OnRequestLogin={HandleRequestLogin}
|
||||
OnEntryCreated={RefreshSidebar}
|
||||
UseHyphenBullets={Settings ? Settings.UseHyphenBullets : true}
|
||||
UseAsciiFolderIcons={Settings ? Settings.UseAsciiFolderIcons : true}
|
||||
@@ -340,6 +363,7 @@ export default function App() {
|
||||
UseHyphenBullets={Settings ? Settings.UseHyphenBullets : true}
|
||||
UseAsciiFolderIcons={Settings ? Settings.UseAsciiFolderIcons : true}
|
||||
ConfirmBeforeDelete={ConfirmBeforeDelete}
|
||||
IsGuest={IsGuest}
|
||||
/>
|
||||
) : (
|
||||
<PreviewPane
|
||||
@@ -350,6 +374,7 @@ export default function App() {
|
||||
ShowGitBlame={Settings ? Settings.ShowGitBlame : false}
|
||||
ShowBlameAvatars={Settings ? Settings.ShowBlameAvatars : false}
|
||||
StickyToolbar={Settings ? Settings.StickyToolbar : true}
|
||||
IsGuest={IsGuest}
|
||||
/>
|
||||
)}
|
||||
{!ViewIsDirectory && !ViewNoteFilePath && (
|
||||
|
||||
@@ -22,6 +22,7 @@ export default function DirectoryPane({
|
||||
UseHyphenBullets,
|
||||
UseAsciiFolderIcons,
|
||||
ConfirmBeforeDelete,
|
||||
IsGuest,
|
||||
}) {
|
||||
const [Entries, SetEntries] = useState([]);
|
||||
const [LoadError, SetLoadError] = useState(null);
|
||||
@@ -139,10 +140,12 @@ export default function DirectoryPane({
|
||||
|
||||
return (
|
||||
<div className="DirectoryPane">
|
||||
<div className="PreviewToolbar">
|
||||
<button onClick={OpenCreateFileModal}>New File</button>
|
||||
<button onClick={OpenCreateDirectoryModal}>New Directory</button>
|
||||
</div>
|
||||
{!IsGuest && (
|
||||
<div className="PreviewToolbar">
|
||||
<button onClick={OpenCreateFileModal}>New File</button>
|
||||
<button onClick={OpenCreateDirectoryModal}>New Directory</button>
|
||||
</div>
|
||||
)}
|
||||
{LoadError && <div className="SidebarError">{LoadError}</div>}
|
||||
<div className="DirectoryList">
|
||||
{Entries.map((Entry) => (
|
||||
@@ -159,29 +162,31 @@ export default function DirectoryPane({
|
||||
: GetFileIcon(UseHyphenBullets)}
|
||||
</span>
|
||||
<span className="TreeLabel">{Entry.Name}</span>
|
||||
<span className="TreeRowActions">
|
||||
<button
|
||||
className="TreeRowActionButton"
|
||||
onClick={(Event) => HandleRequestLockEdit(Event, Entry)}
|
||||
title="Access control"
|
||||
>
|
||||
🔒
|
||||
</button>
|
||||
<button
|
||||
className="TreeRowActionButton"
|
||||
onClick={(Event) => HandleRename(Event, Entry)}
|
||||
title="Rename / move"
|
||||
>
|
||||
✎
|
||||
</button>
|
||||
<button
|
||||
className="TreeRowActionButton"
|
||||
onClick={(Event) => HandleDelete(Event, Entry)}
|
||||
title="Delete"
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
</span>
|
||||
{!IsGuest && (
|
||||
<span className="TreeRowActions">
|
||||
<button
|
||||
className="TreeRowActionButton"
|
||||
onClick={(Event) => HandleRequestLockEdit(Event, Entry)}
|
||||
title="Access control"
|
||||
>
|
||||
🔒
|
||||
</button>
|
||||
<button
|
||||
className="TreeRowActionButton"
|
||||
onClick={(Event) => HandleRename(Event, Entry)}
|
||||
title="Rename / move"
|
||||
>
|
||||
✎
|
||||
</button>
|
||||
<button
|
||||
className="TreeRowActionButton"
|
||||
onClick={(Event) => HandleDelete(Event, Entry)}
|
||||
title="Delete"
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
{Entries.length === 0 && !LoadError && (
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { useState } from "react";
|
||||
|
||||
import { Bootstrap, Login } from "../Api.js";
|
||||
|
||||
export default function LoginScreen({ IsBootstrap, OnAuthenticated }) {
|
||||
export default function LoginScreen({ IsBootstrap, OnAuthenticated, OnContinueAsGuest }) {
|
||||
const [Username, SetUsername] = useState("");
|
||||
const [Password, SetPassword] = useState("");
|
||||
const [ConfirmPassword, SetConfirmPassword] = useState("");
|
||||
@@ -74,6 +74,11 @@ export default function LoginScreen({ IsBootstrap, OnAuthenticated }) {
|
||||
<button type="submit" disabled={IsSubmitting}>
|
||||
{IsSubmitting ? "..." : IsBootstrap ? "Create account & log in" : "Log in"}
|
||||
</button>
|
||||
{!IsBootstrap && OnContinueAsGuest && (
|
||||
<button type="button" className="LoginGuestButton" onClick={OnContinueAsGuest}>
|
||||
Continue as Guest
|
||||
</button>
|
||||
)}
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -170,6 +170,7 @@ export default function PreviewPane({
|
||||
ShowGitBlame,
|
||||
ShowBlameAvatars,
|
||||
StickyToolbar,
|
||||
IsGuest,
|
||||
}) {
|
||||
const [Content, SetContent] = useState("");
|
||||
const [ResolvedContent, SetResolvedContent] = useState("");
|
||||
@@ -259,7 +260,7 @@ export default function PreviewPane({
|
||||
return (
|
||||
<div className="PreviewFrame">
|
||||
<div className={ToolbarClass}>
|
||||
<button onClick={() => SetIsEditing(true)}>Edit</button>
|
||||
{!IsGuest && <button onClick={() => SetIsEditing(true)}>Edit</button>}
|
||||
</div>
|
||||
<iframe title={FilePath} sandbox="" src={GetRawFileUrl(RootName, FilePath)} />
|
||||
</div>
|
||||
@@ -270,7 +271,7 @@ export default function PreviewPane({
|
||||
return (
|
||||
<div className="PreviewMarkdown">
|
||||
<div className={ToolbarClass}>
|
||||
<button onClick={() => SetIsEditing(true)}>Edit</button>
|
||||
{!IsGuest && <button onClick={() => SetIsEditing(true)}>Edit</button>}
|
||||
</div>
|
||||
<div
|
||||
className="MarkdownBody"
|
||||
@@ -292,7 +293,7 @@ export default function PreviewPane({
|
||||
return (
|
||||
<div className="PreviewText">
|
||||
<div className={ToolbarClass}>
|
||||
<button onClick={() => SetIsEditing(true)}>Edit</button>
|
||||
{!IsGuest && <button onClick={() => SetIsEditing(true)}>Edit</button>}
|
||||
</div>
|
||||
<pre className="TextBody">{ResolvedContent}</pre>
|
||||
</div>
|
||||
@@ -306,14 +307,17 @@ export default function PreviewPane({
|
||||
{(FileType === "markdown" || FileType === "text" || FileType === "html") && (
|
||||
<button onClick={() => SetIsEditing(false)}>View</button>
|
||||
)}
|
||||
<button onClick={HandleSave} disabled={IsSaving}>
|
||||
{IsSaving ? "Saving…" : "Save"}
|
||||
</button>
|
||||
{!IsGuest && (
|
||||
<button onClick={HandleSave} disabled={IsSaving}>
|
||||
{IsSaving ? "Saving…" : "Save"}
|
||||
</button>
|
||||
)}
|
||||
{SaveError && <span className="SaveErrorText">{SaveError}</span>}
|
||||
</div>
|
||||
<CodeMirror
|
||||
value={Content}
|
||||
height="100%"
|
||||
editable={!IsGuest}
|
||||
extensions={[
|
||||
...GetLanguageExtension(FileType),
|
||||
...(ShowGitBlame ? [BuildBlameGutter(BlameMap, ShowBlameAvatars)] : []),
|
||||
|
||||
@@ -30,6 +30,7 @@ function TreeNode({
|
||||
UseAsciiFolderIcons,
|
||||
NavigateIntoDirectories,
|
||||
ConfirmBeforeDelete,
|
||||
IsGuest,
|
||||
}) {
|
||||
const [IsExpanded, SetIsExpanded] = useState(false);
|
||||
const [Children, SetChildren] = useState(null);
|
||||
@@ -134,17 +135,19 @@ function TreeNode({
|
||||
: GetFileIcon(UseHyphenBullets)}
|
||||
</span>
|
||||
<span className="TreeLabel">{Entry.Name}</span>
|
||||
<span className="TreeRowActions">
|
||||
<button className="TreeRowActionButton" onClick={HandleLockClick} title="Access control">
|
||||
🔒
|
||||
</button>
|
||||
<button className="TreeRowActionButton" onClick={HandleRename} title="Rename / move">
|
||||
✎
|
||||
</button>
|
||||
<button className="TreeRowActionButton" onClick={HandleDelete} title="Delete">
|
||||
✕
|
||||
</button>
|
||||
</span>
|
||||
{!IsGuest && (
|
||||
<span className="TreeRowActions">
|
||||
<button className="TreeRowActionButton" onClick={HandleLockClick} title="Access control">
|
||||
🔒
|
||||
</button>
|
||||
<button className="TreeRowActionButton" onClick={HandleRename} title="Rename / move">
|
||||
✎
|
||||
</button>
|
||||
<button className="TreeRowActionButton" onClick={HandleDelete} title="Delete">
|
||||
✕
|
||||
</button>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
{IsExpanded && Children && (
|
||||
<div className="TreeChildren">
|
||||
@@ -167,6 +170,7 @@ function TreeNode({
|
||||
UseAsciiFolderIcons={UseAsciiFolderIcons}
|
||||
NavigateIntoDirectories={NavigateIntoDirectories}
|
||||
ConfirmBeforeDelete={ConfirmBeforeDelete}
|
||||
IsGuest={IsGuest}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
@@ -175,7 +179,7 @@ function TreeNode({
|
||||
);
|
||||
}
|
||||
|
||||
function UserBadge({ CurrentUser, OnOpenSettings }) {
|
||||
function UserBadge({ CurrentUser, OnOpenSettings, OnRequestLogin }) {
|
||||
const [AvatarFailed, SetAvatarFailed] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -184,6 +188,16 @@ function UserBadge({ CurrentUser, OnOpenSettings }) {
|
||||
|
||||
if (!CurrentUser) return null;
|
||||
|
||||
if (CurrentUser.IsGuest) {
|
||||
return (
|
||||
<span className="UserBadge" onClick={OnRequestLogin} title="Browsing as Guest - click to log in">
|
||||
<span className="UserBadgeInitial" style={{ background: `var(--${CurrentUser.Colour || "Purple"})` }}>
|
||||
G
|
||||
</span>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
const AvatarUrl = CurrentUser.AvatarNonce
|
||||
? `${GetAvatarUrl(CurrentUser.Username)}&v=${CurrentUser.AvatarNonce}`
|
||||
: GetAvatarUrl(CurrentUser.Username);
|
||||
@@ -221,12 +235,14 @@ export default function Sidebar({
|
||||
OnEntryRenamed,
|
||||
OnEntryDeleted,
|
||||
OnOpenSettings,
|
||||
OnRequestLogin,
|
||||
OnEntryCreated,
|
||||
UseHyphenBullets,
|
||||
UseAsciiFolderIcons,
|
||||
NavigateIntoDirectories,
|
||||
NewEntryButtonsAtTop,
|
||||
ConfirmBeforeDelete,
|
||||
IsGuest,
|
||||
}) {
|
||||
const [RootEntries, SetRootEntries] = useState([]);
|
||||
const [LoadError, SetLoadError] = useState(null);
|
||||
@@ -299,13 +315,15 @@ export default function Sidebar({
|
||||
SaraView
|
||||
</span>
|
||||
<span className="SidebarHeaderRight">
|
||||
<UserBadge CurrentUser={CurrentUser} OnOpenSettings={OnOpenSettings} />
|
||||
<button className="SettingsButton" onClick={OnOpenSettings}>
|
||||
⚙
|
||||
</button>
|
||||
<UserBadge CurrentUser={CurrentUser} OnOpenSettings={OnOpenSettings} OnRequestLogin={OnRequestLogin} />
|
||||
{!IsGuest && (
|
||||
<button className="SettingsButton" onClick={OnOpenSettings}>
|
||||
⚙
|
||||
</button>
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
{NewEntryButtonsAtTop && (
|
||||
{NewEntryButtonsAtTop && !IsGuest && (
|
||||
<div className="SidebarNewEntry SidebarNewEntryTop">
|
||||
<button onClick={OpenCreateFileModal}>New File</button>
|
||||
<button onClick={OpenCreateDirectoryModal}>New Directory</button>
|
||||
@@ -332,10 +350,11 @@ export default function Sidebar({
|
||||
UseAsciiFolderIcons={UseAsciiFolderIcons}
|
||||
NavigateIntoDirectories={NavigateIntoDirectories}
|
||||
ConfirmBeforeDelete={ConfirmBeforeDelete}
|
||||
IsGuest={IsGuest}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
{!NewEntryButtonsAtTop && (
|
||||
{!NewEntryButtonsAtTop && !IsGuest && (
|
||||
<div className="SidebarNewEntry">
|
||||
<button onClick={OpenCreateFileModal}>New File</button>
|
||||
<button onClick={OpenCreateDirectoryModal}>New Directory</button>
|
||||
|
||||
@@ -897,3 +897,8 @@ img,
|
||||
.LoginBox button:hover {
|
||||
background: var(--Border);
|
||||
}
|
||||
|
||||
.LoginGuestButton {
|
||||
border-color: var(--Border) !important;
|
||||
color: var(--TextMuted) !important;
|
||||
}
|
||||
Reference in new issue
Block a user