@rmdes/indiekit-endpoint-podroll 1.0.3 → 1.0.4

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/views/dashboard.njk +174 -29
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rmdes/indiekit-endpoint-podroll",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "Podcast roll endpoint for Indiekit. Aggregates podcast episodes from FreshRSS, displays on frontend with OPML sidebar.",
5
5
  "keywords": [
6
6
  "indiekit",
@@ -1,83 +1,228 @@
1
1
  {% extends "document.njk" %}
2
2
 
3
3
  {% block content %}
4
+ <style>
5
+ .pr-dashboard {
6
+ display: flex;
7
+ flex-direction: column;
8
+ gap: var(--space-xl, 2rem);
9
+ }
10
+
11
+ .pr-section {
12
+ background: var(--color-offset, #f5f5f5);
13
+ border-radius: var(--border-radius-small, 0.5rem);
14
+ padding: var(--space-m, 1.5rem);
15
+ }
16
+
17
+ .pr-section h2 {
18
+ font: var(--font-heading, bold 1.25rem/1.4 sans-serif);
19
+ margin-block-end: var(--space-s, 0.75rem);
20
+ padding-block-end: var(--space-xs, 0.5rem);
21
+ border-block-end: 1px solid var(--color-outline-variant, #ddd);
22
+ }
23
+
24
+ .pr-section p.pr-hint {
25
+ color: var(--color-on-offset, #666);
26
+ font: var(--font-caption, 0.875rem/1.4 sans-serif);
27
+ margin-block-end: var(--space-m, 1rem);
28
+ }
29
+
30
+ .pr-stats-grid {
31
+ display: grid;
32
+ grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
33
+ gap: var(--space-s, 0.75rem);
34
+ }
35
+
36
+ .pr-stat {
37
+ background: var(--color-background, #fff);
38
+ border-radius: var(--border-radius-small, 0.5rem);
39
+ padding: var(--space-s, 0.75rem);
40
+ text-align: center;
41
+ }
42
+
43
+ .pr-stat dt {
44
+ color: var(--color-on-offset, #666);
45
+ font: var(--font-caption, 0.875rem/1.4 sans-serif);
46
+ margin-block-end: var(--space-2xs, 0.25rem);
47
+ }
48
+
49
+ .pr-stat dd {
50
+ font: var(--font-subhead, bold 1.125rem/1.4 sans-serif);
51
+ margin: 0;
52
+ }
53
+
54
+ .pr-form {
55
+ display: flex;
56
+ flex-direction: column;
57
+ gap: var(--space-m, 1rem);
58
+ }
59
+
60
+ .pr-field {
61
+ display: flex;
62
+ flex-direction: column;
63
+ gap: var(--space-2xs, 0.25rem);
64
+ }
65
+
66
+ .pr-field label {
67
+ font: var(--font-label, bold 0.875rem/1.4 sans-serif);
68
+ }
69
+
70
+ .pr-field .pr-field-hint {
71
+ color: var(--color-on-offset, #666);
72
+ font: var(--font-caption, 0.875rem/1.4 sans-serif);
73
+ }
74
+
75
+ .pr-field input {
76
+ appearance: none;
77
+ background-color: var(--color-background, #fff);
78
+ border: 1px solid var(--color-outline-variant, #ccc);
79
+ border-radius: var(--border-radius-small, 0.25rem);
80
+ font: var(--font-body, 0.875rem/1.4 sans-serif);
81
+ padding: calc(var(--space-s, 0.75rem) / 2) var(--space-s, 0.75rem);
82
+ width: 100%;
83
+ }
84
+
85
+ .pr-field input:focus {
86
+ border-color: var(--color-primary, #0066cc);
87
+ outline: 2px solid var(--color-primary, #0066cc);
88
+ outline-offset: 1px;
89
+ }
90
+
91
+ .pr-field-static {
92
+ display: flex;
93
+ justify-content: space-between;
94
+ align-items: baseline;
95
+ padding: calc(var(--space-s, 0.75rem) / 2) 0;
96
+ border-block-start: 1px solid var(--color-outline-variant, #eee);
97
+ }
98
+
99
+ .pr-field-static dt {
100
+ color: var(--color-on-offset, #666);
101
+ font: var(--font-caption, 0.875rem/1.4 sans-serif);
102
+ }
103
+
104
+ .pr-field-static dd {
105
+ margin: 0;
106
+ font: var(--font-body, 0.875rem/1.4 sans-serif);
107
+ }
108
+
109
+ .pr-api-list {
110
+ list-style: none;
111
+ padding: 0;
112
+ margin: 0;
113
+ display: flex;
114
+ flex-direction: column;
115
+ gap: var(--space-xs, 0.5rem);
116
+ }
117
+
118
+ .pr-api-list li {
119
+ background: var(--color-background, #fff);
120
+ border-radius: var(--border-radius-small, 0.25rem);
121
+ padding: var(--space-xs, 0.5rem) var(--space-s, 0.75rem);
122
+ font: var(--font-caption, 0.875rem/1.4 sans-serif);
123
+ }
124
+
125
+ .pr-api-list code {
126
+ font-weight: 600;
127
+ color: var(--color-primary, #0066cc);
128
+ }
129
+
130
+ .pr-notification {
131
+ border-radius: var(--border-radius-small, 0.25rem);
132
+ padding: var(--space-s, 0.75rem) var(--space-m, 1rem);
133
+ margin-block-end: var(--space-s, 0.75rem);
134
+ }
135
+
136
+ .pr-notification--success {
137
+ background: var(--color-success, #d4edda);
138
+ color: var(--color-on-success, #155724);
139
+ }
140
+
141
+ .pr-notification--error {
142
+ background: var(--color-error, #f8d7da);
143
+ color: var(--color-on-error, #721c24);
144
+ }
145
+ </style>
146
+
4
147
  <header class="page-header">
5
148
  <h1 class="page-header__title">{{ __("podroll.title") }}</h1>
6
149
  <p class="page-header__description">{{ __("podroll.description") }}</p>
7
150
  </header>
8
151
 
9
152
  {% if request.query.synced %}
10
- <div class="notification notification--success">
153
+ <div class="pr-notification pr-notification--success">
11
154
  {{ __("podroll.syncSuccess") }}
12
155
  </div>
13
156
  {% endif %}
14
157
 
15
158
  {% if request.query.cleared %}
16
- <div class="notification notification--success">
159
+ <div class="pr-notification pr-notification--success">
17
160
  {{ __("podroll.clearSuccess") }}
18
161
  </div>
19
162
  {% endif %}
20
163
 
21
164
  {% if request.query.saved %}
22
- <div class="notification notification--success">
165
+ <div class="pr-notification pr-notification--success">
23
166
  {{ __("podroll.settingsSaved") }}
24
167
  </div>
25
168
  {% endif %}
26
169
 
27
170
  {% if request.query.error %}
28
- <div class="notification notification--error">
171
+ <div class="pr-notification pr-notification--error">
29
172
  {{ __("podroll.syncError") }}: {{ request.query.error }}
30
173
  </div>
31
174
  {% endif %}
32
175
 
33
- <div class="dashboard">
34
- <section class="dashboard__section">
176
+ <div class="pr-dashboard">
177
+ <section class="pr-section">
35
178
  <h2>{{ __("podroll.stats") }}</h2>
36
- <dl class="definition-list">
37
- <div class="definition-list__item">
179
+ <dl class="pr-stats-grid">
180
+ <div class="pr-stat">
38
181
  <dt>{{ __("podroll.episodeCount") }}</dt>
39
182
  <dd>{{ stats.episodeCount }}</dd>
40
183
  </div>
41
- <div class="definition-list__item">
184
+ <div class="pr-stat">
42
185
  <dt>{{ __("podroll.sourceCount") }}</dt>
43
186
  <dd>{{ stats.sourceCount }}</dd>
44
187
  </div>
45
- <div class="definition-list__item">
188
+ <div class="pr-stat">
46
189
  <dt>{{ __("podroll.lastEpisodesSync") }}</dt>
47
190
  <dd>{{ stats.lastEpisodesSync | date("PPpp") if stats.lastEpisodesSync else __("podroll.never") }}</dd>
48
191
  </div>
49
- <div class="definition-list__item">
192
+ <div class="pr-stat">
50
193
  <dt>{{ __("podroll.lastSourcesSync") }}</dt>
51
194
  <dd>{{ stats.lastSourcesSync | date("PPpp") if stats.lastSourcesSync else __("podroll.never") }}</dd>
52
195
  </div>
53
196
  </dl>
54
197
  </section>
55
198
 
56
- <section class="dashboard__section">
199
+ <section class="pr-section">
57
200
  <h2>{{ __("podroll.configuration") }}</h2>
58
- <p class="hint">{{ __("podroll.configurationHelp") }}</p>
59
- <form method="post" action="{{ application.podrollEndpoint }}/settings">
60
- <div class="field">
61
- <label class="field__label" for="episodesUrl">{{ __("podroll.episodesUrl") }}</label>
62
- <p class="field__hint" id="episodesUrl-hint">{{ __("podroll.episodesUrlHelp") }}</p>
63
- <input class="field__input" type="url" id="episodesUrl" name="episodesUrl" value="{{ config.episodesUrl }}" aria-describedby="episodesUrl-hint" placeholder="https://...">
201
+ <p class="pr-hint">{{ __("podroll.configurationHelp") }}</p>
202
+ <form method="post" action="{{ application.podrollEndpoint }}/settings" class="pr-form">
203
+ <div class="pr-field">
204
+ <label for="episodesUrl">{{ __("podroll.episodesUrl") }}</label>
205
+ <span class="pr-field-hint" id="episodesUrl-hint">{{ __("podroll.episodesUrlHelp") }}</span>
206
+ <input type="url" id="episodesUrl" name="episodesUrl" value="{{ config.episodesUrl }}" aria-describedby="episodesUrl-hint" placeholder="https://...">
64
207
  </div>
65
- <div class="field">
66
- <label class="field__label" for="opmlUrl">{{ __("podroll.opmlUrl") }}</label>
67
- <p class="field__hint" id="opmlUrl-hint">{{ __("podroll.opmlUrlHelp") }}</p>
68
- <input class="field__input" type="url" id="opmlUrl" name="opmlUrl" value="{{ config.opmlUrl }}" aria-describedby="opmlUrl-hint" placeholder="https://...">
208
+ <div class="pr-field">
209
+ <label for="opmlUrl">{{ __("podroll.opmlUrl") }}</label>
210
+ <span class="pr-field-hint" id="opmlUrl-hint">{{ __("podroll.opmlUrlHelp") }}</span>
211
+ <input type="url" id="opmlUrl" name="opmlUrl" value="{{ config.opmlUrl }}" aria-describedby="opmlUrl-hint" placeholder="https://...">
69
212
  </div>
70
- <div class="field">
213
+ <dl class="pr-field-static">
71
214
  <dt>{{ __("podroll.syncInterval") }}</dt>
72
215
  <dd>{{ (config.syncInterval / 60000) | round }} {{ __("podroll.minutes") }}</dd>
216
+ </dl>
217
+ <div>
218
+ <button type="submit" class="button button--primary">
219
+ {{ __("podroll.saveSettings") }}
220
+ </button>
73
221
  </div>
74
- <button type="submit" class="button button--primary">
75
- {{ __("podroll.saveSettings") }}
76
- </button>
77
222
  </form>
78
223
  </section>
79
224
 
80
- <section class="dashboard__section">
225
+ <section class="pr-section">
81
226
  <h2>{{ __("podroll.actions") }}</h2>
82
227
  <div class="button-group">
83
228
  <form method="post" action="{{ application.podrollEndpoint }}/sync" style="display: inline;">
@@ -93,9 +238,9 @@
93
238
  </div>
94
239
  </section>
95
240
 
96
- <section class="dashboard__section">
241
+ <section class="pr-section">
97
242
  <h2>{{ __("podroll.apiEndpoints") }}</h2>
98
- <ul class="api-list">
243
+ <ul class="pr-api-list">
99
244
  <li><code>GET {{ application.podrollEndpoint }}/api/episodes</code> - {{ __("podroll.apiEpisodes") }}</li>
100
245
  <li><code>GET {{ application.podrollEndpoint }}/api/sources</code> - {{ __("podroll.apiSources") }}</li>
101
246
  <li><code>GET {{ application.podrollEndpoint }}/api/status</code> - {{ __("podroll.apiStatus") }}</li>