Skip to content

Commit 2fab3da

Browse files
committed
Display files and folders as a nice file tree
1 parent 94cd41b commit 2fab3da

File tree

9 files changed

+380
-43
lines changed

9 files changed

+380
-43
lines changed

markopolis/data_dantic.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,18 @@ class BacklinkList(BaseModel):
7575
backlinks: List[Backlink]
7676

7777

78+
class FileItem(BaseModel):
79+
title: str
80+
link: str
81+
82+
83+
class FolderItem(BaseModel):
84+
folder: str
85+
members: "list[FileItem | FolderItem]"
86+
87+
7888
class MarkdownFileList(BaseModel):
79-
files: List[str]
89+
files: list[FolderItem]
8090

8191

8292
class Raw(BaseModel):

markopolis/fastapp.py

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -202,12 +202,6 @@ async def load_page(request: Request):
202202
toc = F.get_headings("home")
203203
backlinks = F.get_backlinks("home")
204204

205-
if isinstance(posts, D.Error):
206-
logger.warning(f"Error in posts: {posts.error}")
207-
posts = []
208-
else:
209-
posts = posts.files
210-
211205
if isinstance(content, D.Error):
212206
logger.error(f"Error in content: {content.error}")
213207
raise HTTPException(
@@ -257,12 +251,6 @@ async def get_note_html(request: Request, path: str):
257251
toc = F.get_headings(path)
258252
backlinks = F.get_backlinks(path)
259253

260-
if isinstance(posts, D.Error):
261-
logger.warning(f"Error in posts: {posts.error}")
262-
posts = []
263-
else:
264-
posts = posts.files
265-
266254
if isinstance(content, D.Error):
267255
logger.error(f"Error in content: {content.error}")
268256
raise HTTPException(

markopolis/funcs.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@
3131
__all__ = ["list_md", "get_metadata", "get_note", "get_headings"]
3232

3333

34-
def list_md():
34+
def list_md() -> MarkdownFileList | Error:
3535
files, error = list_markdown_files()
3636

37-
if files is not None:
38-
return MarkdownFileList(files=files)
37+
if files:
38+
return MarkdownFileList(files=[files]) # Ensure this is a list of FolderItems
3939

4040
return Error(error=error)
4141

markopolis/md.py

Lines changed: 65 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import os
22
import base64
33
import markdown
4+
import markopolis.data_dantic as D
45
from typing import Dict, Optional, Any, Tuple, List
56
from .md_extensions import (
67
CalloutExtension,
@@ -20,21 +21,72 @@
2021
MDROOT = settings.md_path
2122

2223

23-
def list_markdown_files():
24-
if not os.path.exists(MDROOT):
25-
return None, f"The directory {MDROOT} does not exist."
24+
# Parse title from markdown file metadata
25+
def get_markdown_title(filepath: str) -> str:
26+
try:
27+
with open(filepath, "r", encoding="utf-8") as f:
28+
first_line = f.readline().strip()
29+
if first_line.startswith("---"):
30+
metadata = ""
31+
for line in f:
32+
if line.strip() == "---":
33+
break
34+
metadata += line
35+
36+
metadata_dict = yaml.safe_load(metadata)
37+
if isinstance(metadata_dict, dict) and "title" in metadata_dict:
38+
return metadata_dict["title"]
39+
except Exception as e:
40+
logger.error(f"Error reading file {filepath}: {e}")
41+
42+
# Fallback to filename if title metadata is not present
43+
return os.path.splitext(os.path.basename(filepath))[0]
2644

45+
46+
# Recursively list folders and files
47+
def list_markdown_files(
48+
directory: str = "/", root: str = MDROOT
49+
) -> Tuple[Optional[D.FolderItem], Optional[str]]:
50+
if not os.path.exists(root):
51+
return None, f"The directory {root} does not exist."
52+
53+
folder_item = D.FolderItem(folder=directory, members=[])
54+
folders = []
2755
files = []
28-
for root, _, filenames in os.walk(MDROOT):
29-
for filename in filenames:
30-
if filename.endswith(".md"):
31-
# Get the relative path from MDROOT
32-
rel_path = os.path.relpath(os.path.join(root, filename), MDROOT)
33-
# Remove the .md extension
34-
rel_path_without_ext = os.path.splitext(rel_path)[0]
35-
files.append(rel_path_without_ext)
36-
37-
return files, ""
56+
57+
# Separate folders and markdown files
58+
for item in sorted(os.listdir(root)):
59+
item_path = os.path.join(root, item)
60+
rel_path = os.path.relpath(item_path, MDROOT)
61+
62+
if os.path.isdir(item_path):
63+
# Recurse into subfolder
64+
subfolder_item, error = list_markdown_files(directory=item, root=item_path)
65+
if error:
66+
logger.error(f"Error in subfolder: {error}")
67+
continue
68+
if (
69+
subfolder_item and subfolder_item.members
70+
): # Only include non-empty folders
71+
folders.append(subfolder_item)
72+
elif item.endswith(".md"):
73+
# It's a markdown file
74+
title = get_markdown_title(item_path)
75+
link = os.path.splitext(rel_path)[0] # Remove the .md extension
76+
file_item = D.FileItem(title=title, link=link)
77+
files.append(file_item)
78+
79+
# Sort folders and files lexicographically
80+
folders = sorted(folders, key=lambda x: x.folder)
81+
files = sorted(files, key=lambda x: x.title)
82+
83+
# Combine sorted folders and files, with folders appearing first
84+
folder_item.members = folders + files
85+
86+
if not folder_item.members:
87+
return None, None # Return None for empty folders
88+
89+
return folder_item, None
3890

3991

4092
def clean_filename(filename):

markopolis/md/Markdown-Syntax.md

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
---
2+
publish: true
3+
tags:
4+
- syntax
5+
- markdown
6+
---
7+
8+
# Headings
9+
10+
```markdown
11+
# Heading 1
12+
## Heading 2
13+
### Heading 3
14+
#### Heading 4
15+
##### Heading 5
16+
```
17+
18+
19+
# Heading 1
20+
## Heading 2
21+
### Heading 3
22+
#### Heading 4
23+
##### Heading 5
24+
25+
## Horizontal line
26+
27+
---
28+
29+
## Images
30+
31+
### embed images
32+
Image names should be unique. Duplicate images will be overwritten.
33+
34+
```markdown
35+
![[image.png]]
36+
```
37+
38+
![[image.png]]
39+
40+
### external images
41+
42+
```markdown
43+
![Engelbart](https://history-computer.com/ModernComputer/Basis/images/Engelbart.jpg)
44+
```
45+
46+
![Engelbart](https://history-computer.com/ModernComputer/Basis/images/Engelbart.jpg)
47+
48+
## Wikilinks
49+
50+
```markdown
51+
[[Installation]]
52+
[[f1/test]]
53+
[[f2/test]]
54+
```
55+
56+
[[Installation]]
57+
[[f1/test]]
58+
[[f2/test]]
59+
60+
## Text formatting
61+
```
62+
**Bold text**
63+
*Italic text*
64+
~~this puts a strikethrough~~
65+
==this highlights text==
66+
**Bold text and _nested italic_ text**
67+
***Bold and italic text***
68+
```
69+
70+
**Bold text**
71+
*Italic text*
72+
~~this puts a strikethrough~~
73+
==this highlights text==
74+
**Bold text and _nested italic_ text**
75+
***Bold and italic text***
76+
77+
## Footnotes
78+
79+
```markdown
80+
This is a simple footnote[^1].
81+
82+
83+
[^1]: This is the referenced text.
84+
[^2]: Add 2 spaces at the start of each new line.
85+
This lets you write footnotes that span multiple lines.
86+
[^note]: Named footnotes still appear as numbers, but can make it easier to identify and link references.
87+
```
88+
89+
This is a simple footnote[^1].
90+
91+
92+
## Quotes
93+
94+
```markdown
95+
> Human beings face ever more complex and urgent problems, and their effectiveness in dealing with these problems is a matter that is critical to the stability and continued progress of society.
96+
97+
\- Doug Engelbart, 1961
98+
```
99+
100+
> Human beings face ever more complex and urgent problems, and their effectiveness in dealing with these problems is a matter that is critical to the stability and continued progress of society.
101+
102+
\- Doug Engelbart, 1961
103+
104+
## Tables
105+
106+
```
107+
| First name | Last name |
108+
| ---------- | --------- |
109+
| Max | Planck |
110+
| Marie | Curie |
111+
```
112+
113+
| First name | Last name |
114+
| ---------- | --------- |
115+
| Max | Planck |
116+
| Marie | Curie |
117+
118+
The vertical bars on either side of the table are optional.
119+
120+
Cells don't need to be perfectly aligned with the columns. Each header row must have at least two hyphens.
121+
122+
```markdown
123+
First name | Last name
124+
-- | --
125+
Max | Planck
126+
Marie | Curie
127+
```
128+
129+
First name | Last name
130+
-- | --
131+
Max | Planck
132+
Marie | Curie
133+
134+
## Mermaid diagrams
135+
136+
Some text.
137+
138+
```mermaid
139+
graph TB
140+
A --> B
141+
B --> C
142+
```
143+
144+
```mermaid
145+
flowchart LR
146+
147+
148+
149+
A[Osaka 7-8] --> B[Tokyo 9-11]
150+
B -.Nagano .-> C[Matsumoto]
151+
C -.Nagano & Toyama.-> D[Takayama 12] <--> D1(Hida no Sato village)
152+
B -.Nagano & Toyama.-> D
153+
C <-.bus.-> D
154+
D --Toyama---> E <--> D2([Onsen 14]) --> F
155+
E[Kanazawa 13] ---> F[Kyoto 15-18] <--> F2(Uji) <--> F1(Nara)
156+
F <-.-> F4(Himeji)
157+
```
158+
159+
## Callouts
160+
161+
> [!abstract]
162+
> Lorem ipsum dolor sit amet
163+
164+
> [!info]
165+
> Lorem ipsum dolor sit amet
166+
167+
> [!todo]
168+
> Lorem ipsum dolor sit amet
169+
170+
> [!tip]
171+
> Lorem ipsum dolor sit amet
172+
173+
> [!success]
174+
> Lorem ipsum dolor sit amet
175+
176+
> [!question]
177+
> Lorem ipsum dolor sit amet
178+
179+
> [!warning]
180+
> Lorem ipsum dolor sit amet
181+
182+
> [!failure]
183+
> Lorem ipsum dolor sit amet
184+
185+
> [!danger]
186+
> Lorem ipsum dolor sit amet
187+
188+
> [!bug]
189+
> Lorem ipsum dolor sit amet
190+
191+
> [!example]
192+
> Lorem ipsum dolor sit amet
193+
194+
> [!quote]
195+
> Lorem ipsum dolor sit amet
196+
197+
> [!tip] Title-only callout
198+
199+
### Foldable callouts
200+
201+
You can make a callout foldable by adding a plus (+) or a minus (-) directly after the type identifier.
202+
203+
A plus sign expands the callout by default, and a minus sign collapses it instead.
204+
205+
> [!faq]-
206+
> Are callouts foldable?
207+
> Yes! In a foldable callout, the contents are hidden when the callout is collapsed.
208+
209+
[^1]: This is the referenced text.
210+
[^2]: Add 2 spaces at the start of each new line.
211+
This lets you write footnotes that span multiple lines.
212+
[^note]: Named footnotes still appear as numbers, but can make it easier to identify and link references.

markopolis/md/f1/test.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,6 @@
22
publish: true
33
---
44

5-
Hello world
5+
Hello world from f1
6+
7+
[[home]]

markopolis/md/f2/test.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
publish: true
33
---
44

5-
Hello World
5+
Hello World from f2

0 commit comments

Comments
 (0)