Author:
Hash:
Timestamp:
+1362 -445 +/-46 browse
Kevin Schoon [me@kevinschoon.com]
bbdaa91e2b03edc1787595657c186f28b23d5cd2
Tue, 17 Jun 2025 12:33:59 +0000 (1 week ago)
1 | diff --git a/README.md b/README.md |
2 | index cd3da6e..d9b5f78 100644 |
3 | --- a/README.md |
4 | +++ b/README.md |
5 | @@ -1,451 +1,14 @@ |
6 | - # ForgeFeed |
7 | + # Public Website of [forge-feed.org](https://forge-feed.org) |
8 | |
9 | - *NOTE: This specification is a W.I.P and should not yet be implemented |
10 | - anywhere.* |
11 | + ## Usage |
12 | |
13 | - ForgeFeed is a collection of specifications and recommendations which when |
14 | - implemented can enhance interoperability and content discovery of different |
15 | - [code forges](https://en.wikipedia.org/wiki/Forge_(software)) |
16 | - across the internet. |
17 | + You'll need to install [zola](https://www.getzola.org). |
18 | |
19 | - Below we cover the following specifications: |
20 | - |
21 | - Repository URI - URI Identifier for WebFinger Queries |
22 | - WebFinger Query - Metadata Queries via WebFinger |
23 | - RSS Specification - Repository Discovery via RSS |
24 | - |
25 | - |
26 | - ## Repository URI |
27 | - |
28 | - A repository URI identifies a code repository and optionally the host that is |
29 | - resides on. This value is similar to |
30 | - [RFC7565](https://datatracker.ietf.org/doc/html/rfc7565). The slug and hostname |
31 | - part MUST match the URI path specification as defined in |
32 | - [RFC3986-3.3](https://www.rfc-editor.org/rfc/rfc3986#section-3.3) while the |
33 | - hostname, if specified, must match |
34 | - [RFC3986-3.2.2](https://www.rfc-editor.org/rfc/rfc3986#section-3.2.2) |
35 | - |
36 | - repository-uri = prefix slug hostname |
37 | - |
38 | - prefix = "repository:" |
39 | - slug = rfc3986-path |
40 | - hostname = [@ rfc3986-hostname] |
41 | - |
42 | - ### Slug |
43 | - |
44 | - The Slug represents a unique string that identifies a repository at a |
45 | - particular code forge. Repository refers to a VCS managed codebase of some |
46 | - kind, e.g. a Git repository. |
47 | - |
48 | - ### Hostname |
49 | - |
50 | - If the hostname part is missing then the address of the server receiving the |
51 | - query is assumed. For example the following two queries are equivalent: |
52 | - |
53 | - ```text |
54 | - https://example.org/.well-known/webfinger?resource=repository:example/spartacus |
55 | - https://example.org/.well-known/webfinger?resource=repository:example/spartacus@example.org |
56 | - ``` |
57 | - |
58 | - TODO: Make this an actual spec, for now, some Python: |
59 | - |
60 | - ```python |
61 | - from urllib.parse import urlparse, quote_plus |
62 | - |
63 | - def from_string(text): |
64 | - url = urlparse(text) |
65 | - if not url.path: |
66 | - return (None, None) |
67 | - split = url.path.split("@", 1) |
68 | - if len(split) == 2: |
69 | - return (split[0], split[1]) |
70 | - return (split[0], None) |
71 | - |
72 | - def to_string(slug, domain=None): |
73 | - if domain: |
74 | - return quote_plus(f"repository:{slug}@{domain}") |
75 | - else: |
76 | - return quote_plus(f"repository:{slug}") |
77 | - ``` |
78 | - |
79 | - |
80 | - ## WebFinger Query |
81 | - |
82 | - A [WebFinger](https://webfinger.net/spec/) query may be used to identify |
83 | - detailed information about a public repository at a particular forge. Here is |
84 | - an example response about a fictitious repository: |
85 | - |
86 | - `GET https://example.org/.well-known/webfinger?resource=repository:example/spartacus` |
87 | - |
88 | - ```json |
89 | - { |
90 | - "subject": "repository:example/spartacus", |
91 | - "aliases": [ |
92 | - "https://example.org/example/spartacus" |
93 | - ], |
94 | - "links": [ |
95 | - { |
96 | - "rel": "http://webfinger.net/rel/avatar", |
97 | - "href": "https://example.org/stylized-logo.png" |
98 | - }, |
99 | - { |
100 | - "rel": "http://forge-feed.org/rel/description", |
101 | - "titles": { |
102 | - "en-us": "A Text Adventure Written in FORTRAN 77", |
103 | - "es": "Una Aventura de Texto Escrita en FORTRAN 77" |
104 | - } |
105 | - }, |
106 | - { |
107 | - "rel": "http://feed-forge.org/rel/clone", |
108 | - "href": "https://example.org/example/spartacus", |
109 | - "properties": { |
110 | - "http://feed-forge.org/ns/vcs-type": "git" |
111 | - } |
112 | - }, |
113 | - { |
114 | - "rel": "http://forge-feed.org/rel/license", |
115 | - "href": "https://example.com/example/spartacus/tree/LICENSE", |
116 | - "properties": { |
117 | - "spdx-identifier": "GPL-2.0-or-later" |
118 | - } |
119 | - }, |
120 | - { |
121 | - "rel": "http://forge-feed.org/rel/chatroom", |
122 | - "href": "ircs://irc.libera.chat/#spartacus-game" |
123 | - "properties": { |
124 | - "http://feed-forge.org/ns/chatroom": "irc" |
125 | - } |
126 | - }, |
127 | - { |
128 | - "rel": "http://forge-feed.org/rel/label", |
129 | - "properties": { |
130 | - "http://feed-forge.org/ns/label": "fortran" |
131 | - } |
132 | - }, |
133 | - { |
134 | - "rel": "http://forge-feed.org/rel/label", |
135 | - "properties": { |
136 | - "http://feed-forge.org/ns/label": "text-adventure" |
137 | - } |
138 | - } |
139 | - ] |
140 | - } |
141 | - ``` |
142 | - |
143 | - ### Properties |
144 | - |
145 | - #### http://feed-forge.org/ns/vcs-type |
146 | - |
147 | - Identifies VCS types, valid strings are: |
148 | - |
149 | - bzr (GNU Bazaar) bazaar.canonical.com |
150 | - darcs (Darcs) darcs.net |
151 | - fossil (Fossil) fossil-scm.org |
152 | - git (Git) git-scm.com |
153 | - hg (Mercurial) mercurial-scm.org |
154 | - pijul (Pijul) pijul.org |
155 | - svn (Apache Subversion) subversion.apache.org |
156 | - |
157 | - #### http://feed-forge.org/ns/chatroom |
158 | - |
159 | - Hint describing the backing type of chatroom. See [uri-schemes](https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml). |
160 | - |
161 | - matrix |
162 | - irc |
163 | - xmpp |
164 | - |
165 | - #### http://feed-forge.org/ns/spdx-identifier |
166 | - |
167 | - Refers to a valid SPDX identifier, see [license-list](https://spdx.org/licenses/) |
168 | - |
169 | - ### Link Extension Types |
170 | - |
171 | - #### Avatar |
172 | - |
173 | - Forges that allow users to configure a logo can expose this information as |
174 | - an avatar for use in other applications. |
175 | - |
176 | - ```json |
177 | - { |
178 | - "rel": "http://webfinger.net/rel/avatar", |
179 | - "href": "https://example.org/stylized-logo.png" |
180 | - } |
181 | - ``` |
182 | - |
183 | - #### Homepage |
184 | - |
185 | - Link to an HTTP representation of the project codebase |
186 | - |
187 | - ```json |
188 | - { |
189 | - "rel": "http://feed-forge.org/rel/homepage", |
190 | - "href": "https://example.org/example/spartacus" |
191 | - } |
192 | - ``` |
193 | - |
194 | - #### Description |
195 | - |
196 | - A short text representation of the repository. |
197 | - |
198 | - ```json |
199 | - { |
200 | - "rel": "http://example.org/rel/description", |
201 | - "titles": { |
202 | - "en-us": "A Text Adventure Written in FORTRAN 77", |
203 | - "es": "Una Aventura de Texto Escrita en FORTRAN 77" |
204 | - } |
205 | - } |
206 | - ``` |
207 | - |
208 | - #### License |
209 | - |
210 | - A license SPDX identifier and link to the license's full text. |
211 | - |
212 | - ```json |
213 | - { |
214 | - "rel": "http://feed-forge.org/rel/license", |
215 | - "href": "https://example.com/example/spartacus/tree/LICENSE", |
216 | - "properties": { |
217 | - "http://feed-forge.org/ns/spdx-identifier": "GPL-2.0-or-later" |
218 | - } |
219 | - } |
220 | - ``` |
221 | - |
222 | - ### Clone Links |
223 | - |
224 | - Clone links define how one can download a copy of the remote |
225 | - software onto their own server. |
226 | - |
227 | - ```json |
228 | - { |
229 | - "rel": "http://feed-forge.org/rel/clone", |
230 | - "href": "https://example.org/example/spartacus", |
231 | - "properties": { |
232 | - "http://feed-forge.org/ns/vcs-type": "git" |
233 | - } |
234 | - } |
235 | + ```sh |
236 | + zola serve |
237 | ``` |
238 | |
239 | - #### Chat Links |
240 | - |
241 | - Links to chatrooms: IRC, Matrix, XMPP, etc. |
242 | - |
243 | - ```json |
244 | - { |
245 | - "rel": "http://feed-forge.org/rel/chatroom", |
246 | - "href": "ircs://irc.libera.chat/#spartacus-game" |
247 | - "properties": { |
248 | - "http://feed-forge.org/ns/chatroom": "irc" |
249 | - } |
250 | - }, |
251 | - { |
252 | - "rel": "http://feed-forge.org/rel/chatroom", |
253 | - "href": "matrix:r/spartacus-game#example.org", |
254 | - "properties": { |
255 | - "http://feed-forge.org/ns/chatroom": "matrix" |
256 | - } |
257 | - }, |
258 | - { |
259 | - "rel": "http://feed-forge.org/rel/chatroom", |
260 | - "href": "xmpp:example.org/spartacus-game", |
261 | - "properties": { |
262 | - "http://feed-forge.org/ns/chatroom": "xmpp" |
263 | - } |
264 | - } |
265 | - ``` |
266 | - |
267 | - #### Mailing Lists |
268 | - |
269 | - Links to associated mailing lists, forms, etc. |
270 | - |
271 | - ```json |
272 | - { |
273 | - "rel": "http://feed-forge.org/rel/mailing-list", |
274 | - "href": "mailto://list-name@mail.example.org", |
275 | - "properties": { |
276 | - "http://feed-forge.org/ns/mailing-list-subscribe": "mailto://subscribe+list-name@mail.example.org", |
277 | - "http://feed-forge.org/ns/mailing-list-unsubscribe": "mailto://unsubscribe+list-name@mail.example.org" |
278 | - } |
279 | - } |
280 | - ``` |
281 | - |
282 | - |
283 | - #### Free-Form Tags |
284 | - |
285 | - Arbitrary, free-form tags. |
286 | - |
287 | - ```json |
288 | - { |
289 | - "rel": "http://example.org/rel/label", |
290 | - "properties": { |
291 | - "http://feed-forge.org/ns/label": "fortran" |
292 | - } |
293 | - }, |
294 | - { |
295 | - "rel": "http://example.org/rel/label", |
296 | - "properties": { |
297 | - "label": "text-adventure" |
298 | - } |
299 | - } |
300 | - ``` |
301 | - |
302 | - ### Security |
303 | - |
304 | - Repositories which are not publicly available should not be identifiable by |
305 | - making webfinger queries at all. A repository which is private MUST return |
306 | - the same response as a repository which does not exist when making a webfinger |
307 | - request. |
308 | - |
309 | - GET https://example.org/.well-known/webfinger?resource=repository:example/spartacus |
310 | - 200 |
311 | - GET https://example.org/.well-known/webfinger?resource=repository:example/private-repository |
312 | - 404 |
313 | - GET https://example.org/.well-known/webfinger?resource=repository:example/non-existent-repository |
314 | - 404 |
315 | - |
316 | - # RSS Feeds |
317 | - |
318 | - Your forge needs to expose an RSS feed in order for other peers to determine |
319 | - what code repositories exist in your server. Your server should expose |
320 | - repositories ordered by recent updates. The heuristic you use to determine |
321 | - "recently updated" depends on your forge. The simplest way to determine recent |
322 | - activity is likely by your VCS's concept of a "commit". |
323 | - |
324 | - ## Determine if a Host Supports Forge Feed |
325 | - |
326 | - In order to participate in ForgeFeed your forge MUST present an HTML link |
327 | - element such as below at the root domain of your forge. For example, |
328 | - `code.example.org` MUST have a link element present in it's html header: |
329 | - |
330 | - ```html |
331 | - <html> |
332 | - <head> |
333 | - <title>My Forge</title> |
334 | - <link |
335 | - rel="alternate" |
336 | - type="application/rss+xml" |
337 | - title="Recent Forge Activity" |
338 | - href="https://code.example.org/firehose.xml" /> |
339 | - <!-- index-url refers to the RSS link on the current webpage which contains forge updates --> |
340 | - <meta name="forge-feed:index-url" content="https://code.example.org/firehose.xml"/> |
341 | - </head> |
342 | - <body> |
343 | - ... |
344 | - </body> |
345 | - </html> |
346 | - ``` |
347 | - |
348 | - The link MAY have a title of "Recent Forge Activity" such that it uniquely |
349 | - identifies this feed as being related to forge updates. A server MUST provide a |
350 | - meta tag with the name forge-feed:index where the content of the tag matches |
351 | - the href of an RSS link listed on this page which should be used for indexing |
352 | - by external crawlers. Applications which rely on the forge-feed:index meta |
353 | - tag MUST stop crawling the serving website if this tag is no longer present |
354 | - in the pages HTML. |
355 | - |
356 | - ### An example Feed |
357 | - |
358 | - Below is an example RSS feed with an optional repository section (described |
359 | - below). |
360 | - |
361 | - ```xml |
362 | - <?xml version="1.0" encoding="utf-8"?> |
363 | - <rss version="2.0"> |
364 | - <channel> |
365 | - <title>Firehose</title> |
366 | - <link>https://code.example.org/browse</link> |
367 | - <description>Recent Activity @ code.example.org</description> |
368 | - <lastBuildDate>Tue, 03 Jun 2025 14:18:48 +0000</lastBuildDate> |
369 | - <ttl>60</ttl> |
370 | - <item> |
371 | - <title>Spartacus</title> |
372 | - <description>A Text Adventure Written in FORTRAN 77<description/> |
373 | - <author>admin@example.org (Administrator)</author> |
374 | - <!-- Link to an HTTP representation of the repository --> |
375 | - <link>https://example.org/example/spartacus</link> |
376 | - <!-- Guid may be the repository name at a particular commit id--> |
377 | - <guid>https://example.org/example/spartacus@f28ce68f16e338355e55372bc788e8ea5feda470</guid> |
378 | - <pubDate>Sun, 25 May 2025 18:23:03 +0200</pubDate> |
379 | - <!-- Optional enclosure with an image reference if your forge supports this --> |
380 | - <enclosure url="https://example.org/example/spartacus/raw/main/logo.png" length="12216320" type="image/png" /> |
381 | - <!-- Although highly recommended, the fields below are optional --> |
382 | - <repository> |
383 | - <!-- repository URI described above --> |
384 | - <webfinger>repository:example/spartacus</webfinger> |
385 | - </repository> |
386 | - </item> |
387 | - </channel> |
388 | - </rss> |
389 | - ``` |
390 | - |
391 | - ### Repository Extension |
392 | - |
393 | - In order to facilitate discovery by external indexes it is highly recommended |
394 | - that your server implement the webfinger repository specification described |
395 | - above so that repository indexes may populate their state with rich information |
396 | - about code repositories hosted on your server. |
397 | - |
398 | - ```xml |
399 | - <repository> |
400 | - <webfinger>repository:example/spartacus@example.org</webfinger> |
401 | - </repository> |
402 | - ``` |
403 | - |
404 | - If the host section of the URI is included that is MUST match domain name |
405 | - of the server which is providing the feed. |
406 | - |
407 | - ### Security Concerns |
408 | - |
409 | - #### Private Repositories |
410 | - |
411 | - Forge-feed enabled RSS feeds have no support for sharing private repositories |
412 | - and any repository that is not shared publicly on the internet must be hidden |
413 | - from the RSS activity feed stream. If your forge provides the ability to change |
414 | - a repository from public to private it must be understood that clients may |
415 | - already have cached versions of your repository data. |
416 | - |
417 | - ### Recommendations for Enumerating Repository Events |
418 | - |
419 | - #### Specify a Maximum Timeframe |
420 | - |
421 | - Your activity feed should not include repository events that are older than 1 |
422 | - week. |
423 | - |
424 | - #### Repository Items SHOULD be Unique |
425 | - |
426 | - Although it is permitted to return duplicate repositories in the feed forges |
427 | - SHOULD only return unique repositories in a given window. |
428 | - |
429 | - #### Event "Clamping" |
430 | - |
431 | - It may be undesirable to enumerate repository events items with the simple |
432 | - heuristic of |
433 | - |
434 | - end = time.now() |
435 | - start = end - 6h |
436 | - |
437 | - events = repository_events_between(start, end) |
438 | - |
439 | - Because the oldest repository events will fall out of the time window on |
440 | - subsequent queries by RSS readers. This can cause some RSS readers to |
441 | - frequently request new content from your feed. Instead events can be |
442 | - "clamped" within a certain time period. For example you may choose to |
443 | - publish four buckets of updates per day: |
444 | - |
445 | - 00:00:00 06:00:00 |
446 | - 06:00:00 12:00:00 |
447 | - 12:00:00 18:00:00 |
448 | - 18:00:00 00:00:00 |
449 | - |
450 | - For example if the current time is 2021-03-05 13:00:55 UTC you could use |
451 | - the following example to return a summary of repository events from the |
452 | - previous time bucket. |
453 | - |
454 | - now = time.now() |
455 | - start = now.set_time("06:00:00") |
456 | - end = now.set_time("12:00:00") |
457 | - |
458 | - events = repository_events_between(start, end) |
459 | + ### Attributions |
460 | |
461 | - This approach with a TTL value of 60 (minutes) will reduce excess requests |
462 | - from some readers but allow all clients to receive timely updates. |
463 | + Theme is modified from [Minimal](https://github.com/semanticdata/zola-minimal/) by |
464 | + Miguel Pimentel. |
465 | diff --git a/config.toml b/config.toml |
466 | new file mode 100644 |
467 | index 0000000..14a4082 |
468 | --- /dev/null |
469 | +++ b/config.toml |
470 | @@ -0,0 +1,18 @@ |
471 | + # The URL the site will be built for |
472 | + base_url = "https://forge-feed.org" |
473 | + |
474 | + # Whether to automatically compile all Sass files in the sass directory |
475 | + compile_sass = true |
476 | + |
477 | + # Whether to build a search index to be used later on by a JavaScript library |
478 | + build_search_index = false |
479 | + |
480 | + description = "ForgeFeed Specifications" |
481 | + |
482 | + [markdown] |
483 | + # Whether to do syntax highlighting |
484 | + # Theme can be customised by setting the `highlight_theme` variable to a theme supported by Zola |
485 | + highlight_code = true |
486 | + |
487 | + [extra] |
488 | + # Put all your custom variables here |
489 | diff --git a/content/_index.md b/content/_index.md |
490 | new file mode 100644 |
491 | index 0000000..e5f1e2a |
492 | --- /dev/null |
493 | +++ b/content/_index.md |
494 | @@ -0,0 +1,21 @@ |
495 | + --- |
496 | + title: Forge-Feed |
497 | + --- |
498 | + |
499 | + **Please note that these specifications are currently PROVISIONAL |
500 | + and should not be implemented.** |
501 | + |
502 | + ForgeFeed is a collection of specifications and recommendations which when |
503 | + implemented can enhance interoperability and content discovery of different |
504 | + [code forges](https://en.wikipedia.org/wiki/Forge_(software)) |
505 | + across the internet. |
506 | + |
507 | + NOTE that all specifications provided below MAY be implemented indepedenantly |
508 | + at the descrescion of the developer however it is a recommended that a server |
509 | + implement them all for maximum effect. |
510 | + |
511 | + The following specifications are currently covered: |
512 | + |
513 | + * [WebFinger Project Identification](/webfinger-project) - Identify Software Projects via WebFinger |
514 | + * [WebFinger Repository Identification](/webfinger-repository) - Identify VCS Repository Content via WebFinger |
515 | + * [Atom Feed Project Discovery](/project-atom-feed) - Subscribe to a forge over Atom |
516 | diff --git a/content/project-atom-feed.md b/content/project-atom-feed.md |
517 | new file mode 100644 |
518 | index 0000000..4f55b97 |
519 | --- /dev/null |
520 | +++ b/content/project-atom-feed.md |
521 | @@ -0,0 +1,145 @@ |
522 | + --- |
523 | + title: Atom Feed |
524 | + date: 2023-11-17 |
525 | + --- |
526 | + |
527 | + # Atom Feeds |
528 | + |
529 | + Your forge should expose an [Atom](https://www.rfc-editor.org/rfc/rfc4287) |
530 | + feed in order for other peers to subscribe to interesting code projects that |
531 | + are developed on your forge. The server should expose projects ordered by those |
532 | + which have been recently updated. THe heuristic you use to determine what has |
533 | + been updated depends on your forge. A common way to do this may be to simply |
534 | + look at your VCS's concept of a commit and order updates with that. |
535 | + |
536 | + ## Determine if a Host Supports Forge Feed |
537 | + |
538 | + In order to participate in ForgeFeed your forge MUST present an HTML link |
539 | + element such as below at the root domain of your forge. For example, |
540 | + `code.example.org` MUST have a link element present in it's html header: |
541 | + |
542 | + ```html |
543 | + <html> |
544 | + <head> |
545 | + <title>My Forge</title> |
546 | + <link |
547 | + rel="alternate" |
548 | + type="application/atom+xml" |
549 | + title="Recent Forge Activity" |
550 | + href="https://code.example.org/firehose.xml" /> |
551 | + <!-- index-url refers to the RSS link on the current webpage which contains forge updates --> |
552 | + <meta name="forge-feed:index-url" content="https://code.example.org/firehose.xml"/> |
553 | + </head> |
554 | + <body> |
555 | + ... |
556 | + </body> |
557 | + </html> |
558 | + ``` |
559 | + |
560 | + The link MAY have a title of "Recent Forge Activity" such that it uniquely |
561 | + identifies this feed as being related to forge updates. A server MUST provide a |
562 | + meta tag with the name forge-feed:index where the content of the tag matches |
563 | + the href of an Atom link listed on this page which should be used for indexing |
564 | + by external crawlers. Applications which rely on the forge-feed:index meta |
565 | + tag MUST stop crawling the serving website if this tag is no longer present |
566 | + in the pages HTML. |
567 | + |
568 | + ### An example Feed |
569 | + |
570 | + Below is an example Atom feed with an optional repository section (described below). |
571 | + |
572 | + ```xml |
573 | + <?xml version="1.0" encoding="utf-8"?> |
574 | + <feed xmlns="http://www.w3.org/2005/Atom" |
575 | + xmlns:forge-feed="http://forge-feed.org/project-atom-feed"> |
576 | + |
577 | + <title>Acme Forge Firehose</title> |
578 | + <subtitle>Recent Project Updates @ Acme Forge</subtitle> |
579 | + <link href="https://code.example.org/firehose.xml" rel="self" /> |
580 | + <link href="https://code.example.org/" /> |
581 | + <id>urn:uuid:44decbfc-ec17-42fa-994e-67dc13029072</id> |
582 | + <updated>2025-06-18T11:23:02Z</updated> |
583 | + |
584 | + <entry> |
585 | + <title>Spartacus Game</title> |
586 | + <link href="https://code.example.org/spartacus" /> |
587 | + <id>urn:uuid:51b2ad2b-34ff-4a69-9f45-a300bf296d05</id> |
588 | + <published>2025-06-18T11:23:02Z</published> |
589 | + <updated>2025-06-18T11:23:02Z</updated> |
590 | + <summary>A Game Engine & Text Adventure Written in FORTRAN 77</summary> |
591 | + <forge-feed:project>project:spartacus</forge-feed:project> |
592 | + </entry> |
593 | + </feed> |
594 | + ``` |
595 | + |
596 | + ### ForgeFeed Extension |
597 | + |
598 | + In order to facilitate discovery by external indexes it is highly recommended |
599 | + that your server implement the webfinger [project specification](/webfinger-project) |
600 | + so that repository indexes may populate their state with rich information |
601 | + about code repositories hosted on your server. |
602 | + |
603 | + The extension currently supports only a single field called `project`. |
604 | + |
605 | + ```xml |
606 | + <forge-feed:project>project:spartacus</forge-feed:project> |
607 | + ``` |
608 | + |
609 | + If the host section of the URI is included that is MUST match domain name |
610 | + of the server which is providing the feed. |
611 | + |
612 | + ### Security Concerns |
613 | + |
614 | + #### Private Projects |
615 | + |
616 | + Forge-feed enabled Atom feeds have no support for sharing private projects |
617 | + and any project that is not shared publicly on the internet must be hidden |
618 | + from the Atom activity feed stream. If your forge provides the ability to change |
619 | + a project from public to private it must be understood that clients may |
620 | + already have cached versions of your project data. |
621 | + |
622 | + ### Recommendations for Enumerating Project Events |
623 | + |
624 | + #### Specify a Maximum Timeframe |
625 | + |
626 | + Your activity feed should not include project events that are older than 1 |
627 | + week. |
628 | + |
629 | + #### Project Items SHOULD be Unique |
630 | + |
631 | + Although it is permitted to return duplicate projects the feed SHOULD only |
632 | + return unique projects in a given window. |
633 | + |
634 | + #### Event "Clamping" |
635 | + |
636 | + It may be undesirable to enumerate project events items with the simple |
637 | + heuristic of |
638 | + |
639 | + end = time.now() |
640 | + start = end - 6h |
641 | + |
642 | + events = project_events_between(start, end) |
643 | + |
644 | + Because the oldest project events will fall out of the time window on |
645 | + subsequent queries by feed readers. This can cause some feed readers to |
646 | + frequently request new content from your server. Instead events can be |
647 | + "clamped" within a certain time period. For example you may choose to |
648 | + publish four buckets of updates per day: |
649 | + |
650 | + 00:00:00 06:00:00 |
651 | + 06:00:00 12:00:00 |
652 | + 12:00:00 18:00:00 |
653 | + 18:00:00 00:00:00 |
654 | + |
655 | + For example if the current time is 2021-03-05 13:00:55 UTC you could use |
656 | + the following example to return a summary of project events from the |
657 | + previous time bucket. |
658 | + |
659 | + now = time.now() |
660 | + start = now.set_time("06:00:00") |
661 | + end = now.set_time("12:00:00") |
662 | + |
663 | + events = project_events_between(start, end) |
664 | + |
665 | + This approach with a TTL value of 60 (minutes) will reduce excess requests |
666 | + from some readers but allow all clients to receive timely updates. |
667 | diff --git a/content/webfinger-project.md b/content/webfinger-project.md |
668 | new file mode 100644 |
669 | index 0000000..b419c0c |
670 | --- /dev/null |
671 | +++ b/content/webfinger-project.md |
672 | @@ -0,0 +1,293 @@ |
673 | + --- |
674 | + title: Project Discovery via WebFinger |
675 | + --- |
676 | + |
677 | + A project refers to a software project which may contain multiple repositories |
678 | + as well as other resources such as mailing lists, bug trackers, links to |
679 | + chatrooms, etc. NOTE that some forges do not make a distinction between a |
680 | + project and a repository. If your forge does not then you MAY choose to expose |
681 | + repositories as a project with a single repository resource link. |
682 | + |
683 | + # Project URI |
684 | + |
685 | + A project URI identifies a software project and optionally the host that is |
686 | + resides on. This value is similar to |
687 | + [RFC7565](https://datatracker.ietf.org/doc/html/rfc7565). The slug and hostname |
688 | + part MUST match the URI path specification as defined in |
689 | + [RFC3986-3.3](https://www.rfc-editor.org/rfc/rfc3986#section-3.3) while the |
690 | + hostname, if specified, must match |
691 | + [RFC3986-3.2.2](https://www.rfc-editor.org/rfc/rfc3986#section-3.2.2). |
692 | + |
693 | + project-uri = prefix slug hostname |
694 | + |
695 | + prefix = "project:" |
696 | + slug = rfc3986-path |
697 | + hostname = [@ rfc3986-hostname] |
698 | + |
699 | + ### Slug |
700 | + |
701 | + The Slug represents a unique string that identifies a project at a particular code forge. |
702 | + |
703 | + ### Hostname |
704 | + |
705 | + If the hostname part is missing then the address of the server receiving the |
706 | + query is assumed. For example the following two queries are equivalent: |
707 | + |
708 | + ```text |
709 | + https://example.org/.well-known/webfinger?resource=project:spartacus |
710 | + https://example.org/.well-known/webfinger?resource=project:spartacus@example.org |
711 | + ``` |
712 | + |
713 | + TODO: Make this an actual spec, for now, some Python: |
714 | + |
715 | + ```python |
716 | + from urllib.parse import urlparse, quote_plus |
717 | + |
718 | + def from_string(text): |
719 | + url = urlparse(text) |
720 | + if not url.path: |
721 | + return (None, None) |
722 | + split = url.path.split("@", 1) |
723 | + if len(split) == 2: |
724 | + return (split[0], split[1]) |
725 | + return (split[0], None) |
726 | + |
727 | + def to_string(slug, domain=None): |
728 | + if domain: |
729 | + return quote_plus(f"project:{slug}@{domain}") |
730 | + else: |
731 | + return quote_plus(f"project:{slug}") |
732 | + ``` |
733 | + |
734 | + |
735 | + ### Properties |
736 | + |
737 | + #### http://forge-feed.org/rel/repository |
738 | + |
739 | + Reference to a VCS managed code repository. |
740 | + |
741 | + #### http://feed-forge.org/ns/chatroom |
742 | + |
743 | + Hint describing the backing type of chatroom. See [uri-schemes](https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml). |
744 | + |
745 | + matrix |
746 | + irc |
747 | + xmpp |
748 | + |
749 | + ### Link Extension Types |
750 | + |
751 | + #### Avatar |
752 | + |
753 | + Forges that allow users to configure a logo can expose this information as |
754 | + an avatar for use in other applications. |
755 | + |
756 | + ```json |
757 | + { |
758 | + "rel": "http://webfinger.net/rel/avatar", |
759 | + "href": "https://example.org/stylized-logo.png" |
760 | + } |
761 | + ``` |
762 | + |
763 | + #### Homepage |
764 | + |
765 | + Link to an HTTP representation of the project homepage. |
766 | + |
767 | + ```json |
768 | + { |
769 | + "rel": "http://feed-forge.org/rel/homepage", |
770 | + "href": "https://example.org/example/spartacus" |
771 | + } |
772 | + ``` |
773 | + |
774 | + #### Description |
775 | + |
776 | + A short text representation of the project. |
777 | + |
778 | + ```json |
779 | + { |
780 | + "rel": "http://example.org/rel/description", |
781 | + "titles": { |
782 | + "en-us": "A Text Adventure Written in FORTRAN 77", |
783 | + "es": "Una Aventura de Texto Escrita en FORTRAN 77" |
784 | + } |
785 | + } |
786 | + ``` |
787 | + |
788 | + #### Chat Links |
789 | + |
790 | + Links to chatrooms: IRC, Matrix, XMPP, etc. |
791 | + |
792 | + ```json |
793 | + { |
794 | + "rel": "http://feed-forge.org/rel/chatroom", |
795 | + "href": "ircs://irc.libera.chat/#spartacus-game", |
796 | + "properties": { |
797 | + "http://feed-forge.org/ns/chatroom": "irc" |
798 | + } |
799 | + } |
800 | + ``` |
801 | + |
802 | + #### Mailing Lists |
803 | + |
804 | + Links to associated mailing lists, forms, etc. |
805 | + |
806 | + ```json |
807 | + { |
808 | + "rel": "http://feed-forge.org/rel/mailing-list", |
809 | + "href": "mailto://list-name@mail.example.org", |
810 | + "properties": { |
811 | + "http://feed-forge.org/ns/mailing-list-subscribe": "mailto://subscribe+list-name@mail.example.org", |
812 | + "http://feed-forge.org/ns/mailing-list-unsubscribe": "mailto://unsubscribe+list-name@mail.example.org" |
813 | + } |
814 | + } |
815 | + ``` |
816 | + |
817 | + #### Ticketing Systems |
818 | + |
819 | + Links to issue tracking systems. |
820 | + |
821 | + ```json |
822 | + { |
823 | + "ref": "http://forge-feed.org/rel/ticketing-system", |
824 | + "href": "https://example.org/bugs", |
825 | + } |
826 | + ``` |
827 | + |
828 | + #### Repository Links |
829 | + |
830 | + Links of code repositories associated with this software project. |
831 | + |
832 | + ```json |
833 | + { |
834 | + "rel": "http://example.org/rel/repository", |
835 | + "href": "https://example.org/example/spartacus", |
836 | + "properties": { |
837 | + "http://forge-feed.org/rel/repository": "repository:example/spartacus" |
838 | + } |
839 | + } |
840 | + ``` |
841 | + |
842 | + ## Example Multi-Repository Query |
843 | + |
844 | + A [WebFinger](https://webfinger.net/spec/) query may be used to identify |
845 | + detailed information about a public repository at a particular forge. Here is |
846 | + an example response about a fictitious project which has two code repositories |
847 | + associated with it as well as chat links, and a bug tracking system. |
848 | + |
849 | + `GET https://example.org/.well-known/webfinger?resource=project:spartacus` |
850 | + |
851 | + ```json |
852 | + { |
853 | + "subject": "project:spartacus", |
854 | + "aliases": [ |
855 | + "https://example.org" |
856 | + ], |
857 | + "links": [ |
858 | + { |
859 | + "rel": "http://webfinger.net/rel/avatar", |
860 | + "href": "https://example.org/stylized-logo.png" |
861 | + }, |
862 | + { |
863 | + "rel": "http://feed-forge.org/rel/homepage", |
864 | + "href": "https://code.example.org/spartacus" |
865 | + }, |
866 | + { |
867 | + "rel": "http://forge-feed.org/rel/description", |
868 | + "titles": { |
869 | + "en-us": "A Text Adventure Written in FORTRAN 77", |
870 | + "es": "Una Aventura de Texto Escrita en FORTRAN 77" |
871 | + } |
872 | + }, |
873 | + { |
874 | + "rel": "http://forge-feed.org/rel/chatroom", |
875 | + "href": "ircs://irc.libera.chat/#spartacus-game", |
876 | + "properties": { |
877 | + "http://feed-forge.org/ns/chatroom": "irc" |
878 | + } |
879 | + }, |
880 | + { |
881 | + "rel": "http://forge-feed.org/rel/ticketing-system", |
882 | + "href": "https://example.org/bugs" |
883 | + }, |
884 | + { |
885 | + "rel": "http://forge-feed.org/rel/label", |
886 | + "properties": { |
887 | + "http://feed-forge.org/ns/label": "fortran" |
888 | + } |
889 | + }, |
890 | + { |
891 | + "rel": "http://forge-feed.org/rel/label", |
892 | + "properties": { |
893 | + "http://feed-forge.org/ns/label": "text-adventure" |
894 | + } |
895 | + }, |
896 | + { |
897 | + "rel": "http://forge-feed.org/rel/repository", |
898 | + "href": "https://code.example.org/spartacus/spartan-engine", |
899 | + "titles": { |
900 | + "en-us": "The Spartan Game Engine" |
901 | + }, |
902 | + "properties": { |
903 | + "http://forge-feed.org/rel/repository-uri": "repository:spartacus/game-engine" |
904 | + } |
905 | + }, |
906 | + { |
907 | + "rel": "http://forge-feed.org/rel/repository", |
908 | + "href": "https://code.example.org/spartacus/game", |
909 | + "titles": { |
910 | + "en-us": "Implementation of the Spartacus Text Adventure game" |
911 | + }, |
912 | + "properties": { |
913 | + "http://forge-feed.org/rel/repository-uri": "repository:spartacus/game" |
914 | + } |
915 | + }, |
916 | + { |
917 | + "rel": "http://forge-feed.org/rel/repository", |
918 | + "href": "https://code.example.org/spartacus/game", |
919 | + "titles": { |
920 | + "en-us": "Promotional Website for the Spartacus Game" |
921 | + }, |
922 | + "properties": { |
923 | + "http://forge-feed.org/rel/repository-uri": "repository:spartacus/www" |
924 | + } |
925 | + } |
926 | + ] |
927 | + } |
928 | + ``` |
929 | + |
930 | + ## Example Single Repository Query |
931 | + |
932 | + Here is an example of a project with only a single repository associated with it. |
933 | + |
934 | + ```json |
935 | + { |
936 | + "subject": "project:fuu/bar", |
937 | + "links": [ |
938 | + { |
939 | + "rel": "http://forge-feed.org/rel/repository", |
940 | + "href": "https://code.example.org/fuu/bar", |
941 | + "titles": { |
942 | + "en-us": "Baz Qux" |
943 | + }, |
944 | + "properties": { |
945 | + "http://forge-feed.org/rel/repository-uri": "repository:fuu/bar" |
946 | + } |
947 | + } |
948 | + ] |
949 | + } |
950 | + ``` |
951 | + |
952 | + ### Security |
953 | + |
954 | + Projects which are not publicly available should not be identifiable by |
955 | + making webfinger queries at all. A project which is private MUST return |
956 | + the same response as a repository which does not exist when making a webfinger |
957 | + request. |
958 | + |
959 | + |
960 | + GET https://example.org/.well-known/webfinger?resource=project:example/spartacus |
961 | + 200 |
962 | + GET https://example.org/.well-known/webfinger?resource=project:example/private-project |
963 | + 404 |
964 | + GET https://example.org/.well-known/webfinger?resource=project:example/non-existent-project |
965 | + 404 |
966 | diff --git a/content/webfinger-repository.md b/content/webfinger-repository.md |
967 | new file mode 100644 |
968 | index 0000000..26c75e0 |
969 | --- /dev/null |
970 | +++ b/content/webfinger-repository.md |
971 | @@ -0,0 +1,215 @@ |
972 | + --- |
973 | + title: Repository Discovery via WebFinger |
974 | + --- |
975 | + |
976 | + A repository refers to a version control managed source code which may be |
977 | + browsed over HTTP or downloaded with specific tooling. |
978 | + |
979 | + ## Repository URI |
980 | + |
981 | + A repository URI identifies a code repository and optionally the host that is |
982 | + resides on. This value is similar to |
983 | + [RFC7565](https://datatracker.ietf.org/doc/html/rfc7565). The slug and hostname |
984 | + part MUST match the URI path specification as defined in |
985 | + [RFC3986-3.3](https://www.rfc-editor.org/rfc/rfc3986#section-3.3) while the |
986 | + hostname, if specified, must match |
987 | + [RFC3986-3.2.2](https://www.rfc-editor.org/rfc/rfc3986#section-3.2.2) |
988 | + |
989 | + repository-uri = prefix slug hostname |
990 | + |
991 | + prefix = "repository:" |
992 | + slug = rfc3986-path |
993 | + hostname = [@ rfc3986-hostname] |
994 | + |
995 | + ### Slug |
996 | + |
997 | + The Slug represents a unique string that identifies a repository at a |
998 | + particular code forge. Repository refers to a VCS managed codebase of some |
999 | + kind, e.g. a Git repository. |
1000 | + |
1001 | + ### Hostname |
1002 | + |
1003 | + If the hostname part is missing then the address of the server receiving the |
1004 | + query is assumed. For example the following two queries are equivalent: |
1005 | + |
1006 | + ```text |
1007 | + https://example.org/.well-known/webfinger?resource=repository:spartacus/game |
1008 | + https://example.org/.well-known/webfinger?resource=repository:spartacus/game@example.org |
1009 | + ``` |
1010 | + |
1011 | + TODO: Make this an actual spec, for now, some Python: |
1012 | + |
1013 | + ```python |
1014 | + from urllib.parse import urlparse, quote_plus |
1015 | + |
1016 | + def from_string(text): |
1017 | + url = urlparse(text) |
1018 | + if not url.path: |
1019 | + return (None, None) |
1020 | + split = url.path.split("@", 1) |
1021 | + if len(split) == 2: |
1022 | + return (split[0], split[1]) |
1023 | + return (split[0], None) |
1024 | + |
1025 | + def to_string(slug, domain=None): |
1026 | + if domain: |
1027 | + return quote_plus(f"repository:{slug}@{domain}") |
1028 | + else: |
1029 | + return quote_plus(f"repository:{slug}") |
1030 | + ``` |
1031 | + |
1032 | + ### Properties |
1033 | + |
1034 | + #### http://feed-forge.org/ns/vcs-type |
1035 | + |
1036 | + Identifies VCS types, valid strings are: |
1037 | + |
1038 | + bzr (GNU Bazaar) bazaar.canonical.com |
1039 | + darcs (Darcs) darcs.net |
1040 | + fossil (Fossil) fossil-scm.org |
1041 | + git (Git) git-scm.com |
1042 | + hg (Mercurial) mercurial-scm.org |
1043 | + pijul (Pijul) pijul.org |
1044 | + svn (Apache Subversion) subversion.apache.org |
1045 | + |
1046 | + #### http://feed-forge.org/ns/spdx-identifier |
1047 | + |
1048 | + Refers to a valid SPDX identifier, see [license-list](https://spdx.org/licenses/) |
1049 | + |
1050 | + ### Link Extension Types |
1051 | + |
1052 | + #### Avatar |
1053 | + |
1054 | + Forges that allow users to configure a logo can expose this information as |
1055 | + an avatar for use in other applications. |
1056 | + |
1057 | + ```json |
1058 | + { |
1059 | + "rel": "http://webfinger.net/rel/avatar", |
1060 | + "href": "https://example.org/stylized-logo.png" |
1061 | + } |
1062 | + ``` |
1063 | + |
1064 | + #### Homepage |
1065 | + |
1066 | + Link to an HTTP representation of the repository. |
1067 | + |
1068 | + ```json |
1069 | + { |
1070 | + "rel": "http://feed-forge.org/rel/homepage", |
1071 | + "href": "https://example.org/spartacus/game" |
1072 | + } |
1073 | + ``` |
1074 | + |
1075 | + #### Description |
1076 | + |
1077 | + A short text representation of the repository. |
1078 | + |
1079 | + ```json |
1080 | + { |
1081 | + "rel": "http://example.org/rel/description", |
1082 | + "titles": { |
1083 | + "en-us": "A Text Adventure Written in FORTRAN 77", |
1084 | + "es": "Una Aventura de Texto Escrita en FORTRAN 77" |
1085 | + } |
1086 | + } |
1087 | + ``` |
1088 | + |
1089 | + #### License |
1090 | + |
1091 | + A license SPDX identifier and link to the license's full text. |
1092 | + |
1093 | + ```json |
1094 | + { |
1095 | + "rel": "http://feed-forge.org/rel/license", |
1096 | + "href": "https://example.com/example/spartacus/tree/LICENSE", |
1097 | + "properties": { |
1098 | + "http://feed-forge.org/ns/spdx-identifier": "GPL-2.0-or-later" |
1099 | + } |
1100 | + } |
1101 | + ``` |
1102 | + |
1103 | + #### Clone Links |
1104 | + |
1105 | + Clone links define how one can download a copy of the remote |
1106 | + software onto their own server. |
1107 | + |
1108 | + ```json |
1109 | + { |
1110 | + "rel": "http://feed-forge.org/rel/clone", |
1111 | + "href": "https://example.org/example/spartacus", |
1112 | + "properties": { |
1113 | + "http://feed-forge.org/ns/vcs-type": "git" |
1114 | + } |
1115 | + } |
1116 | + ``` |
1117 | + |
1118 | + ## WebFinger Query |
1119 | + |
1120 | + A [WebFinger](https://webfinger.net/spec/) query may be used to identify |
1121 | + detailed information about a public repository at a particular forge. Here is |
1122 | + an example response about a fictitious repository: |
1123 | + |
1124 | + `GET https://example.org/.well-known/webfinger?resource=repository:spartacus/game` |
1125 | + |
1126 | + ```json |
1127 | + { |
1128 | + "subject": "repository:spartacus/game", |
1129 | + "aliases": [ |
1130 | + "https://example.org/spartacus/game" |
1131 | + ], |
1132 | + "links": [ |
1133 | + { |
1134 | + "rel": "http://webfinger.net/rel/avatar", |
1135 | + "href": "https://example.org/stylized-logo.png" |
1136 | + }, |
1137 | + { |
1138 | + "rel": "http://forge-feed.org/rel/description", |
1139 | + "titles": { |
1140 | + "en-us": "A Text Adventure Written in FORTRAN 77", |
1141 | + "es": "Una Aventura de Texto Escrita en FORTRAN 77" |
1142 | + } |
1143 | + }, |
1144 | + { |
1145 | + "rel": "http://feed-forge.org/rel/clone", |
1146 | + "href": "https://example.org/spartacus/game", |
1147 | + "properties": { |
1148 | + "http://feed-forge.org/ns/vcs-type": "git" |
1149 | + } |
1150 | + }, |
1151 | + { |
1152 | + "rel": "http://forge-feed.org/rel/license", |
1153 | + "href": "https://example.com/spartacus/game/tree/LICENSE", |
1154 | + "properties": { |
1155 | + "spdx-identifier": "GPL-2.0-or-later" |
1156 | + } |
1157 | + }, |
1158 | + { |
1159 | + "rel": "http://forge-feed.org/rel/label", |
1160 | + "properties": { |
1161 | + "http://feed-forge.org/ns/label": "fortran" |
1162 | + } |
1163 | + }, |
1164 | + { |
1165 | + "rel": "http://forge-feed.org/rel/label", |
1166 | + "properties": { |
1167 | + "http://feed-forge.org/ns/label": "text-adventure" |
1168 | + } |
1169 | + } |
1170 | + ] |
1171 | + } |
1172 | + ``` |
1173 | + |
1174 | + ### Security |
1175 | + |
1176 | + Repositories which are not publicly available should not be identifiable by |
1177 | + making webfinger queries at all. A repository which is private MUST return |
1178 | + the same response as a repository which does not exist when making a webfinger |
1179 | + request. |
1180 | + |
1181 | + GET https://example.org/.well-known/webfinger?resource=repository:spartacus/game |
1182 | + 200 |
1183 | + GET https://example.org/.well-known/webfinger?resource=repository:example/private-repository |
1184 | + 404 |
1185 | + GET https://example.org/.well-known/webfinger?resource=repository:example/non-existent-repository |
1186 | + 404 |
1187 | diff --git a/public/android-chrome-192x192.png b/public/android-chrome-192x192.png |
1188 | new file mode 100644 |
1189 | index 0000000..f6137eb |
1190 | Binary files /dev/null and b/public/android-chrome-192x192.png differ |
1191 | diff --git a/public/android-chrome-512x512.png b/public/android-chrome-512x512.png |
1192 | new file mode 100644 |
1193 | index 0000000..c77c2af |
1194 | Binary files /dev/null and b/public/android-chrome-512x512.png differ |
1195 | diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png |
1196 | new file mode 100644 |
1197 | index 0000000..aaeaa8d |
1198 | Binary files /dev/null and b/public/apple-touch-icon.png differ |
1199 | diff --git a/public/favicon-16x16.png b/public/favicon-16x16.png |
1200 | new file mode 100644 |
1201 | index 0000000..29dd09f |
1202 | Binary files /dev/null and b/public/favicon-16x16.png differ |
1203 | diff --git a/public/favicon-32x32.png b/public/favicon-32x32.png |
1204 | new file mode 100644 |
1205 | index 0000000..811ba56 |
1206 | Binary files /dev/null and b/public/favicon-32x32.png differ |
1207 | diff --git a/public/favicon.ico b/public/favicon.ico |
1208 | new file mode 100644 |
1209 | index 0000000..de83549 |
1210 | Binary files /dev/null and b/public/favicon.ico differ |
1211 | diff --git a/public/img/codeberg.svg b/public/img/codeberg.svg |
1212 | new file mode 100644 |
1213 | index 0000000..068702a |
1214 | --- /dev/null |
1215 | +++ b/public/img/codeberg.svg |
1216 | @@ -0,0 +1,19 @@ |
1217 | + <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="svg-badge" height="168" width="564" viewBox="0 0 564 168"> |
1218 | + <defs> |
1219 | + <linearGradient xlink:href="#a" id="b" gradientUnits="userSpaceOnUse" x1="42519.285" y1="-7078.789" x2="42575.336" y2="-6966.931" /> |
1220 | + <linearGradient id="a"> |
1221 | + <stop offset="0" stop-color="#fff" stop-opacity="0" /> |
1222 | + <stop offset=".495" stop-color="#71c2ff" /> |
1223 | + <stop offset="1" stop-color="#39aaff" /> |
1224 | + </linearGradient> |
1225 | + </defs> |
1226 | + <rect id="rect" ry="15.111" y="2" x="2" height="164" width="560" fill="none" stroke="#a6a6a6" stroke-width="4" stroke-linejoin="round" paint-order="fill stroke markers" /> |
1227 | + <text style="line-height:0%;-inkscape-font-specification:'Inter';marker:none" x="203.16" y="-85.813" transform="matrix(1.0087 0 0 .99138 -19.194 133.848)" color="#000" font-weight="400" font-size="11.814" font-family="Inter, 'DejaVu Sans', sans-serif" letter-spacing="0" word-spacing="0" overflow="visible" fill="#2185d0" stroke-width=".985"> |
1228 | + <tspan id="claim-svg" style="line-height:1;-inkscape-font-specification:'Inter'" x="203.16" y="-85.813" font-size="33.596">GET IT ON</tspan> |
1229 | + </text> |
1230 | + <path aria-label="Codeberg" d="M214.654 71.02c-8.453 0-15.047 2.79-19.803 8.369-4.803 5.577-7.215 12.943-7.215 22.096 0 7.034 1.764 13.158 5.281 18.372 4.862 7.275 12.274 10.912 22.2 10.912 6.907 0 12.922-2.516 18.049-7.548l-4.718-7.185c-4.57 2.85-8.512 4.275-11.844 4.275-5.069 0-9.112-1.91-12.12-5.729-2.847-3.638-4.271-8.004-4.271-13.097 0-5.76 1.211-10.428 3.613-14.005 2.773-4.183 6.694-6.274 11.747-6.274 3.65 0 7.684 1.574 12.11 4.728l4.734-7.546c-5.925-4.91-11.844-7.368-17.763-7.368zm167.7 0l-11.657 6.456v52.201h9.441l.925-4.091c2.843 3.455 6.844 5.183 12.03 5.183 5.238 0 9.638-1.548 13.224-4.64 4.56-4.061 6.85-10.033 6.85-17.914 0-6.122-1.547-11.033-4.634-14.732-3.523-4.184-8.38-6.275-14.612-6.275-2.226 0-4.266.418-6.105 1.274-2.348 1.09-4.176 2.607-5.462 4.546zm-62.745.183l-11.674 6.367v13.186c-2.895-2.304-6.471-3.455-10.722-3.455-4.93 0-9.16 1.606-12.667 4.82-4.692 4.304-7.056 10.427-7.056 18.37 0 5.638 1.466 10.247 4.362 13.824 3.454 4.304 8.486 6.456 15.085 6.456 2.343 0 4.622-.517 6.838-1.547 2.232-1.03 3.83-2.334 4.825-3.909l1.663 4.364h9.346zm-65.647 16.098c-6.057 0-10.956 1.878-14.718 5.636-4.139 4.123-6.206 9.52-6.206 16.188 0 5.88 1.855 10.854 5.553 14.916 4.134 4.486 9.272 6.73 15.371 6.73 5.255 0 9.84-1.759 13.783-5.275 4.75-4.183 7.125-9.641 7.125-16.371 0-5.758-1.599-10.638-4.808-14.641-3.826-4.79-9.192-7.183-16.1-7.183zm91.746 0c-5.988 0-10.914 1.94-14.819 5.82-4.314 4.245-6.477 9.609-6.477 16.096 0 6.61 1.923 11.792 5.744 15.552 4.017 4 9.596 6.002 16.758 6.002 6.647 0 12.205-1.94 16.641-5.822l-2.964-6.092c-4.368 2.426-8.56 3.637-12.572 3.637-2.842 0-5.302-.908-7.401-2.728-2.051-1.88-3.194-4.214-3.417-7.001h28.852v-4.183c0-6.003-1.6-10.885-4.809-14.643-3.693-4.427-8.884-6.638-15.536-6.638zm92.543 0c-5.978 0-10.909 1.94-14.803 5.82-4.326 4.245-6.472 9.609-6.472 16.096 0 6.61 1.907 11.792 5.733 15.552 4 4 9.585 6.002 16.753 6.002 6.658 0 12.205-1.94 16.652-5.822l-2.954-6.092c-4.389 2.426-8.587 3.637-12.588 3.637-2.837 0-5.308-.908-7.406-2.728-2.04-1.88-3.183-4.214-3.427-7.001h28.878v-4.183c0-6.003-1.605-10.885-4.814-14.643-3.709-4.427-8.879-6.638-15.552-6.638zm45.163 0c-1.838 0-3.672.485-5.462 1.455-1.727.908-2.901 2-3.512 3.272l-1.11-3.635h-9.9v41.286h11.477V100.03c.978-2.12 2.524-3.18 4.623-3.18 2.28 0 4.442 1.15 6.466 3.454l9.814-5.274c-2.71-5.154-6.844-7.73-12.396-7.73zm30.121 0c-4.883 0-9.107 1.606-12.683 4.82-4.691 4.304-7.024 10.427-7.024 18.37 0 5.577 1.435 10.186 4.336 13.824 3.4 4.304 8.188 6.456 14.351 6.456 5.064 0 8.974-2.032 11.759-6.094 0 9.094-3.342 13.642-10 13.642-4.697 0-8.921-1.213-12.683-3.638l-2.954 5.82c4.856 4.365 10.637 6.549 17.295 6.549 6.413 0 11.354-1.85 14.813-5.549 3.502-3.758 5.266-9.125 5.255-16.098v-37.01h-8.974l-.914 4.455c0-.604-.893-1.515-2.688-2.728-2.716-1.879-6.005-2.82-9.889-2.82zm-167.923 8.094c5.553 0 8.496 2.97 8.794 8.912h-17.869c.675-5.942 3.704-8.912 9.075-8.912zm92.554 0c5.547 0 8.474 2.97 8.788 8.912h-17.858c.674-5.942 3.703-8.912 9.07-8.912zm-184.204.089c5.989 0 8.98 4.547 8.98 13.64 0 8.732-2.991 13.097-8.98 13.097-5.982 0-8.98-4.365-8.98-13.096 0-9.094 2.998-13.641 8.98-13.641zm45.748 0c2.04 0 3.794.67 5.282 2.002 1.53 1.272 2.518 2.908 2.943 4.909v11.55c-.318 2.243-1.408 4.243-3.315 6.002-1.913 1.698-3.985 2.547-6.2 2.547-5.989 0-8.98-4.516-8.98-13.55 0-4.123.924-7.396 2.778-9.82 1.85-2.426 4.347-3.64 7.492-3.64zm216.312 0c1.982 0 3.762.7 5.377 2.093 1.669 1.335 2.625 2.94 2.875 4.818v10.46c0 2.607-.935 4.878-2.785 6.82-1.854 1.878-4.043 2.819-6.572 2.819-6.047 0-9.075-4.516-9.075-13.55 0-4.123.924-7.396 2.779-9.82 1.849-2.426 4.325-3.64 7.401-3.64zm-124.322.094c2.832 0 5.048 1.211 6.663 3.637 1.594 2.425 2.407 5.728 2.407 9.912 0 4.244-.866 7.58-2.598 10.006-1.727 2.424-4.07 3.637-7.019 3.637-2.295 0-4.31-.76-6.03-2.274-1.68-1.518-2.604-3.396-2.769-5.637v-9.916c0-2.606.893-4.818 2.673-6.637 1.854-1.817 4.075-2.728 6.673-2.728z" style="line-height:1.25;-inkscape-font-specification:'Tajawal Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal" font-weight="700" font-size="17.899" font-family="Tajawal" letter-spacing="-.285" word-spacing="0" fill="#2185d0" /> |
1231 | + <g paint-order="stroke markers fill"> |
1232 | + <path style="font-variation-settings:normal" d="M42519.285-7078.79a.76.568 0 00-.738.675l33.586 125.888a87.182 87.182 0 0039.381-33.763l-71.565-92.52a.76.568 0 00-.664-.28z" transform="matrix(.75692 0 0 .74393 -32088.397 5317.32)" opacity=".5" fill="url(#b)" /> |
1233 | + <path d="M93.742 20.95A65.99 64.857 0 0028 85.807a65.99 64.857 0 0010.076 34.447l55.019-69.909a1.03.756 0 011.785 0l55.022 69.912a65.99 64.857 0 0010.078-34.45A65.99 64.857 0 0093.99 20.95a65.99 64.857 0 00-.248 0z" fill="#2185d0" /> |
1234 | + </g> |
1235 | + </svg> |
1236 | \ No newline at end of file |
1237 | diff --git a/public/img/logo.png b/public/img/logo.png |
1238 | new file mode 100644 |
1239 | index 0000000..93e608e |
1240 | Binary files /dev/null and b/public/img/logo.png differ |
1241 | diff --git a/public/img/logo.svg b/public/img/logo.svg |
1242 | new file mode 100644 |
1243 | index 0000000..cdc0267 |
1244 | --- /dev/null |
1245 | +++ b/public/img/logo.svg |
1246 | @@ -0,0 +1 @@ |
1247 | + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200"><g transform="translate(0 -852.36)"><rect width="180" height="180" x="10" y="862.36" rx="8.546" ry="7.52" style="fill-opacity:.24215;fill:#e7eab7"/><path d="M159.21 52.277c0 12.686-11.082 22.97-24.752 22.97s-24.752-10.284-24.752-22.97 11.082-22.97 24.752-22.97 24.752 10.284 24.752 22.97z" style="fill-opacity:.89686;fill:#b3b3b3" transform="matrix(.6464 0 0 .69655 -38.912 967.95)"/><path d="M118.91 1020.4c.102-.453.25-.888.344-1.344a72.568 72.568 0 0 0 1.094-7.219c.248-2.444.375-4.927.375-7.437s-.127-4.993-.375-7.438-.61-4.851-1.094-7.218a72.281 72.281 0 0 0-1.813-6.97 72.276 72.276 0 0 0-2.437-6.687c-.92-2.175-1.943-4.283-3.063-6.343s-2.318-4.066-3.625-6-2.705-3.798-4.187-5.594a73.377 73.377 0 0 0-4.72-5.156c-1.644-1.645-3.36-3.237-5.155-4.72s-3.66-2.88-5.594-4.187c-1.934-1.306-3.94-2.505-6-3.625s-4.169-2.142-6.344-3.062a72.255 72.255 0 0 0-6.687-2.438 72.245 72.245 0 0 0-6.97-1.812 72.57 72.57 0 0 0-7.218-1.094c-2.445-.248-4.927-.375-7.437-.375s-4.993.127-7.438.375-4.852.61-7.219 1.094c-.456.093-.89.242-1.344.344v25.5c1.704-.552 3.345-1.23 5.125-1.594 1.595-.327 3.228-.583 4.875-.75s3.309-.25 5-.25 3.353.082 5 .25c1.648.167 3.28.423 4.875.75 3.19.652 6.257 1.604 9.188 2.844s5.737 2.77 8.344 4.53a49.125 49.125 0 0 1 7.25 5.97 49.138 49.138 0 0 1 5.969 7.25 49.135 49.135 0 0 1 4.53 8.343 48.502 48.502 0 0 1 2.845 9.188c.326 1.595.582 3.228.75 4.875s.25 3.308.25 5c0 1.691-.083 3.353-.25 5a49.126 49.126 0 0 1-.75 4.875c-.365 1.78-1.043 3.42-1.594 5.125h25.5z" style="fill-opacity:.89686;fill:#b3b3b3"/><path d="M48 874.36c-4.487 0-8.911.212-13.281.656-.92.094-1.805.294-2.719.407v29.562c1.894-.303 3.76-.68 5.688-.875 3.388-.345 6.833-.532 10.312-.532 3.478 0 6.924.187 10.312.532 3.388.344 6.72.86 10 1.53a99.75 99.75 0 0 1 18.906 5.844c3.014 1.275 5.956 2.699 8.812 4.25s5.632 3.252 8.313 5.063 5.261 3.727 7.75 5.781 4.876 4.252 7.156 6.531 4.478 4.668 6.531 7.157c2.054 2.488 3.97 5.069 5.781 7.75s3.511 5.456 5.063 8.312 2.975 5.798 4.25 8.813 2.393 6.094 3.375 9.25a99.975 99.975 0 0 1 2.469 9.656c.671 3.28 1.187 6.612 1.531 10 .344 3.388.531 6.834.531 10.313 0 3.479-.187 6.924-.531 10.312-.196 1.927-.572 3.794-.875 5.687h29.562c.112-.914.313-1.799.406-2.718.444-4.37.656-8.794.656-13.281 0-4.488-.212-8.911-.656-13.281-.444-4.37-1.134-8.675-2-12.906a129.23 129.23 0 0 0-3.187-12.47c-1.266-4.07-2.73-8.049-4.375-11.937a129.601 129.601 0 0 0-11.969-22.094c-2.336-3.458-4.85-6.79-7.5-10s-5.434-6.31-8.375-9.25-6.04-5.726-9.25-8.375-6.542-5.164-10-7.5a129.885 129.885 0 0 0-22.094-11.97 128.88 128.88 0 0 0-11.938-4.374 129.205 129.205 0 0 0-12.469-3.188c-4.231-.866-8.536-1.556-12.906-2-4.349-.48-8.773-.69-13.26-.69z" style="fill-opacity:.89686;fill:#b3b3b3"/></g></svg> |
1248 | \ No newline at end of file |
1249 | diff --git a/public/img/minimal-favicon.png b/public/img/minimal-favicon.png |
1250 | new file mode 100644 |
1251 | index 0000000..e7cdbde |
1252 | Binary files /dev/null and b/public/img/minimal-favicon.png differ |
1253 | diff --git a/public/img/minimal-minimal.png b/public/img/minimal-minimal.png |
1254 | new file mode 100644 |
1255 | index 0000000..8f60a03 |
1256 | Binary files /dev/null and b/public/img/minimal-minimal.png differ |
1257 | diff --git a/public/img/minimal-thumbnail.png b/public/img/minimal-thumbnail.png |
1258 | new file mode 100644 |
1259 | index 0000000..e6c0478 |
1260 | Binary files /dev/null and b/public/img/minimal-thumbnail.png differ |
1261 | diff --git a/public/img/sourcehut.svg b/public/img/sourcehut.svg |
1262 | new file mode 100644 |
1263 | index 0000000..c7a12e9 |
1264 | --- /dev/null |
1265 | +++ b/public/img/sourcehut.svg |
1266 | @@ -0,0 +1,77 @@ |
1267 | + <?xml version="1.0" encoding="UTF-8" standalone="no"?> |
1268 | + <!-- Created with Inkscape (http://www.inkscape.org/) --> |
1269 | + |
1270 | + <svg |
1271 | + width="300" |
1272 | + height="80" |
1273 | + viewBox="0 0 79.375001 21.166666" |
1274 | + version="1.1" |
1275 | + id="svg5" |
1276 | + inkscape:version="1.1 (c68e22c387, 2021-05-23)" |
1277 | + sodipodi:docname="sourcehut-black.svg" |
1278 | + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" |
1279 | + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" |
1280 | + xmlns="http://www.w3.org/2000/svg" |
1281 | + xmlns:svg="http://www.w3.org/2000/svg"> |
1282 | + <sodipodi:namedview |
1283 | + id="namedview7" |
1284 | + pagecolor="#505050" |
1285 | + bordercolor="#ffffff" |
1286 | + borderopacity="1" |
1287 | + inkscape:pageshadow="0" |
1288 | + inkscape:pageopacity="0" |
1289 | + inkscape:pagecheckerboard="1" |
1290 | + inkscape:document-units="px" |
1291 | + showgrid="false" |
1292 | + units="px" |
1293 | + height="80px" |
1294 | + inkscape:zoom="3.0930415" |
1295 | + inkscape:cx="152.6006" |
1296 | + inkscape:cy="77.75518" |
1297 | + inkscape:window-width="1920" |
1298 | + inkscape:window-height="1059" |
1299 | + inkscape:window-x="0" |
1300 | + inkscape:window-y="0" |
1301 | + inkscape:window-maximized="1" |
1302 | + inkscape:current-layer="layer1" /> |
1303 | + <defs |
1304 | + id="defs2"> |
1305 | + <rect |
1306 | + x="72.43578" |
1307 | + y="4.989779" |
1308 | + width="233.3009" |
1309 | + height="93.363552" |
1310 | + id="rect22993" /> |
1311 | + <rect |
1312 | + x="76.460692" |
1313 | + y="7.5029808" |
1314 | + width="210.43456" |
1315 | + height="46.880685" |
1316 | + id="rect5098" /> |
1317 | + </defs> |
1318 | + <g |
1319 | + inkscape:label="Layer 1" |
1320 | + inkscape:groupmode="layer" |
1321 | + id="layer1"> |
1322 | + <path |
1323 | + d="m 10.58314,1.3501934 c -5.1005652,0 -9.23314,4.1325746 -9.23314,9.2331386 0,5.100566 4.1325748,9.233141 9.23314,9.233141 5.100565,0 9.23314,-4.132575 9.23314,-9.233141 0,-5.100564 -4.132575,-9.2331386 -9.23314,-9.2331386 z m 0,16.6792216 c -4.1139596,0 -7.4460807,-3.332121 -7.4460807,-7.446083 0,-4.1139582 3.3321211,-7.4460793 7.4460807,-7.4460793 4.11396,0 7.446082,3.3321211 7.446082,7.4460793 0,4.113962 -3.332122,7.446083 -7.446082,7.446083 z" |
1324 | + id="path49" |
1325 | + style="stroke-width:0.0372303" /> |
1326 | + <text |
1327 | + xml:space="preserve" |
1328 | + transform="scale(0.26458333)" |
1329 | + id="text22991" |
1330 | + style="fill:black;fill-opacity:1;line-height:1.25;stroke:none;font-family:sans-serif;font-style:normal;font-weight:normal;font-size:40px;white-space:pre;shape-inside:url(#rect22993)" /> |
1331 | + <text |
1332 | + xml:space="preserve" |
1333 | + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.2889px;line-height:1.25;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583" |
1334 | + x="22.349714" |
1335 | + y="13.896598" |
1336 | + id="text29885"><tspan |
1337 | + sodipodi:role="line" |
1338 | + id="tspan29883" |
1339 | + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.2889px;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583" |
1340 | + x="22.349714" |
1341 | + y="13.896598">sourcehut</tspan></text> |
1342 | + </g> |
1343 | + </svg> |
1344 | diff --git a/public/site.webmanifest b/public/site.webmanifest |
1345 | new file mode 100644 |
1346 | index 0000000..06d341a |
1347 | --- /dev/null |
1348 | +++ b/public/site.webmanifest |
1349 | @@ -0,0 +1,19 @@ |
1350 | + { |
1351 | + "name": "", |
1352 | + "short_name": "", |
1353 | + "icons": [ |
1354 | + { |
1355 | + "src": "/android-chrome-192x192.png", |
1356 | + "sizes": "192x192", |
1357 | + "type": "image/png" |
1358 | + }, |
1359 | + { |
1360 | + "src": "/android-chrome-512x512.png", |
1361 | + "sizes": "512x512", |
1362 | + "type": "image/png" |
1363 | + } |
1364 | + ], |
1365 | + "theme_color": "#ffffff", |
1366 | + "background_color": "#ffffff", |
1367 | + "display": "standalone" |
1368 | + } |
1369 | diff --git a/public/styles.css b/public/styles.css |
1370 | new file mode 100644 |
1371 | index 0000000..85b557a |
1372 | --- /dev/null |
1373 | +++ b/public/styles.css |
1374 | @@ -0,0 +1 @@ |
1375 | + .wrapper{width:860px;margin:0 auto}header{width:170px;float:left;position:fixed;-webkit-font-smoothing:subpixel-antialiased}body{background-color:#fff;padding:50px;font:14px/1.5 "Noto Sans","Helvetica Neue",Helvetica,Arial,sans-serif;color:#222;font-weight:400}h1,h2,h3,h4,h5,h6{color:#222;margin:0 0 20px}p,ul,ol,table,pre,dl{margin:0 0 20px}h1,h2,h3{line-height:1.1}h1{font-size:28px}a{color:#267cb9;text-decoration:none}a:hover,a:focus{color:salmon}a small{font-size:11px;color:#000;margin-top:-.3em;display:block}a:hover small{color:#777}strong{color:#222;font-weight:700}section{width:600px;float:right;padding-bottom:50px}small{font-size:11px}hr{border:0;background:#e5e5e5;height:1px;margin:0 0 20px}footer{width:270px;float:left;position:fixed;bottom:50px;-webkit-font-smoothing:subpixel-antialiased}pre{padding:8px 15px;border-radius:5px;border:1px solid #e5e5e5;overflow-x:auto}ul.downloads{list-style:none;height:40px;padding:0;background:#f4f4f4;border-radius:5px;border:1px solid #e0e0e0;width:270px}.downloads li{width:89px;float:left;border-right:1px solid #e0e0e0;height:40px}.downloads li:first-child a{border-radius:5px 0 0 5px}.downloads li:last-child a{border-radius:0 5px 5px 0}.downloads a{line-height:1;font-size:11px;display:block;text-align:center;padding-top:6px;height:34px}.downloads a:hover,.downloads a:focus{font-weight:bold}.downloads ul a:active{background-color:#f0f0f0}.downloads li+li+li{border-right:none;width:89px}.downloads a strong{font-size:14px;display:block;color:#222}.site-logo{margin-bottom:1rem;width:100%}@media print,screen and (max-width: 960px){div.wrapper{width:auto;margin:0}header,section,footer{float:none;position:static;width:auto}header{padding-right:320px}section{border:1px solid #e5e5e5;border-width:1px 0;padding:20px 0;margin:0 0 20px}header a small{display:inline}header ul{position:absolute;right:50px;top:52px}}@media print,screen and (max-width: 720px){body{word-wrap:break-word}header{padding:0}header ul,header p.view{position:static;margin:1rem auto}pre,code{word-wrap:normal;text-wrap:wrap}}@media print,screen and (max-width: 480px){body{padding:15px}.downloads{width:100%;margin:1rem auto}.downloads li,.downloads li+li+li{width:33%}}@media print{body{padding:.4in;font-size:12pt;color:#444}}::selection{background:#639;color:#fff}table{margin:1rem auto;border-collapse:collapse}table thead th,table tfoot th{color:#202020;background:rgba(0,0,0,.15)}table caption{padding:.5em}table th,table td{padding:.5em;border:1px solid #e5e5e5}pre,code{font-family:monospace}code{border-radius:3px}pre{overflow:auto}pre code{background-color:rgba(0,0,0,0);color:inherit}@media (prefers-color-scheme: dark){.sourcehut{filter:invert(100%)}body{background-color:#222;color:#fff}strong{color:#fff}h1,h2,h3,h4,h5,h6{color:#fff}a small{color:#fff}} |
1376 | \ No newline at end of file |
1377 | diff --git a/sass/_base.scss b/sass/_base.scss |
1378 | new file mode 100644 |
1379 | index 0000000..073be69 |
1380 | --- /dev/null |
1381 | +++ b/sass/_base.scss |
1382 | @@ -0,0 +1,114 @@ |
1383 | + @use "variables"; |
1384 | + |
1385 | + .wrapper { |
1386 | + width: 860px; |
1387 | + margin: 0 auto; |
1388 | + } |
1389 | + |
1390 | + header { |
1391 | + width: 170px; |
1392 | + float: left; |
1393 | + position: fixed; |
1394 | + -webkit-font-smoothing: subpixel-antialiased; |
1395 | + } |
1396 | + |
1397 | + body { |
1398 | + background-color: #fff; |
1399 | + padding: 50px; |
1400 | + font: |
1401 | + 14px/1.5 "Noto Sans", |
1402 | + "Helvetica Neue", |
1403 | + Helvetica, |
1404 | + Arial, |
1405 | + sans-serif; |
1406 | + color: #222; |
1407 | + font-weight: 400; |
1408 | + } |
1409 | + |
1410 | + h1, |
1411 | + h2, |
1412 | + h3, |
1413 | + h4, |
1414 | + h5, |
1415 | + h6 { |
1416 | + color: #222; |
1417 | + margin: 0 0 20px; |
1418 | + } |
1419 | + |
1420 | + p, |
1421 | + ul, |
1422 | + ol, |
1423 | + table, |
1424 | + pre, |
1425 | + dl { |
1426 | + margin: 0 0 20px; |
1427 | + } |
1428 | + |
1429 | + h1, |
1430 | + h2, |
1431 | + h3 { |
1432 | + line-height: 1.1; |
1433 | + } |
1434 | + |
1435 | + h1 { |
1436 | + font-size: 28px; |
1437 | + } |
1438 | + |
1439 | + a { |
1440 | + color: #267cb9; |
1441 | + text-decoration: none; |
1442 | + } |
1443 | + |
1444 | + a:hover, |
1445 | + a:focus { |
1446 | + color: salmon; |
1447 | + } |
1448 | + |
1449 | + a small { |
1450 | + font-size: 11px; |
1451 | + color: black; |
1452 | + margin-top: -0.3em; |
1453 | + display: block; |
1454 | + } |
1455 | + |
1456 | + a:hover small { |
1457 | + color: #777; |
1458 | + } |
1459 | + |
1460 | + strong { |
1461 | + color: #222; |
1462 | + font-weight: 700; |
1463 | + } |
1464 | + |
1465 | + section { |
1466 | + width: 600px; |
1467 | + float: right; |
1468 | + padding-bottom: 50px; |
1469 | + } |
1470 | + |
1471 | + small { |
1472 | + font-size: 11px; |
1473 | + } |
1474 | + |
1475 | + hr { |
1476 | + border: 0; |
1477 | + background: #e5e5e5; |
1478 | + height: 1px; |
1479 | + margin: 0 0 20px; |
1480 | + } |
1481 | + |
1482 | + footer { |
1483 | + width: 270px; |
1484 | + float: left; |
1485 | + position: fixed; |
1486 | + bottom: 50px; |
1487 | + -webkit-font-smoothing: subpixel-antialiased; |
1488 | + } |
1489 | + |
1490 | + pre { |
1491 | + padding: 8px 15px; |
1492 | + // background: #f8f8f8; |
1493 | + border-radius: 5px; |
1494 | + border: 1px solid #e5e5e5; |
1495 | + overflow-x: auto; |
1496 | + } |
1497 | diff --git a/sass/_classes.scss b/sass/_classes.scss |
1498 | new file mode 100644 |
1499 | index 0000000..a00bb4c |
1500 | --- /dev/null |
1501 | +++ b/sass/_classes.scss |
1502 | @@ -0,0 +1,58 @@ |
1503 | + ul.downloads { |
1504 | + list-style: none; |
1505 | + height: 40px; |
1506 | + padding: 0; |
1507 | + background: #f4f4f4; |
1508 | + border-radius: 5px; |
1509 | + border: 1px solid #e0e0e0; |
1510 | + width: 270px; |
1511 | + } |
1512 | + |
1513 | + .downloads li { |
1514 | + width: 89px; |
1515 | + float: left; |
1516 | + border-right: 1px solid #e0e0e0; |
1517 | + height: 40px; |
1518 | + } |
1519 | + |
1520 | + .downloads li:first-child a { |
1521 | + border-radius: 5px 0 0 5px; |
1522 | + } |
1523 | + |
1524 | + .downloads li:last-child a { |
1525 | + border-radius: 0 5px 5px 0; |
1526 | + } |
1527 | + |
1528 | + .downloads a { |
1529 | + line-height: 1; |
1530 | + font-size: 11px; |
1531 | + display: block; |
1532 | + text-align: center; |
1533 | + padding-top: 6px; |
1534 | + height: 34px; |
1535 | + } |
1536 | + |
1537 | + .downloads a:hover, |
1538 | + .downloads a:focus { |
1539 | + font-weight: bold; |
1540 | + } |
1541 | + |
1542 | + .downloads ul a:active { |
1543 | + background-color: #f0f0f0; |
1544 | + } |
1545 | + |
1546 | + .downloads li + li + li { |
1547 | + border-right: none; |
1548 | + width: 89px; |
1549 | + } |
1550 | + |
1551 | + .downloads a strong { |
1552 | + font-size: 14px; |
1553 | + display: block; |
1554 | + color: #222; |
1555 | + } |
1556 | + |
1557 | + .site-logo { |
1558 | + margin-bottom: 1rem; |
1559 | + width: 100%; |
1560 | + } |
1561 | diff --git a/sass/_code.scss b/sass/_code.scss |
1562 | new file mode 100644 |
1563 | index 0000000..0dd3c6d |
1564 | --- /dev/null |
1565 | +++ b/sass/_code.scss |
1566 | @@ -0,0 +1,17 @@ |
1567 | + pre, |
1568 | + code { |
1569 | + font-family: monospace; |
1570 | + } |
1571 | + |
1572 | + code { |
1573 | + border-radius: 3px; |
1574 | + } |
1575 | + |
1576 | + pre { |
1577 | + overflow: auto; |
1578 | + } |
1579 | + |
1580 | + pre code { |
1581 | + background-color: transparent; |
1582 | + color: inherit; |
1583 | + } |
1584 | diff --git a/sass/_custom.scss b/sass/_custom.scss |
1585 | new file mode 100644 |
1586 | index 0000000..213f60b |
1587 | --- /dev/null |
1588 | +++ b/sass/_custom.scss |
1589 | @@ -0,0 +1,30 @@ |
1590 | + // Custom CSS code goes here |
1591 | + |
1592 | + @media (prefers-color-scheme: dark) { |
1593 | + |
1594 | + .sourcehut { |
1595 | + filter: invert(100%) ; |
1596 | + } |
1597 | + |
1598 | + body { |
1599 | + background-color: #222; |
1600 | + color: #FFF |
1601 | + } |
1602 | + |
1603 | + strong { |
1604 | + color: #FFF; |
1605 | + } |
1606 | + |
1607 | + h1, |
1608 | + h2, |
1609 | + h3, |
1610 | + h4, |
1611 | + h5, |
1612 | + h6 { |
1613 | + color: #FFF; |
1614 | + } |
1615 | + |
1616 | + a small { |
1617 | + color: white; |
1618 | + } |
1619 | + } |
1620 | diff --git a/sass/_layout.scss b/sass/_layout.scss |
1621 | new file mode 100644 |
1622 | index 0000000..38fd882 |
1623 | --- /dev/null |
1624 | +++ b/sass/_layout.scss |
1625 | @@ -0,0 +1,86 @@ |
1626 | + @media print, screen and (max-width: 960px) { |
1627 | + div.wrapper { |
1628 | + width: auto; |
1629 | + margin: 0; |
1630 | + } |
1631 | + |
1632 | + header, |
1633 | + section, |
1634 | + footer { |
1635 | + float: none; |
1636 | + position: static; |
1637 | + width: auto; |
1638 | + } |
1639 | + |
1640 | + header { |
1641 | + padding-right: 320px; |
1642 | + } |
1643 | + |
1644 | + section { |
1645 | + border: 1px solid #e5e5e5; |
1646 | + border-width: 1px 0; |
1647 | + padding: 20px 0; |
1648 | + margin: 0 0 20px; |
1649 | + } |
1650 | + |
1651 | + header a small { |
1652 | + display: inline; |
1653 | + } |
1654 | + |
1655 | + header ul { |
1656 | + position: absolute; |
1657 | + right: 50px; |
1658 | + top: 52px; |
1659 | + } |
1660 | + } |
1661 | + |
1662 | + @media print, screen and (max-width: 720px) { |
1663 | + body { |
1664 | + word-wrap: break-word; |
1665 | + } |
1666 | + |
1667 | + header { |
1668 | + padding: 0; |
1669 | + } |
1670 | + |
1671 | + header ul, |
1672 | + header p.view { |
1673 | + position: static; |
1674 | + margin: 1rem auto; |
1675 | + } |
1676 | + |
1677 | + pre, |
1678 | + code { |
1679 | + word-wrap: normal; |
1680 | + text-wrap: wrap; |
1681 | + } |
1682 | + } |
1683 | + |
1684 | + @media print, screen and (max-width: 480px) { |
1685 | + body { |
1686 | + padding: 15px; |
1687 | + } |
1688 | + |
1689 | + .downloads { |
1690 | + width: 100%; |
1691 | + margin: 1rem auto; |
1692 | + } |
1693 | + |
1694 | + .downloads li, |
1695 | + .downloads li + li + li { |
1696 | + width: 33%; |
1697 | + } |
1698 | + } |
1699 | + |
1700 | + @media print { |
1701 | + body { |
1702 | + padding: 0.4in; |
1703 | + font-size: 12pt; |
1704 | + color: #444; |
1705 | + } |
1706 | + } |
1707 | + |
1708 | + ::selection { |
1709 | + background: rebeccapurple; |
1710 | + color: white; |
1711 | + } |
1712 | diff --git a/sass/_tables.scss b/sass/_tables.scss |
1713 | new file mode 100644 |
1714 | index 0000000..96350d2 |
1715 | --- /dev/null |
1716 | +++ b/sass/_tables.scss |
1717 | @@ -0,0 +1,22 @@ |
1718 | + @use "variables"; |
1719 | + |
1720 | + table { |
1721 | + margin: 1rem auto; |
1722 | + border-collapse: collapse; |
1723 | + } |
1724 | + |
1725 | + table thead th, |
1726 | + table tfoot th { |
1727 | + color: variables.$font-color; |
1728 | + background: rgba(0, 0, 0, 0.15); |
1729 | + } |
1730 | + |
1731 | + table caption { |
1732 | + padding: 0.5em; |
1733 | + } |
1734 | + |
1735 | + table th, |
1736 | + table td { |
1737 | + padding: 0.5em; |
1738 | + border: 1px solid variables.$border-color; |
1739 | + } |
1740 | diff --git a/sass/_variables.scss b/sass/_variables.scss |
1741 | new file mode 100644 |
1742 | index 0000000..17151b8 |
1743 | --- /dev/null |
1744 | +++ b/sass/_variables.scss |
1745 | @@ -0,0 +1,28 @@ |
1746 | + // Variables |
1747 | + $font-color: #202020; |
1748 | + $bg-color: #fff; |
1749 | + $border-color: #e5e5e5; |
1750 | + $section-width: 500px; |
1751 | + $header-width: 270px; |
1752 | + $footer-width: 270px; |
1753 | + $wrapper-width: 860px; |
1754 | + $link-color: #267cb9; |
1755 | + $link-color-hover: #069; |
1756 | + $font-color-small: #777; |
1757 | + $font-color-code: #333; |
1758 | + $font-size-small: 11px; |
1759 | + $font-family: "Noto Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; |
1760 | + $font-family-code: |
1761 | + Monaco, |
1762 | + Bitstream Vera Sans Mono, |
1763 | + Lucida Console, |
1764 | + Terminal, |
1765 | + Consolas, |
1766 | + Liberation Mono, |
1767 | + DejaVu Sans Mono, |
1768 | + Courier New, |
1769 | + monospace; |
1770 | + |
1771 | + $media-max-width: 960px; |
1772 | + $media-max-width-smaller: 720px; |
1773 | + $media-max-width-even-smaller: 480px; |
1774 | diff --git a/sass/styles.scss b/sass/styles.scss |
1775 | new file mode 100644 |
1776 | index 0000000..8fca72c |
1777 | --- /dev/null |
1778 | +++ b/sass/styles.scss |
1779 | @@ -0,0 +1,7 @@ |
1780 | + @use "variables"; |
1781 | + @use "base"; |
1782 | + @use "classes"; |
1783 | + @use "layout"; |
1784 | + @use "tables"; |
1785 | + @use "code"; |
1786 | + @use "custom"; |
1787 | diff --git a/static/android-chrome-192x192.png b/static/android-chrome-192x192.png |
1788 | new file mode 100644 |
1789 | index 0000000..f6137eb |
1790 | Binary files /dev/null and b/static/android-chrome-192x192.png differ |
1791 | diff --git a/static/android-chrome-512x512.png b/static/android-chrome-512x512.png |
1792 | new file mode 100644 |
1793 | index 0000000..c77c2af |
1794 | Binary files /dev/null and b/static/android-chrome-512x512.png differ |
1795 | diff --git a/static/apple-touch-icon.png b/static/apple-touch-icon.png |
1796 | new file mode 100644 |
1797 | index 0000000..aaeaa8d |
1798 | Binary files /dev/null and b/static/apple-touch-icon.png differ |
1799 | diff --git a/static/favicon-16x16.png b/static/favicon-16x16.png |
1800 | new file mode 100644 |
1801 | index 0000000..29dd09f |
1802 | Binary files /dev/null and b/static/favicon-16x16.png differ |
1803 | diff --git a/static/favicon-32x32.png b/static/favicon-32x32.png |
1804 | new file mode 100644 |
1805 | index 0000000..811ba56 |
1806 | Binary files /dev/null and b/static/favicon-32x32.png differ |
1807 | diff --git a/static/favicon.ico b/static/favicon.ico |
1808 | new file mode 100644 |
1809 | index 0000000..de83549 |
1810 | Binary files /dev/null and b/static/favicon.ico differ |
1811 | diff --git a/static/img/codeberg.svg b/static/img/codeberg.svg |
1812 | new file mode 100644 |
1813 | index 0000000..068702a |
1814 | --- /dev/null |
1815 | +++ b/static/img/codeberg.svg |
1816 | @@ -0,0 +1,19 @@ |
1817 | + <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="svg-badge" height="168" width="564" viewBox="0 0 564 168"> |
1818 | + <defs> |
1819 | + <linearGradient xlink:href="#a" id="b" gradientUnits="userSpaceOnUse" x1="42519.285" y1="-7078.789" x2="42575.336" y2="-6966.931" /> |
1820 | + <linearGradient id="a"> |
1821 | + <stop offset="0" stop-color="#fff" stop-opacity="0" /> |
1822 | + <stop offset=".495" stop-color="#71c2ff" /> |
1823 | + <stop offset="1" stop-color="#39aaff" /> |
1824 | + </linearGradient> |
1825 | + </defs> |
1826 | + <rect id="rect" ry="15.111" y="2" x="2" height="164" width="560" fill="none" stroke="#a6a6a6" stroke-width="4" stroke-linejoin="round" paint-order="fill stroke markers" /> |
1827 | + <text style="line-height:0%;-inkscape-font-specification:'Inter';marker:none" x="203.16" y="-85.813" transform="matrix(1.0087 0 0 .99138 -19.194 133.848)" color="#000" font-weight="400" font-size="11.814" font-family="Inter, 'DejaVu Sans', sans-serif" letter-spacing="0" word-spacing="0" overflow="visible" fill="#2185d0" stroke-width=".985"> |
1828 | + <tspan id="claim-svg" style="line-height:1;-inkscape-font-specification:'Inter'" x="203.16" y="-85.813" font-size="33.596">GET IT ON</tspan> |
1829 | + </text> |
1830 | + <path aria-label="Codeberg" d="M214.654 71.02c-8.453 0-15.047 2.79-19.803 8.369-4.803 5.577-7.215 12.943-7.215 22.096 0 7.034 1.764 13.158 5.281 18.372 4.862 7.275 12.274 10.912 22.2 10.912 6.907 0 12.922-2.516 18.049-7.548l-4.718-7.185c-4.57 2.85-8.512 4.275-11.844 4.275-5.069 0-9.112-1.91-12.12-5.729-2.847-3.638-4.271-8.004-4.271-13.097 0-5.76 1.211-10.428 3.613-14.005 2.773-4.183 6.694-6.274 11.747-6.274 3.65 0 7.684 1.574 12.11 4.728l4.734-7.546c-5.925-4.91-11.844-7.368-17.763-7.368zm167.7 0l-11.657 6.456v52.201h9.441l.925-4.091c2.843 3.455 6.844 5.183 12.03 5.183 5.238 0 9.638-1.548 13.224-4.64 4.56-4.061 6.85-10.033 6.85-17.914 0-6.122-1.547-11.033-4.634-14.732-3.523-4.184-8.38-6.275-14.612-6.275-2.226 0-4.266.418-6.105 1.274-2.348 1.09-4.176 2.607-5.462 4.546zm-62.745.183l-11.674 6.367v13.186c-2.895-2.304-6.471-3.455-10.722-3.455-4.93 0-9.16 1.606-12.667 4.82-4.692 4.304-7.056 10.427-7.056 18.37 0 5.638 1.466 10.247 4.362 13.824 3.454 4.304 8.486 6.456 15.085 6.456 2.343 0 4.622-.517 6.838-1.547 2.232-1.03 3.83-2.334 4.825-3.909l1.663 4.364h9.346zm-65.647 16.098c-6.057 0-10.956 1.878-14.718 5.636-4.139 4.123-6.206 9.52-6.206 16.188 0 5.88 1.855 10.854 5.553 14.916 4.134 4.486 9.272 6.73 15.371 6.73 5.255 0 9.84-1.759 13.783-5.275 4.75-4.183 7.125-9.641 7.125-16.371 0-5.758-1.599-10.638-4.808-14.641-3.826-4.79-9.192-7.183-16.1-7.183zm91.746 0c-5.988 0-10.914 1.94-14.819 5.82-4.314 4.245-6.477 9.609-6.477 16.096 0 6.61 1.923 11.792 5.744 15.552 4.017 4 9.596 6.002 16.758 6.002 6.647 0 12.205-1.94 16.641-5.822l-2.964-6.092c-4.368 2.426-8.56 3.637-12.572 3.637-2.842 0-5.302-.908-7.401-2.728-2.051-1.88-3.194-4.214-3.417-7.001h28.852v-4.183c0-6.003-1.6-10.885-4.809-14.643-3.693-4.427-8.884-6.638-15.536-6.638zm92.543 0c-5.978 0-10.909 1.94-14.803 5.82-4.326 4.245-6.472 9.609-6.472 16.096 0 6.61 1.907 11.792 5.733 15.552 4 4 9.585 6.002 16.753 6.002 6.658 0 12.205-1.94 16.652-5.822l-2.954-6.092c-4.389 2.426-8.587 3.637-12.588 3.637-2.837 0-5.308-.908-7.406-2.728-2.04-1.88-3.183-4.214-3.427-7.001h28.878v-4.183c0-6.003-1.605-10.885-4.814-14.643-3.709-4.427-8.879-6.638-15.552-6.638zm45.163 0c-1.838 0-3.672.485-5.462 1.455-1.727.908-2.901 2-3.512 3.272l-1.11-3.635h-9.9v41.286h11.477V100.03c.978-2.12 2.524-3.18 4.623-3.18 2.28 0 4.442 1.15 6.466 3.454l9.814-5.274c-2.71-5.154-6.844-7.73-12.396-7.73zm30.121 0c-4.883 0-9.107 1.606-12.683 4.82-4.691 4.304-7.024 10.427-7.024 18.37 0 5.577 1.435 10.186 4.336 13.824 3.4 4.304 8.188 6.456 14.351 6.456 5.064 0 8.974-2.032 11.759-6.094 0 9.094-3.342 13.642-10 13.642-4.697 0-8.921-1.213-12.683-3.638l-2.954 5.82c4.856 4.365 10.637 6.549 17.295 6.549 6.413 0 11.354-1.85 14.813-5.549 3.502-3.758 5.266-9.125 5.255-16.098v-37.01h-8.974l-.914 4.455c0-.604-.893-1.515-2.688-2.728-2.716-1.879-6.005-2.82-9.889-2.82zm-167.923 8.094c5.553 0 8.496 2.97 8.794 8.912h-17.869c.675-5.942 3.704-8.912 9.075-8.912zm92.554 0c5.547 0 8.474 2.97 8.788 8.912h-17.858c.674-5.942 3.703-8.912 9.07-8.912zm-184.204.089c5.989 0 8.98 4.547 8.98 13.64 0 8.732-2.991 13.097-8.98 13.097-5.982 0-8.98-4.365-8.98-13.096 0-9.094 2.998-13.641 8.98-13.641zm45.748 0c2.04 0 3.794.67 5.282 2.002 1.53 1.272 2.518 2.908 2.943 4.909v11.55c-.318 2.243-1.408 4.243-3.315 6.002-1.913 1.698-3.985 2.547-6.2 2.547-5.989 0-8.98-4.516-8.98-13.55 0-4.123.924-7.396 2.778-9.82 1.85-2.426 4.347-3.64 7.492-3.64zm216.312 0c1.982 0 3.762.7 5.377 2.093 1.669 1.335 2.625 2.94 2.875 4.818v10.46c0 2.607-.935 4.878-2.785 6.82-1.854 1.878-4.043 2.819-6.572 2.819-6.047 0-9.075-4.516-9.075-13.55 0-4.123.924-7.396 2.779-9.82 1.849-2.426 4.325-3.64 7.401-3.64zm-124.322.094c2.832 0 5.048 1.211 6.663 3.637 1.594 2.425 2.407 5.728 2.407 9.912 0 4.244-.866 7.58-2.598 10.006-1.727 2.424-4.07 3.637-7.019 3.637-2.295 0-4.31-.76-6.03-2.274-1.68-1.518-2.604-3.396-2.769-5.637v-9.916c0-2.606.893-4.818 2.673-6.637 1.854-1.817 4.075-2.728 6.673-2.728z" style="line-height:1.25;-inkscape-font-specification:'Tajawal Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal" font-weight="700" font-size="17.899" font-family="Tajawal" letter-spacing="-.285" word-spacing="0" fill="#2185d0" /> |
1831 | + <g paint-order="stroke markers fill"> |
1832 | + <path style="font-variation-settings:normal" d="M42519.285-7078.79a.76.568 0 00-.738.675l33.586 125.888a87.182 87.182 0 0039.381-33.763l-71.565-92.52a.76.568 0 00-.664-.28z" transform="matrix(.75692 0 0 .74393 -32088.397 5317.32)" opacity=".5" fill="url(#b)" /> |
1833 | + <path d="M93.742 20.95A65.99 64.857 0 0028 85.807a65.99 64.857 0 0010.076 34.447l55.019-69.909a1.03.756 0 011.785 0l55.022 69.912a65.99 64.857 0 0010.078-34.45A65.99 64.857 0 0093.99 20.95a65.99 64.857 0 00-.248 0z" fill="#2185d0" /> |
1834 | + </g> |
1835 | + </svg> |
1836 | \ No newline at end of file |
1837 | diff --git a/static/img/logo.png b/static/img/logo.png |
1838 | new file mode 100644 |
1839 | index 0000000..93e608e |
1840 | Binary files /dev/null and b/static/img/logo.png differ |
1841 | diff --git a/static/img/logo.svg b/static/img/logo.svg |
1842 | new file mode 100644 |
1843 | index 0000000..cdc0267 |
1844 | --- /dev/null |
1845 | +++ b/static/img/logo.svg |
1846 | @@ -0,0 +1 @@ |
1847 | + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200"><g transform="translate(0 -852.36)"><rect width="180" height="180" x="10" y="862.36" rx="8.546" ry="7.52" style="fill-opacity:.24215;fill:#e7eab7"/><path d="M159.21 52.277c0 12.686-11.082 22.97-24.752 22.97s-24.752-10.284-24.752-22.97 11.082-22.97 24.752-22.97 24.752 10.284 24.752 22.97z" style="fill-opacity:.89686;fill:#b3b3b3" transform="matrix(.6464 0 0 .69655 -38.912 967.95)"/><path d="M118.91 1020.4c.102-.453.25-.888.344-1.344a72.568 72.568 0 0 0 1.094-7.219c.248-2.444.375-4.927.375-7.437s-.127-4.993-.375-7.438-.61-4.851-1.094-7.218a72.281 72.281 0 0 0-1.813-6.97 72.276 72.276 0 0 0-2.437-6.687c-.92-2.175-1.943-4.283-3.063-6.343s-2.318-4.066-3.625-6-2.705-3.798-4.187-5.594a73.377 73.377 0 0 0-4.72-5.156c-1.644-1.645-3.36-3.237-5.155-4.72s-3.66-2.88-5.594-4.187c-1.934-1.306-3.94-2.505-6-3.625s-4.169-2.142-6.344-3.062a72.255 72.255 0 0 0-6.687-2.438 72.245 72.245 0 0 0-6.97-1.812 72.57 72.57 0 0 0-7.218-1.094c-2.445-.248-4.927-.375-7.437-.375s-4.993.127-7.438.375-4.852.61-7.219 1.094c-.456.093-.89.242-1.344.344v25.5c1.704-.552 3.345-1.23 5.125-1.594 1.595-.327 3.228-.583 4.875-.75s3.309-.25 5-.25 3.353.082 5 .25c1.648.167 3.28.423 4.875.75 3.19.652 6.257 1.604 9.188 2.844s5.737 2.77 8.344 4.53a49.125 49.125 0 0 1 7.25 5.97 49.138 49.138 0 0 1 5.969 7.25 49.135 49.135 0 0 1 4.53 8.343 48.502 48.502 0 0 1 2.845 9.188c.326 1.595.582 3.228.75 4.875s.25 3.308.25 5c0 1.691-.083 3.353-.25 5a49.126 49.126 0 0 1-.75 4.875c-.365 1.78-1.043 3.42-1.594 5.125h25.5z" style="fill-opacity:.89686;fill:#b3b3b3"/><path d="M48 874.36c-4.487 0-8.911.212-13.281.656-.92.094-1.805.294-2.719.407v29.562c1.894-.303 3.76-.68 5.688-.875 3.388-.345 6.833-.532 10.312-.532 3.478 0 6.924.187 10.312.532 3.388.344 6.72.86 10 1.53a99.75 99.75 0 0 1 18.906 5.844c3.014 1.275 5.956 2.699 8.812 4.25s5.632 3.252 8.313 5.063 5.261 3.727 7.75 5.781 4.876 4.252 7.156 6.531 4.478 4.668 6.531 7.157c2.054 2.488 3.97 5.069 5.781 7.75s3.511 5.456 5.063 8.312 2.975 5.798 4.25 8.813 2.393 6.094 3.375 9.25a99.975 99.975 0 0 1 2.469 9.656c.671 3.28 1.187 6.612 1.531 10 .344 3.388.531 6.834.531 10.313 0 3.479-.187 6.924-.531 10.312-.196 1.927-.572 3.794-.875 5.687h29.562c.112-.914.313-1.799.406-2.718.444-4.37.656-8.794.656-13.281 0-4.488-.212-8.911-.656-13.281-.444-4.37-1.134-8.675-2-12.906a129.23 129.23 0 0 0-3.187-12.47c-1.266-4.07-2.73-8.049-4.375-11.937a129.601 129.601 0 0 0-11.969-22.094c-2.336-3.458-4.85-6.79-7.5-10s-5.434-6.31-8.375-9.25-6.04-5.726-9.25-8.375-6.542-5.164-10-7.5a129.885 129.885 0 0 0-22.094-11.97 128.88 128.88 0 0 0-11.938-4.374 129.205 129.205 0 0 0-12.469-3.188c-4.231-.866-8.536-1.556-12.906-2-4.349-.48-8.773-.69-13.26-.69z" style="fill-opacity:.89686;fill:#b3b3b3"/></g></svg> |
1848 | \ No newline at end of file |
1849 | diff --git a/static/img/minimal-favicon.png b/static/img/minimal-favicon.png |
1850 | new file mode 100644 |
1851 | index 0000000..e7cdbde |
1852 | Binary files /dev/null and b/static/img/minimal-favicon.png differ |
1853 | diff --git a/static/img/minimal-minimal.png b/static/img/minimal-minimal.png |
1854 | new file mode 100644 |
1855 | index 0000000..8f60a03 |
1856 | Binary files /dev/null and b/static/img/minimal-minimal.png differ |
1857 | diff --git a/static/img/minimal-thumbnail.png b/static/img/minimal-thumbnail.png |
1858 | new file mode 100644 |
1859 | index 0000000..e6c0478 |
1860 | Binary files /dev/null and b/static/img/minimal-thumbnail.png differ |
1861 | diff --git a/static/img/sourcehut.svg b/static/img/sourcehut.svg |
1862 | new file mode 100644 |
1863 | index 0000000..c7a12e9 |
1864 | --- /dev/null |
1865 | +++ b/static/img/sourcehut.svg |
1866 | @@ -0,0 +1,77 @@ |
1867 | + <?xml version="1.0" encoding="UTF-8" standalone="no"?> |
1868 | + <!-- Created with Inkscape (http://www.inkscape.org/) --> |
1869 | + |
1870 | + <svg |
1871 | + width="300" |
1872 | + height="80" |
1873 | + viewBox="0 0 79.375001 21.166666" |
1874 | + version="1.1" |
1875 | + id="svg5" |
1876 | + inkscape:version="1.1 (c68e22c387, 2021-05-23)" |
1877 | + sodipodi:docname="sourcehut-black.svg" |
1878 | + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" |
1879 | + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" |
1880 | + xmlns="http://www.w3.org/2000/svg" |
1881 | + xmlns:svg="http://www.w3.org/2000/svg"> |
1882 | + <sodipodi:namedview |
1883 | + id="namedview7" |
1884 | + pagecolor="#505050" |
1885 | + bordercolor="#ffffff" |
1886 | + borderopacity="1" |
1887 | + inkscape:pageshadow="0" |
1888 | + inkscape:pageopacity="0" |
1889 | + inkscape:pagecheckerboard="1" |
1890 | + inkscape:document-units="px" |
1891 | + showgrid="false" |
1892 | + units="px" |
1893 | + height="80px" |
1894 | + inkscape:zoom="3.0930415" |
1895 | + inkscape:cx="152.6006" |
1896 | + inkscape:cy="77.75518" |
1897 | + inkscape:window-width="1920" |
1898 | + inkscape:window-height="1059" |
1899 | + inkscape:window-x="0" |
1900 | + inkscape:window-y="0" |
1901 | + inkscape:window-maximized="1" |
1902 | + inkscape:current-layer="layer1" /> |
1903 | + <defs |
1904 | + id="defs2"> |
1905 | + <rect |
1906 | + x="72.43578" |
1907 | + y="4.989779" |
1908 | + width="233.3009" |
1909 | + height="93.363552" |
1910 | + id="rect22993" /> |
1911 | + <rect |
1912 | + x="76.460692" |
1913 | + y="7.5029808" |
1914 | + width="210.43456" |
1915 | + height="46.880685" |
1916 | + id="rect5098" /> |
1917 | + </defs> |
1918 | + <g |
1919 | + inkscape:label="Layer 1" |
1920 | + inkscape:groupmode="layer" |
1921 | + id="layer1"> |
1922 | + <path |
1923 | + d="m 10.58314,1.3501934 c -5.1005652,0 -9.23314,4.1325746 -9.23314,9.2331386 0,5.100566 4.1325748,9.233141 9.23314,9.233141 5.100565,0 9.23314,-4.132575 9.23314,-9.233141 0,-5.100564 -4.132575,-9.2331386 -9.23314,-9.2331386 z m 0,16.6792216 c -4.1139596,0 -7.4460807,-3.332121 -7.4460807,-7.446083 0,-4.1139582 3.3321211,-7.4460793 7.4460807,-7.4460793 4.11396,0 7.446082,3.3321211 7.446082,7.4460793 0,4.113962 -3.332122,7.446083 -7.446082,7.446083 z" |
1924 | + id="path49" |
1925 | + style="stroke-width:0.0372303" /> |
1926 | + <text |
1927 | + xml:space="preserve" |
1928 | + transform="scale(0.26458333)" |
1929 | + id="text22991" |
1930 | + style="fill:black;fill-opacity:1;line-height:1.25;stroke:none;font-family:sans-serif;font-style:normal;font-weight:normal;font-size:40px;white-space:pre;shape-inside:url(#rect22993)" /> |
1931 | + <text |
1932 | + xml:space="preserve" |
1933 | + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.2889px;line-height:1.25;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583" |
1934 | + x="22.349714" |
1935 | + y="13.896598" |
1936 | + id="text29885"><tspan |
1937 | + sodipodi:role="line" |
1938 | + id="tspan29883" |
1939 | + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.2889px;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583" |
1940 | + x="22.349714" |
1941 | + y="13.896598">sourcehut</tspan></text> |
1942 | + </g> |
1943 | + </svg> |
1944 | diff --git a/static/site.webmanifest b/static/site.webmanifest |
1945 | new file mode 100644 |
1946 | index 0000000..06d341a |
1947 | --- /dev/null |
1948 | +++ b/static/site.webmanifest |
1949 | @@ -0,0 +1,19 @@ |
1950 | + { |
1951 | + "name": "", |
1952 | + "short_name": "", |
1953 | + "icons": [ |
1954 | + { |
1955 | + "src": "/android-chrome-192x192.png", |
1956 | + "sizes": "192x192", |
1957 | + "type": "image/png" |
1958 | + }, |
1959 | + { |
1960 | + "src": "/android-chrome-512x512.png", |
1961 | + "sizes": "512x512", |
1962 | + "type": "image/png" |
1963 | + } |
1964 | + ], |
1965 | + "theme_color": "#ffffff", |
1966 | + "background_color": "#ffffff", |
1967 | + "display": "standalone" |
1968 | + } |
1969 | diff --git a/templates/base.html b/templates/base.html |
1970 | new file mode 100644 |
1971 | index 0000000..18d1d59 |
1972 | --- /dev/null |
1973 | +++ b/templates/base.html |
1974 | @@ -0,0 +1,55 @@ |
1975 | + <!DOCTYPE html> |
1976 | + <html lang="en-US"> |
1977 | + <head> |
1978 | + <meta charset="UTF-8" /> |
1979 | + <meta http-equiv="X-UA-Compatible" content="IE=edge" /> |
1980 | + <meta name="viewport" content="width=device-width, initial-scale=1" /> |
1981 | + <title>{% block title %}{{ config.title }}{% endblock title %}</title> |
1982 | + <meta |
1983 | + name="description" |
1984 | + itemprop="about" |
1985 | + content="{{config.description}}" |
1986 | + /> |
1987 | + <link rel="stylesheet" href="{{ get_url(path='styles.css') | safe }}" /> |
1988 | + </head> |
1989 | + |
1990 | + <body> |
1991 | + <div class="wrapper"> |
1992 | + <header> |
1993 | + <a href="{{ get_url(path='/') | safe }}"> |
1994 | + <img |
1995 | + src="{{ get_url(path='img/logo.svg') | safe }}" |
1996 | + class="site-logo" |
1997 | + alt="Logo" |
1998 | + width="275px" |
1999 | + height="auto" |
2000 | + /></a> |
2001 | + |
2002 | + <p>{{ config.description }}</p> |
2003 | + |
2004 | + |
2005 | + <a href="https://codeberg.org/ayllu/forge-feed"> |
2006 | + <img |
2007 | + src="{{ get_url(path='img/codeberg.svg') | safe }}" |
2008 | + class="site-logo" |
2009 | + alt="Logo" |
2010 | + /> |
2011 | + </a> |
2012 | + |
2013 | + <a href="https://git.sr.ht/~kevinschoon/forge-feed"> |
2014 | + <img |
2015 | + src="{{ get_url(path='img/sourcehut.svg') | safe }}" |
2016 | + class="site-logo sourcehut" |
2017 | + alt="Logo" |
2018 | + /> |
2019 | + </a> |
2020 | + </header> |
2021 | + |
2022 | + <section> {% block content %} {% endblock content %} </section> |
2023 | + |
2024 | + <footer> |
2025 | + <p><small>.</small></p> |
2026 | + </footer> |
2027 | + </div> |
2028 | + </body> |
2029 | + </html> |
2030 | diff --git a/templates/index.html b/templates/index.html |
2031 | new file mode 100644 |
2032 | index 0000000..3312f62 |
2033 | --- /dev/null |
2034 | +++ b/templates/index.html |
2035 | @@ -0,0 +1,6 @@ |
2036 | + {% extends "base.html" %} |
2037 | + |
2038 | + {% block content %} |
2039 | + <h1>{{ section.title }}</h1> |
2040 | + {{ section.content | safe }} |
2041 | + {% endblock content %} |
2042 | \ No newline at end of file |
2043 | diff --git a/templates/page.html b/templates/page.html |
2044 | new file mode 100644 |
2045 | index 0000000..d911e83 |
2046 | --- /dev/null |
2047 | +++ b/templates/page.html |
2048 | @@ -0,0 +1,6 @@ |
2049 | + {% extends "base.html" %} |
2050 | + |
2051 | + {% block content %} |
2052 | + <h1>{{ page.title }}</h1> |
2053 | + {{ page.content | safe }} |
2054 | + {% endblock content %} |
2055 | \ No newline at end of file |