skrift 0.1.0a13__py3-none-any.whl → 0.1.0a15__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.
@@ -4,6 +4,28 @@
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>{% block title %}{{ site_name() }}{% endblock %}</title>
7
+
8
+ {# SEO Meta Tags #}
9
+ {% block seo_meta %}
10
+ {% if seo_meta %}
11
+ {% if seo_meta.description %}<meta name="description" content="{{ seo_meta.description }}">{% endif %}
12
+ {% if seo_meta.robots %}<meta name="robots" content="{{ seo_meta.robots }}">{% endif %}
13
+ <link rel="canonical" href="{{ seo_meta.canonical_url }}">
14
+ {% endif %}
15
+ {% endblock %}
16
+
17
+ {# OpenGraph Tags #}
18
+ {% block og_meta %}
19
+ {% if og_meta %}
20
+ <meta property="og:title" content="{{ og_meta.title }}">
21
+ {% if og_meta.description %}<meta property="og:description" content="{{ og_meta.description }}">{% endif %}
22
+ {% if og_meta.image %}<meta property="og:image" content="{{ og_meta.image }}">{% endif %}
23
+ <meta property="og:url" content="{{ og_meta.url }}">
24
+ <meta property="og:site_name" content="{{ og_meta.site_name }}">
25
+ <meta property="og:type" content="{{ og_meta.type }}">
26
+ {% endif %}
27
+ {% endblock %}
28
+
7
29
  <link rel="preconnect" href="https://fonts.googleapis.com">
8
30
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
31
  <link href="https://fonts.googleapis.com/css2?family=Cinzel:wght@500;600&family=Lora:ital,wght@0,400;0,600;1,400;1,600&display=swap" rel="stylesheet">
@@ -33,10 +55,26 @@
33
55
  </header>
34
56
 
35
57
  <main class="container{% block main_class %}{% endblock %}">
36
- {% if flash %}
37
- <div class="flash-messages">
38
- <article role="alert">{{ flash }}</article>
39
- </div>
58
+ {# Enhanced flash messages with types #}
59
+ {% if flash_messages %}
60
+ <div class="flash-messages" role="status" aria-live="polite">
61
+ {% for msg in flash_messages %}
62
+ <article role="alert" class="flash flash-{{ msg.type.value }}" {% if msg.dismissible %}data-dismissible{% endif %}>
63
+ <span class="flash-message">{{ msg.message }}</span>
64
+ {% if msg.dismissible %}
65
+ <button type="button" class="flash-dismiss" aria-label="Dismiss">&times;</button>
66
+ {% endif %}
67
+ </article>
68
+ {% endfor %}
69
+ </div>
70
+ {# Backwards compatibility: old single flash string #}
71
+ {% elif flash %}
72
+ <div class="flash-messages" role="status" aria-live="polite">
73
+ <article role="alert" class="flash flash-info" data-dismissible>
74
+ <span class="flash-message">{{ flash }}</span>
75
+ <button type="button" class="flash-dismiss" aria-label="Dismiss">&times;</button>
76
+ </article>
77
+ </div>
40
78
  {% endif %}
41
79
 
42
80
  {% block content %}{% endblock %}
@@ -48,5 +86,21 @@
48
86
  </footer>
49
87
 
50
88
  {% block scripts %}{% endblock %}
89
+
90
+ <script>
91
+ // Flash message dismissal
92
+ document.querySelectorAll('.flash-dismiss').forEach(btn => {
93
+ btn.addEventListener('click', () => {
94
+ btn.closest('.flash').remove();
95
+ });
96
+ });
97
+ // Auto-dismiss success messages after 5 seconds
98
+ document.querySelectorAll('.flash-success[data-dismissible]').forEach(flash => {
99
+ setTimeout(() => {
100
+ flash.style.opacity = '0';
101
+ setTimeout(() => flash.remove(), 300);
102
+ }, 5000);
103
+ });
104
+ </script>
51
105
  </body>
52
106
  </html>
@@ -14,7 +14,7 @@
14
14
  </header>
15
15
 
16
16
  <div class="page-content">
17
- {{ page.content | safe }}
17
+ {{ page.content | markdown | safe }}
18
18
  </div>
19
19
 
20
20
  {% if not page.is_published %}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: skrift
3
- Version: 0.1.0a13
3
+ Version: 0.1.0a15
4
4
  Summary: A lightweight async Python CMS for crafting modern websites
5
5
  Requires-Python: >=3.13
6
6
  Requires-Dist: advanced-alchemy>=0.26.0
@@ -9,6 +9,8 @@ Requires-Dist: alembic>=1.14.0
9
9
  Requires-Dist: asyncpg>=0.30.0
10
10
  Requires-Dist: httpx>=0.28.0
11
11
  Requires-Dist: litestar[cryptography,jinja,standard]>=2.14.0
12
+ Requires-Dist: markdown-it-py>=3.0.0
13
+ Requires-Dist: mdit-py-plugins>=0.4.0
12
14
  Requires-Dist: pydantic-settings>=2.7.0
13
15
  Requires-Dist: python-dotenv>=1.0.0
14
16
  Requires-Dist: pyyaml>=6.0.0
@@ -33,6 +35,11 @@ A modern Litestar-powered content management framework with multi-provider OAuth
33
35
  - **Dynamic Controllers**: Load controllers from `app.yaml` configuration
34
36
  - **SQLAlchemy Integration**: Async database support with SQLite/PostgreSQL
35
37
  - **Client-Side Sessions**: Encrypted cookie sessions for horizontal scalability
38
+ - **Hook/Filter System**: WordPress-like extensibility with async support
39
+ - **SEO Metadata**: Built-in meta descriptions, OpenGraph tags, and robots directives
40
+ - **Content Scheduling**: Schedule pages to publish at a future date
41
+ - **Page Revisions**: Automatic content history with restore capability
42
+ - **Sitemap & Robots.txt**: Auto-generated with filter extensibility
36
43
 
37
44
  ## Quick Start
38
45
 
@@ -119,11 +126,17 @@ skrift/
119
126
  ├── skrift/ # Main Python package
120
127
  │ ├── asgi.py # Application factory
121
128
  │ ├── config.py # Settings management
122
- │ ├── controllers/ # Route handlers
129
+ │ ├── controllers/ # Route handlers (auth, web, sitemap)
123
130
  │ ├── admin/ # Admin panel
124
131
  │ ├── auth/ # RBAC and guards
125
132
  │ ├── db/ # Models and services
126
- │ ├── lib/ # Template resolver
133
+ ├── models/ # Page, User, Role, PageRevision
134
+ │ │ └── services/ # page_service, revision_service
135
+ │ ├── lib/ # Core utilities
136
+ │ │ ├── hooks.py # Hook/filter system
137
+ │ │ ├── seo.py # SEO metadata utilities
138
+ │ │ ├── flash.py # Enhanced flash messages
139
+ │ │ └── template.py # Template resolver
127
140
  │ └── setup/ # Setup wizard
128
141
  ├── templates/ # Jinja2 templates
129
142
  ├── static/ # Static assets
@@ -1,11 +1,11 @@
1
1
  skrift/__init__.py,sha256=eXE5PFVkJpH5XsV_ZlrTIeFPUPrmcHYAj4GpRS3R5PY,29
2
2
  skrift/__main__.py,sha256=wt6JZL9nBhKU36vdyurhOEtWy7w3C9zohyy24PLcKho,164
3
3
  skrift/alembic.ini,sha256=mYguI6CbMCTyfHctsGiTyf9Z5gv21FdeI3qtfgOHO3A,1815
4
- skrift/asgi.py,sha256=qtP0aq9C6-bIZgbXiwJeF_3dY8O0cM2U_5hkajKMjBc,23032
4
+ skrift/asgi.py,sha256=7uPvgsGMpZJyPOjIGxL9QlXTRLWh9uRAhcg-RdBS1c8,23355
5
5
  skrift/cli.py,sha256=aT-7pXvOuuZC-Eypx1h-xCiqaBKhIFjSqd5Ky_dHna0,4214
6
6
  skrift/config.py,sha256=ZDOrYgp6gC6fE1nEZgrAOouoykhRo2NZo5U1-WLdDSc,7862
7
7
  skrift/admin/__init__.py,sha256=x81Cj_ilVmv6slaMl16HHyT_AgrnLxKEWkS0RPa4V9s,289
8
- skrift/admin/controller.py,sha256=5ZDypvKHXLNDESsKNsdsH2E3Si5OqlpzttFl7Ot8aF0,15651
8
+ skrift/admin/controller.py,sha256=gSprerjhxqxaH2lHm8vbLuz-jslN553FpbKF7jwEm9Y,19607
9
9
  skrift/admin/navigation.py,sha256=VwttFoIUIJy5rONKIkJd5w4CNkUpeK22_OfLGHecN34,3382
10
10
  skrift/alembic/env.py,sha256=GaQx7D-3f0zVTV4YJNhN0GOfqHL99N4VBfMzjZJz0Bc,2673
11
11
  skrift/alembic/script.py.mako,sha256=MEqL-2qATlST9TAOeYgscMn1uy6HUS9NFvDgl93dMj8,635
@@ -16,27 +16,38 @@ skrift/alembic/versions/20260122_175637_a9c55348eae7_remove_page_type_column.py,
16
16
  skrift/alembic/versions/20260122_200000_add_settings_table.py,sha256=aG4pxp18fwonGAWt7EoT0XaiIEmu7zltSrj8e2a8QZU,1310
17
17
  skrift/alembic/versions/20260129_add_oauth_accounts.py,sha256=KPuzJ5J13FEbSbyziuB-nfO67i4cRgBeQnygn-uNQx8,5412
18
18
  skrift/alembic/versions/20260129_add_provider_metadata.py,sha256=prDfnYM0cODBSYb9xYqW5Dab2WDjHNkkEMRH-hI7BIA,846
19
+ skrift/alembic/versions/20260202_add_content_scheduling.py,sha256=b5eTIzVmHO5x9UJDwwqQG1gLDNxTzxY0qIl0xTkgZA4,1079
20
+ skrift/alembic/versions/20260202_add_page_ordering.py,sha256=4MdupLfmaM0oftbmRMGOUIDrT55yFCqQ8v9uCOofOZQ,941
21
+ skrift/alembic/versions/20260202_add_page_revisions.py,sha256=LKmxerftfWguGbIjveemnm9nEZ9ZjTm5rdEwoRiUVBY,2179
22
+ skrift/alembic/versions/20260202_add_seo_fields.py,sha256=rLnRY1RyckoVno6miUlTtgv_IceIFJRj3OS7aUVXcKE,1546
19
23
  skrift/auth/__init__.py,sha256=uHMqty3dgDSYlReVT96WhygzH6qNAWSVDWoxumzxmsA,1155
20
24
  skrift/auth/guards.py,sha256=QePajHsGnJ4R_hlhzblr5IoAgZcY5jzeZ64bJwDL9hM,4451
21
25
  skrift/auth/roles.py,sha256=Cvwv8v7Li6CJHhucTuzxRjaNmS530F9sbbQlCPRqhm4,3291
22
26
  skrift/auth/services.py,sha256=h6GTXdN5UMRYglnaFz4asMoutVkSSAyL3_Vt56N26pA,5441
23
27
  skrift/controllers/__init__.py,sha256=bVr0tsSGz7jBi002Lqd1AA1FQd7ZA_IagsqTKpiHiK0,147
24
28
  skrift/controllers/auth.py,sha256=ohYjBJiRa5RDQKUQjL3nR6lzm4uUZcfIgnF2G-QY5o8,21905
25
- skrift/controllers/web.py,sha256=vmoBS1u5G9gCBu65S49yqZn_WBKlmsqlcvX5tYXTKnE,2348
29
+ skrift/controllers/sitemap.py,sha256=Yfz2ElHrkZVMhAN5ixriU5RwEFJ713rS0Uezj90Bfts,3814
30
+ skrift/controllers/web.py,sha256=J-kbmzwJcKfiBvNbF8yR7GHGo0jhvWzY77YstJi_pcI,2968
26
31
  skrift/db/__init__.py,sha256=uSghyDFT2K4SFiEqUzdjCGzWpS-Oy6Sd1FUappau-v0,52
27
32
  skrift/db/base.py,sha256=QJplFj9235kZdScASEpvyNHln6YW2hqbHwJEYZ3OSsc,173
28
- skrift/db/models/__init__.py,sha256=wFF9YWe7rhIWIzRuMtAWVDcZdJsNcKnjfhKbLZw9JVs,341
33
+ skrift/db/models/__init__.py,sha256=DtgYPLs8rTLNFmZ0-HzD_8uhvaGRtayZCrxpMhAo88U,413
29
34
  skrift/db/models/oauth_account.py,sha256=fzmApdtrRYeEWLl35Y7H0YtF7CWjzrpG-lknBOuYRc8,1840
30
- skrift/db/models/page.py,sha256=CI5W2sWq0zbKHxfwH5TpmGdJ4zlTicckzpdZtaqjJVE,1019
35
+ skrift/db/models/page.py,sha256=pYMWBmQ7FfDiFcyBU3xV4kbpWboimZw5TZtVDOcr73o,2068
36
+ skrift/db/models/page_revision.py,sha256=S2TO8hR5ThPFRk1Ovdn3lFau6D2H6TLhfFX6ekp_OTI,1399
31
37
  skrift/db/models/role.py,sha256=VkwkF3XWemmFtkUpQRk6RTIBfcukrU-0PUPCeo8x834,1768
32
38
  skrift/db/models/setting.py,sha256=Am4HTyq2LFR408R6BZb--slys1xM8YLYq9HTq_gybD0,392
33
39
  skrift/db/models/user.py,sha256=kkR3h0CphUyvOGJOpiZH6Qp28LqW2OriwVTfybs7vuY,1338
34
40
  skrift/db/services/__init__.py,sha256=qAC24IPOYg6AampUWonmLeajljQRMwUw0lgXksQG6Nk,69
35
41
  skrift/db/services/oauth_service.py,sha256=1065tYGvrSer0X28GblibrSz2BjwVjl3tndXk1plthE,5208
36
- skrift/db/services/page_service.py,sha256=cXJ-urV7LjUDoVsT1P52f6wcOsur3T-pvqKkGG4xlvI,5246
37
- skrift/db/services/setting_service.py,sha256=eqFxukn8QFrDHQbaBILOLjP1nr34JPIPFT_NnhmeaTY,5613
38
- skrift/lib/__init__.py,sha256=PL66bS4_-90zJDMsQSnzqkkxwkO_3aLcYl9l9cDrE2Y,65
42
+ skrift/db/services/page_service.py,sha256=vVuxy7rNC9J6iCGFtmnt7Jrgo3cFm-vscdWcZ2RuMOQ,9830
43
+ skrift/db/services/revision_service.py,sha256=YBHeSac6V2_K3AKzDqup8fg0nys9nVLGOnLYD7GkxUQ,3701
44
+ skrift/db/services/setting_service.py,sha256=9u8LUMxnZAeSxf98_8GZXi5uioT4Jz-rYdIbs6wa4KE,5869
45
+ skrift/lib/__init__.py,sha256=XodsWJweaIpHtVkAHkEZHcCY8NSOBrUWxUQGZidP9l0,359
39
46
  skrift/lib/exceptions.py,sha256=p8ceLIQCc7agCwW6-mhBDAuMAMxZDcf9TDLC6PfztU4,5803
47
+ skrift/lib/flash.py,sha256=nWX7H8s218oBOE4d9kE6asHG_TNM4BbWJ7qrN65-Ewc,2921
48
+ skrift/lib/hooks.py,sha256=HsrOM-mVZSd1mSlNsj8YpfjJ7HwufDjFSnVUenmnwjA,8710
49
+ skrift/lib/markdown.py,sha256=fPLUIAsmFXC64Os2RngQG7P2xRKBd1RO8fh7b5_gV1U,950
50
+ skrift/lib/seo.py,sha256=3fAfXn_7Jpq_OhINpcbQznixLcJTbaD-I86_Je2SFoo,2512
40
51
  skrift/lib/template.py,sha256=4_urkRfvth75yNeQ5TyGTHvkvs3vVef7TcwZx0k285k,4226
41
52
  skrift/setup/__init__.py,sha256=3VjFPMES5y0M5cQ9R4C1xazqiEPEDqTPjX9-3rBMXnA,478
42
53
  skrift/setup/config_writer.py,sha256=YFH3FVjXN7Rum2fzGVPAQRkjdc9b0bHECDqMKYiEkhg,6347
@@ -44,17 +55,18 @@ skrift/setup/controller.py,sha256=v0Ey8T7ptJ5A3vOqQ1TUAXH1bQwA0288J5uyUWMihsw,34
44
55
  skrift/setup/middleware.py,sha256=Nai8ZG2vHldngmAhq7kWzAwKRNcP5tHKhJHa5dCh404,2941
45
56
  skrift/setup/providers.py,sha256=0BFKB6168NcmtXxFF6ofHgEDMQD2FbXkexsqrARVtDI,7967
46
57
  skrift/setup/state.py,sha256=RMe9LtIjzDoOm9u-Nk5-KAnr_JBiQIjWDpTP9E30ezc,9304
47
- skrift/static/css/style.css,sha256=-Ijp4PCugWzhHhtZTaRUAITHJDW-0AsbNpDCFI1njVQ,20943
48
- skrift/templates/base.html,sha256=4bg4s4VdES0dSvhJYLgrfrN26ynqeq1-3jyKPkWWVWk,2065
58
+ skrift/static/css/style.css,sha256=6in8KjmwythfQV9pGt-uSCJCoHG1OijrdDOOad7oYBk,22978
59
+ skrift/templates/base.html,sha256=s6gylukPyBvb9StgNz8MRZr4h3QT3C8GTMiwOu23nC0,4421
49
60
  skrift/templates/error-404.html,sha256=sJrDaF3Or3Nyki8mxo3wBxLLzgy4wkB9p9wdS8pRA6k,409
50
61
  skrift/templates/error-500.html,sha256=MR0wJ1JKLqdmdvsoJbQnZxLkxDPE59LrlbtVPKLM8-A,401
51
62
  skrift/templates/error.html,sha256=tg45Hj0wNc9QiZKBVVQ2WsqDiAkByXZnuehTdJPclXc,415
52
63
  skrift/templates/index.html,sha256=lzZlnoZ2luY__OtRVa61mpQIgcopAbkKa2rS9XRfRlI,172
53
- skrift/templates/page.html,sha256=kY1j7TH6dFnvWnYwBEGCIEvardjLhnFMnM3NbAnKszQ,759
64
+ skrift/templates/page.html,sha256=aSTypibx86SzIhO7GTff8XXVrW8D-XbHNaTo_UT31oc,770
54
65
  skrift/templates/admin/admin.html,sha256=8sErpGKedl7Hf_CMeu53bUEHptH1FqdBX9LT3z-1HcU,454
55
66
  skrift/templates/admin/base.html,sha256=JX1MPw9XTY8jCT2M6iHUwEj8NPNOdZPca2cDUEs9kfQ,659
56
- skrift/templates/admin/pages/edit.html,sha256=s-uZ4BYG7BdnWYTBSS1mr5aFL8XfT8h-KNiSIraWmHw,1322
57
- skrift/templates/admin/pages/list.html,sha256=LYh1vEwSHkyXihjcy5PIo33iA7UeIxprw4Gsn1WZMm4,2185
67
+ skrift/templates/admin/pages/edit.html,sha256=WqA1xYg5ZbDmH77wuu-8pvxsQ0scS6QpYXlzrLKxAj8,3859
68
+ skrift/templates/admin/pages/list.html,sha256=KHjqIQMNV1Ts6Fgx9p_waiGOb9lVcAgLCMmomKAQoeA,2602
69
+ skrift/templates/admin/pages/revisions.html,sha256=hthxdcKqz_DUHzky_5dn6cDEsZWR49W2sqKTiJjhVpA,2075
58
70
  skrift/templates/admin/settings/site.html,sha256=xHZCZGj9XqyLKCe2eoBlpI3oFIx5VoG_5FP-VAF2mz4,1516
59
71
  skrift/templates/admin/users/list.html,sha256=9GWql1la5Srm-OOgooHR9Eouk7ZL66K_FXY6HAAB5lA,1732
60
72
  skrift/templates/admin/users/roles.html,sha256=pos-ZM-gXYCN_D8DZpzwEBEm_WvmOKMMPz-3xJqs7nY,1473
@@ -68,7 +80,7 @@ skrift/templates/setup/configuring.html,sha256=2KHW9h2BrJgL_kO5IizbAYs4pnFLyRf76
68
80
  skrift/templates/setup/database.html,sha256=gU4-315-QraHa2Eq4Fh3b55QpOM2CkJzh27_Yz13frA,5495
69
81
  skrift/templates/setup/restart.html,sha256=GHg31F_e2uLFhWUzJoalk0Y0oYLqsFWyZXWKX3mblbY,1355
70
82
  skrift/templates/setup/site.html,sha256=PSOH-q1-ZBl47iSW9-Ad6lEfJn_fzdGD3Pk4vb3xgK4,1680
71
- skrift-0.1.0a13.dist-info/METADATA,sha256=cNzAjQrohmMJZJv-euANW_JjoWI5Lm6KSzG0daFjT7o,6436
72
- skrift-0.1.0a13.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
73
- skrift-0.1.0a13.dist-info/entry_points.txt,sha256=uquZ5Mumqr0xwYTpTcNiJtFSITGfF6_QCCy2DZJSZig,42
74
- skrift-0.1.0a13.dist-info/RECORD,,
83
+ skrift-0.1.0a15.dist-info/METADATA,sha256=6_eCcfYQ2K5uH_acqd3Q3FmEby0a1Yx710xIiEBa3rs,7267
84
+ skrift-0.1.0a15.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
85
+ skrift-0.1.0a15.dist-info/entry_points.txt,sha256=uquZ5Mumqr0xwYTpTcNiJtFSITGfF6_QCCy2DZJSZig,42
86
+ skrift-0.1.0a15.dist-info/RECORD,,