diff options
author | 2012-07-27 04:48:50 -0400 | |
---|---|---|
committer | 2012-07-27 04:48:50 -0400 | |
commit | 7e3c1e008d6b2eff10d412993df293fce2156151 (patch) | |
tree | bd1d1395c452df84573e7a8acb560e623e4ad063 | |
parent | 1192e305c7fa7ba0b6572cc8c450127d6458b0af (diff) |
webapp now uses twitter bootstrap
mocked up the main screen, and am actually pretty happy with it!
-rw-r--r-- | Assistant/Threads/WebApp.hs | 24 | ||||
-rw-r--r-- | debian/copyright | 382 | ||||
-rw-r--r-- | doc/design/assistant/blog/day_45__long_polling/full.png | bin | 0 -> 55185 bytes | |||
-rw-r--r-- | doc/design/assistant/blog/day_45__long_polling/phone.png | bin | 0 -> 41602 bytes | |||
-rw-r--r-- | static/css/bootstrap-responsive.css | 686 | ||||
-rw-r--r-- | static/css/bootstrap.css (renamed from static/bootstrap.css) | 4 | ||||
-rw-r--r-- | static/glyphicons-halflings-white.png | bin | 4352 -> 0 bytes | |||
-rw-r--r-- | static/glyphicons-halflings.png | bin | 4352 -> 0 bytes | |||
-rw-r--r-- | static/js/bootstrap-dropdown.js | 92 | ||||
-rw-r--r-- | templates/bootstrap.hamlet | 52 | ||||
-rw-r--r-- | templates/default-layout.hamlet | 13 | ||||
-rw-r--r-- | templates/longpolling.julius | 4 | ||||
-rw-r--r-- | templates/status.hamlet | 28 |
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 Binary files differnew file mode 100644 index 000000000..3963ae1dc --- /dev/null +++ b/doc/design/assistant/blog/day_45__long_polling/full.png diff --git a/doc/design/assistant/blog/day_45__long_polling/phone.png b/doc/design/assistant/blog/day_45__long_polling/phone.png Binary files differnew file mode 100644 index 000000000..389334d95 --- /dev/null +++ b/doc/design/assistant/blog/day_45__long_polling/phone.png 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 Binary files differdeleted file mode 100644 index a20760bfd..000000000 --- a/static/glyphicons-halflings-white.png +++ /dev/null diff --git a/static/glyphicons-halflings.png b/static/glyphicons-halflings.png Binary files differdeleted file mode 100644 index 92d4445df..000000000 --- a/static/glyphicons-halflings.png +++ /dev/null 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 ← + <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 → + <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 ← + <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} |