Skip to content

Commit cc87ad8

Browse files
committed
improve website
1 parent b5ccf27 commit cc87ad8

39 files changed

Lines changed: 462 additions & 78 deletions

docs/index.md

Lines changed: 78 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,91 @@
11
---
2-
title: x2py Documentation
3-
audience: users, developers, maintainers
2+
title: x2py
3+
audience: users
44
prerequisites: none
5-
related: user/index.md, developer/index.md, maintainer/README.md
5+
related: user/getting-started/index.md, user/getting-started/installation.md
66
status: maintained
77
publication: reviewed
88
---
99

10-
# x2py Documentation
10+
# x2py
1111

12-
x2py website documentation is divided into User, Developer, and Maintainer
13-
lanes. Only reviewed lanes and pages appear in the published site.
12+
x2py turns supported Fortran source into an importable Python extension. It
13+
also exposes the parsed interface as language-neutral semantic IR and editable
14+
`.pyi` contracts, so unsupported boundaries are reported before wrapper code is
15+
compiled.
1416

15-
## User Documentation
17+
## Try x2py
1618

17-
[User documentation](user/index.md) explains how to install x2py, build and use
18-
wrappers, understand generated contracts, diagnose failures, and distribute
19-
artifacts. Start here when x2py is a tool you are using.
19+
This first example wraps a scalar Fortran function. Create `scale.f90`:
2020

21-
## Developer Documentation
21+
<!-- x2py-doc-source: tests/data/fortran/wrapper/scale.f90 -->
22+
```fortran
23+
real(8) function scale(value, factor) result(output)
24+
real(8), intent(in) :: value
25+
real(8), intent(in) :: factor
26+
output = value * factor
27+
end function scale
28+
```
2229

23-
[Developer documentation](developer/index.md) explains how to change x2py,
24-
locate implementation ownership, add features, run focused tests, and prepare a
25-
contribution. Start here when you are modifying the codebase.
30+
Build the Python extension from the directory containing that file:
2631

27-
## Maintainer Documentation
32+
```bash
33+
python3 -m x2py scale.f90
34+
```
2835

29-
[Maintainer documentation](maintainer/README.md) records project governance,
30-
accepted design decisions, internal architecture, release policy, and active
31-
roadmaps.
36+
The command creates an importable `scale` extension beside the source and keeps
37+
its generated wrapper and build artifacts under `__x2py__/`. Call the native
38+
function from Python with the exact NumPy scalar types required by its
39+
contract:
40+
41+
```python
42+
import numpy as np
43+
44+
import scale
45+
46+
result = scale.scale(np.float64(3.0), np.float64(2.5))
47+
print(result)
48+
```
49+
50+
The call prints:
51+
52+
```text
53+
7.5
54+
```
55+
56+
The generated function is inspectable from Python:
57+
58+
```python
59+
print(scale.scale.__doc__)
60+
```
61+
62+
Its docstring describes the public signature, accepted dtypes, result, and
63+
call-time type error:
64+
65+
```text
66+
scale(value, factor) -> float64
67+
68+
Parameters
69+
----------
70+
value : float64
71+
factor : float64
72+
73+
Returns
74+
-------
75+
result : float64
76+
77+
Raises
78+
------
79+
TypeError
80+
If an argument has an incompatible Python type or dtype.
81+
```
82+
83+
That is the basic x2py workflow: provide native source, build an extension,
84+
import it, and call the generated Python surface.
85+
86+
## Continue With Getting Started
87+
88+
This preview assumes x2py, NumPy, and a supported native compiler are already
89+
available. [Getting Started](user/getting-started/index.md) walks through
90+
installation and verification first, then rebuilds this function and explains
91+
its generated contract and artifacts.

docs/javascripts/code-copy.js

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
(function () {
2+
"use strict";
3+
4+
const copyIcon = `
5+
<svg class="x2py-copy-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
6+
<rect x="8" y="8" width="12" height="13" rx="2"></rect>
7+
<path d="M16 8V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h3"></path>
8+
</svg>`;
9+
const copiedIcon = `
10+
<svg class="x2py-copied-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
11+
<path d="m5 12 4 4L19 6"></path>
12+
</svg>`;
13+
14+
function fallbackCopy(text) {
15+
const textarea = document.createElement("textarea");
16+
textarea.value = text;
17+
textarea.setAttribute("readonly", "");
18+
textarea.style.position = "fixed";
19+
textarea.style.opacity = "0";
20+
document.body.appendChild(textarea);
21+
textarea.select();
22+
23+
try {
24+
if (!document.execCommand("copy")) {
25+
throw new Error("The browser rejected the copy command.");
26+
}
27+
} finally {
28+
textarea.remove();
29+
}
30+
}
31+
32+
async function copyText(text) {
33+
if (navigator.clipboard && window.isSecureContext) {
34+
await navigator.clipboard.writeText(text);
35+
return;
36+
}
37+
fallbackCopy(text);
38+
}
39+
40+
function addCopyButton(code) {
41+
const pre = code.closest("pre");
42+
if (!pre) {
43+
return;
44+
}
45+
46+
const parent = pre.parentElement;
47+
const host =
48+
parent && (parent.classList.contains("highlight") || parent.classList.contains("codehilite"))
49+
? parent
50+
: pre;
51+
if (host.classList.contains("x2py-copy-host")) {
52+
return;
53+
}
54+
55+
host.classList.add("x2py-copy-host");
56+
const button = document.createElement("button");
57+
button.type = "button";
58+
button.className = "x2py-code-copy";
59+
button.setAttribute("aria-label", "Copy code to clipboard");
60+
button.title = "Copy";
61+
button.innerHTML = copyIcon + copiedIcon;
62+
63+
let resetTimer;
64+
button.addEventListener("click", async function () {
65+
window.clearTimeout(resetTimer);
66+
button.disabled = true;
67+
try {
68+
await copyText(code.textContent);
69+
button.classList.add("is-copied");
70+
button.setAttribute("aria-label", "Copied to clipboard");
71+
button.title = "Copied";
72+
} catch (_error) {
73+
button.classList.add("is-error");
74+
button.setAttribute("aria-label", "Could not copy to clipboard");
75+
button.title = "Copy failed";
76+
} finally {
77+
button.disabled = false;
78+
resetTimer = window.setTimeout(function () {
79+
button.classList.remove("is-copied", "is-error");
80+
button.setAttribute("aria-label", "Copy code to clipboard");
81+
button.title = "Copy";
82+
}, 2000);
83+
}
84+
});
85+
86+
host.appendChild(button);
87+
}
88+
89+
function addCopyButtons() {
90+
document.querySelectorAll("pre code").forEach(addCopyButton);
91+
}
92+
93+
if (document.readyState === "loading") {
94+
document.addEventListener("DOMContentLoaded", addCopyButtons);
95+
} else {
96+
addCopyButtons();
97+
}
98+
})();

docs/maintainer/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,5 @@ Implementation orientation, source maps, feature workflows, tests, and
3535
contribution requirements remain in the separate
3636
[Developer documentation](../developer/index.md) lane.
3737

38-
The historical [old documentation archive](../old_docs) is retained for
39-
comparison only and is excluded from active navigation.
38+
The historical `docs/old_docs/` archive is retained for comparison only and is
39+
excluded from the website and active navigation.

docs/maintainer/documentation-architecture.md

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,22 @@ contains only pages explicitly marked as reviewed.
3131
7. User-facing source-driven examples show the complete input source before the
3232
command that consumes it. Generated paths must come from an immediately
3333
preceding command, and commands show their expected result.
34+
8. The website keeps its documentation navigation expanded and renders an
35+
accessible copy control on every code block, including command-output and
36+
result blocks.
37+
9. On desktop-sized viewports, the page body starts beside the navigation and
38+
uses a `1200px` maximum width: wider than the theme default for code and
39+
tables, but still bounded for readable prose. Any unused space remains on
40+
the far right rather than separating the sidebar from the content.
41+
10. Code and result blocks use a consistent responsive width capped at `56rem`.
42+
They reserve dedicated right-side space for the copy control, and long lines
43+
scroll inside the block instead of widening the page.
44+
45+
`docs/index.md` is the user-first project entrance. Its body introduces x2py,
46+
shows the shortest checked source-to-import workflow and its generated function
47+
docstring, and sends the reader into Getting Started. Developer, Maintainer,
48+
and deeper User Guide destinations stay available through site navigation
49+
instead of competing with that first task.
3450

3551
## Audience Lanes
3652

@@ -92,7 +108,10 @@ HTML, search, or the sitemap. When a reviewed index or overview mentions a
92108
draft page, the production build renders that page name as plain text until the
93109
target becomes publishable. Links to existing repository evidence outside the
94110
`docs/` tree are rewritten to the matching file or directory on GitHub; links
95-
to missing targets remain unchanged so the strict build can reject them.
111+
to missing targets remain unchanged so the strict build can reject them. Links
112+
to another active documentation page or directory must stay relative to
113+
`docs/` and resolve inside the website. The hook never rewrites a target inside
114+
`docs/` to GitHub.
96115

97116
Use the normal local server to preview exactly what GitHub Pages will publish:
98117

@@ -139,13 +158,19 @@ docs/
139158
internal-architecture/
140159
roadmap/
141160
CI and release policy
161+
javascripts/
162+
code-copy.js
163+
stylesheets/
164+
site.css
165+
code-copy.css
142166
old_docs/
143167
```
144168

145-
New active pages must be created in one of the three lanes. Do not restore
146-
top-level topic directories or place maintainer rules beside the website
147-
landing page. Historical `old_docs/` material is never eligible for website
148-
publication.
169+
New active pages must be created in one of the three lanes. Website-only static
170+
behavior and presentation assets live in `javascripts/` and `stylesheets/`.
171+
Do not restore top-level topic directories or place maintainer rules beside the
172+
website landing page. Historical `old_docs/` material is never eligible for
173+
website publication.
149174

150175
## Continuous Documentation Quality
151176

docs/stylesheets/code-copy.css

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
.x2py-copy-host {
2+
position: relative;
3+
}
4+
5+
.x2py-code-copy {
6+
position: absolute;
7+
z-index: 2;
8+
top: 0.45rem;
9+
right: 0.45rem;
10+
display: inline-flex;
11+
width: 2rem;
12+
height: 2rem;
13+
align-items: center;
14+
justify-content: center;
15+
padding: 0;
16+
color: #404040;
17+
background: rgb(255 255 255 / 92%);
18+
border: 1px solid #d6d6d6;
19+
border-radius: 0.2rem;
20+
cursor: pointer;
21+
opacity: 0.35;
22+
transition: color 0.15s ease, background-color 0.15s ease, opacity 0.15s ease;
23+
}
24+
25+
.x2py-copy-host:hover > .x2py-code-copy,
26+
.x2py-code-copy:focus-visible,
27+
.x2py-code-copy.is-copied,
28+
.x2py-code-copy.is-error {
29+
opacity: 1;
30+
}
31+
32+
.x2py-code-copy:hover {
33+
color: #ffffff;
34+
background: #2980b9;
35+
border-color: #2980b9;
36+
}
37+
38+
.x2py-code-copy:focus-visible {
39+
outline: 3px solid #f1c40f;
40+
outline-offset: 2px;
41+
}
42+
43+
.x2py-code-copy.is-copied {
44+
color: #ffffff;
45+
background: #27ae60;
46+
border-color: #27ae60;
47+
}
48+
49+
.x2py-code-copy.is-error {
50+
color: #ffffff;
51+
background: #c0392b;
52+
border-color: #c0392b;
53+
}
54+
55+
.x2py-code-copy svg {
56+
width: 1.1rem;
57+
height: 1.1rem;
58+
fill: none;
59+
stroke: currentcolor;
60+
stroke-linecap: round;
61+
stroke-linejoin: round;
62+
stroke-width: 2;
63+
}
64+
65+
.x2py-copied-icon,
66+
.x2py-code-copy.is-copied .x2py-copy-icon {
67+
display: none;
68+
}
69+
70+
.x2py-code-copy.is-copied .x2py-copied-icon {
71+
display: block;
72+
}
73+
74+
@media (hover: none) {
75+
.x2py-code-copy {
76+
opacity: 0.8;
77+
}
78+
}

docs/stylesheets/site.css

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
.wy-nav-content {
2+
max-width: 1200px;
3+
margin: 0;
4+
}
5+
6+
.rst-content pre {
7+
width: 100%;
8+
max-width: 56rem;
9+
padding-right: 3.25rem;
10+
}

docs/user/getting-started/beginner-workflow.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ audience: users
44
prerequisites: first wrapped module
55
related: ../tutorials/basic-wrapper.md, ../examples/verified-cookbook.md, ../reference/cli-commands.md
66
status: maintained
7-
publication: draft
7+
publication: reviewed
88
---
99

1010
# Common Beginner Workflow
@@ -15,7 +15,7 @@ into `build/`, run a small Python check, and cleanly rebuild when the native
1515
contract changes.
1616

1717
Use the `scale.f90` input from the
18-
[README Quick Start](../../../README.md#installation--quick-start). Keep the same filename when
18+
[homepage example](../../index.md#try-x2py). Keep the same filename when
1919
you move it into a project layout.
2020

2121
## 1. Create A Small Project Layout

0 commit comments

Comments
 (0)