Signed-off-by: Skylar "The Cobra" Widulski <cobra@vern.cc>
This commit is contained in:
Skylar "The Cobra" Widulski 2023-06-22 16:41:02 -04:00
commit fdaa3ae41d
Signed by: cobra
GPG Key ID: 4FD8F812083FF6F9
7 changed files with 731 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.swp

56
meme.scm Normal file
View File

@ -0,0 +1,56 @@
;; Copyright (C) 2023 Skylar Widulski <cobra@vern.cc>
;;
;; This file is part of MeMe
;;
;; MeMe is free software: you can redistribute it and/or modify it under the
;; terms of the GNU Affero General Public License as published by the Free
;; Software Foundation, either version 3 of the License, or (at your option) any
;; later version.
;;
;; This program is distributed in the hope that it will be useful, but WITHOUT
;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
;; for more details.
;;
;; You should have received a copy of the GNU Affero General Public License
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
(define-module (meme)
#:use-module (meme regex)
#:use-module (meme templates)
#:use-module (meme pages)
#:use-module (meme scraping)
#:use-module (web server)
#:use-module (web uri)
#:use-module (web request)
#:use-module (web http)
#:use-module (ice-9 textual-ports))
(define (handler request request-body)
(let ((uri (request-uri request))
(path (uri-path (request-uri request)))
(path-components
(split-and-decode-uri-path
(uri-path
(request-uri request)))))
(cond
((equal? path "/style.css")
(values '((content-type . (text/css)))
(call-with-input-file "static/style.css" get-string-all)))
((equal? path "/proxy")
(proxy-page (uri-query uri)))
((or (equal? path "/")
(equal? (car path-components)
"page"))
(article-list-page path))
(else (error-page 404)))))
(if (not (provided? 'regex))
(begin
(display "A POSIX regex library is required")
(newline)
(quit 1)))
(run-server handler 'http '(#:port 8003
#:addr 0))

69
meme/pages.scm Normal file
View File

@ -0,0 +1,69 @@
;; Copyright (C) 2023 Skylar Widulski <cobra@vern.cc>
;;
;; This file is part of MeMe
;;
;; MeMe is free software: you can redistribute it and/or modify it under the
;; terms of the GNU Affero General Public License as published by the Free
;; Software Foundation, either version 3 of the License, or (at your option) any
;; later version.
;;
;; This program is distributed in the hope that it will be useful, but WITHOUT
;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
;; for more details.
;;
;; You should have received a copy of the GNU Affero General Public License
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
(define-module (meme pages)
#:use-module (meme templates)
#:use-module (web response)
#:use-module (web client)
#:use-module (ice-9 receive)
#:export (error-page
article-list-page
proxy-page))
(define base-url "https://knowyourmeme.com")
(define good-response
(build-response #:code 200
#:headers `((content-type . (text/html)))))
(define (error-page code)
(values (build-response #:code code
#:headers `((content-type . (text/html)))) (error-template code)))
(define (article-list-page path)
(let ((resp "")
(body ""))
(receive (_resp _body) (http-request (string-append base-url path))
(set! resp _resp)
(set! body _body))
(if (equal? (response-code resp) 200)
(begin
(values good-response (article-list-template body)))
(error-page (response-code resp)))))
(define (proxy-page query)
(let ((resp "")
(body "")
(url ""))
(map (lambda (p)
(if (equal? (car p) "url")
(set! url (cadr p))))
(map (lambda (s)
(string-split s #\=))
(string-split (substring query 0) #\&)))
(if (equal? (substring url 0 22) "https://i.kym-cdn.com/")
(begin
(receive (_resp _body) (http-request url)
(set! resp _resp)
(set! body _body))
(if (equal? (response-code resp) 200)
(values (build-response #:code 200
#:headers `((content-type . ,(response-content-type resp))))
body)
(error-page 404)))
(error-page 400))))

58
meme/regex.scm Normal file
View File

@ -0,0 +1,58 @@
;; Copyright (C) 2023 Skylar Widulski <cobra@vern.cc>
;;
;; This file is part of MeMe
;;
;; MeMe is free software: you can redistribute it and/or modify it under the
;; terms of the GNU Affero General Public License as published by the Free
;; Software Foundation, either version 3 of the License, or (at your option) any
;; later version.
;;
;; This program is distributed in the hope that it will be useful, but WITHOUT
;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
;; for more details.
;;
;; You should have received a copy of the GNU Affero General Public License
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
(define-module (meme regex)
#:use-module (ice-9 regex)
#:export (no-post-regex
leaderboard-regex
trending-section-regex
trending-regex
articles-section-regex
articles-regex
sidebar-section-regex
sidebar-gallery-regex
sidebar-trending-regex
pagination-regex))
(define no-post-regex (make-regexp "([^<>]*)[<>]"))
(define leaderboard-regex
(make-regexp "<li data-index='[0-9]+'> <article class='rel c entry' id='([^']*)'> <a href=\"([^\"]*)\" class=\"photo left\" target=\"_self\"><img alt=\"[^\"]*\" fetchpriority=\"low\" height=\"112\" src=\"([^\"]*)\" title=\"[^\"]*\" width=\"198\" /> <div class='info abs'> <div class='c'> ([^<]*) </div> </div> </a></article> </li>"))
(define trending-section-regex
(make-regexp "<section id=\"trending-bar\">(.*)</section>"))
(define trending-regex
(make-regexp "<a href=\"([^\"]*)\" title=\"[^\"]*\">([^<>]*)</a>"))
(define articles-section-regex
(make-regexp "<div class='newsfeed' id='feed_items'>([^<>]*)</div>"))
(define articles-regex
(make-regexp "<article class='nf_item [^']* c' data-title=['\"][^=]*['\"] data-type='[^']*' id='([^']*)'>\n<div class='c rel'>\n(<div class=\"faves abs\"><div class='fave'>\n<a href=\"[^\"]*\" class=\"favorite\" data-item-id=\"[^\"]*\" data-item-type=\"[^\"]*\" data-method=\"post\" data-remote=\"true\" rel=\"nofollow\" title=\"[^\"]*\"><span class=\"num\">([^<>]*)</span>\n</a></div>\n</div>\n|)<section>\n<h1><a href=\"([^\"]*)\" class=\"newsfeed-title\" title=\"([^\"]*)\">[^<>]*</a></h1>\n(<div class='media'>\n)?<div class=\"media\">(<a href=\"([^\"]*)\" class=\"stamp newsfeed-stamp label( newsfeed-stamp-tooltip)?\" rel=\"nofollow\" style=\"background-color: #[^\"]*\" target=\"_self\" title=\"([^\"]*)\">([^<>]*)</a>)? ?<a href=\"[^\"]*\" class=\"newsfeed-image\" rel=\"nofollow\">(<div class=\"play large-video\"></div>\n)?<picture><source srcset=\"([^\"]*)\" /><img alt=\"[^\"]*\" class=\"newsfeed_photo\" data-src=\"[^\"]*\" height=\"[^\"]*\" loading=\"lazy\" src=\"[^\"]*\" title=\"[^\"]*\" width=\"680\" /></picture></a></div>\n(</div>\n)?<br>\n<div class=\"summary\">(<p>([^\x02]*)\x02</p>)?</div>\n<p class=\"left_aligned_timestamp\"><em>([^<>]*)</em></p>\n<p><a href=\"[^\"]*\" class=\"comments_count newsfeed-comments\" rel=\"nofollow\">([^<>]*) comments</a></p>\n</section>\n</div>\n</article>"))
(define sidebar-section-regex
(make-regexp "<aside class='right' id='sidebar'>\n*(.*)</aside>"))
(define sidebar-gallery-regex
(make-regexp "<div class='sidebar_box c' id='[^']*'> <h3> ([^<>]*) </h3> <table> <tr class='row-[0-9]+'> <td> <a href=\"([^\"]*)\"><img alt=\"([^\"]*)\"( class=\"top-gallery-thumbnail\")? data-src=\"([^\"]*)\" height=\"[^\"]*\" loading=\"lazy\" src=\"[^\"]*\" width=\"[^\"]*\" /></a> <h4> <a href=\"[^\"]*\">([^<>]*)</a> </h4> </td> <td> <a href=\"([^\"]*)\"><img alt=\"([^\"]*)\"( class=\"top-gallery-thumbnail\")? data-src=\"([^\"]*)\" height=\"[^\"]*\" loading=\"lazy\" src=\"[^\"]*\" width=\"[^\"]*\" /></a> <h4> <a href=\"[^\"]*\">([^<>]*)</a> </h4> </td> </tr> <tr class='row-[0-9]+'> <td> <a href=\"([^\"]*)\"><img alt=\"([^\"]*)\"( class=\"top-gallery-thumbnail\")? data-src=\"([^\"]*)\" height=\"[^\"]*\" loading=\"lazy\" src=\"[^\"]*\" width=\"[^\"]*\" /></a> <h4> <a href=\"[^\"]*\">([^<>]*)</a> </h4> </td> <td> <a href=\"([^\"]*)\"><img alt=\"([^\"]*)\"( class=\"top-gallery-thumbnail\")? data-src=\"([^\"]*)\" height=\"[^\"]*\" loading=\"lazy\" src=\"[^\"]*\" width=\"[^\"]*\" /></a> <h4> <a href=\"[^\"]*\">([^<>]*)</a> </h4> </td> </tr> </table> </div>"))
(define sidebar-trending-regex
(make-regexp "<div class='sidebar_box' id='[^']*'> <h3> <a href=\"([^\"]*)\">([^<>]*)</a> </h3> <table> <tr> <td> <a href=\"([^\"]*)\"><img alt=\"[^\"]*\" data-src=\"([^\"]*)\" height=\"[^\"]*\" loading=\"lazy\" src=\"[^\"]*\" width=\"[^\"]*\" /></a> </td> <td> <a href=\"([^\"]*)\"><img alt=\"[^\"]*\" data-src=\"([^\"]*)\" height=\"[^\"]*\" loading=\"lazy\" src=\"[^\"]*\" width=\"[^\"]*\" /></a> </td> <td> <a href=\"([^\"]*)\"><img alt=\"[^\"]*\" data-src=\"([^\"]*)\" height=\"[^\"]*\" loading=\"lazy\" src=\"[^\"]*\" width=\"[^\"]*\" /></a> </td> </tr> <tr> <td> <a href=\"([^\"]*)\"><img alt=\"[^\"]*\" data-src=\"([^\"]*)\" height=\"[^\"]*\" loading=\"lazy\" src=\"[^\"]*\" width=\"[^\"]*\" /></a> </td> <td> <a href=\"([^\"]*)\"><img alt=\"[^\"]*\" data-src=\"([^\"]*)\" height=\"[^\"]*\" loading=\"lazy\" src=\"[^\"]*\" width=\"[^\"]*\" /></a> </td> <td> <a href=\"([^\"]*)\"><img alt=\"[^\"]*\" data-src=\"([^\"]*)\" height=\"[^\"]*\" loading=\"lazy\" src=\"[^\"]*\" width=\"[^\"]*\" /></a> </td> </tr> <tr> <td> <a href=\"([^\"]*)\"><img alt=\"[^\"]*\" data-src=\"([^\"]*)\" height=\"[^\"]*\" loading=\"lazy\" src=\"[^\"]*\" width=\"[^\"]*\" /></a> </td> <td> <a href=\"([^\"]*)\"><img alt=\"[^\"]*\" data-src=\"([^\"]*)\" height=\"[^\"]*\" loading=\"lazy\" src=\"[^\"]*\" width=\"[^\"]*\" /></a> </td> <td> <a href=\"([^\"]*)\"><img alt=\"[^\"]*\" data-src=\"([^\"]*)\" height=\"[^\"]*\" loading=\"lazy\" src=\"[^\"]*\" width=\"[^\"]*\" /></a> </td> </tr> </table> </div>"))
(define pagination-regex
(make-regexp "(<div class=\"pagination\">[^\n]*</div>)</div>"))

101
meme/scraping.scm Normal file
View File

@ -0,0 +1,101 @@
;; Copyright (C) 2023 Skylar Widulski <cobra@vern.cc>
;;
;; This file is part of MeMe
;;
;; MeMe is free software: you can redistribute it and/or modify it under the
;; terms of the GNU Affero General Public License as published by the Free
;; Software Foundation, either version 3 of the License, or (at your option) any
;; later version.
;;
;; This program is distributed in the hope that it will be useful, but WITHOUT
;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
;; for more details.
;;
;; You should have received a copy of the GNU Affero General Public License
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
(define-module (meme scraping)
#:use-module (meme regex)
#:use-module (ice-9 regex)
#:use-module (ice-9 string-fun)
#:export (get-leaderboard
get-trending
get-articles
get-sidebar-gallery
get-sidebar-trending
get-pagination))
(define (no-post reg)
(regexp-substitute/global #f no-post-regex reg 1))
(define (get-leaderboard body)
(map (lambda (s)
(string-split s #\x01))
(string-split
(no-post
(regexp-substitute/global #f leaderboard-regex body
1 "\x01" 2 "\x01" 3 "\x01" 4 "\x00" 'post))
#\x00)))
(define (get-trending body)
(map (lambda (s)
(string-split s #\x01))
(string-split
(no-post
(regexp-substitute/global #f trending-regex
(regexp-substitute/global
#f trending-section-regex body 1)
1 "\x01" 2 "\x00" 'post))
#\x00)))
(define (get-articles body)
(map (lambda (s)
(string-split s #\x01))
(string-split
(no-post
(regexp-substitute/global #f articles-regex
(regexp-substitute/global
#f articles-section-regex
(string-replace-substring
body
"</p></div>"
"\x02</p></div>") 1)
1 "\x01" 3 "\x01" 4 "\x01" 5 "\x01"
8 "\x01" 10 "\x01" 11 "\x01" 13 "\x01"
16 "\x01" 17 "\x01" 18 "\x00" 'post))
#\x00)))
(define (get-sidebar-gallery body)
(map (lambda (s)
(string-split s #\x01))
(string-split
(no-post
(regexp-substitute/global #f sidebar-gallery-regex
(regexp-substitute/global
#f sidebar-section-regex body 1)
1 "\x01" 2 "\x01" 3 "\x01" 5 "\x01"
6 "\x01" 7 "\x01" 8 "\x01" 10 "\x01"
11 "\x01" 12 "\x01" 13 "\x01" 15 "\x01"
16 "\x01" 17 "\x01" 18 "\x01" 20 "\x01"
21 "\x00" 'post))
#\x00)))
(define (get-sidebar-trending body)
(map (lambda (s)
(string-split s #\x01))
(string-split
(no-post
(regexp-substitute/global #f sidebar-trending-regex
(regexp-substitute/global
#f sidebar-section-regex body 1)
1 "\x01" 2 "\x01" 3 "\x01" 4 "\x01"
5 "\x01" 6 "\x01" 7 "\x01" 8 "\x01"
9 "\x01" 10 "\x01" 11 "\x01" 12 "\x01"
13 "\x01" 14 "\x01" 15 "\x01" 16 "\x01"
17 "\x01" 18 "\x01" 19 "\x01" 20 "\x00"
'post))
#\x00)))
(define (get-pagination body)
(regexp-substitute/global #f pagination-regex body 1))

274
meme/templates.scm Normal file
View File

@ -0,0 +1,274 @@
;; Copyright (C) 2023 Skylar Widulski <cobra@vern.cc>
;;
;; This file is part of MeMe
;;
;; MeMe is free software: you can redistribute it and/or modify it under the
;; terms of the GNU Affero General Public License as published by the Free
;; Software Foundation, either version 3 of the License, or (at your option) any
;; later version.
;;
;; This program is distributed in the hope that it will be useful, but WITHOUT
;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
;; for more details.
;;
;; You should have received a copy of the GNU Affero General Public License
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
(define-module (meme templates)
#:use-module (meme scraping)
#:use-module (htmlprag)
#:export (error-template
article-list-template))
(define (proxy url)
(string-append "/proxy?url=" url))
(define (html-head title)
`(head (title ,title)
(meta (@ (charset "UTF-8")))
(meta (@ (name "viewport") (content "width=device-width")))
(link (@ (rel "stylesheet") (href "/style.css")))
(link (@ (rel "icon") (type "image/png") (href "/favicon.png")))))
(define heading
`(header
(div (@ (class "box heading"))
(ul (@ (class "navbar"))
(li (@ (class "home"))
(a (@ (href "/")) "home"))
(li (@ (class "memes"))
(a (@ (href "/memes")) "memes")
(div (@ (class "dropdown box"))
(ul
(li (a (@ (href "/memes/submissions")) "submissions"))
(li (a (@ (href "/memes/researching")) "researching"))
(li (a (@ (href "/memes/newsworthy")) "newsworthy"))
(li (a (@ (href "/memes/popular")) "popular"))
(li (a (@ (href "/memes/deadpool")) "deadpool"))
(li (a (@ (href "/memes/all")) "all")))))
(li (@ (class "categories"))
(a (@ (href "/categories")) "categories")
(div (@ (class "dropdown box"))
(ul
(li (a (@ (href "/categories/culture")) "cultures"))
(li (a (@ (href "/categories/event")) "events"))
(li (a (@ (href "/categories/meme")) "memes"))
(li (a (@ (href "/categories/person")) "people"))
(li (a (@ (href "/categories/site")) "sites"))
(li (a (@ (href "/categories/subculture"))
"subcultures")))))
(li (@ (class "news"))
(a (@ (href "/news")) "news"))
(li (@ (class "images"))
(a (@ (href "/photos")) "images")
(div (@ (class "dropdown box"))
(ul
(li (a (@ (href "/photos/trending")) "trending"))
(li (a (@ (href "/photos/most-commented"))
"most comments"))
(li (a (@ (href "/photos/most-favorited"))
"most favorites"))
(li (a (@ (href "/photos/most-liked")) "most likes"))
(li (a (@ (href "/photos/least-liked")) "least likes"))
(li (a (@ (href "/photos/most-viewed")) "most views"))
(li (a (@ (href "/photos/templates")) "template")))))
(li (@ (class "videos"))
(a (@ (href "/videos")) "videos")
(div (@ (class "dropdown box"))
(ul
(li (a (@ (href "/videos/trending")) "trending"))
(li (a (@ (href "/videos/most-commemted"))
"most comments"))
(li (a (@ (href "/videos/most-favorited"))
"most favorites"))
(li (a (@ (href "/videos/most-liked")) "most likes"))
(li (a (@ (href "/videos/most-viewed"))
"most views")))))
(li (@ (class "editorials"))
(a (@ (href "/editorials")) "editorial")
(div (@ (class "dropdown box"))
(ul
(li (a (@ (href "/editorials/interviews"))
"interviews"))
(li (a (@ (href "/editorials/in-the-media"))
"in the media"))
(li (a (@ (href "/editorials/white-papers"))
"white papers"))
(li (a (@ (href "/editorials/episode-notes"))
"episode notes"))
(li (a (@ (href "/editorials/behind-the-scenes"))
"behind the scenes"))
(li (a (@ (href "/editorials/meme-review"))
"meme review"))
(li (a (@ (href "/editorials/collections"))
"collections"))
(li (a (@ (href "/editorials/poll")) "poll"))
(li (a (@ (href "/editorials/guides")) "guides"))
(li (a (@ (href "/editorials/meme-insider"))
"meme-insider"))
(li (a (@ (href "/editorials/insights"))
"insights")))))
(li (@ (class "episodes"))
(a (@ (href "/episodes"))))))))
(define (leaderboard-as-sxml leaderboard)
`(div (@ (class "leaderboard box"))
(ul (@ (class "leaderboard"))
,(map (lambda (l)
(if (equal? (length l) 4)
`(li (@ (id ,(car l)))
(a (@ (href ,(cadr l)))
(img (@ (src ,(proxy (caddr l)))
(alt ,(cadddr l))))
(p (@ (class "tooltip box")) ,(cadddr l))))
`()))
leaderboard))))
(define (trending-as-sxml trending)
`(div (@ (class "trending box"))
(p "trending:")
,(map (lambda (l)
(if (equal? (length l) 2)
`(p (a (@ (href ,(car l))) ,(html->shtml (cadr l))))
`()))
trending)))
(define (articles-as-sxml articles)
`(div (@ (class "articles box"))
(ul (@ (class "articles-list"))
,(map (lambda (l)
(if (equal? (length l) 11)
`(li (@ (class "article"))
(a (@ (href ,(caddr l)))
(h1 ,(html->shtml (cadddr l)))
(img (@ (src ,(proxy (car (list-tail l 7))))
(alt ,(cadddr l))))
,(if (not (equal? (car (list-tail l 8)) "#f"))
`(p ,(html->shtml (car (list-tail l 8))))
`())
(ul (@ (class "rl"))
(li (@ (class "list-date"))
(i ,(car (list-tail l 9))))
(li (@ (class "list-favcom"))
,(string-append
(if (not (equal? (cadr l) "#f"))
(string-append (cadr l)
" favorites, ")
"")
(car (list-tail l 10))
" comments"))))
(hr))
`()))
articles))))
(define (sidebar-gallery-as-sxml sidebar-gallery)
`(div (@ (class "sidebar box"))
,(map (lambda (l)
(if (equal? (length l) 17)
`(div
(h3 ,(html->shtml (car l)))
(table (@ (class "gallery"))
(tr (td (a (@ (href ,(cadr l)))
(img (@ (src ,(proxy (cadddr l)))
(alt ,(caddr l))))
(p (b ,(html->shtml
(car (list-tail l 4)))))))
(td (a (@ (href ,(car (list-tail l 5))))
(img (@ (src
,(proxy
(car (list-tail l 7))))
(alt ,(car (list-tail l 6)))))
(p (b ,(html->shtml
(car (list-tail l 8))))))))
(tr (td (a (@ (href ,(car (list-tail l 9))))
(img (@ (src
,(proxy
(car (list-tail l 11))))
(alt ,(car (list-tail l 10)))))
(p (b ,(html->shtml
(car (list-tail l 12)))))))
(td (a (@ (href ,(car (list-tail l 13))))
(img (@ (src
,(proxy
(car (list-tail l 15))))
(alt ,(car (list-tail l 14)))))
(p (b ,(html->shtml
(car (list-tail l 16))))))))))
`()))
sidebar-gallery)))
(define (sidebar-trending-as-sxml sidebar-trending)
`(div (@ (class "sidebar box"))
,(map (lambda (l)
(if (equal? (length l) 20)
`(div
(h3 (a (@ (href ,(car l)))
,(cadr l)))
(table (@ (class "trending-images"))
(tr (td (a (@ (href ,(caddr l)))
(img (@ (src ,(proxy (cadddr l)))))))
(td (a (@ (href ,(car (list-tail l 4))))
(img (@ (src
,(proxy
(car (list-tail l 5))))))))
(td (a (@ (href ,(car (list-tail l 6))))
(img (@ (src
,(proxy
(car (list-tail l 7)))))))))
(tr (td (a (@ (href ,(car (list-tail l 8))))
(img (@ (src
,(proxy
(car (list-tail l 9))))))))
(td (a (@ (href ,(car (list-tail l 10))))
(img (@ (src
,(proxy
(car (list-tail l 11))))))))
(td (a (@ (href ,(car (list-tail l 12))))
(img (@ (src
,(proxy
(car
(list-tail l 13)))))))))
(tr (td (a (@ (href ,(car (list-tail l 14))))
(img (@ (src
,(proxy
(car (list-tail l 15))))))))
(td (a (@ (href ,(car (list-tail l 16))))
(img (@ (src
,(proxy
(car (list-tail l 17))))))))
(td (a (@ (href ,(car (list-tail l 18))))
(img (@ (src
,(proxy
(car
(list-tail l 19)))))))))))
`()))
sidebar-trending)))
(define (pagination-as-sxml pagination)
`(div (@ (class "pagination box"))
,(html->shtml pagination)))
(define (error-template code)
(shtml->html
`(html ,(html-head (string-append (number->string code) " | MeMe"))
(body
,heading
(center
(h1 (@ (class "error")) ,(number->string code)))))))
(define (article-list-template body)
(shtml->html
`(html ,(html-head "MeMe")
(body
,heading
,(leaderboard-as-sxml (get-leaderboard body))
,(trending-as-sxml (get-trending body))
(div (@ (class "left"))
,(articles-as-sxml (get-articles body))
,(pagination-as-sxml (get-pagination body)))
(div (@ (class "right"))
,(sidebar-gallery-as-sxml (get-sidebar-gallery body))
,(sidebar-trending-as-sxml (get-sidebar-trending body)))))))

172
static/style.css Normal file
View File

@ -0,0 +1,172 @@
body {
font-family: Fira Sans, Liberation Sans, DejaVu Sans, sans-serif;
font-size: 1.1em;
line-height: 1.5em;
color: #ffc8dd;
background-color: #2e2016;
hyphens: auto;
max-width: 1280px;
margin: 0 auto;
}
h1 {
line-height: 1.5em;
max-width: 90%;
}
h1.error {
line-height: 0;
font-size: 20em;
}
a {
color: #ff99c8;
text-decoration: none;
}
.box {
border: 5px solid #c6888d;
border-radius: 5px;
margin: 1%;
background-color: #473032;
display: inline-block;
vertical-align: top;
}
.left {
margin: 1%;
display: flex;
flex-direction: column;
width: 60%;
float: left;
display: inline-block;
}
.right {
margin: 1%;
display: flex;
flex-direction: column;
width: 34%;
float: right;
display: inline-block;
}
.sidebar.box,
.articles.box,
.pagination.box {
margin: 0 0 5% 0;
width: 100%;
}
.trending.box,
.leaderboard.box,
.heading.box {
line-height: 0;
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.leaderboard.box p {
line-height: 1.1em;
}
ul.navbar {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
list-style-type: none;
align-items: center;
width: 80%;
}
.dropdown,
.tooltip {
display: none;
position: absolute;
margin-left: 0;
margin-top: 0;
padding: 0.5% 0;
}
hr {
width: 90%;
}
div.dropdown ul {
list-style-type: none;
margin-left: -20%;
}
ul.navbar li:hover div.dropdown,
div.dropdown:hover,
ul.leaderboard li:hover p {
display: block;
}
ul.leaderboard {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
list-style-type: none;
align-items: center;
margin: 0%;
padding: 1% 0;
width: 95%;
}
div.trending p {
display: inline-block;
padding: 0 1%;
}
ul.articles-list {
list-style-type: none;
}
li.article img {
max-width: 80%;
}
li.article hr {
margin-left: 0;
}
ul.rl {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
list-style-type: none;
margin-left: -40px;
margin-right: 10%;
}
h3 {
text-align: center;
}
table.gallery tr td {
width: 50%;
vertical-align: top;
}
table.gallery img {
width: 100%;
}
table.trending-images tr td {
width: 30%;
}
table.trending-images img {
width: 100%;
}
.articles.box {
margin-bottom: 1%;
}
.pagination.box {
text-align: center;
margin-top: 0;
}