aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Joey Hess <joey@kitenet.net>2012-07-27 04:48:50 -0400
committerGravatar Joey Hess <joey@kitenet.net>2012-07-27 04:48:50 -0400
commit7e3c1e008d6b2eff10d412993df293fce2156151 (patch)
treebd1d1395c452df84573e7a8acb560e623e4ad063
parent1192e305c7fa7ba0b6572cc8c450127d6458b0af (diff)
webapp now uses twitter bootstrap
mocked up the main screen, and am actually pretty happy with it!
-rw-r--r--Assistant/Threads/WebApp.hs24
-rw-r--r--debian/copyright382
-rw-r--r--doc/design/assistant/blog/day_45__long_polling/full.pngbin0 -> 55185 bytes
-rw-r--r--doc/design/assistant/blog/day_45__long_polling/phone.pngbin0 -> 41602 bytes
-rw-r--r--static/css/bootstrap-responsive.css686
-rw-r--r--static/css/bootstrap.css (renamed from static/bootstrap.css)4
-rw-r--r--static/glyphicons-halflings-white.pngbin4352 -> 0 bytes
-rw-r--r--static/glyphicons-halflings.pngbin4352 -> 0 bytes
-rw-r--r--static/js/bootstrap-dropdown.js92
-rw-r--r--templates/bootstrap.hamlet52
-rw-r--r--templates/default-layout.hamlet13
-rw-r--r--templates/longpolling.julius4
-rw-r--r--templates/status.hamlet28
13 files changed, 877 insertions, 408 deletions
diff --git a/Assistant/Threads/WebApp.hs b/Assistant/Threads/WebApp.hs
index f82a1fb6b..050d62cf1 100644
--- a/Assistant/Threads/WebApp.hs
+++ b/Assistant/Threads/WebApp.hs
@@ -47,11 +47,16 @@ mkYesod "WebApp" [parseRoutes|
|]
instance Yesod WebApp where
- defaultLayout contents = do
- page <- widgetToPageContent contents
+ defaultLayout widget = do
mmsg <- getMessage
webapp <- getYesod
- hamletToRepHtml $(hamletFile $ hamletTemplate "default-layout")
+ page <- widgetToPageContent $ do
+ addStylesheet $ StaticR css_bootstrap_css
+ addStylesheet $ StaticR css_bootstrap_responsive_css
+ addScript $ StaticR jquery_full_js
+ addScript $ StaticR js_bootstrap_dropdown_js
+ $(widgetFile "default-layout")
+ hamletToRepHtml $(hamletFile $ hamletTemplate "bootstrap")
{- Require an auth token be set when accessing any (non-static route) -}
isAuthorized _ _ = checkAuthToken secretToken
@@ -68,7 +73,7 @@ instance Yesod WebApp where
{- Add to any widget to make it auto-update.
-
- - The widget should have a html element with id=poll, which will be
+ - The widget should have a html element with id=updating, which will be
- replaced when it's updated.
-
- Updating is done by getting html from the gethtml route.
@@ -80,7 +85,7 @@ instance Yesod WebApp where
- state.
-}
autoUpdate :: Text -> Route WebApp -> Route WebApp -> Int -> Int -> Widget
-autoUpdate poll gethtml home ms_delay ms_startdelay = do
+autoUpdate updating gethtml home ms_delay ms_startdelay = do
{- Fallback refreshing is provided for non-javascript browsers. -}
let delayseconds = show $ ms_to_seconds ms_delay
toWidgetHead $(hamletFile $ hamletTemplate "metarefresh")
@@ -88,7 +93,6 @@ autoUpdate poll gethtml home ms_delay ms_startdelay = do
{- Use long polling to update the status display. -}
let delay = show ms_delay
let startdelay = show ms_startdelay
- addScript $ StaticR jquery_full_js
$(widgetFile "longpolling")
where
ms_to_seconds :: Int -> Int
@@ -100,15 +104,13 @@ statusDisplay = do
webapp <- lift getYesod
time <- show <$> liftIO getCurrentTime
- poll <- lift newIdent
+ updating <- lift newIdent
$(widgetFile "status")
- autoUpdate poll StatusR HomeR (3000 :: Int) (40 :: Int)
+ autoUpdate updating StatusR HomeR (3000 :: Int) (40 :: Int)
getHomeR :: Handler RepHtml
-getHomeR = defaultLayout $ do
- statusDisplay
- [whamlet|<p><a href="@{ConfigR}">config|]
+getHomeR = defaultLayout statusDisplay
{- Called by client to poll for a new webapp status display.
-
diff --git a/debian/copyright b/debian/copyright
index 7f906a64a..4cab3a048 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -57,7 +57,7 @@ License: MIT or GPL-2
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-Files: static/bootstrap.css
+Files: static/*/bootstrap*
Copyright: 2011-2012 Twitter, Inc.
License: Apache-2.0
Licensed under the Apache License, Version 2.0 (the "License");
@@ -74,383 +74,3 @@ License: Apache-2.0
.
The complete text of the Apache License is distributed in
/usr/share/common-licenses/Apache-2.0 on Debian systems.
-
-Files: static/glyphicons*
-Copyright: 2010-2012 Jan Kovarik <glyphicons@gmail.com>
-License: CC-BY-3.0
- Creative Commons Attribution 3.0 License
- .
- THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS
- OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR
- "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER
- APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS
- AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS
- PROHIBITED.
- .
- BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU
- ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE.
- TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A
- CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE
- IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND
- CONDITIONS.
- .
- 1. Definitions
- .
- a) "Adaptation" means a work based upon
- the Work, or upon the Work and other pre-existing works,
- such as a translation, adaptation, derivative work,
- arrangement of music or other alterations of a literary
- or artistic work, or phonogram or performance and
- includes cinematographic adaptations or any other form in
- which the Work may be recast, transformed, or adapted
- including in any form recognizably derived from the
- original, except that a work that constitutes a
- Collection will not be considered an Adaptation for the
- purpose of this License. For the avoidance of doubt,
- where the Work is a musical work, performance or
- phonogram, the synchronization of the Work in
- timed-relation with a moving image ("synching") will be
- considered an Adaptation for the purpose of this
- License.
- .
- b) "Collection"</strong> means a collection of
- literary or artistic works, such as encyclopedias and
- anthologies, or performances, phonograms or broadcasts,
- or other works or subject matter other than works listed
- in Section 1(f) below, which, by reason of the selection
- and arrangement of their contents, constitute
- intellectual creations, in which the Work is included in
- its entirety in unmodified form along with one or more
- other contributions, each constituting separate and
- independent works in themselves, which together are
- assembled into a collective whole. A work that
- constitutes a Collection will not be considered an
- Adaptation (as defined above) for the purposes of this
- License.
- .
- c) "Distribute" means to make available
- to the public the original and copies of the Work or
- Adaptation, as appropriate, through sale or other
- transfer of ownership.
- .
- d) "Licensor" means the individual,
- individuals, entity or entities that offer(s) the Work
- under the terms of this License.
- .
- e) "Original Author" means, in the case
- of a literary or artistic work, the individual,
- individuals, entity or entities who created the Work or
- if no individual or entity can be identified, the
- publisher; and in addition (i) in the case of a
- performance the actors, singers, musicians, dancers, and
- other persons who act, sing, deliver, declaim, play in,
- interpret or otherwise perform literary or artistic works
- or expressions of folklore; (ii) in the case of a
- phonogram the producer being the person or legal entity
- who first fixes the sounds of a performance or other
- sounds; and, (iii) in the case of broadcasts, the
- organization that transmits the broadcast.
- .
- f) "Work" means the literary and/or
- artistic work offered under the terms of this License
- including without limitation any production in the
- literary, scientific and artistic domain, whatever may be
- the mode or form of its expression including digital
- form, such as a book, pamphlet and other writing; a
- lecture, address, sermon or other work of the same
- nature; a dramatic or dramatico-musical work; a
- choreographic work or entertainment in dumb show; a
- musical composition with or without words; a
- cinematographic work to which are assimilated works
- expressed by a process analogous to cinematography; a
- work of drawing, painting, architecture, sculpture,
- engraving or lithography; a photographic work to which
- are assimilated works expressed by a process analogous to
- photography; a work of applied art; an illustration, map,
- plan, sketch or three-dimensional work relative to
- geography, topography, architecture or science; a
- performance; a broadcast; a phonogram; a compilation of
- data to the extent it is protected as a copyrightable
- work; or a work performed by a variety or circus
- performer to the extent it is not otherwise considered a
- literary or artistic work.
- .
- g) "You"</strong> means an individual or entity
- exercising rights under this License who has not
- previously violated the terms of this License with
- respect to the Work, or who has received express
- permission from the Licensor to exercise rights under
- this License despite a previous violation.
- .
- h) "Publicly Perform" means to perform
- public recitations of the Work and to communicate to the
- public those public recitations, by any means or process,
- including by wire or wireless means or public digital
- performances; to make available to the public Works in
- such a way that members of the public may access these
- Works from a place and at a place individually chosen by
- them; to perform the Work to the public by any means or
- process and the communication to the public of the
- performances of the Work, including by public digital
- performance; to broadcast and rebroadcast the Work by any
- means including signs, sounds or images.
- .
- i) "Reproduce" means to make copies of
- the Work by any means including without limitation by
- sound or visual recordings and the right of fixation and
- reproducing fixations of the Work, including storage of a
- protected performance or phonogram in digital form or
- other electronic medium.
- .
- 2. Fair Dealing Rights. Nothing in this
- License is intended to reduce, limit, or restrict any uses
- free from copyright or rights arising from limitations or
- exceptions that are provided for in connection with the
- copyright protection under copyright law or other
- applicable laws.
- .
- 3. License Grant. Subject to the terms
- and conditions of this License, Licensor hereby grants You
- a worldwide, royalty-free, non-exclusive, perpetual (for
- the duration of the applicable copyright) license to
- exercise the rights in the Work as stated below:</p>
- .
- a) to Reproduce the Work, to incorporate the Work into
- one or more Collections, and to Reproduce the Work as
- incorporated in the Collections;
- .
- b) to create and Reproduce Adaptations provided that any
- such Adaptation, including any translation in any medium,
- takes reasonable steps to clearly label, demarcate or
- otherwise identify that changes were made to the original
- Work. For example, a translation could be marked "The
- original work was translated from English to Spanish," or
- a modification could indicate "The original work has been
- modified.";
- .
- c) to Distribute and Publicly Perform the Work including
- as incorporated in Collections; and,
- .
- d) to Distribute and Publicly Perform Adaptations.
- .
- e) For the avoidance of doubt:
- .
- i) Non-waivable Compulsory License
- Schemes. In those jurisdictions in which the
- right to collect royalties through any statutory or
- compulsory licensing scheme cannot be waived, the
- Licensor reserves the exclusive right to collect such
- royalties for any exercise by You of the rights
- granted under this License;
- .
- ii) Waivable Compulsory License
- Schemes. In those jurisdictions in which the
- right to collect royalties through any statutory or
- compulsory licensing scheme can be waived, the
- Licensor waives the exclusive right to collect such
- royalties for any exercise by You of the rights
- granted under this License; and,
- .
- iii) Voluntary License Schemes. The
- Licensor waives the right to collect royalties,
- whether individually or, in the event that the
- Licensor is a member of a collecting society that
- administers voluntary licensing schemes, via that
- society, from any exercise by You of the rights
- granted under this License.
- .
- The above rights may be exercised in all media and
- formats whether now known or hereafter devised. The above
- rights include the right to make such modifications as are
- technically necessary to exercise the rights in other media
- and formats. Subject to Section 8(f), all rights not
- expressly granted by Licensor are hereby reserved.
- .
- 4. Restrictions. The license granted in
- Section 3 above is expressly made subject to and limited by
- the following restrictions:
- .
- a) You may Distribute or Publicly Perform the Work only
- under the terms of this License. You must include a copy
- of, or the Uniform Resource Identifier (URI) for, this
- License with every copy of the Work You Distribute or
- Publicly Perform. You may not offer or impose any terms
- on the Work that restrict the terms of this License or
- the ability of the recipient of the Work to exercise the
- rights granted to that recipient under the terms of the
- License. You may not sublicense the Work. You must keep
- intact all notices that refer to this License and to the
- disclaimer of warranties with every copy of the Work You
- Distribute or Publicly Perform. When You Distribute or
- Publicly Perform the Work, You may not impose any
- effective technological measures on the Work that
- restrict the ability of a recipient of the Work from You
- to exercise the rights granted to that recipient under
- the terms of the License. This Section 4(a) applies to
- the Work as incorporated in a Collection, but this does
- not require the Collection apart from the Work itself to
- be made subject to the terms of this License. If You
- create a Collection, upon notice from any Licensor You
- must, to the extent practicable, remove from the
- Collection any credit as required by Section 4(b), as
- requested. If You create an Adaptation, upon notice from
- any Licensor You must, to the extent practicable, remove
- from the Adaptation any credit as required by Section
- 4(b), as requested.
- .
- b) If You Distribute, or Publicly Perform the Work or
- any Adaptations or Collections, You must, unless a
- request has been made pursuant to Section 4(a), keep
- intact all copyright notices for the Work and provide,
- reasonable to the medium or means You are utilizing: (i)
- the name of the Original Author (or pseudonym, if
- applicable) if supplied, and/or if the Original Author
- and/or Licensor designate another party or parties (e.g.,
- a sponsor institute, publishing entity, journal) for
- attribution ("Attribution Parties") in Licensor's
- copyright notice, terms of service or by other reasonable
- means, the name of such party or parties; (ii) the title
- of the Work if supplied; (iii) to the extent reasonably
- practicable, the URI, if any, that Licensor specifies to
- be associated with the Work, unless such URI does not
- refer to the copyright notice or licensing information
- for the Work; and (iv) , consistent with Section 3(b), in
- the case of an Adaptation, a credit identifying the use
- of the Work in the Adaptation (e.g., "French translation
- of the Work by Original Author," or "Screenplay based on
- original Work by Original Author"). The credit required
- by this Section 4 (b) may be implemented in any
- reasonable manner; provided, however, that in the case of
- a Adaptation or Collection, at a minimum such credit will
- appear, if a credit for all contributing authors of the
- Adaptation or Collection appears, then as part of these
- credits and in a manner at least as prominent as the
- credits for the other contributing authors. For the
- avoidance of doubt, You may only use the credit required
- by this Section for the purpose of attribution in the
- manner set out above and, by exercising Your rights under
- this License, You may not implicitly or explicitly assert
- or imply any connection with, sponsorship or endorsement
- by the Original Author, Licensor and/or Attribution
- Parties, as appropriate, of You or Your use of the Work,
- without the separate, express prior written permission of
- the Original Author, Licensor and/or Attribution
- Parties.
- .
- c) Except as otherwise agreed in writing by the Licensor
- or as may be otherwise permitted by applicable law, if
- You Reproduce, Distribute or Publicly Perform the Work
- either by itself or as part of any Adaptations or
- Collections, You must not distort, mutilate, modify or
- take other derogatory action in relation to the Work
- which would be prejudicial to the Original Author's honor
- or reputation. Licensor agrees that in those
- jurisdictions (e.g. Japan), in which any exercise of the
- right granted in Section 3(b) of this License (the right
- to make Adaptations) would be deemed to be a distortion,
- mutilation, modification or other derogatory action
- prejudicial to the Original Author's honor and
- reputation, the Licensor will waive or not assert, as
- appropriate, this Section, to the fullest extent
- permitted by the applicable national law, to enable You
- to reasonably exercise Your right under Section 3(b) of
- this License (right to make Adaptations) but not
- otherwise.
- .
- 5. Representations, Warranties and
- Disclaimer
- .
- UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN
- WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO
- REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE
- WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING,
- WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY,
- FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE
- ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE
- PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE.
- SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED
- WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.
- .
- 6. Limitation on Liability. EXCEPT TO
- THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL
- LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY
- SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY
- DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK,
- EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF
- SUCH DAMAGES.
- .
- 7. Termination
- .
- a) This License and the rights granted hereunder will
- terminate automatically upon any breach by You of the
- terms of this License. Individuals or entities who have
- received Adaptations or Collections from You under this
- License, however, will not have their licenses terminated
- provided such individuals or entities remain in full
- compliance with those licenses. Sections 1, 2, 5, 6, 7,
- and 8 will survive any termination of this License.</li>
- .
- b) Subject to the above terms and conditions, the
- license granted here is perpetual (for the duration of
- the applicable copyright in the Work). Notwithstanding
- the above, Licensor reserves the right to release the
- Work under different license terms or to stop
- distributing the Work at any time; provided, however that
- any such election will not serve to withdraw this License
- (or any other license that has been, or is required to
- be, granted under the terms of this License), and this
- License will continue in full force and effect unless
- terminated as stated above.
- .
- 8. Miscellaneous
- .
- a) Each time You Distribute or Publicly Perform the Work
- or a Collection, the Licensor offers to the recipient a
- license to the Work on the same terms and conditions as
- the license granted to You under this License.
- .
- b) Each time You Distribute or Publicly Perform an
- Adaptation, Licensor offers to the recipient a license to
- the original Work on the same terms and conditions as the
- license granted to You under this License.
- .
- c) If any provision of this License is invalid or
- unenforceable under applicable law, it shall not affect
- the validity or enforceability of the remainder of the
- terms of this License, and without further action by the
- parties to this agreement, such provision shall be
- reformed to the minimum extent necessary to make such
- provision valid and enforceable.
- .
- d) No term or provision of this License shall be deemed
- waived and no breach consented to unless such waiver or
- consent shall be in writing and signed by the party to be
- charged with such waiver or consent.
- .
- e) This License constitutes the entire agreement between
- the parties with respect to the Work licensed here. There
- are no understandings, agreements or representations with
- respect to the Work not specified here. Licensor shall
- not be bound by any additional provisions that may appear
- in any communication from You. This License may not be
- modified without the mutual written agreement of the
- Licensor and You.
- .
- f) The rights granted under, and the subject matter
- referenced, in this License were drafted utilizing the
- terminology of the Berne Convention for the Protection of
- Literary and Artistic Works (as amended on September 28,
- 1979), the Rome Convention of 1961, the WIPO Copyright
- Treaty of 1996, the WIPO Performances and Phonograms
- Treaty of 1996 and the Universal Copyright Convention (as
- revised on July 24, 1971). These rights and subject
- matter take effect in the relevant jurisdiction in which
- the License terms are sought to be enforced according to
- the corresponding provisions of the implementation of
- those treaty provisions in the applicable national law.
- If the standard suite of rights granted under applicable
- copyright law includes additional rights not granted
- under this License, such additional rights are deemed to
- be included in the License; this License is not intended
- to restrict the license of any rights under applicable
- law.
diff --git a/doc/design/assistant/blog/day_45__long_polling/full.png b/doc/design/assistant/blog/day_45__long_polling/full.png
new file mode 100644
index 000000000..3963ae1dc
--- /dev/null
+++ b/doc/design/assistant/blog/day_45__long_polling/full.png
Binary files differ
diff --git a/doc/design/assistant/blog/day_45__long_polling/phone.png b/doc/design/assistant/blog/day_45__long_polling/phone.png
new file mode 100644
index 000000000..389334d95
--- /dev/null
+++ b/doc/design/assistant/blog/day_45__long_polling/phone.png
Binary files differ
diff --git a/static/css/bootstrap-responsive.css b/static/css/bootstrap-responsive.css
new file mode 100644
index 000000000..0bc6de916
--- /dev/null
+++ b/static/css/bootstrap-responsive.css
@@ -0,0 +1,686 @@
+/*!
+ * Bootstrap Responsive v2.0.2
+ *
+ * Copyright 2012 Twitter, Inc
+ * Licensed under the Apache License v2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Designed and built with all the love in the world @twitter by @mdo and @fat.
+ */
+.clearfix {
+ *zoom: 1;
+}
+.clearfix:before,
+.clearfix:after {
+ display: table;
+ content: "";
+}
+.clearfix:after {
+ clear: both;
+}
+.hide-text {
+ overflow: hidden;
+ text-indent: 100%;
+ white-space: nowrap;
+}
+.input-block-level {
+ display: block;
+ width: 100%;
+ min-height: 28px;
+ /* Make inputs at least the height of their button counterpart */
+
+ /* Makes inputs behave like true block-level elements */
+
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ -ms-box-sizing: border-box;
+ box-sizing: border-box;
+}
+.hidden {
+ display: none;
+ visibility: hidden;
+}
+.visible-phone {
+ display: none;
+}
+.visible-tablet {
+ display: none;
+}
+.visible-desktop {
+ display: block;
+}
+.hidden-phone {
+ display: block;
+}
+.hidden-tablet {
+ display: block;
+}
+.hidden-desktop {
+ display: none;
+}
+@media (max-width: 767px) {
+ .visible-phone {
+ display: block;
+ }
+ .hidden-phone {
+ display: none;
+ }
+ .hidden-desktop {
+ display: block;
+ }
+ .visible-desktop {
+ display: none;
+ }
+}
+@media (min-width: 768px) and (max-width: 979px) {
+ .visible-tablet {
+ display: block;
+ }
+ .hidden-tablet {
+ display: none;
+ }
+ .hidden-desktop {
+ display: block;
+ }
+ .visible-desktop {
+ display: none;
+ }
+}
+@media (max-width: 480px) {
+ .nav-collapse {
+ -webkit-transform: translate3d(0, 0, 0);
+ }
+ .page-header h1 small {
+ display: block;
+ line-height: 18px;
+ }
+ input[type="checkbox"],
+ input[type="radio"] {
+ border: 1px solid #ccc;
+ }
+ .form-horizontal .control-group > label {
+ float: none;
+ width: auto;
+ padding-top: 0;
+ text-align: left;
+ }
+ .form-horizontal .controls {
+ margin-left: 0;
+ }
+ .form-horizontal .control-list {
+ padding-top: 0;
+ }
+ .form-horizontal .form-actions {
+ padding-left: 10px;
+ padding-right: 10px;
+ }
+ .modal {
+ position: absolute;
+ top: 10px;
+ left: 10px;
+ right: 10px;
+ width: auto;
+ margin: 0;
+ }
+ .modal.fade.in {
+ top: auto;
+ }
+ .modal-header .close {
+ padding: 10px;
+ margin: -10px;
+ }
+ .carousel-caption {
+ position: static;
+ }
+}
+@media (max-width: 767px) {
+ body {
+ padding-left: 20px;
+ padding-right: 20px;
+ }
+ .navbar-fixed-top {
+ margin-left: -20px;
+ margin-right: -20px;
+ }
+ .container {
+ width: auto;
+ }
+ .row-fluid {
+ width: 100%;
+ }
+ .row {
+ margin-left: 0;
+ }
+ .row > [class*="span"],
+ .row-fluid > [class*="span"] {
+ float: none;
+ display: block;
+ width: auto;
+ margin: 0;
+ }
+ .thumbnails [class*="span"] {
+ width: auto;
+ }
+ input[class*="span"],
+ select[class*="span"],
+ textarea[class*="span"],
+ .uneditable-input {
+ display: block;
+ width: 100%;
+ min-height: 28px;
+ /* Make inputs at least the height of their button counterpart */
+
+ /* Makes inputs behave like true block-level elements */
+
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ -ms-box-sizing: border-box;
+ box-sizing: border-box;
+ }
+ .input-prepend input[class*="span"],
+ .input-append input[class*="span"] {
+ width: auto;
+ }
+}
+@media (min-width: 768px) and (max-width: 979px) {
+ .row {
+ margin-left: -20px;
+ *zoom: 1;
+ }
+ .row:before,
+ .row:after {
+ display: table;
+ content: "";
+ }
+ .row:after {
+ clear: both;
+ }
+ [class*="span"] {
+ float: left;
+ margin-left: 20px;
+ }
+ .container,
+ .navbar-fixed-top .container,
+ .navbar-fixed-bottom .container {
+ width: 724px;
+ }
+ .span12 {
+ width: 724px;
+ }
+ .span11 {
+ width: 662px;
+ }
+ .span10 {
+ width: 600px;
+ }
+ .span9 {
+ width: 538px;
+ }
+ .span8 {
+ width: 476px;
+ }
+ .span7 {
+ width: 414px;
+ }
+ .span6 {
+ width: 352px;
+ }
+ .span5 {
+ width: 290px;
+ }
+ .span4 {
+ width: 228px;
+ }
+ .span3 {
+ width: 166px;
+ }
+ .span2 {
+ width: 104px;
+ }
+ .span1 {
+ width: 42px;
+ }
+ .offset12 {
+ margin-left: 764px;
+ }
+ .offset11 {
+ margin-left: 702px;
+ }
+ .offset10 {
+ margin-left: 640px;
+ }
+ .offset9 {
+ margin-left: 578px;
+ }
+ .offset8 {
+ margin-left: 516px;
+ }
+ .offset7 {
+ margin-left: 454px;
+ }
+ .offset6 {
+ margin-left: 392px;
+ }
+ .offset5 {
+ margin-left: 330px;
+ }
+ .offset4 {
+ margin-left: 268px;
+ }
+ .offset3 {
+ margin-left: 206px;
+ }
+ .offset2 {
+ margin-left: 144px;
+ }
+ .offset1 {
+ margin-left: 82px;
+ }
+ .row-fluid {
+ width: 100%;
+ *zoom: 1;
+ }
+ .row-fluid:before,
+ .row-fluid:after {
+ display: table;
+ content: "";
+ }
+ .row-fluid:after {
+ clear: both;
+ }
+ .row-fluid > [class*="span"] {
+ float: left;
+ margin-left: 2.762430939%;
+ }
+ .row-fluid > [class*="span"]:first-child {
+ margin-left: 0;
+ }
+ .row-fluid > .span12 {
+ width: 99.999999993%;
+ }
+ .row-fluid > .span11 {
+ width: 91.436464082%;
+ }
+ .row-fluid > .span10 {
+ width: 82.87292817100001%;
+ }
+ .row-fluid > .span9 {
+ width: 74.30939226%;
+ }
+ .row-fluid > .span8 {
+ width: 65.74585634900001%;
+ }
+ .row-fluid > .span7 {
+ width: 57.182320438000005%;
+ }
+ .row-fluid > .span6 {
+ width: 48.618784527%;
+ }
+ .row-fluid > .span5 {
+ width: 40.055248616%;
+ }
+ .row-fluid > .span4 {
+ width: 31.491712705%;
+ }
+ .row-fluid > .span3 {
+ width: 22.928176794%;
+ }
+ .row-fluid > .span2 {
+ width: 14.364640883%;
+ }
+ .row-fluid > .span1 {
+ width: 5.801104972%;
+ }
+ input,
+ textarea,
+ .uneditable-input {
+ margin-left: 0;
+ }
+ input.span12, textarea.span12, .uneditable-input.span12 {
+ width: 714px;
+ }
+ input.span11, textarea.span11, .uneditable-input.span11 {
+ width: 652px;
+ }
+ input.span10, textarea.span10, .uneditable-input.span10 {
+ width: 590px;
+ }
+ input.span9, textarea.span9, .uneditable-input.span9 {
+ width: 528px;
+ }
+ input.span8, textarea.span8, .uneditable-input.span8 {
+ width: 466px;
+ }
+ input.span7, textarea.span7, .uneditable-input.span7 {
+ width: 404px;
+ }
+ input.span6, textarea.span6, .uneditable-input.span6 {
+ width: 342px;
+ }
+ input.span5, textarea.span5, .uneditable-input.span5 {
+ width: 280px;
+ }
+ input.span4, textarea.span4, .uneditable-input.span4 {
+ width: 218px;
+ }
+ input.span3, textarea.span3, .uneditable-input.span3 {
+ width: 156px;
+ }
+ input.span2, textarea.span2, .uneditable-input.span2 {
+ width: 94px;
+ }
+ input.span1, textarea.span1, .uneditable-input.span1 {
+ width: 32px;
+ }
+}
+@media (max-width: 979px) {
+ body {
+ padding-top: 0;
+ }
+ .navbar-fixed-top {
+ position: static;
+ margin-bottom: 18px;
+ }
+ .navbar-fixed-top .navbar-inner {
+ padding: 5px;
+ }
+ .navbar .container {
+ width: auto;
+ padding: 0;
+ }
+ .navbar .brand {
+ padding-left: 10px;
+ padding-right: 10px;
+ margin: 0 0 0 -5px;
+ }
+ .navbar .nav-collapse {
+ clear: left;
+ }
+ .navbar .nav {
+ float: none;
+ margin: 0 0 9px;
+ }
+ .navbar .nav > li {
+ float: none;
+ }
+ .navbar .nav > li > a {
+ margin-bottom: 2px;
+ }
+ .navbar .nav > .divider-vertical {
+ display: none;
+ }
+ .navbar .nav .nav-header {
+ color: #999999;
+ text-shadow: none;
+ }
+ .navbar .nav > li > a,
+ .navbar .dropdown-menu a {
+ padding: 6px 15px;
+ font-weight: bold;
+ color: #999999;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+ }
+ .navbar .dropdown-menu li + li a {
+ margin-bottom: 2px;
+ }
+ .navbar .nav > li > a:hover,
+ .navbar .dropdown-menu a:hover {
+ background-color: #222222;
+ }
+ .navbar .dropdown-menu {
+ position: static;
+ top: auto;
+ left: auto;
+ float: none;
+ display: block;
+ max-width: none;
+ margin: 0 15px;
+ padding: 0;
+ background-color: transparent;
+ border: none;
+ -webkit-border-radius: 0;
+ -moz-border-radius: 0;
+ border-radius: 0;
+ -webkit-box-shadow: none;
+ -moz-box-shadow: none;
+ box-shadow: none;
+ }
+ .navbar .dropdown-menu:before,
+ .navbar .dropdown-menu:after {
+ display: none;
+ }
+ .navbar .dropdown-menu .divider {
+ display: none;
+ }
+ .navbar-form,
+ .navbar-search {
+ float: none;
+ padding: 9px 15px;
+ margin: 9px 0;
+ border-top: 1px solid #222222;
+ border-bottom: 1px solid #222222;
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
+ -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
+ }
+ .navbar .nav.pull-right {
+ float: none;
+ margin-left: 0;
+ }
+ .navbar-static .navbar-inner {
+ padding-left: 10px;
+ padding-right: 10px;
+ }
+ .btn-navbar {
+ display: block;
+ }
+ .nav-collapse {
+ overflow: hidden;
+ height: 0;
+ }
+}
+@media (min-width: 980px) {
+ .nav-collapse.collapse {
+ height: auto !important;
+ overflow: visible !important;
+ }
+}
+@media (min-width: 1200px) {
+ .row {
+ margin-left: -30px;
+ *zoom: 1;
+ }
+ .row:before,
+ .row:after {
+ display: table;
+ content: "";
+ }
+ .row:after {
+ clear: both;
+ }
+ [class*="span"] {
+ float: left;
+ margin-left: 30px;
+ }
+ .container,
+ .navbar-fixed-top .container,
+ .navbar-fixed-bottom .container {
+ width: 1170px;
+ }
+ .span12 {
+ width: 1170px;
+ }
+ .span11 {
+ width: 1070px;
+ }
+ .span10 {
+ width: 970px;
+ }
+ .span9 {
+ width: 870px;
+ }
+ .span8 {
+ width: 770px;
+ }
+ .span7 {
+ width: 670px;
+ }
+ .span6 {
+ width: 570px;
+ }
+ .span5 {
+ width: 470px;
+ }
+ .span4 {
+ width: 370px;
+ }
+ .span3 {
+ width: 270px;
+ }
+ .span2 {
+ width: 170px;
+ }
+ .span1 {
+ width: 70px;
+ }
+ .offset12 {
+ margin-left: 1230px;
+ }
+ .offset11 {
+ margin-left: 1130px;
+ }
+ .offset10 {
+ margin-left: 1030px;
+ }
+ .offset9 {
+ margin-left: 930px;
+ }
+ .offset8 {
+ margin-left: 830px;
+ }
+ .offset7 {
+ margin-left: 730px;
+ }
+ .offset6 {
+ margin-left: 630px;
+ }
+ .offset5 {
+ margin-left: 530px;
+ }
+ .offset4 {
+ margin-left: 430px;
+ }
+ .offset3 {
+ margin-left: 330px;
+ }
+ .offset2 {
+ margin-left: 230px;
+ }
+ .offset1 {
+ margin-left: 130px;
+ }
+ .row-fluid {
+ width: 100%;
+ *zoom: 1;
+ }
+ .row-fluid:before,
+ .row-fluid:after {
+ display: table;
+ content: "";
+ }
+ .row-fluid:after {
+ clear: both;
+ }
+ .row-fluid > [class*="span"] {
+ float: left;
+ margin-left: 2.564102564%;
+ }
+ .row-fluid > [class*="span"]:first-child {
+ margin-left: 0;
+ }
+ .row-fluid > .span12 {
+ width: 100%;
+ }
+ .row-fluid > .span11 {
+ width: 91.45299145300001%;
+ }
+ .row-fluid > .span10 {
+ width: 82.905982906%;
+ }
+ .row-fluid > .span9 {
+ width: 74.358974359%;
+ }
+ .row-fluid > .span8 {
+ width: 65.81196581200001%;
+ }
+ .row-fluid > .span7 {
+ width: 57.264957265%;
+ }
+ .row-fluid > .span6 {
+ width: 48.717948718%;
+ }
+ .row-fluid > .span5 {
+ width: 40.170940171000005%;
+ }
+ .row-fluid > .span4 {
+ width: 31.623931624%;
+ }
+ .row-fluid > .span3 {
+ width: 23.076923077%;
+ }
+ .row-fluid > .span2 {
+ width: 14.529914530000001%;
+ }
+ .row-fluid > .span1 {
+ width: 5.982905983%;
+ }
+ input,
+ textarea,
+ .uneditable-input {
+ margin-left: 0;
+ }
+ input.span12, textarea.span12, .uneditable-input.span12 {
+ width: 1160px;
+ }
+ input.span11, textarea.span11, .uneditable-input.span11 {
+ width: 1060px;
+ }
+ input.span10, textarea.span10, .uneditable-input.span10 {
+ width: 960px;
+ }
+ input.span9, textarea.span9, .uneditable-input.span9 {
+ width: 860px;
+ }
+ input.span8, textarea.span8, .uneditable-input.span8 {
+ width: 760px;
+ }
+ input.span7, textarea.span7, .uneditable-input.span7 {
+ width: 660px;
+ }
+ input.span6, textarea.span6, .uneditable-input.span6 {
+ width: 560px;
+ }
+ input.span5, textarea.span5, .uneditable-input.span5 {
+ width: 460px;
+ }
+ input.span4, textarea.span4, .uneditable-input.span4 {
+ width: 360px;
+ }
+ input.span3, textarea.span3, .uneditable-input.span3 {
+ width: 260px;
+ }
+ input.span2, textarea.span2, .uneditable-input.span2 {
+ width: 160px;
+ }
+ input.span1, textarea.span1, .uneditable-input.span1 {
+ width: 60px;
+ }
+ .thumbnails {
+ margin-left: -30px;
+ }
+ .thumbnails > li {
+ margin-left: 30px;
+ }
+}
diff --git a/static/bootstrap.css b/static/css/bootstrap.css
index 495188af7..dee87331f 100644
--- a/static/bootstrap.css
+++ b/static/css/bootstrap.css
@@ -1395,7 +1395,7 @@ table .span24 {
height: 14px;
line-height: 14px;
vertical-align: text-top;
- background-image: url("../img/glyphicons-halflings.png");
+ background-image: url("/static/img/glyphicons-halflings.png");
background-position: 14px 14px;
background-repeat: no-repeat;
*margin-right: .3em;
@@ -1405,7 +1405,7 @@ table .span24 {
*margin-left: 0;
}
.icon-white {
- background-image: url("../img/glyphicons-halflings-white.png");
+ background-image: url("/static/img/glyphicons-halflings-white.png");
}
.icon-glass {
background-position: 0 0;
diff --git a/static/glyphicons-halflings-white.png b/static/glyphicons-halflings-white.png
deleted file mode 100644
index a20760bfd..000000000
--- a/static/glyphicons-halflings-white.png
+++ /dev/null
Binary files differ
diff --git a/static/glyphicons-halflings.png b/static/glyphicons-halflings.png
deleted file mode 100644
index 92d4445df..000000000
--- a/static/glyphicons-halflings.png
+++ /dev/null
Binary files differ
diff --git a/static/js/bootstrap-dropdown.js b/static/js/bootstrap-dropdown.js
new file mode 100644
index 000000000..2bf885874
--- /dev/null
+++ b/static/js/bootstrap-dropdown.js
@@ -0,0 +1,92 @@
+/* ============================================================
+ * bootstrap-dropdown.js v2.0.2
+ * http://twitter.github.com/bootstrap/javascript.html#dropdowns
+ * ============================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============================================================ */
+
+
+!function( $ ){
+
+ "use strict"
+
+ /* DROPDOWN CLASS DEFINITION
+ * ========================= */
+
+ var toggle = '[data-toggle="dropdown"]'
+ , Dropdown = function ( element ) {
+ var $el = $(element).on('click.dropdown.data-api', this.toggle)
+ $('html').on('click.dropdown.data-api', function () {
+ $el.parent().removeClass('open')
+ })
+ }
+
+ Dropdown.prototype = {
+
+ constructor: Dropdown
+
+ , toggle: function ( e ) {
+ var $this = $(this)
+ , selector = $this.attr('data-target')
+ , $parent
+ , isActive
+
+ if (!selector) {
+ selector = $this.attr('href')
+ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
+ }
+
+ $parent = $(selector)
+ $parent.length || ($parent = $this.parent())
+
+ isActive = $parent.hasClass('open')
+
+ clearMenus()
+ !isActive && $parent.toggleClass('open')
+
+ return false
+ }
+
+ }
+
+ function clearMenus() {
+ $(toggle).parent().removeClass('open')
+ }
+
+
+ /* DROPDOWN PLUGIN DEFINITION
+ * ========================== */
+
+ $.fn.dropdown = function ( option ) {
+ return this.each(function () {
+ var $this = $(this)
+ , data = $this.data('dropdown')
+ if (!data) $this.data('dropdown', (data = new Dropdown(this)))
+ if (typeof option == 'string') data[option].call($this)
+ })
+ }
+
+ $.fn.dropdown.Constructor = Dropdown
+
+
+ /* APPLY TO STANDARD DROPDOWN ELEMENTS
+ * =================================== */
+
+ $(function () {
+ $('html').on('click.dropdown.data-api', clearMenus)
+ $('body').on('click.dropdown.data-api', toggle, Dropdown.prototype.toggle)
+ })
+
+}( window.jQuery );
diff --git a/templates/bootstrap.hamlet b/templates/bootstrap.hamlet
new file mode 100644
index 000000000..c03c459a6
--- /dev/null
+++ b/templates/bootstrap.hamlet
@@ -0,0 +1,52 @@
+$doctype 5
+<html>
+ <head>
+ <title>#{baseTitle webapp} #{pageTitle page}
+ <link rel="icon" href=@{StaticR favicon_ico} type="image/x-icon">
+ <meta name="viewport" content="width=device-width,initial-scale=1.0">
+ <style type="text/css">
+ body {
+ padding-top: 60px;
+ padding-bottom: 40px;
+ }
+ .sidebar-nav {
+ padding: 9px 0;
+ }
+ ^{pageHead page}
+ <body>
+
+ <div class="navbar navbar-fixed-top">
+ <div class="navbar-inner">
+ <div class="container">
+ <a class="brand" href="#">
+ git-annex
+ <ul class="nav">
+ <li class="active">
+ <a href="#">Dashboard</a>
+ <li>
+ <a href="@{ConfigR}">Config</a>
+ <ul class="nav pull-right">
+ <li class="dropdown" id="menu1">
+ <a class="dropdown-toggle" data-toggle="dropdown" href="#menu1">
+ Current Repository: #{baseTitle webapp}
+ <b class="caret"></b>
+ <ul class="dropdown-menu">
+ <li><a href="#">#{baseTitle webapp}</a></li>
+ <li class="divider"></li>
+ <li><a href="#">Add new repository</a></li>
+
+ <div class="container-fluid">
+ <div class="row-fluid">
+ <div class="span3">
+ <div class="sidebar-nav">
+ <div class="alert alert-info">
+ <b>This is just a demo.</b> If this were not just a demo,
+ I'd not be filling this sidebar with silly alerts.
+ <div class="alert alert-success">
+ <b>Well done!</b>
+ You successfully read this important alert message.
+ <div class="alert alert-error">
+ <b>Whoops!</b>
+ Unable to connect to blah blah..
+ <div class="span9">
+ ^{pageBody page}
diff --git a/templates/default-layout.hamlet b/templates/default-layout.hamlet
index bd16969f9..3701e3c42 100644
--- a/templates/default-layout.hamlet
+++ b/templates/default-layout.hamlet
@@ -1,10 +1,3 @@
-$doctype 5
-<html>
- <head>
- <title>#{baseTitle webapp} #{pageTitle page}
- <link rel="icon" href=@{StaticR favicon_ico} type="image/x-icon">
- ^{pageHead page}
- <body>
- $maybe msg <- mmsg
- <div #message>#{msg}
- ^{pageBody page}
+$maybe msg <- mmsg
+ <div #message>#{msg}
+^{widget}
diff --git a/templates/longpolling.julius b/templates/longpolling.julius
index 351f2f8c6..eff8d3f44 100644
--- a/templates/longpolling.julius
+++ b/templates/longpolling.julius
@@ -1,5 +1,5 @@
-// Uses long-polling to update a div with id=#{poll}
+// Uses long-polling to update a div with id=#{updating}
// The gethtml route should return a new div, with the same id.
//
// Maximum update frequency is controlled by #{startdelay}
@@ -16,7 +16,7 @@ $.LongPoll = (function() {
'url': '@{gethtml}',
'dataType': 'html',
'success': function(data, status, jqxhr) {
- $('##{poll}').replaceWith(data);
+ $('##{updating}').replaceWith(data);
setTimeout($.LongPoll.send, #{delay});
numerrs=0;
},
diff --git a/templates/status.hamlet b/templates/status.hamlet
index 1f975b35f..1da189d1f 100644
--- a/templates/status.hamlet
+++ b/templates/status.hamlet
@@ -1,2 +1,26 @@
-<div id="#{poll}">
- polled at #{time}
+<span id="#{updating}">
+ <div class="hero-unit">
+ <div class="row-fluid">
+ <h3>
+ foo &larr;
+ <small>usb drive</small>
+ <small class="pull-right">40% of 10 mb</small>
+ <div class="progress progress-striped">
+ <div class="bar" style="width: 40%;">
+ <div class="row-fluid">
+ <h3>
+ some_filenames_are_long_and_ugly_like_this_one.mp3 &rarr;
+ <small>Amazon S3</small>
+ <small class="pull-right">10% of 50 mb</small>
+ <div class="progress progress-striped">
+ <div class="bar" style="width: 10%;">
+ <div class="row-fluid">
+ <h3>
+ bigfile &larr;
+ <small>usb drive</small>
+ <small class="pull-right">0% of 512 mb</small>
+ <div class="progress progress-striped">
+ <div class="bar" style="width: 0%;">
+ <footer>
+ <span>
+ polled at #{time}