mirror of
https://git.srhtnin.garden/sarah/SaraView.git
synced 2026-10-13 18:28:14 +02:00
Added .sv_* files that are files for directories. So you can now edit
directories as files.
This commit is contained in:
1 parent
70a390f7cf
commit
6083e00504
9 files changed
+176
-18
No files matched your search
@@ -10,6 +10,3 @@ Frontend/dist/
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
.vscode/
|
.vscode/
|
||||||
.idea/
|
.idea/
|
||||||
|
|
||||||
# Misc
|
|
||||||
.Todo/
|
|
||||||
+76
-3
@@ -38,6 +38,64 @@ def ClassifyFile(EntryPath: Path) -> str:
|
|||||||
return FileTypeMap.get(EntryPath.suffix.lower(), "unknown")
|
return FileTypeMap.get(EntryPath.suffix.lower(), "unknown")
|
||||||
|
|
||||||
|
|
||||||
|
NoteFilePrefix = ".sv_"
|
||||||
|
DefaultNoteExtension = ".md"
|
||||||
|
|
||||||
|
|
||||||
|
def IsNoteFile(EntryName: str) -> bool:
|
||||||
|
"""A directory's own "file" - editable/viewable like any other file, but
|
||||||
|
hidden from normal listings behind the ShowSvFiles setting.
|
||||||
|
"""
|
||||||
|
return EntryName.startswith(NoteFilePrefix)
|
||||||
|
|
||||||
|
|
||||||
|
def FindDirectoryNote(DirectoryPath: Path) -> Path | None:
|
||||||
|
"""Find a directory's note file, whatever extension it currently has."""
|
||||||
|
Prefix = f"{NoteFilePrefix}{DirectoryPath.name}."
|
||||||
|
|
||||||
|
for Candidate in DirectoryPath.iterdir():
|
||||||
|
if Candidate.is_file() and Candidate.name.startswith(Prefix):
|
||||||
|
return Candidate
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def EnsureDirectoryNote(DirectoryPath: Path) -> Path:
|
||||||
|
"""Find a directory's note file, creating one (defaulting to markdown)
|
||||||
|
if it doesn't have one yet - e.g. a directory that predates this feature.
|
||||||
|
"""
|
||||||
|
Existing = FindDirectoryNote(DirectoryPath)
|
||||||
|
if Existing is not None:
|
||||||
|
return Existing
|
||||||
|
|
||||||
|
NotePath = DirectoryPath / f"{NoteFilePrefix}{DirectoryPath.name}{DefaultNoteExtension}"
|
||||||
|
NotePath.touch()
|
||||||
|
return NotePath
|
||||||
|
|
||||||
|
|
||||||
|
def GetDirectoryNoteInfo(DirectoryPath: Path) -> dict[str, Any] | None:
|
||||||
|
"""Read-only lookup for listings - never creates a note."""
|
||||||
|
NotePath = FindDirectoryNote(DirectoryPath)
|
||||||
|
|
||||||
|
if NotePath is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return {"Name": NotePath.name, "FileType": ClassifyFile(NotePath)}
|
||||||
|
|
||||||
|
|
||||||
|
def RenameDirectoryNote(DirectoryPath: Path, OldDirectoryName: str) -> None:
|
||||||
|
"""After a directory is renamed/moved, keep its note file's name (which
|
||||||
|
embeds the directory's own name) in sync, preserving its extension.
|
||||||
|
"""
|
||||||
|
OldPrefix = f"{NoteFilePrefix}{OldDirectoryName}."
|
||||||
|
|
||||||
|
for Candidate in DirectoryPath.iterdir():
|
||||||
|
if Candidate.is_file() and Candidate.name.startswith(OldPrefix):
|
||||||
|
NewName = f"{NoteFilePrefix}{DirectoryPath.name}{Candidate.suffix}"
|
||||||
|
Candidate.rename(DirectoryPath / NewName)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
def ListRoots() -> list[dict[str, Any]]:
|
def ListRoots() -> list[dict[str, Any]]:
|
||||||
"""Return the configured roots as a flat list for the frontend."""
|
"""Return the configured roots as a flat list for the frontend."""
|
||||||
return [{"Name": Name} for Name in GetRoots()]
|
return [{"Name": Name} for Name in GetRoots()]
|
||||||
@@ -52,6 +110,7 @@ def CreateEntry(RootName: str, RelativePath: str, IsDirectory: bool) -> None:
|
|||||||
|
|
||||||
if IsDirectory:
|
if IsDirectory:
|
||||||
EntryPath.mkdir(parents=False)
|
EntryPath.mkdir(parents=False)
|
||||||
|
EnsureDirectoryNote(EntryPath)
|
||||||
else:
|
else:
|
||||||
EntryPath.parent.mkdir(parents=True, exist_ok=True)
|
EntryPath.parent.mkdir(parents=True, exist_ok=True)
|
||||||
EntryPath.touch()
|
EntryPath.touch()
|
||||||
@@ -70,6 +129,7 @@ def MoveEntry(RootName: str, SourceRelativePath: str, DestinationRelativePath: s
|
|||||||
if DestinationPath.exists():
|
if DestinationPath.exists():
|
||||||
raise FileExistsError(f"{DestinationPath.name} already exists.")
|
raise FileExistsError(f"{DestinationPath.name} already exists.")
|
||||||
|
|
||||||
|
OldName = SourcePath.name
|
||||||
DestinationPath.parent.mkdir(parents=True, exist_ok=True)
|
DestinationPath.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -78,6 +138,9 @@ def MoveEntry(RootName: str, SourceRelativePath: str, DestinationRelativePath: s
|
|||||||
# Cross-device or other rename failures — fall back to a copy+delete.
|
# Cross-device or other rename failures — fall back to a copy+delete.
|
||||||
shutil.move(str(SourcePath), str(DestinationPath))
|
shutil.move(str(SourcePath), str(DestinationPath))
|
||||||
|
|
||||||
|
if DestinationPath.is_dir():
|
||||||
|
RenameDirectoryNote(DestinationPath, OldName)
|
||||||
|
|
||||||
|
|
||||||
def DeleteEntry(RootName: str, RelativePath: str) -> None:
|
def DeleteEntry(RootName: str, RelativePath: str) -> None:
|
||||||
"""Delete a file, or an entire directory tree."""
|
"""Delete a file, or an entire directory tree."""
|
||||||
@@ -92,11 +155,17 @@ def DeleteEntry(RootName: str, RelativePath: str) -> None:
|
|||||||
EntryPath.unlink()
|
EntryPath.unlink()
|
||||||
|
|
||||||
|
|
||||||
def ListDirectory(RootName: str, RelativePath: str, ShowHidden: bool = False) -> list[dict[str, Any]]:
|
def ListDirectory(
|
||||||
|
RootName: str, RelativePath: str, ShowHidden: bool = False, ShowSvFiles: bool = False
|
||||||
|
) -> list[dict[str, Any]]:
|
||||||
"""List the immediate contents of a directory.
|
"""List the immediate contents of a directory.
|
||||||
|
|
||||||
SaraTag's internal files are always hidden, regardless of ShowHidden.
|
SaraTag's internal files are always hidden, regardless of ShowHidden.
|
||||||
Dotfiles/dotfolders are hidden unless ShowHidden is True.
|
Note files (.sv_*) are hidden unless ShowSvFiles is True - independently
|
||||||
|
of ShowHidden, since they're an implementation detail rather than a
|
||||||
|
normal dotfile. Every directory's Note metadata is still attached
|
||||||
|
regardless of ShowSvFiles, so clicking the directory can open it.
|
||||||
|
Other dotfiles/dotfolders are hidden unless ShowHidden is True.
|
||||||
"""
|
"""
|
||||||
DirectoryPath = ResolvePath(RootName, RelativePath)
|
DirectoryPath = ResolvePath(RootName, RelativePath)
|
||||||
|
|
||||||
@@ -114,7 +183,10 @@ def ListDirectory(RootName: str, RelativePath: str, ShowHidden: bool = False) ->
|
|||||||
if IsInternalPath(EntryPath):
|
if IsInternalPath(EntryPath):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if not ShowHidden and EntryPath.name.startswith("."):
|
if IsNoteFile(EntryPath.name):
|
||||||
|
if not ShowSvFiles:
|
||||||
|
continue
|
||||||
|
elif not ShowHidden and EntryPath.name.startswith("."):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
IsDirectory = EntryPath.is_dir()
|
IsDirectory = EntryPath.is_dir()
|
||||||
@@ -124,6 +196,7 @@ def ListDirectory(RootName: str, RelativePath: str, ShowHidden: bool = False) ->
|
|||||||
"IsDirectory": IsDirectory,
|
"IsDirectory": IsDirectory,
|
||||||
"FileType": None if IsDirectory else ClassifyFile(EntryPath),
|
"FileType": None if IsDirectory else ClassifyFile(EntryPath),
|
||||||
"Size": None if IsDirectory else EntryPath.stat().st_size,
|
"Size": None if IsDirectory else EntryPath.stat().st_size,
|
||||||
|
"Note": GetDirectoryNoteInfo(EntryPath) if IsDirectory else None,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+32
-3
@@ -18,7 +18,15 @@ from BookReader import ReadBookForFile
|
|||||||
from Blame import LoadBlame, RenameUserInBlame, UpdateBlameOnSave
|
from Blame import LoadBlame, RenameUserInBlame, UpdateBlameOnSave
|
||||||
from Core import ResolvePath
|
from Core import ResolvePath
|
||||||
from Editor import WriteTextFile
|
from Editor import WriteTextFile
|
||||||
from Explorer import ClassifyFile, CreateEntry, DeleteEntry, ListDirectory, ListRoots, MoveEntry
|
from Explorer import (
|
||||||
|
ClassifyFile,
|
||||||
|
CreateEntry,
|
||||||
|
DeleteEntry,
|
||||||
|
EnsureDirectoryNote,
|
||||||
|
ListDirectory,
|
||||||
|
ListRoots,
|
||||||
|
MoveEntry,
|
||||||
|
)
|
||||||
from Groups import (
|
from Groups import (
|
||||||
CreateGroup,
|
CreateGroup,
|
||||||
DeleteGroup,
|
DeleteGroup,
|
||||||
@@ -378,8 +386,10 @@ def GetTreeEndpoint(
|
|||||||
RequirePathAccessible(Root, Path, CurrentUser)
|
RequirePathAccessible(Root, Path, CurrentUser)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
ShowHidden = LoadSettings(CurrentUser["Username"]).get("ShowHiddenFolders", False)
|
UserSettings = LoadSettings(CurrentUser["Username"])
|
||||||
Entries = ListDirectory(Root, Path, ShowHidden)
|
ShowHidden = UserSettings.get("ShowHiddenFolders", False)
|
||||||
|
ShowSvFiles = UserSettings.get("ShowSvFiles", False)
|
||||||
|
Entries = ListDirectory(Root, Path, ShowHidden, ShowSvFiles)
|
||||||
except (ValueError, NotADirectoryError, FileNotFoundError) as Error:
|
except (ValueError, NotADirectoryError, FileNotFoundError) as Error:
|
||||||
raise HTTPException(status_code=400, detail=str(Error))
|
raise HTTPException(status_code=400, detail=str(Error))
|
||||||
|
|
||||||
@@ -400,6 +410,25 @@ def GetTreeEndpoint(
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@Application.post("/api/note")
|
||||||
|
def PostNoteEndpoint(Root: str, Path: str, CurrentUser: dict = Depends(GetCurrentUser)) -> dict:
|
||||||
|
"""Find (or create, for a directory that predates this feature) the
|
||||||
|
directory's own note file, so it can be opened like any other file.
|
||||||
|
"""
|
||||||
|
RequirePathAccessible(Root, Path, CurrentUser)
|
||||||
|
|
||||||
|
try:
|
||||||
|
DirectoryPath = ResolvePath(Root, Path)
|
||||||
|
except ValueError as Error:
|
||||||
|
raise HTTPException(status_code=400, detail=str(Error))
|
||||||
|
|
||||||
|
if not DirectoryPath.is_dir():
|
||||||
|
raise HTTPException(status_code=400, detail="Not a directory.")
|
||||||
|
|
||||||
|
NotePath = EnsureDirectoryNote(DirectoryPath)
|
||||||
|
return {"Name": NotePath.name, "FileType": ClassifyFile(NotePath)}
|
||||||
|
|
||||||
|
|
||||||
class CreateEntryRequest(BaseModel):
|
class CreateEntryRequest(BaseModel):
|
||||||
IsDirectory: bool
|
IsDirectory: bool
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ DefaultSettings: dict[str, Any] = {
|
|||||||
"FontSize": 14,
|
"FontSize": 14,
|
||||||
"ThemeName": "CatppuccinMocha",
|
"ThemeName": "CatppuccinMocha",
|
||||||
"ShowHiddenFolders": False,
|
"ShowHiddenFolders": False,
|
||||||
|
"ShowSvFiles": False,
|
||||||
"ShowBreadcrumbs": True,
|
"ShowBreadcrumbs": True,
|
||||||
"UseHyphenBullets": True,
|
"UseHyphenBullets": True,
|
||||||
"UseAsciiFolderIcons": True,
|
"UseAsciiFolderIcons": True,
|
||||||
|
|||||||
@@ -194,6 +194,11 @@ export function DeleteEntry(RootName, RelativePath) {
|
|||||||
return FetchJson(`/tree?${Params}`, { method: "DELETE" });
|
return FetchJson(`/tree?${Params}`, { method: "DELETE" });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function EnsureDirectoryNote(RootName, RelativePath) {
|
||||||
|
const Params = new URLSearchParams({ Root: RootName, Path: RelativePath });
|
||||||
|
return FetchJson(`/note?${Params}`, { method: "POST" });
|
||||||
|
}
|
||||||
|
|
||||||
// --- Settings / themes -------------------------------------------------
|
// --- Settings / themes -------------------------------------------------
|
||||||
|
|
||||||
export function FetchSettings() {
|
export function FetchSettings() {
|
||||||
|
|||||||
+49
-7
@@ -7,7 +7,14 @@ import DirectoryPane from "./Components/DirectoryPane.jsx";
|
|||||||
import TagPanel from "./Components/TagPanel.jsx";
|
import TagPanel from "./Components/TagPanel.jsx";
|
||||||
import SettingsPanel from "./Components/SettingsPanel.jsx";
|
import SettingsPanel from "./Components/SettingsPanel.jsx";
|
||||||
import LoginScreen from "./Components/LoginScreen.jsx";
|
import LoginScreen from "./Components/LoginScreen.jsx";
|
||||||
import { FetchAuthStatus, FetchMe, FetchRoots, FetchSettings, FetchTheme } from "./Api.js";
|
import {
|
||||||
|
EnsureDirectoryNote,
|
||||||
|
FetchAuthStatus,
|
||||||
|
FetchMe,
|
||||||
|
FetchRoots,
|
||||||
|
FetchSettings,
|
||||||
|
FetchTheme,
|
||||||
|
} from "./Api.js";
|
||||||
import { PaletteRoles } from "./ThemeRoles.js";
|
import { PaletteRoles } from "./ThemeRoles.js";
|
||||||
|
|
||||||
function ApplyTheme(Palette) {
|
function ApplyTheme(Palette) {
|
||||||
@@ -41,6 +48,7 @@ export default function App() {
|
|||||||
const [ViewPath, SetViewPath] = useState("");
|
const [ViewPath, SetViewPath] = useState("");
|
||||||
const [ViewIsDirectory, SetViewIsDirectory] = useState(true);
|
const [ViewIsDirectory, SetViewIsDirectory] = useState(true);
|
||||||
const [ViewFileType, SetViewFileType] = useState(null);
|
const [ViewFileType, SetViewFileType] = useState(null);
|
||||||
|
const [ViewNoteFilePath, SetViewNoteFilePath] = useState(null);
|
||||||
const [CurrentDirectoryPath, SetCurrentDirectoryPath] = useState("");
|
const [CurrentDirectoryPath, SetCurrentDirectoryPath] = useState("");
|
||||||
const [SidebarKey, SetSidebarKey] = useState(0);
|
const [SidebarKey, SetSidebarKey] = useState(0);
|
||||||
const [Settings, SetSettings] = useState(null);
|
const [Settings, SetSettings] = useState(null);
|
||||||
@@ -104,6 +112,7 @@ export default function App() {
|
|||||||
SetViewPath(FilePath);
|
SetViewPath(FilePath);
|
||||||
SetViewIsDirectory(false);
|
SetViewIsDirectory(false);
|
||||||
SetViewFileType(FileType);
|
SetViewFileType(FileType);
|
||||||
|
SetViewNoteFilePath(null);
|
||||||
SetCurrentDirectoryPath(GetParentPath(FilePath));
|
SetCurrentDirectoryPath(GetParentPath(FilePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,6 +120,7 @@ export default function App() {
|
|||||||
SetViewPath(DirectoryPath);
|
SetViewPath(DirectoryPath);
|
||||||
SetViewIsDirectory(true);
|
SetViewIsDirectory(true);
|
||||||
SetViewFileType(null);
|
SetViewFileType(null);
|
||||||
|
SetViewNoteFilePath(null);
|
||||||
SetCurrentDirectoryPath(DirectoryPath);
|
SetCurrentDirectoryPath(DirectoryPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,9 +128,34 @@ export default function App() {
|
|||||||
SetCurrentDirectoryPath(DirectoryPath);
|
SetCurrentDirectoryPath(DirectoryPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
function HandleEntrySelect(EntryPath, IsDirectory, FileType) {
|
// A directory is opened the same way a file is - via its own note file -
|
||||||
|
// rather than by drilling into its listing. Browsing a directory's
|
||||||
|
// contents happens separately, through the sidebar tree.
|
||||||
|
function HandleSelectDirectoryNote(DirectoryPath, NoteName, NoteFileType) {
|
||||||
|
SetViewPath(DirectoryPath);
|
||||||
|
SetViewIsDirectory(false);
|
||||||
|
SetViewFileType(NoteFileType);
|
||||||
|
SetViewNoteFilePath(`${DirectoryPath}/${NoteName}`);
|
||||||
|
SetCurrentDirectoryPath(DirectoryPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function OpenDirectoryNote(DirectoryPath, Note) {
|
||||||
|
if (Note) {
|
||||||
|
HandleSelectDirectoryNote(DirectoryPath, Note.Name, Note.FileType);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const Created = await EnsureDirectoryNote(ActiveRoot, DirectoryPath);
|
||||||
|
HandleSelectDirectoryNote(DirectoryPath, Created.Name, Created.FileType);
|
||||||
|
} catch (Error) {
|
||||||
|
window.alert(Error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function HandleEntrySelect(EntryPath, IsDirectory, FileType, Note) {
|
||||||
if (IsDirectory) {
|
if (IsDirectory) {
|
||||||
HandleNavigateDirectory(EntryPath);
|
OpenDirectoryNote(EntryPath, Note);
|
||||||
} else {
|
} else {
|
||||||
HandleSelectFile(EntryPath, FileType);
|
HandleSelectFile(EntryPath, FileType);
|
||||||
}
|
}
|
||||||
@@ -133,7 +168,11 @@ export default function App() {
|
|||||||
function HandleEntryRenamed(OldPath, NewPath, IsDirectory) {
|
function HandleEntryRenamed(OldPath, NewPath, IsDirectory) {
|
||||||
RefreshSidebar();
|
RefreshSidebar();
|
||||||
|
|
||||||
if (!ViewIsDirectory && ViewPath === OldPath) {
|
if (ViewNoteFilePath && ViewPath === OldPath) {
|
||||||
|
// Viewing this directory's own note - the server already renamed the
|
||||||
|
// note file to match, so just re-resolve it under the new path.
|
||||||
|
OpenDirectoryNote(NewPath, null);
|
||||||
|
} else if (!ViewIsDirectory && ViewPath === OldPath) {
|
||||||
HandleSelectFile(NewPath, ViewFileType);
|
HandleSelectFile(NewPath, ViewFileType);
|
||||||
} else if (ViewIsDirectory && ViewPath === OldPath) {
|
} else if (ViewIsDirectory && ViewPath === OldPath) {
|
||||||
HandleNavigateDirectory(NewPath);
|
HandleNavigateDirectory(NewPath);
|
||||||
@@ -178,6 +217,7 @@ export default function App() {
|
|||||||
CurrentDirectoryPath={CurrentDirectoryPath}
|
CurrentDirectoryPath={CurrentDirectoryPath}
|
||||||
CurrentUser={CurrentUser}
|
CurrentUser={CurrentUser}
|
||||||
OnSelectFile={HandleSelectFile}
|
OnSelectFile={HandleSelectFile}
|
||||||
|
OnSelectDirectory={OpenDirectoryNote}
|
||||||
OnNavigateDirectory={HandleNavigateDirectory}
|
OnNavigateDirectory={HandleNavigateDirectory}
|
||||||
OnBrowseDirectory={HandleBrowseDirectory}
|
OnBrowseDirectory={HandleBrowseDirectory}
|
||||||
OnEntryRenamed={HandleEntryRenamed}
|
OnEntryRenamed={HandleEntryRenamed}
|
||||||
@@ -197,7 +237,7 @@ export default function App() {
|
|||||||
<Breadcrumb
|
<Breadcrumb
|
||||||
RootName={ActiveRoot}
|
RootName={ActiveRoot}
|
||||||
FilePath={ViewPath}
|
FilePath={ViewPath}
|
||||||
IsDirectory={ViewIsDirectory}
|
IsDirectory={ViewIsDirectory || Boolean(ViewNoteFilePath)}
|
||||||
OnNavigate={HandleNavigateDirectory}
|
OnNavigate={HandleNavigateDirectory}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
@@ -234,7 +274,7 @@ export default function App() {
|
|||||||
) : (
|
) : (
|
||||||
<PreviewPane
|
<PreviewPane
|
||||||
RootName={ActiveRoot}
|
RootName={ActiveRoot}
|
||||||
FilePath={ViewPath}
|
FilePath={ViewNoteFilePath || ViewPath}
|
||||||
FileType={ViewFileType}
|
FileType={ViewFileType}
|
||||||
OnNavigateLink={HandleSelectFile}
|
OnNavigateLink={HandleSelectFile}
|
||||||
ShowGitBlame={Settings ? Settings.ShowGitBlame : false}
|
ShowGitBlame={Settings ? Settings.ShowGitBlame : false}
|
||||||
@@ -242,7 +282,9 @@ export default function App() {
|
|||||||
StickyToolbar={Settings ? Settings.StickyToolbar : true}
|
StickyToolbar={Settings ? Settings.StickyToolbar : true}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{!ViewIsDirectory && <TagPanel RootName={ActiveRoot} FilePath={ViewPath} />}
|
{!ViewIsDirectory && !ViewNoteFilePath && (
|
||||||
|
<TagPanel RootName={ActiveRoot} FilePath={ViewPath} />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{IsSettingsOpen && (
|
{IsSettingsOpen && (
|
||||||
|
|||||||
@@ -149,7 +149,9 @@ export default function DirectoryPane({
|
|||||||
<div
|
<div
|
||||||
className="DirectoryEntry"
|
className="DirectoryEntry"
|
||||||
key={Entry.Name}
|
key={Entry.Name}
|
||||||
onClick={() => OnEntrySelect(JoinPath(Entry.Name), Entry.IsDirectory, Entry.FileType)}
|
onClick={() =>
|
||||||
|
OnEntrySelect(JoinPath(Entry.Name), Entry.IsDirectory, Entry.FileType, Entry.Note)
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<span className="TreeIcon">
|
<span className="TreeIcon">
|
||||||
{Entry.IsDirectory
|
{Entry.IsDirectory
|
||||||
|
|||||||
@@ -323,6 +323,11 @@ export default function SettingsPanel({
|
|||||||
<Switch Checked={Settings.ShowHiddenFolders} OnChange={(Event) => UpdateField("ShowHiddenFolders", Event.target.checked)} />
|
<Switch Checked={Settings.ShowHiddenFolders} OnChange={(Event) => UpdateField("ShowHiddenFolders", Event.target.checked)} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="SettingsRowInline">
|
||||||
|
<label className="SettingsLabel">Show directory note files (.sv_*)</label>
|
||||||
|
<Switch Checked={Settings.ShowSvFiles} OnChange={(Event) => UpdateField("ShowSvFiles", Event.target.checked)} />
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="SettingsRowInline">
|
<div className="SettingsRowInline">
|
||||||
<label className="SettingsLabel">Show breadcrumbs</label>
|
<label className="SettingsLabel">Show breadcrumbs</label>
|
||||||
<Switch Checked={Settings.ShowBreadcrumbs} OnChange={(Event) => UpdateField("ShowBreadcrumbs", Event.target.checked)} />
|
<Switch Checked={Settings.ShowBreadcrumbs} OnChange={(Event) => UpdateField("ShowBreadcrumbs", Event.target.checked)} />
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ function TreeNode({
|
|||||||
SelectedFile,
|
SelectedFile,
|
||||||
CurrentDirectoryPath,
|
CurrentDirectoryPath,
|
||||||
OnSelectFile,
|
OnSelectFile,
|
||||||
|
OnSelectDirectory,
|
||||||
OnNavigateDirectory,
|
OnNavigateDirectory,
|
||||||
OnBrowseDirectory,
|
OnBrowseDirectory,
|
||||||
OnEntryRenamed,
|
OnEntryRenamed,
|
||||||
@@ -65,7 +66,7 @@ function TreeNode({
|
|||||||
OnBrowseDirectory(FullPath);
|
OnBrowseDirectory(FullPath);
|
||||||
|
|
||||||
if (NavigateIntoDirectories) {
|
if (NavigateIntoDirectories) {
|
||||||
OnNavigateDirectory(FullPath);
|
OnSelectDirectory(FullPath, Entry.Note);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,6 +157,7 @@ function TreeNode({
|
|||||||
SelectedFile={SelectedFile}
|
SelectedFile={SelectedFile}
|
||||||
CurrentDirectoryPath={CurrentDirectoryPath}
|
CurrentDirectoryPath={CurrentDirectoryPath}
|
||||||
OnSelectFile={OnSelectFile}
|
OnSelectFile={OnSelectFile}
|
||||||
|
OnSelectDirectory={OnSelectDirectory}
|
||||||
OnNavigateDirectory={OnNavigateDirectory}
|
OnNavigateDirectory={OnNavigateDirectory}
|
||||||
OnBrowseDirectory={OnBrowseDirectory}
|
OnBrowseDirectory={OnBrowseDirectory}
|
||||||
OnEntryRenamed={OnEntryRenamed}
|
OnEntryRenamed={OnEntryRenamed}
|
||||||
@@ -213,6 +215,7 @@ export default function Sidebar({
|
|||||||
CurrentDirectoryPath,
|
CurrentDirectoryPath,
|
||||||
CurrentUser,
|
CurrentUser,
|
||||||
OnSelectFile,
|
OnSelectFile,
|
||||||
|
OnSelectDirectory,
|
||||||
OnNavigateDirectory,
|
OnNavigateDirectory,
|
||||||
OnBrowseDirectory,
|
OnBrowseDirectory,
|
||||||
OnEntryRenamed,
|
OnEntryRenamed,
|
||||||
@@ -319,6 +322,7 @@ export default function Sidebar({
|
|||||||
SelectedFile={SelectedFile}
|
SelectedFile={SelectedFile}
|
||||||
CurrentDirectoryPath={CurrentDirectoryPath}
|
CurrentDirectoryPath={CurrentDirectoryPath}
|
||||||
OnSelectFile={OnSelectFile}
|
OnSelectFile={OnSelectFile}
|
||||||
|
OnSelectDirectory={OnSelectDirectory}
|
||||||
OnNavigateDirectory={OnNavigateDirectory}
|
OnNavigateDirectory={OnNavigateDirectory}
|
||||||
OnBrowseDirectory={OnBrowseDirectory}
|
OnBrowseDirectory={OnBrowseDirectory}
|
||||||
OnEntryRenamed={OnEntryRenamed}
|
OnEntryRenamed={OnEntryRenamed}
|
||||||
|
|||||||
Reference in new issue
Block a user