moosey-cms 0.1.0__py3-none-any.whl → 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
moosey_cms/helpers.py
CHANGED
|
@@ -8,7 +8,7 @@ https://opensource.org/licenses/MIT
|
|
|
8
8
|
import os
|
|
9
9
|
import frontmatter
|
|
10
10
|
from pathlib import Path
|
|
11
|
-
from typing import List, Dict, Any
|
|
11
|
+
from typing import List, Dict, Any, Optional
|
|
12
12
|
from jinja2 import TemplateNotFound
|
|
13
13
|
from jinja2.sandbox import SandboxedEnvironment
|
|
14
14
|
from datetime import datetime
|
|
@@ -82,63 +82,55 @@ def get_secure_target(user_path: str, relative_to_path: Path) -> Path:
|
|
|
82
82
|
|
|
83
83
|
|
|
84
84
|
@cache_fn(debug=cache_debug)
|
|
85
|
-
def find_best_template(templates, path_str: str, is_index_file: bool = False) -> str:
|
|
85
|
+
def find_best_template(templates, path_str: str, is_index_file: bool = False, frontmatter: Optional[dict] = None) -> str:
|
|
86
86
|
"""
|
|
87
|
-
Determines the best template based on
|
|
88
|
-
path_str: The clean relative path (e.g. 'posts/stories/my-story')
|
|
89
|
-
is_index_file: True if we are rendering a directory index (e.g. 'posts/stories/index.md')
|
|
87
|
+
Determines the best template based on hierarchy or Frontmatter override.
|
|
90
88
|
"""
|
|
89
|
+
|
|
90
|
+
# 0. Check Frontmatter Override First
|
|
91
|
+
if frontmatter and frontmatter.get('template'):
|
|
92
|
+
candidate = frontmatter.get('template')
|
|
93
|
+
# Ensure it ends with .html if user forgot
|
|
94
|
+
if not candidate.endswith('.html'):
|
|
95
|
+
candidate += '.html'
|
|
96
|
+
|
|
97
|
+
if template_exists(templates, candidate):
|
|
98
|
+
return candidate
|
|
91
99
|
|
|
92
100
|
parts = [p for p in path_str.strip("/").split("/") if p]
|
|
93
101
|
|
|
94
|
-
|
|
95
|
-
if len(parts)==0:
|
|
102
|
+
if len(parts) == 0:
|
|
96
103
|
index_candidate = 'index.html'
|
|
97
104
|
if template_exists(templates, index_candidate):
|
|
98
105
|
return index_candidate
|
|
99
106
|
|
|
100
|
-
|
|
101
|
-
# 1. Exact Match (Specific File Override)
|
|
102
|
-
# We skip this for index files, as their "Exact Match" is essentially
|
|
103
|
-
# the folder name check in step 2B.
|
|
107
|
+
# 1. Exact Match
|
|
104
108
|
if not is_index_file:
|
|
105
109
|
candidate = "/".join(parts) + ".html"
|
|
106
|
-
|
|
107
110
|
if template_exists(templates, candidate):
|
|
108
111
|
return candidate
|
|
109
|
-
|
|
110
|
-
# If we didn't find specific 'my-story.html',
|
|
111
|
-
# pop the filename so we start searching from parent 'stories'
|
|
112
112
|
if parts:
|
|
113
113
|
parts.pop()
|
|
114
114
|
|
|
115
115
|
# 2. Recursive Parent Search
|
|
116
116
|
while len(parts) > 0:
|
|
117
|
-
current_folder = parts[-1]
|
|
118
|
-
parent_path = parts[:-1]
|
|
117
|
+
current_folder = parts[-1]
|
|
118
|
+
parent_path = parts[:-1]
|
|
119
119
|
|
|
120
|
-
# A. Singular Check
|
|
121
|
-
# e.g. "posts/story.html"
|
|
122
|
-
# Only valid if we are NOT rendering a directory list (index file)
|
|
120
|
+
# A. Singular Check
|
|
123
121
|
if not is_index_file:
|
|
124
122
|
singular_name = singularize(current_folder)
|
|
125
123
|
singular_candidate = "/".join(parent_path + [singular_name]) + ".html"
|
|
126
|
-
|
|
127
|
-
print('>>>>parts', parts)
|
|
128
|
-
|
|
129
124
|
if template_exists(templates, singular_candidate):
|
|
130
125
|
return singular_candidate
|
|
131
126
|
|
|
132
|
-
# B. Plural/Folder Check
|
|
133
|
-
# e.g. "posts/stories.html"
|
|
127
|
+
# B. Plural/Folder Check
|
|
134
128
|
plural_candidate = "/".join(parts) + ".html"
|
|
135
129
|
if template_exists(templates, plural_candidate):
|
|
136
130
|
return plural_candidate
|
|
137
131
|
|
|
138
|
-
# Traverse up
|
|
139
132
|
parts.pop()
|
|
140
133
|
|
|
141
|
-
|
|
142
134
|
# 3. Final Fallback
|
|
143
135
|
return "page.html"
|
|
144
136
|
|
|
@@ -147,17 +139,16 @@ def find_best_template(templates, path_str: str, is_index_file: bool = False) ->
|
|
|
147
139
|
def parse_markdown_file(file):
|
|
148
140
|
data = frontmatter.load(file)
|
|
149
141
|
stats = file.stat()
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
"
|
|
154
|
-
|
|
155
|
-
|
|
142
|
+
|
|
143
|
+
# Ensure date metadata exists
|
|
144
|
+
if "date" not in data.metadata or not isinstance(data.metadata["date"], dict):
|
|
145
|
+
data.metadata["date"] = {}
|
|
146
|
+
|
|
147
|
+
data.metadata["date"]["updated"] = datetime.fromtimestamp(stats.st_mtime)
|
|
148
|
+
data.metadata["date"]["created"] = datetime.fromtimestamp(stats.st_ctime)
|
|
156
149
|
data.metadata["slug"] = slugify(str(file.stem))
|
|
157
150
|
|
|
158
151
|
data.html = parse_markdown(data.content)
|
|
159
|
-
|
|
160
|
-
|
|
161
152
|
return data
|
|
162
153
|
|
|
163
154
|
|
|
@@ -176,8 +167,7 @@ def ensure_sandbox_filters(main_templates):
|
|
|
176
167
|
# template_render_content only in sandbox mode
|
|
177
168
|
@cache_fn(debug=cache_debug)
|
|
178
169
|
def template_render_content(templates, content, data, safe=True):
|
|
179
|
-
if not content:
|
|
180
|
-
return ""
|
|
170
|
+
if not content: return ""
|
|
181
171
|
|
|
182
172
|
try:
|
|
183
173
|
# Sync filters/globals from the main app to our sandbox
|
|
@@ -196,51 +186,95 @@ def template_render_content(templates, content, data, safe=True):
|
|
|
196
186
|
|
|
197
187
|
@cache_fn(debug=cache_debug)
|
|
198
188
|
def get_directory_navigation(
|
|
199
|
-
physical_folder: Path, current_url: str, relative_to_path: Path
|
|
189
|
+
physical_folder: Path, current_url: str, relative_to_path: Path, mode: str = "production"
|
|
200
190
|
) -> List[Dict[str, Any]]:
|
|
201
191
|
"""
|
|
202
|
-
Scans
|
|
192
|
+
Scans folder for sidebar menu. Supports advanced frontmatter features.
|
|
203
193
|
"""
|
|
204
194
|
if not physical_folder.exists() or not physical_folder.is_dir():
|
|
205
195
|
return []
|
|
206
196
|
|
|
207
197
|
items = []
|
|
208
198
|
try:
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
199
|
+
for entry in physical_folder.iterdir():
|
|
200
|
+
if entry.name.startswith("."): continue
|
|
201
|
+
if entry.name == "index.md": continue
|
|
202
|
+
if entry.is_dir() and not (entry / 'index.md').exists(): continue
|
|
203
|
+
|
|
204
|
+
# Determine Metadata Source
|
|
205
|
+
meta_file = entry / 'index.md' if entry.is_dir() else entry
|
|
206
|
+
|
|
207
|
+
# Defaults
|
|
208
|
+
sort_weight = 9999
|
|
209
|
+
display_title = entry.stem.replace("-", " ").title()
|
|
210
|
+
nav_group = None
|
|
211
|
+
external_url = None
|
|
212
|
+
is_visible = True
|
|
213
|
+
target = "_self"
|
|
223
214
|
|
|
215
|
+
try:
|
|
216
|
+
# Load minimal metadata
|
|
217
|
+
post = frontmatter.load(meta_file)
|
|
218
|
+
meta = post.metadata
|
|
219
|
+
|
|
220
|
+
# 1. Visibility & Draft Check
|
|
221
|
+
if meta.get('visible') is False:
|
|
222
|
+
is_visible = False
|
|
223
|
+
|
|
224
|
+
if meta.get('draft') is True and mode != 'development':
|
|
225
|
+
is_visible = False
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
if not is_visible:
|
|
229
|
+
continue
|
|
230
|
+
|
|
231
|
+
# 2. Ordering
|
|
232
|
+
if 'order' in meta: sort_weight = int(meta['order'])
|
|
233
|
+
|
|
234
|
+
# 3. Titles & Grouping
|
|
235
|
+
if 'nav_title' in meta: display_title = meta['nav_title']
|
|
236
|
+
elif 'title' in meta: display_title = meta['title']
|
|
237
|
+
|
|
238
|
+
nav_group = meta.get('group')
|
|
239
|
+
|
|
240
|
+
# 4. External Links
|
|
241
|
+
if 'external_link' in meta:
|
|
242
|
+
external_url = meta['external_link']
|
|
243
|
+
target = "_blank"
|
|
244
|
+
elif 'redirect' in meta:
|
|
245
|
+
external_url = meta['redirect']
|
|
246
|
+
|
|
247
|
+
except Exception:
|
|
248
|
+
pass
|
|
224
249
|
|
|
225
250
|
# Build URL
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
251
|
+
if external_url:
|
|
252
|
+
entry_url = external_url
|
|
253
|
+
is_active = False # External links are never 'active' page
|
|
254
|
+
else:
|
|
255
|
+
try:
|
|
256
|
+
rel_path = entry.relative_to(relative_to_path)
|
|
257
|
+
url_slug = str(rel_path).replace(".md", "").replace("\\", "/")
|
|
258
|
+
entry_url = f"/{url_slug}"
|
|
259
|
+
is_active = (entry_url == current_url)
|
|
260
|
+
except ValueError:
|
|
261
|
+
continue
|
|
262
|
+
|
|
263
|
+
items.append({
|
|
264
|
+
"name": display_title,
|
|
265
|
+
"url": entry_url,
|
|
266
|
+
"is_active": is_active,
|
|
267
|
+
"is_dir": entry.is_dir(),
|
|
268
|
+
"weight": sort_weight,
|
|
269
|
+
"group": nav_group,
|
|
270
|
+
"target": target
|
|
271
|
+
})
|
|
272
|
+
|
|
273
|
+
# Sorting: Weight first, then Name
|
|
274
|
+
items.sort(key=lambda x: (x['weight'], x['name']))
|
|
275
|
+
|
|
242
276
|
except OSError:
|
|
243
|
-
pass
|
|
277
|
+
pass
|
|
244
278
|
|
|
245
279
|
return items
|
|
246
280
|
|
moosey_cms/main.py
CHANGED
|
@@ -211,6 +211,12 @@ def init_routes(app, dirs: Dirs, templates, mode, reloader):
|
|
|
211
211
|
md_data = helpers.parse_markdown_file(target_file)
|
|
212
212
|
front_matter = md_data.metadata
|
|
213
213
|
|
|
214
|
+
# never render drafts in production
|
|
215
|
+
if front_matter.get("draft") is True and mode != "development":
|
|
216
|
+
return templates.TemplateResponse(
|
|
217
|
+
"404.html", {"request": request}, status_code=404
|
|
218
|
+
)
|
|
219
|
+
|
|
214
220
|
# Merge front matter
|
|
215
221
|
template_data = {
|
|
216
222
|
**template_data,
|
|
@@ -219,7 +225,6 @@ def init_routes(app, dirs: Dirs, templates, mode, reloader):
|
|
|
219
225
|
"site_code": app.state.site_code,
|
|
220
226
|
}
|
|
221
227
|
|
|
222
|
-
|
|
223
228
|
# Render jinja inside frontmatter strings
|
|
224
229
|
for k in front_matter:
|
|
225
230
|
if isinstance(front_matter[k], str):
|
|
@@ -227,7 +232,6 @@ def init_routes(app, dirs: Dirs, templates, mode, reloader):
|
|
|
227
232
|
templates, front_matter[k], template_data, False
|
|
228
233
|
)
|
|
229
234
|
|
|
230
|
-
|
|
231
235
|
html_content = md_data.html
|
|
232
236
|
|
|
233
237
|
# Render jinja inside markdown body
|
|
@@ -248,13 +252,14 @@ def init_routes(app, dirs: Dirs, templates, mode, reloader):
|
|
|
248
252
|
physical_folder=nav_folder,
|
|
249
253
|
current_url=current_url,
|
|
250
254
|
relative_to_path=dirs["content"],
|
|
255
|
+
mode=mode,
|
|
251
256
|
)
|
|
252
257
|
breadcrumbs = helpers.get_breadcrumbs(full_path)
|
|
253
258
|
|
|
254
259
|
# 7. Find Template
|
|
255
260
|
search_path = "" if clean_path == "index" else clean_path
|
|
256
261
|
template_name = helpers.find_best_template(
|
|
257
|
-
templates, search_path, is_index_file=is_index
|
|
262
|
+
templates, search_path, is_index_file=is_index, frontmatter=front_matter
|
|
258
263
|
)
|
|
259
264
|
|
|
260
265
|
template_data = {**template_data, **md_data}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: moosey-cms
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Add your description here
|
|
5
5
|
Requires-Python: >=3.9
|
|
6
6
|
Requires-Dist: cachetools>=6.2.4
|
|
@@ -162,129 +162,55 @@ A user visits **`/posts/post-1`**.
|
|
|
162
162
|
|
|
163
163
|
**Resolution Order:**
|
|
164
164
|
|
|
165
|
-
1.
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
3. **`templates/posts.html`** (Plural Parent):
|
|
172
|
-
If no singular template exists, the system looks for the folder's name. This allows articles to inherit the layout of their parent section if desired.
|
|
173
|
-
|
|
174
|
-
4. **`templates/page.html`** (Global Fallback):
|
|
175
|
-
If no specific, singular, or plural templates are found, the system defaults to the generic page layout.
|
|
176
|
-
|
|
177
|
-
**Important Notes:**
|
|
178
|
-
|
|
179
|
-
* **The Index File:** For a directory route like `/posts` to work, a **`content/posts/index.md`** file must exist. This tells the CMS that the folder is a navigable section containing content. Without it, accessing `/posts` will return a 404 error.
|
|
180
|
-
* **Navigation:** If `content/posts/index.md` is missing, the `posts` folder will be omitted from auto-generated menus and sidebars (`nav_items`).
|
|
181
|
-
|
|
182
|
-
### Inside a Template
|
|
183
|
-
|
|
184
|
-
Your templates have access to powerful context variables:
|
|
185
|
-
|
|
186
|
-
* `content`: The rendered HTML from your Markdown.
|
|
187
|
-
* `metadata`: The YAML frontmatter from the markdown file.
|
|
188
|
-
* `site_data`: Global site configuration.
|
|
189
|
-
* `breadcrumbs`: Auto-generated breadcrumb navigation.
|
|
190
|
-
* `nav_items`: List of sibling pages/folders for sidebar navigation.
|
|
191
|
-
|
|
192
|
-
**Example `page.html`:**
|
|
193
|
-
|
|
194
|
-
```html
|
|
195
|
-
{% extends "base.html" %}
|
|
196
|
-
|
|
197
|
-
{% block content %}
|
|
198
|
-
<h1>{{ title }}</h1>
|
|
199
|
-
|
|
200
|
-
<!-- Render Breadcrumbs -->
|
|
201
|
-
<nav>
|
|
202
|
-
{% for crumb in breadcrumbs %}
|
|
203
|
-
<a href="{{ crumb.url }}">{{ crumb.name }}</a> /
|
|
204
|
-
{% endfor %}
|
|
205
|
-
</nav>
|
|
206
|
-
|
|
207
|
-
<!-- Render Content -->
|
|
208
|
-
<article>
|
|
209
|
-
{{ content | safe }}
|
|
210
|
-
</article>
|
|
211
|
-
|
|
212
|
-
<!-- Automatic Sidebar -->
|
|
213
|
-
<aside>
|
|
214
|
-
{% for item in nav_items %}
|
|
215
|
-
<a href="{{ item.url }}" class="{% if item.is_active %}active{% endif %}">
|
|
216
|
-
{{ item.name }}
|
|
217
|
-
</a>
|
|
218
|
-
{% endfor %}
|
|
219
|
-
</aside>
|
|
220
|
-
{% endblock %}
|
|
221
|
-
```
|
|
165
|
+
1. **Frontmatter Override:** If `post-1.md` contains `template: special.html`, that template is used immediately.
|
|
166
|
+
2. **Exact Match:** `templates/posts/post-1.html`.
|
|
167
|
+
3. **Singular Parent:** `templates/post.html` (Perfect for generic blog posts).
|
|
168
|
+
4. **Plural Parent:** `templates/posts.html` (Perfect for section indexes).
|
|
169
|
+
5. **Fallback:** `templates/page.html`.
|
|
222
170
|
|
|
223
171
|
---
|
|
224
172
|
|
|
225
|
-
## 📝
|
|
173
|
+
## 📝 Frontmatter Configuration
|
|
226
174
|
|
|
227
|
-
|
|
228
|
-
You can define metadata at the top of any Markdown file. These values are passed to your template.
|
|
175
|
+
You can control routing, visibility, and layout directly from the Markdown file YAML frontmatter.
|
|
229
176
|
|
|
230
|
-
|
|
231
|
-
|
|
177
|
+
### Basic Metadata
|
|
178
|
+
```yaml
|
|
232
179
|
title: My Amazing Post
|
|
233
180
|
date: 2024-01-01
|
|
234
|
-
|
|
235
|
-
---
|
|
236
|
-
|
|
237
|
-
# Hello World
|
|
238
|
-
|
|
239
|
-
This is content.
|
|
181
|
+
description: A short summary for SEO.
|
|
240
182
|
```
|
|
241
183
|
|
|
242
|
-
###
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
* **Filters:** All standard Moosey filters (`fancy_date`, `read_time`, etc.) are available.
|
|
258
|
-
|
|
259
|
-
### Included Extensions
|
|
260
|
-
Moosey includes `pymdown-extensions` to provide:
|
|
261
|
-
* Tables
|
|
262
|
-
* Task Lists `[x]`
|
|
263
|
-
* Emojis `:smile:`
|
|
264
|
-
* Code Fences with highlighting
|
|
265
|
-
* Admonitions (Alerts/Callouts)
|
|
266
|
-
* Math/Arithmatex
|
|
184
|
+
### Organization & Navigation
|
|
185
|
+
| Key | Type | Description |
|
|
186
|
+
| :--- | :--- | :--- |
|
|
187
|
+
| `order` | `int` | Sort order in sidebars. Lower numbers appear first. Default: `9999`. |
|
|
188
|
+
| `nav_title` | `str` | Short title to display in sidebars (if different from `title`). |
|
|
189
|
+
| `visible` | `bool` | Set to `false` to hide from sidebars/menus (page remains accessible via URL). |
|
|
190
|
+
| `draft` | `bool` | If `true`, the page is only visible in `development` mode. |
|
|
191
|
+
| `group` | `str` | Group sidebar items under a heading (requires template support). |
|
|
192
|
+
|
|
193
|
+
### Advanced Routing
|
|
194
|
+
| Key | Type | Description |
|
|
195
|
+
| :--- | :--- | :--- |
|
|
196
|
+
| `template` | `str` | Force a specific template file (e.g., `template: landing.html`). |
|
|
197
|
+
| `external_link` | `str` | The sidebar link will point to this external URL instead of the page itself. |
|
|
198
|
+
| `redirect` | `str` | Alias for `external_link`. |
|
|
267
199
|
|
|
200
|
+
**Example:**
|
|
201
|
+
```yaml
|
|
202
|
+
---
|
|
203
|
+
title: API Documentation
|
|
204
|
+
nav_title: API Docs
|
|
205
|
+
weight: 1
|
|
206
|
+
group: "Developer Tools"
|
|
207
|
+
external_link: "https://api.mysite.com"
|
|
268
208
|
---
|
|
269
|
-
|
|
270
|
-
## 🛠️ SEO & Metadata
|
|
271
|
-
|
|
272
|
-
Moosey CMS includes a robust SEO helper. In your `base.html` `<head>`, simply add:
|
|
273
|
-
|
|
274
|
-
```html
|
|
275
|
-
<head>
|
|
276
|
-
<!-- Automatically generates Title, Meta Description, OpenGraph,
|
|
277
|
-
Twitter Cards, and JSON-LD Structured Data -->
|
|
278
|
-
{{ seo() }}
|
|
279
|
-
|
|
280
|
-
<!-- Or override specific values -->
|
|
281
|
-
{{ seo(title="Custom Title", image="/static/custom.jpg") }}
|
|
282
|
-
</head>
|
|
283
209
|
```
|
|
284
210
|
|
|
285
211
|
---
|
|
286
212
|
|
|
287
|
-
## 🧩 Custom Filters
|
|
213
|
+
## 🧩 Custom Filters & Logic
|
|
288
214
|
|
|
289
215
|
Moosey CMS comes packed with a comprehensive library of Jinja2 filters to help you format your data effortlessly.
|
|
290
216
|
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
moosey_cms/.python-version,sha256=e1X45ntWI8S-8_ppEojalDfXnTq6FW3kjUgdsyrH0W0,5
|
|
2
|
-
moosey_cms/README.md,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
2
|
moosey_cms/__init__.py,sha256=y7gzxC1LB7qRmjqJHJpN4kEqBNAbuIwNc4xeEI2clMY,184
|
|
4
3
|
moosey_cms/cache.py,sha256=YI6rRb4OVi-Mb1CmMW-jRz0CC9U6YZyszqLmjqLOsq8,2067
|
|
5
4
|
moosey_cms/file_watcher.py,sha256=ViadvrDD2y0MN9VJlz9Kkp31qFkYBhDCoK7xtdA4tAY,923
|
|
6
5
|
moosey_cms/filters.py,sha256=QIHeffZAxn4KqQE4zwR4D7njE96L-oeqHc5DYrYgCpw,15983
|
|
7
|
-
moosey_cms/helpers.py,sha256=
|
|
6
|
+
moosey_cms/helpers.py,sha256=nUP9wPrBWyfsyaTYgYSBVaWcvjgz4Gf0H-SE0DXmCeE,9438
|
|
8
7
|
moosey_cms/hot_reload_script.py,sha256=Dflj5hgHVkVOfjeU7wzEUeVTt684nj22et8jKzVFEGw,2987
|
|
9
|
-
moosey_cms/main.py,sha256=
|
|
8
|
+
moosey_cms/main.py,sha256=Xdxx6RpEWRz1t2RGfpYvQRmgt12mfegUWk86drHHHGk,9104
|
|
10
9
|
moosey_cms/md.py,sha256=m857SKApJkK62wNrMVsypuJAqumbBt5GuPvcnuN1O6w,4970
|
|
11
10
|
moosey_cms/models.py,sha256=Q4MRJ32Zy9GDwnPuHr0VJOuSCN8PlccpTOOXQaZqYqU,3392
|
|
12
11
|
moosey_cms/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
12
|
moosey_cms/pyproject.toml,sha256=lFRsY2yJOKtDWJc-Mfq9s0teGrhmB3ALDJyMltjBOGg,735
|
|
14
13
|
moosey_cms/seo.py,sha256=ubuxb9nTGr3a5a6--zUMwxlZfYBOoGDJCZJeZSa0Bo4,5283
|
|
15
14
|
moosey_cms/static/js/reload-script.js,sha256=hnrVXEWeTK-Y2vLeADmtlZ7fOXpDJMF-0zK09o3mrOA,2247
|
|
16
|
-
moosey_cms-0.
|
|
17
|
-
moosey_cms-0.
|
|
18
|
-
moosey_cms-0.
|
|
15
|
+
moosey_cms-0.2.0.dist-info/METADATA,sha256=EC4s5kqVGf-fzOVQj6I3_vs8ZXCdiYVORLKUYcj1SqU,10998
|
|
16
|
+
moosey_cms-0.2.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
17
|
+
moosey_cms-0.2.0.dist-info/RECORD,,
|
moosey_cms/README.md
DELETED
|
File without changes
|
|
File without changes
|