Skip to content

Commit 09041c5

Browse files
committed
initial skeleton of inline content editor
1 parent 6212d08 commit 09041c5

14 files changed

Lines changed: 2027 additions & 24 deletions

lib/Yancy/Editor/src/app.svelte

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
<script lang="ts">
2+
import ContentTree from "./content-tree.svelte";
3+
import Toolbar from "./toolbar.svelte";
4+
</script>
5+
6+
<div class="yancy-editor">
7+
<nav class="yancy-accordion">
8+
<h2 id="content-tree-button">
9+
<button aria-controls="content-tree" aria-expanded="true">Content</button>
10+
</h2>
11+
<section
12+
id="content-tree"
13+
class="accordion-panel"
14+
aria-labelledby="content-tree-button"
15+
>
16+
<ContentTree></ContentTree>
17+
</section>
18+
<h2 id="database-button">
19+
<button aria-controls="database-list" aria-expanded="false"
20+
>Database</button
21+
>
22+
</h2>
23+
<ul id="database-list" class="accordion-panel" hidden></ul>
24+
</nav>
25+
<main>
26+
<div class="yancy-view">
27+
<Toolbar></Toolbar>
28+
<iframe id="content-view" src="/" title="Content View"></iframe>
29+
</div>
30+
</main>
31+
</div>
32+
33+
<style>
34+
:global(html, body, #app) {
35+
margin: 0;
36+
padding: 0;
37+
width: 100%;
38+
height: 100%;
39+
overflow: hidden;
40+
}
41+
.yancy-editor {
42+
display: flex;
43+
margin: 0;
44+
padding: 0;
45+
width: 100%;
46+
height: 100%;
47+
overflow: hidden;
48+
}
49+
.yancy-editor > nav {
50+
flex: 0 1 20%;
51+
}
52+
.yancy-editor > main {
53+
flex: 0 1 100%;
54+
overflow: hidden;
55+
}
56+
57+
.yancy-accordion {
58+
display: flex;
59+
flex-direction: column;
60+
overflow: hidden;
61+
border-right: 2px solid;
62+
}
63+
.yancy-accordion > h2 {
64+
margin: 0;
65+
padding: 0;
66+
}
67+
.yancy-accordion > h2 button {
68+
background: #ccc;
69+
color: hsl(0deg 0% 13%);
70+
display: block;
71+
font-size: 1rem;
72+
font-weight: normal;
73+
margin: 0;
74+
padding: 0.4em 1.5em;
75+
position: relative;
76+
text-align: left;
77+
width: 100%;
78+
outline: none;
79+
border: 2px outset;
80+
border-width: 2px 0;
81+
}
82+
.yancy-accordion > .accordion-panel {
83+
flex: 0 1 100%;
84+
}
85+
.yancy-accordion > .accordion-panel[hidden] {
86+
display: none;
87+
}
88+
89+
.yancy-view {
90+
width: 100%;
91+
height: 100%;
92+
display: flex;
93+
flex-direction: column;
94+
}
95+
#content-view {
96+
box-sizing: border-box;
97+
flex: 1 1 auto;
98+
width: 100%;
99+
}
100+
</style>
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<script lang="ts">
2+
import { onMount } from "svelte";
3+
4+
type YancyList<T> = {
5+
items: T[];
6+
offset: number;
7+
total: number;
8+
};
9+
type Page = {
10+
pattern: string;
11+
name: string;
12+
};
13+
14+
let pages: Page[];
15+
onMount(async () => {
16+
const res = await fetch("./api/pages");
17+
const list = (await res.json()) as YancyList<Page>;
18+
pages = list.items.sort((a, b) =>
19+
a.pattern < b.pattern ? -1 : a.pattern === b.pattern ? 0 : 1,
20+
);
21+
});
22+
23+
// XXX: Need to arrange the routes into a tree?
24+
</script>
25+
26+
<ul>
27+
{#each pages as page}
28+
<li><span>{page.pattern}</span> <span>{page.name}</span></li>
29+
{/each}
30+
</ul>
31+
32+
<style>
33+
ul {
34+
margin: 0;
35+
padding: 0;
36+
width: 100%;
37+
}
38+
li {
39+
margin: 0;
40+
padding: 0.2em 0.8em;
41+
display: flex;
42+
flex-flow: row wrap;
43+
justify-content: space-between;
44+
}
45+
</style>

lib/Yancy/Editor/src/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { mount } from "svelte";
2+
import App from "./app.svelte";
3+
4+
const app = mount(App, {
5+
target: document.querySelector("#app"),
6+
});
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<div class="toolbar"></div>
2+
3+
<style>
4+
.toolbar {
5+
width: 100%;
6+
height: 2em;
7+
color: black;
8+
background: #ccc;
9+
display: flex;
10+
align-items: center;
11+
margin: 0;
12+
padding: 0;
13+
border-bottom: 2px outset;
14+
}
15+
.toolbar > * {
16+
display: none;
17+
margin: 0.2em;
18+
}
19+
.toolbar > *.show {
20+
display: inline-block;
21+
}
22+
.toolbar + * {
23+
margin-top: 2em;
24+
}
25+
</style>

lib/Yancy/Plugin/Content.pm

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,29 +25,37 @@ sub register( $self, $app, @args ) {
2525

2626
$app->hook( before_dispatch => sub ($c) {
2727
# See if we have an override for this route and render that instead
28-
$app->log->debug('building routes for database pages');
28+
$c->log->debug('building routes for database pages');
2929
my $dbr = Mojolicious::Routes->new(
3030
map { $_ => $app->routes->$_ } qw(base_classes conditions namespaces shortcuts types),
3131
);
3232
my $res = $model->schema('pages')->list({ -not_bool => 'in_app' });
3333
for my $page ( sort { length $b->{pattern} <=> length $a->{pattern} } $res->{items}->@* ) {
34-
$app->log->debug('adding route for database page: ' . $page->{pattern});
35-
my $method = lc $page->{method};
36-
$dbr->$method($page->{pattern})->to(
37-
cb => sub ( $c ) {
38-
$c->render();
39-
},
40-
decode_json($page->{params} // '{}')->%*,
41-
title => $page->{title},
42-
template => $page->{template},
43-
);
34+
my %params = decode_json($page->{params} // '{}')->%*;
35+
if ($params{hidden}) {
36+
next;
37+
}
38+
$c->log->debug('adding route for database page: ' . $page->{pattern});
39+
my $method = lc $page->{method};
40+
$dbr->$method($page->{pattern})->to(
41+
cb => sub ( $c ) {
42+
$c->log->debug('rendering page from database' . $page->{pattern} . ' -- ' . $page->{template});
43+
$c->render();
44+
},
45+
title => $page->{title},
46+
template => $page->{template},
47+
);
4448
}
45-
$app->log->debug('attempting dispatch to database page');
46-
my $ok = $dbr->dispatch($c);
47-
$app->log->debug('dispatch to database page ' . ($ok ? 'success' : 'failed'));
49+
50+
my $ok = 0;
51+
local $@;
52+
eval {
53+
$c->log->debug('attempting dispatch to database page');
54+
$ok = $dbr->dispatch($c);
55+
};
56+
$c->log->debug('dispatch to database page ' . ($ok ? 'success' : 'failed') . ($@ ? " with error: " . ($@ =~ s{\n$}{}r) : ""));
4857
});
4958

50-
$app->helper( content => sub { $self } );
5159
$app->helper( block => sub ($c, $name, $attrs, $content=sub {}) {
5260
# Look up the block in the database
5361
my $res = $self->model->schema('blocks')->list({
@@ -87,14 +95,19 @@ sub init($self, $app) {
8795
if ( $db_route ) {
8896
delete $db_routes{ $name };
8997
next unless $db_route->{in_app};
98+
$self->log->debug('updating database page ' . $name . ': ' . $app_route->{pattern});
9099
$self->model->backend->set(pages => $name => $app_route);
91100
}
92101
else {
102+
$self->log->debug('creating database page ' . $name . ': ' . $app_route->{pattern});
93103
$self->model->backend->create(pages => $app_route);
94104
}
95105
}
96106
# Remaining database routes should be deleted
97-
$self->model->backend->delete( pages => $_->{name} ) for values %db_routes;
107+
for my $page ( values %db_routes ) {
108+
$self->log->debug('deleting database page ' . $page->{name} . ': ' . $page->{pattern});
109+
$self->model->backend->delete( pages => $page->{name} );
110+
}
98111
}
99112

100113
sub _walk_route($self, $parent, $prefix='') {

0 commit comments

Comments
 (0)