create-caspian-app 1.6.4 → 1.8.1
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.
- package/dist/.github/copilot-instructions.md +271 -271
- package/dist/AGENTS.md +470 -461
- package/dist/app-gitignore +2 -0
- package/dist/index.js +2 -2
- package/dist/main.py +424 -64
- package/dist/public/js/pp-reactive-v2.min.js +1 -1
- package/dist/settings/build-static.py +32 -2
- package/dist/settings/check.py +520 -476
- package/dist/src/app/error.py +94 -95
- package/dist/src/app/layout.py +43 -47
- package/package.json +1 -1
package/dist/src/app/error.py
CHANGED
|
@@ -1,95 +1,94 @@
|
|
|
1
|
-
from
|
|
2
|
-
from casp.
|
|
3
|
-
from casp.layout import Metadata
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
metadata = Metadata(
|
|
7
|
-
title="Application Error",
|
|
8
|
-
description="An unexpected error occurred.",
|
|
9
|
-
extra={"robots": "noindex, nofollow"},
|
|
10
|
-
)
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
def page(
|
|
14
|
-
return html(r"""
|
|
15
|
-
<main class="container py-10">
|
|
16
|
-
<div class="mx-auto max-w-2xl rounded bg-white p-6 shadow-sm">
|
|
17
|
-
<div class="flex items-start gap-4">
|
|
18
|
-
<svg class="h-10 w-10 text-red-600"
|
|
19
|
-
viewBox="0 0 24 24"
|
|
20
|
-
fill="none"
|
|
21
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
22
|
-
aria-hidden="true">
|
|
23
|
-
<path d="M11.001 2a1 1 0 0 1 .998 0L21 7v9a3 3 0 0 1-3 3H6a3 3 0 0 1-3-3V7l8.001-5z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
|
24
|
-
<path d="M12 8v4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
|
25
|
-
<path d="M12 16h.01" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
|
26
|
-
</svg>
|
|
27
|
-
|
|
28
|
-
<div class="flex-1">
|
|
29
|
-
<
|
|
30
|
-
<
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
<div class="mt-4 flex flex-wrap gap-2">
|
|
37
|
-
<a href="/"
|
|
38
|
-
class="inline-block rounded border border-gray-200 bg-gray-100 px-3 py-1.5 text-sm text-gray-800 hover:bg-gray-200">
|
|
39
|
-
Home
|
|
40
|
-
</a>
|
|
41
|
-
<button class="inline-block rounded bg-blue-600 px-3 py-1.5 text-sm text-white"
|
|
42
|
-
onclick="window.location.reload()">Reload</button>
|
|
43
|
-
{% if
|
|
44
|
-
<button class="inline-block rounded border border-gray-200 bg-transparent px-3 py-1.5 text-sm text-black"
|
|
45
|
-
onclick="setShowTrace(current => !current)">{showTrace ? "Hide details" : "Show details"}</button>
|
|
46
|
-
{% endif %}
|
|
47
|
-
</div>
|
|
48
|
-
</div>
|
|
49
|
-
</div>
|
|
50
|
-
|
|
51
|
-
{% if
|
|
52
|
-
<section class="mt-4" hidden="{!showTrace}">
|
|
53
|
-
<div class="mb-2 flex items-center justify-between">
|
|
54
|
-
<div class="text-xs text-gray-500">Error details (development only)</div>
|
|
55
|
-
<div class="flex gap-2">
|
|
56
|
-
<button class="rounded border bg-gray-100 px-2 py-1 text-xs text-black"
|
|
57
|
-
onclick="copyTrace()">{traceCopied ? "Copied" : "Copy"}</button>
|
|
58
|
-
<button class="rounded border bg-gray-100 px-2 py-1 text-xs text-black"
|
|
59
|
-
onclick="downloadTrace()">Download</button>
|
|
60
|
-
</div>
|
|
61
|
-
</div>
|
|
62
|
-
<pre pp-ref="{tracePre}"
|
|
63
|
-
class="overflow-auto rounded bg-gray-100 p-4 text-xs text-black">{{
|
|
64
|
-
</section>
|
|
65
|
-
{% endif %}
|
|
66
|
-
|
|
67
|
-
<script>
|
|
68
|
-
const [showTrace, setShowTrace] = pp.state(false);
|
|
69
|
-
const [traceCopied, setTraceCopied] = pp.state(false);
|
|
70
|
-
const tracePre = pp.ref(null);
|
|
71
|
-
|
|
72
|
-
async function copyTrace() {
|
|
73
|
-
if (!tracePre.current) return;
|
|
74
|
-
await navigator.clipboard.writeText(tracePre.current.innerText);
|
|
75
|
-
setTraceCopied(true);
|
|
76
|
-
setTimeout(() => setTraceCopied(false), 2000);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function downloadTrace() {
|
|
80
|
-
if (!tracePre.current) return;
|
|
81
|
-
const blob = new Blob([tracePre.current.innerText], { type: "text/plain" });
|
|
82
|
-
const url = URL.createObjectURL(blob);
|
|
83
|
-
const link = document.createElement("a");
|
|
84
|
-
link.href = url;
|
|
85
|
-
link.download = "error_trace.txt";
|
|
86
|
-
link.click();
|
|
87
|
-
URL.revokeObjectURL(url);
|
|
88
|
-
}
|
|
89
|
-
</script>
|
|
90
|
-
</div>
|
|
91
|
-
</main>
|
|
92
|
-
""",
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
)
|
|
1
|
+
from casp.component_decorator import html
|
|
2
|
+
from casp.errors import ErrorInfo
|
|
3
|
+
from casp.layout import Metadata
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
metadata = Metadata(
|
|
7
|
+
title="Application Error",
|
|
8
|
+
description="An unexpected error occurred.",
|
|
9
|
+
extra={"robots": "noindex, nofollow"},
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def page(error: ErrorInfo):
|
|
14
|
+
return html(r"""
|
|
15
|
+
<main class="container py-10">
|
|
16
|
+
<div class="mx-auto max-w-2xl rounded bg-white p-6 shadow-sm">
|
|
17
|
+
<div class="flex items-start gap-4">
|
|
18
|
+
<svg class="h-10 w-10 text-red-600"
|
|
19
|
+
viewBox="0 0 24 24"
|
|
20
|
+
fill="none"
|
|
21
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
22
|
+
aria-hidden="true">
|
|
23
|
+
<path d="M11.001 2a1 1 0 0 1 .998 0L21 7v9a3 3 0 0 1-3 3H6a3 3 0 0 1-3-3V7l8.001-5z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
|
24
|
+
<path d="M12 8v4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
|
25
|
+
<path d="M12 16h.01" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
|
26
|
+
</svg>
|
|
27
|
+
|
|
28
|
+
<div class="flex-1">
|
|
29
|
+
<p class="text-xs font-medium uppercase tracking-wide text-gray-500">{{ error.status }} · {{ error.reason }}</p>
|
|
30
|
+
<h1 class="mt-1 text-2xl font-semibold text-red-600">Something went wrong</h1>
|
|
31
|
+
<p class="mt-3 text-sm text-gray-700">{{ error.message }}</p>
|
|
32
|
+
{% if error.request_id %}
|
|
33
|
+
<p class="mt-2 text-xs text-gray-500">Reference: {{ error.request_id }}</p>
|
|
34
|
+
{% endif %}
|
|
35
|
+
|
|
36
|
+
<div class="mt-4 flex flex-wrap gap-2">
|
|
37
|
+
<a href="/"
|
|
38
|
+
class="inline-block rounded border border-gray-200 bg-gray-100 px-3 py-1.5 text-sm text-gray-800 hover:bg-gray-200">
|
|
39
|
+
Home
|
|
40
|
+
</a>
|
|
41
|
+
<button class="inline-block rounded bg-blue-600 px-3 py-1.5 text-sm text-white"
|
|
42
|
+
onclick="window.location.reload()">Reload</button>
|
|
43
|
+
{% if error.trace %}
|
|
44
|
+
<button class="inline-block rounded border border-gray-200 bg-transparent px-3 py-1.5 text-sm text-black"
|
|
45
|
+
onclick="setShowTrace(current => !current)">{showTrace ? "Hide details" : "Show details"}</button>
|
|
46
|
+
{% endif %}
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
|
|
51
|
+
{% if error.trace %}
|
|
52
|
+
<section class="mt-4" hidden="{!showTrace}">
|
|
53
|
+
<div class="mb-2 flex items-center justify-between">
|
|
54
|
+
<div class="text-xs text-gray-500">Error details (development only)</div>
|
|
55
|
+
<div class="flex gap-2">
|
|
56
|
+
<button class="rounded border bg-gray-100 px-2 py-1 text-xs text-black"
|
|
57
|
+
onclick="copyTrace()">{traceCopied ? "Copied" : "Copy"}</button>
|
|
58
|
+
<button class="rounded border bg-gray-100 px-2 py-1 text-xs text-black"
|
|
59
|
+
onclick="downloadTrace()">Download</button>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
<pre pp-ref="{tracePre}"
|
|
63
|
+
class="overflow-auto rounded bg-gray-100 p-4 text-xs text-black">{{ error.trace }}</pre>
|
|
64
|
+
</section>
|
|
65
|
+
{% endif %}
|
|
66
|
+
|
|
67
|
+
<script>
|
|
68
|
+
const [showTrace, setShowTrace] = pp.state(false);
|
|
69
|
+
const [traceCopied, setTraceCopied] = pp.state(false);
|
|
70
|
+
const tracePre = pp.ref(null);
|
|
71
|
+
|
|
72
|
+
async function copyTrace() {
|
|
73
|
+
if (!tracePre.current) return;
|
|
74
|
+
await navigator.clipboard.writeText(tracePre.current.innerText);
|
|
75
|
+
setTraceCopied(true);
|
|
76
|
+
setTimeout(() => setTraceCopied(false), 2000);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function downloadTrace() {
|
|
80
|
+
if (!tracePre.current) return;
|
|
81
|
+
const blob = new Blob([tracePre.current.innerText], { type: "text/plain" });
|
|
82
|
+
const url = URL.createObjectURL(blob);
|
|
83
|
+
const link = document.createElement("a");
|
|
84
|
+
link.href = url;
|
|
85
|
+
link.download = "error_trace.txt";
|
|
86
|
+
link.click();
|
|
87
|
+
URL.revokeObjectURL(url);
|
|
88
|
+
}
|
|
89
|
+
</script>
|
|
90
|
+
</div>
|
|
91
|
+
</main>
|
|
92
|
+
""",
|
|
93
|
+
error=error,
|
|
94
|
+
)
|
package/dist/src/app/layout.py
CHANGED
|
@@ -1,47 +1,43 @@
|
|
|
1
|
-
from casp.component_decorator import html
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
</body>
|
|
45
|
-
|
|
46
|
-
</html>
|
|
47
|
-
""")
|
|
1
|
+
from casp.component_decorator import html
|
|
2
|
+
from casp.layout import Metadata
|
|
3
|
+
|
|
4
|
+
# Root defaults, inherited by every page unless overridden. A page title can be
|
|
5
|
+
# formatted for the whole app with `title_template="%s | My App"`.
|
|
6
|
+
metadata = Metadata(description="Powered by Caspian Framework")
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def layout():
|
|
10
|
+
return html(r"""
|
|
11
|
+
<!DOCTYPE html>
|
|
12
|
+
<html lang="{{ current_locale() }}">
|
|
13
|
+
|
|
14
|
+
<head>
|
|
15
|
+
<meta charset="UTF-8" />
|
|
16
|
+
<meta name="viewport"
|
|
17
|
+
content="width=device-width, initial-scale=1.0" />
|
|
18
|
+
<title>{{ metadata.title | default("Caspian App") }}</title>
|
|
19
|
+
{#
|
|
20
|
+
Description, canonical, robots, keywords, Open Graph, Twitter, and every
|
|
21
|
+
`Metadata(extra={...})` entry. Each tag carries `data-pp-meta` so SPA
|
|
22
|
+
navigation replaces the set for the next page.
|
|
23
|
+
#}
|
|
24
|
+
{{ metadata_tags(metadata | default({})) }}
|
|
25
|
+
<link rel="icon"
|
|
26
|
+
href="/favicon.ico"
|
|
27
|
+
type="image/x-icon"
|
|
28
|
+
sizes="16x16" />
|
|
29
|
+
<link href="/css/styles.css" rel="stylesheet" />
|
|
30
|
+
<script type="module" src="/js/main.js"></script>
|
|
31
|
+
</head>
|
|
32
|
+
|
|
33
|
+
<body style="
|
|
34
|
+
opacity: 0;
|
|
35
|
+
pointer-events: none;
|
|
36
|
+
user-select: none;
|
|
37
|
+
transition: opacity 0.18s ease-out;
|
|
38
|
+
">
|
|
39
|
+
<slot />
|
|
40
|
+
</body>
|
|
41
|
+
|
|
42
|
+
</html>
|
|
43
|
+
""")
|