From f046b4d76b5760321f919b3a77c21923aa05ce80 Mon Sep 17 00:00:00 2001 From: Tony Garnock-Jones Date: Sun, 9 Nov 2014 16:28:41 -0500 Subject: [PATCH] Tweaks --- src/bootstrap.rkt | 3 +- src/gravatar.rkt | 20 ++++++++ src/packages.rkt | 2 +- src/site.rkt | 114 +++++++++++++++++++++++++++++---------------- static/mainpage.js | 3 ++ static/style.css | 37 ++++++++++++++- 6 files changed, 136 insertions(+), 43 deletions(-) create mode 100644 src/gravatar.rkt create mode 100644 static/mainpage.js diff --git a/src/bootstrap.rkt b/src/bootstrap.rkt index 0fde7ed..c165181 100644 --- a/src/bootstrap.rkt +++ b/src/bootstrap.rkt @@ -39,6 +39,7 @@ #:title-element [title-element `(h1 ,title)] #:code [code 200] #:message [message #"Okay"] + #:body-class [body-class #f] . body-contents) (response/xexpr @@ -55,7 +56,7 @@ (link ((rel "stylesheet") (href "/style.css") (type "text/css"))) ,@(for/list ((sheet (bootstrap-page-stylesheets))) `(link ((rel "stylesheet") (href ,sheet) (type "text/css"))))) - (body + (body ,@(maybe-splice body-class `((class ,body-class))) (nav ((class "navbar navbar-inverse navbar-fixed-top") (role "navigation")) (div ((class "container")) (div ((class "navbar-header")) diff --git a/src/gravatar.rkt b/src/gravatar.rkt new file mode 100644 index 0000000..d326aeb --- /dev/null +++ b/src/gravatar.rkt @@ -0,0 +1,20 @@ +#lang racket/base + +(provide gravatar-hash + gravatar-image-url) + +(require file/md5) +(require racket/string) + +(define (gravatar-hash email) + (bytes->string/utf-8 + (md5 + (string-downcase + (string-trim email))))) + +(define (gravatar-image-url email [size 80] #:extension [extension ""] #:default [default "identicon"]) + (format "http://www.gravatar.com/avatar/~a~a?s=~a&d=~a" + (gravatar-hash email) + extension + size + default)) diff --git a/src/packages.rkt b/src/packages.rkt index 9f9b9a9..d04c52a 100644 --- a/src/packages.rkt +++ b/src/packages.rkt @@ -217,7 +217,7 @@ (regexp-match? re (@ pkg _SEARCHABLE-TEXT_)))) (define (package-search text tags) - (define res (map (lambda (r) (regexp (regexp-quote r))) (string-split text))) + (define res (map (lambda (r) (regexp (regexp-quote r #f))) (string-split text))) (define packages (manager-rpc 'packages)) (sort-package-names (filter (lambda (package-name) diff --git a/src/site.rkt b/src/site.rkt index e29a0ed..9169786 100644 --- a/src/site.rkt +++ b/src/site.rkt @@ -10,6 +10,7 @@ (require racket/string) (require net/uri-codec) (require web-server/servlet) +(require "gravatar.rkt") (require "bootstrap.rkt") (require "html-utils.rkt") (require "packages.rkt") @@ -121,6 +122,9 @@ (li ((class "dropdown")) (a ((class "dropdown-toggle") (data-toggle "dropdown")) + (img ((src ,(gravatar-image-url (session-email session) + 48)))) + " " ,(session-email session) " " (span ((class "caret")))) @@ -213,6 +217,9 @@ ,(form-group 4 5 `(a ((href ,(embed-url (lambda (req) (register-page))))) "Need to reset your password?")) + ,(form-group 4 5 + `(a ((href ,(embed-url (lambda (req) (register-page))))) + "Register an account")) ,@(maybe-splice error-message (form-group 4 5 @@ -249,27 +256,15 @@ (lambda (embed-url) (bootstrap-response "Register/Reset Account" #:title-element "" - `(div - (h1 "Got a registration or reset code?") - (p "Great! Enter it below, with your chosen password, to log in.") - (form ((class "form-horizontal") - (method "post") - (action ,(embed-url apply-account-code)) - (role "form")) - ,(form-group 2 2 (label "email" "Email address") - 0 5 (email-input "email" email)) - ,(form-group 2 2 (label "code" "Code") - 0 5 (text-input "code" code)) - ,(form-group 2 2 (label "password" "Password") - 0 5 (password-input "password")) - ,(form-group 2 2 (label "password" "Confirm password") - 0 5 (password-input "confirm_password")) - ,@(maybe-splice - error-message - (form-group 4 5 - `(div ((class "alert alert-danger")) - (p ,error-message)))) - ,(form-group 4 5 (primary-button "Continue")))) + `(div ((class "registration-step-container")) + (div ((class "registration-step")) + (div (h1 "Step 1") + (p "Get a code"))) + (span ((class "registration-step-arrow")) "→") + (div ((class "registration-step")) + (div (h1 "Step 2") + (p "Use the code")))) + `(div (h1 "Need a code?") (p "Enter your email address below, and we'll send you one.") @@ -277,9 +272,31 @@ (method "post") (action ,(embed-url notify-of-emailing)) (role "form")) - ,(form-group 2 2 (label "email" "Email address") + ,(form-group 1 3 (label "email" "Email address") 0 5 (email-input "email_for_code")) - ,(form-group 4 5 (primary-button "Email me a code"))))))))) + ,(form-group 4 5 (primary-button "Email me a code")))) + + `(div + (h1 "Got a registration or reset code?") + (p "Great! Enter it below, with your chosen password, to log in.") + (form ((class "form-horizontal") + (method "post") + (action ,(embed-url apply-account-code)) + (role "form")) + ,(form-group 1 3 (label "email" "Email address") + 0 5 (email-input "email" email)) + ,(form-group 1 3 (label "code" "Code") + 0 5 (text-input "code" code)) + ,(form-group 1 3 (label "password" "Password") + 0 5 (password-input "password")) + ,(form-group 1 3 (label "password" "Confirm password") + 0 5 (password-input "confirm_password")) + ,@(maybe-splice + error-message + (form-group 4 5 + `(div ((class "alert alert-danger")) + (p ,error-message)))) + ,(form-group 4 5 (primary-button "Continue"))))))))) (define (apply-account-code request) (define-form-bindings request (email code password confirm_password)) @@ -347,8 +364,12 @@ (named-url search-page) (alist->form-urlencoded (list (cons 'tags (string-join tags)))))) -(define (author-link author-name) - `(a ((href ,(tags-page-url (list (format "author:~a" author-name))))) ,author-name)) +(define (author-link author-name #:gravatar? [gravatar? #f]) + `(a ((href ,(tags-page-url (list (format "author:~a" author-name))))) + ,@(maybe-splice gravatar? + `(img ((src ,(gravatar-image-url author-name 48)))) + " ") + ,author-name)) (define (tag-link tag-name) `(a ((href ,(tags-page-url (list tag-name)))) ,tag-name)) @@ -357,8 +378,9 @@ `(a (,@attributes (href ,(format "http://pkg-build.racket-lang.org/~a" url-suffix))) ,label)) -(define (authors-list authors) - `(ul ((class "authors")) ,@(for/list ((author authors)) `(li ,(author-link author))))) +(define (authors-list authors #:gravatars? [gravatars? #f]) + `(ul ((class "authors")) ,@(for/list ((author authors)) + `(li ,(author-link author #:gravatar? gravatars?))))) (define (package-links #:pretty? [pretty? #t] package-names) (if (and pretty? (null? (or package-names '()))) @@ -434,26 +456,37 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define (main-page request) - (parameterize ((bootstrap-active-navigation nav-index)) + (parameterize ((bootstrap-active-navigation nav-index) + (bootstrap-page-scripts '("/mainpage.js"))) (define package-name-list (package-search "" '((main-distribution #f)))) (authentication-wrap #:request request (bootstrap-response "Racket Package Index" #:title-element "" + #:body-class "main-page" `(div ((class "jumbotron")) - (h1 "Racket Package Index") - (p "These are the packages available via the " + (h1 "Racket Packages") + (p "These are the packages in the " (a ((href "http://docs.racket-lang.org/pkg/getting-started.html")) "Racket package system") ".") - (p "Simply run " (kbd "raco pkg install " (var "package-name")) - " to install a package.") - (p ((class "text-center")) - (span ((class "package-count")) ,(~a (length package-name-list))) - " packages in the index.") + (p (a ((href "http://docs.racket-lang.org/pkg/cmdline.html")) + (kbd "raco pkg install " (var "package-name"))) + " installs a package.") + (p "You can " + (a ((id "create-package-link") + (href ,(named-url edit-package-page))) + (span ((class "label label-success")) + ,(glyphicon 'plus-sign) + " add your own")) + " packages to the index.")) + `(div ((id "search-box")) (form ((role "form") (action ,(named-url search-page))) ,(text-input "q" #:placeholder "Search packages"))) - (package-summary-table package-name-list))))) + `(div + (p ((class "package-count")) + ,(format "~a packages" (length package-name-list))) + ,(package-summary-table package-name-list)))))) (define (logout-page request) (with-site-config @@ -563,7 +596,8 @@ `(table ((class "package-details")) (tr (th "Authors") - (td ,(authors-list (@ pkg authors)))) + (td (div ((class "authors-detail")) + ,(authors-list #:gravatars? #t (@ pkg authors))))) (tr (th "Documentation") (td ,(doc-links (@ pkg build docs)))) (tr (th "Tags") @@ -748,8 +782,8 @@ (define old-name (draft-package-old-name draft)) (define has-old-name? (not (equal? old-name ""))) (bootstrap-response (if has-old-name? - (format "Editing package ~a" old-name) - "Creating a new package") + (format "Edit package ~a" old-name) + "Create a new package") (if error-message `(div ((class "alert alert-danger")) ,(glyphicon 'exclamation-sign) " " ,error-message) @@ -1032,7 +1066,7 @@ (match t [(pregexp #px"!(.*)" (list _ tag)) (list (string->symbol tag) #f)] [tag (list (string->symbol tag) #t)]))) - (bootstrap-response "Search Racket Package Index" + (bootstrap-response "Search Package Index" `(form ((class "form-horizontal") (role "form")) ,(form-group 0 2 (label "q" "Search terms") diff --git a/static/mainpage.js b/static/mainpage.js new file mode 100644 index 0000000..b199f5c --- /dev/null +++ b/static/mainpage.js @@ -0,0 +1,3 @@ +$(document).ready(function () { + $("#q").focus(); +}); diff --git a/static/style.css b/static/style.css index 4d11f59..e3ac3ce 100644 --- a/static/style.css +++ b/static/style.css @@ -52,6 +52,9 @@ ul.list-inline li { padding-right: 0; } ul.authors { list-style: none; padding: 0; } ul.authors a { color: black; } +.authors-detail ul { margin: 0; } +.authors-detail li { margin: 0 0 0.5em 0; } + table.packages h2 { font-size: 160%; margin-top: 0; } ul.build-results, @@ -59,7 +62,13 @@ ul.module-list { list-style: none; padding: 0; } +#search-box { + margin: 2em; +} + .search-results { margin-top: 3em; } + +.main-page .package-count, .search-results .package-count { font-size: 100%; padding: 0.5em; @@ -73,10 +82,10 @@ input#new_version { .confirm-package-deletion { background-color: red; padding: 2em; + width: 50%; display: block; margin-left: auto; margin-right: auto; - width: 50%; text-align: center; color: white; border: solid yellow 1em; @@ -95,6 +104,10 @@ input#new_version { text-decoration: none; } +.jumbotron #create-package-link { + text-decoration: none; +} + /* Sortable tables */ th.headerSortUp::after { content: " ▼"; } th.headerSortDown::after { content: " ▲"; } @@ -104,3 +117,25 @@ th.headerSortDown::after { content: " ▲"; } margin-left: 8px; margin-right: 0px; } + +.registration-step-container { + margin: 2em auto; + display: block; + width: 44em; +} +.registration-step-arrow { + font-size: 300%; +} +.registration-step { + display: inline-block; + background: #5CB85C; /* "success" colour */ + padding: 1em; + margin: 2em; + width: 16em; + text-align: center; + color: white; + text-shadow: 1px 1px 3px #444; + border-radius: 10px; +} +.registration-step h1 { margin: 0.5em; } +.registration-step p { font-size: 140%; } \ No newline at end of file