Skip to content

Commit

Permalink
Merge pull request #68 from pyscript/pe-linked-files
Browse files Browse the repository at this point in the history
Show the code for examples
  • Loading branch information
pauleveritt authored Nov 20, 2022
2 parents 22768b8 + b1c2889 commit 73c2d80
Show file tree
Hide file tree
Showing 13 changed files with 301 additions and 17 deletions.
20 changes: 20 additions & 0 deletions src/psc/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,25 @@ async def example(request: Request) -> _TemplateResponse:
)


async def example_code(request: Request) -> _TemplateResponse:
"""Handle the linked files for the code example."""
example_name = request.path_params["example_name"]
resources: Resources = request.app.state.resources
this_example = resources.examples[example_name]
root_path = "../../.."

return templates.TemplateResponse(
"example_code.jinja2",
dict(
title=f"{this_example.title} Code",
extra_head=this_example.extra_head,
request=request,
root_path=root_path,
linked_files=this_example.linked_files,
),
)


async def content_page(request: Request) -> _TemplateResponse:
"""Handle a content page."""
page_name = request.path_params["page_name"]
Expand Down Expand Up @@ -159,6 +178,7 @@ async def content_page(request: Request) -> _TemplateResponse:
Route("/authors", authors),
Route("/authors/{author_name}.html", author),
Route("/gallery/examples/{example_name}/index.html", example),
Route("/gallery/examples/{example_name}/code.html", example_code),
Route("/gallery/examples/{example_name}/", example),
Route("/pages/{page_name}.html", content_page),
Mount("/gallery", StaticFiles(directory=HERE / "gallery")),
Expand Down
2 changes: 2 additions & 0 deletions src/psc/gallery/examples/antigravity/index.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
---
title: xkcd Antigravity
subtitle: We can fly!
linked_files:
- antigravity.py
---
Based on the [xkcd antigravity](https://xkcd.com/353/)
1 change: 1 addition & 0 deletions src/psc/gallery/examples/hello_world/hello_world.css
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
h1 {
font-weight: normal;
}
3 changes: 3 additions & 0 deletions src/psc/gallery/examples/hello_world/index.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
---
title: Hello World
subtitle: The classic hello world, but in Python -- in a browser!
linked_files:
- hello_world.css
- hello_world.js
---
The *body* description.
4 changes: 4 additions & 0 deletions src/psc/gallery/examples/hello_world_py/index.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
---
title: Hello World Python
subtitle: The hello world example, but in a .py file.
linked_files:
- hello_world.py
- hello_world.css
- hello_world.js
---
The *body* description.
3 changes: 3 additions & 0 deletions src/psc/gallery/examples/interest_calculator/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,8 @@
title: Compound Interest Calculator
subtitle: Enter some numbers, get some numbers.
author: meg-1
linked_files:
- calculator.py
- styles.css
---
The *body* description.
42 changes: 37 additions & 5 deletions src/psc/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,28 @@ class Resource:
extra_head: str = ""


linked_file_mapping = dict(
py="python",
css="css",
html="html",
js="javascript",
)


@dataclass
class LinkedFile:
"""A source file on disk that gets attached to an example."""

path: Path
language: str = field(init=False)
body: str = field(init=False)

def __post_init__(self) -> None:
"""Read the file contents into the body."""
self.language = linked_file_mapping[self.path.suffix[1:]]
self.body = self.path.read_text()


@dataclass
class Example(Resource):
"""Create an example from an HTML location on disk.
Expand All @@ -91,9 +113,10 @@ class Example(Resource):
Meaning, HERE / "examples" / name / "index.html".
"""

subtitle: str = ""
description: str = ""
author: str | None = None
subtitle: str = field(init=False)
description: str = field(init=False)
author: str = field(init=False)
linked_files: list[LinkedFile] = field(default_factory=list)

def __post_init__(self) -> None:
"""Extract most of the data from the HTML file."""
Expand All @@ -107,13 +130,22 @@ def __post_init__(self) -> None:
self.description = str(md.render(md_fm.content))

# Main, extra head example's HTML file.
index_html_file = HERE / "gallery/examples" / self.name / "index.html"
this_example_path = HERE / "gallery/examples" / self.name
index_html_file = this_example_path / "index.html"
if not index_html_file.exists(): # pragma: nocover
raise ValueError(f"No example at {self.name}")
soup = BeautifulSoup(index_html_file.read_text(), "html5lib")
index_html_text = index_html_file.read_text()
soup = BeautifulSoup(index_html_text, "html5lib")
self.extra_head = get_head_nodes(soup)
self.body = get_body_content(soup)

# Process any linked files
linked_paths = [*["index.html"], *md_fm.get("linked_files", [])]
for linked_name in linked_paths:
linked_path = this_example_path / linked_name
linked_file = LinkedFile(path=linked_path)
self.linked_files.append(linked_file)


@dataclass
class Author(Resource):
Expand Down
160 changes: 160 additions & 0 deletions src/psc/static/prism.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
/* PrismJS 1.29.0
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript+python&plugins=custom-class+toolbar+copy-to-clipboard+download-button */
code[class*=language-], pre[class*=language-] {
color: #000;
background: 0 0;
text-shadow: 0 1px #fff;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
font-size: 1em;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none
}

code[class*=language-] ::-moz-selection, code[class*=language-]::-moz-selection, pre[class*=language-] ::-moz-selection, pre[class*=language-]::-moz-selection {
text-shadow: none;
background: #b3d4fc
}

code[class*=language-] ::selection, code[class*=language-]::selection, pre[class*=language-] ::selection, pre[class*=language-]::selection {
text-shadow: none;
background: #b3d4fc
}

@media print {
code[class*=language-], pre[class*=language-] {
text-shadow: none
}
}

pre[class*=language-] {
padding: 1em;
margin: .5em 0;
overflow: auto
}

:not(pre) > code[class*=language-], pre[class*=language-] {
background: #f5f2f0
}

:not(pre) > code[class*=language-] {
padding: .1em;
border-radius: .3em;
white-space: normal
}

.prism--token.prism--cdata, .prism--token.prism--comment, .prism--token.prism--doctype, .prism--token.prism--prolog {
color: #708090
}

.prism--token.prism--punctuation {
color: #999
}

.prism--token.prism--namespace {
opacity: .7
}

.prism--token.prism--boolean, .prism--token.prism--constant, .prism--token.prism--deleted, .prism--token.prism--number, .prism--token.prism--property, .prism--token.prism--symbol, .prism--token.prism--tag {
color: #905
}

.prism--token.prism--attr-name, .prism--token.prism--builtin, .prism--token.prism--char, .prism--token.prism--inserted, .prism--token.prism--selector, .prism--token.prism--string {
color: #690
}

.language-css .prism--token.prism--string, .style .prism--token.prism--string, .prism--token.prism--entity, .prism--token.prism--operator, .prism--token.prism--url {
color: #9a6e3a;
background: hsla(0, 0%, 100%, .5)
}

.prism--token.prism--atrule, .prism--token.prism--attr-value, .prism--token.prism--keyword {
color: #07a
}

.prism--token.prism--class-name, .prism--token.prism--function {
color: #dd4a68
}

.prism--token.prism--important, .prism--token.prism--regex, .prism--token.prism--variable {
color: #e90
}

.prism--token.prism--bold, .prism--token.prism--important {
font-weight: 700
}

.prism--token.prism--italic {
font-style: italic
}

.prism--token.prism--entity {
cursor: help
}

div.code-toolbar {
position: relative
}

div.code-toolbar > .toolbar {
position: absolute;
z-index: 10;
top: .3em;
right: .2em;
transition: opacity .3s ease-in-out;
opacity: 0
}

div.code-toolbar:hover > .toolbar {
opacity: 1
}

div.code-toolbar:focus-within > .toolbar {
opacity: 1
}

div.code-toolbar > .toolbar > .toolbar-item {
display: inline-block
}

div.code-toolbar > .toolbar > .toolbar-item > a {
cursor: pointer
}

div.code-toolbar > .toolbar > .toolbar-item > button {
background: 0 0;
border: 0;
color: inherit;
font: inherit;
line-height: normal;
overflow: visible;
padding: 0;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none
}

div.code-toolbar > .toolbar > .toolbar-item > a, div.code-toolbar > .toolbar > .toolbar-item > button, div.code-toolbar > .toolbar > .toolbar-item > span {
color: #bbb;
font-size: .8em;
padding: 0 .5em;
background: #f5f2f0;
background: rgba(224, 224, 224, .2);
box-shadow: 0 2px 0 0 rgba(0, 0, 0, .2);
border-radius: .5em
}

div.code-toolbar > .toolbar > .toolbar-item > a:focus, div.code-toolbar > .toolbar > .toolbar-item > a:hover, div.code-toolbar > .toolbar > .toolbar-item > button:focus, div.code-toolbar > .toolbar > .toolbar-item > button:hover, div.code-toolbar > .toolbar > .toolbar-item > span:focus, div.code-toolbar > .toolbar > .toolbar-item > span:hover {
color: inherit;
text-decoration: none
}
Loading

0 comments on commit 73c2d80

Please sign in to comment.