From f450f7e13bdc0f6b6f4d99e901647ee9e5425e57 Mon Sep 17 00:00:00 2001 From: Isarra Date: Mon, 30 Nov 2015 03:35:05 +0000 Subject: [PATCH] Make this thing responsive And some other stuff too just because I ran into it on the way: * Added indicators * Fixed js in general * Bumped version number * Added some stupid hacks * Cleaned stuff up * I don't actually know Change-Id: Ifa557c6f0f8a972d8986c3bffdfe08ddb4b39664 --- .jshintignore | 1 + Timeless.skin.php | 25 +- TimelessTemplate.php | 281 +++++-- i18n/en.json | 6 +- i18n/qqq.json | 4 + resources/images/arrow-down-white.png | Bin 227 -> 0 bytes resources/images/arrow-down-white.svg | 5 - resources/images/cat-grey.png | Bin 0 -> 28718 bytes resources/images/cat-grey.svg | 234 ++++++ resources/images/clock-grey.png | Bin 0 -> 586 bytes resources/images/clock-grey.svg | 82 ++ resources/images/editing icons.svg | 220 +++++ resources/images/gear-grey.png | Bin 0 -> 635 bytes resources/images/gear-grey.svg | 35 + resources/images/gear-large-grey.png | Bin 0 -> 877 bytes resources/images/gear-large-grey.svg | 76 ++ resources/images/languages-grey.png | Bin 0 -> 789 bytes resources/images/languages-grey.svg | 39 + resources/images/menu-large-grey.png | Bin 0 -> 231 bytes resources/images/menu-large-grey.svg | 95 +++ resources/images/page-grey.png | Bin 0 -> 251 bytes resources/images/page-grey.svg | 35 + resources/images/pencil-grey.png | Bin 0 -> 469 bytes resources/images/pencil-grey.svg | 39 + resources/images/plus-grey.png | Bin 0 -> 329 bytes resources/images/plus-grey.svg | 48 ++ resources/images/puzzle-grey.png | Bin 0 -> 323 bytes resources/images/puzzle-grey.svg | 53 ++ resources/images/star-filled.png | Bin 529 -> 488 bytes resources/images/star.png | Bin 657 -> 650 bytes resources/images/star.svg | 62 +- resources/images/talk-grey.png | Bin 0 -> 724 bytes resources/images/talk-grey.svg | 77 ++ resources/images/user-large-grey.png | Bin 0 -> 715 bytes resources/images/user-large-grey.svg | 82 ++ resources/images/user.png | Bin 704 -> 0 bytes resources/images/user.svg | 87 -- resources/libraries/jquery.mobile.custom.js | 864 ++++++++++++++++++++ resources/mobile.js | 53 ++ resources/screen-common.less | 231 +++++- resources/screen-desktop-full.less | 19 + resources/screen-desktop-mid.less | 19 + resources/screen-desktop-small.less | 127 +++ resources/screen-desktop.less | 346 ++------ resources/screen-misc.less | 24 + resources/screen-mobile.less | 243 ++++++ resources/variables.less | 134 ++- skin.json | 30 +- 48 files changed, 3183 insertions(+), 493 deletions(-) delete mode 100644 resources/images/arrow-down-white.png delete mode 100644 resources/images/arrow-down-white.svg create mode 100644 resources/images/cat-grey.png create mode 100644 resources/images/cat-grey.svg create mode 100644 resources/images/clock-grey.png create mode 100644 resources/images/clock-grey.svg create mode 100644 resources/images/editing icons.svg create mode 100644 resources/images/gear-grey.png create mode 100644 resources/images/gear-grey.svg create mode 100644 resources/images/gear-large-grey.png create mode 100644 resources/images/gear-large-grey.svg create mode 100644 resources/images/languages-grey.png create mode 100644 resources/images/languages-grey.svg create mode 100644 resources/images/menu-large-grey.png create mode 100644 resources/images/menu-large-grey.svg create mode 100644 resources/images/page-grey.png create mode 100644 resources/images/page-grey.svg create mode 100644 resources/images/pencil-grey.png create mode 100644 resources/images/pencil-grey.svg create mode 100644 resources/images/plus-grey.png create mode 100644 resources/images/plus-grey.svg create mode 100644 resources/images/puzzle-grey.png create mode 100644 resources/images/puzzle-grey.svg create mode 100644 resources/images/talk-grey.png create mode 100644 resources/images/talk-grey.svg create mode 100644 resources/images/user-large-grey.png create mode 100644 resources/images/user-large-grey.svg delete mode 100644 resources/images/user.png delete mode 100644 resources/images/user.svg create mode 100644 resources/libraries/jquery.mobile.custom.js create mode 100644 resources/mobile.js create mode 100644 resources/screen-desktop-full.less create mode 100644 resources/screen-desktop-mid.less create mode 100644 resources/screen-desktop-small.less create mode 100644 resources/screen-misc.less diff --git a/.jshintignore b/.jshintignore index 82eaa05..1395b35 100644 --- a/.jshintignore +++ b/.jshintignore @@ -1,2 +1,3 @@ node_modules/** vendor/** +resources/libraries/** diff --git a/Timeless.skin.php b/Timeless.skin.php index aa595a6..a35d32c 100644 --- a/Timeless.skin.php +++ b/Timeless.skin.php @@ -9,19 +9,30 @@ class SkinTimeless extends SkinTemplate { $template = 'TimelessTemplate', $useHeadElement = true; /** - * Add CSS via ResourceLoader - * * @param $out OutputPage */ - function setupSkinUserCss( OutputPage $out ) { - parent::setupSkinUserCss( $out ); + public function initPage( OutputPage $out ) { + parent::initPage( $out ); - $out->addMeta( 'viewport', 'width=device-width, initial-scale=1.0' ); + $out->addMeta( 'viewport', 'width=device-width, initial-scale=1, maximum-scale=1' ); $out->addModuleStyles( array( 'mediawiki.skinning.content.externallinks', - 'skins.timeless' + 'skins.timeless', + 'skins.timeless.misc' ) ); - $out->addModules( array( 'skins.timeless.js' ) ); + $out->addModules( array( + 'skins.timeless.js', + 'skins.timeless.mobile' + ) ); + } + + /** + * Add CSS via ResourceLoader + * + * @param $out OutputPage + */ + function setupSkinUserCss( OutputPage $out ) { + parent::setupSkinUserCss( $out ); } } diff --git a/TimelessTemplate.php b/TimelessTemplate.php index a2c19af..099073a 100644 --- a/TimelessTemplate.php +++ b/TimelessTemplate.php @@ -23,56 +23,66 @@ class TimelessTemplate extends BaseTemplate { $this->outputLogo( 'p-logo-text', 'text' ); $this->outputSearch(); ?> -
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
-

getMsg( 'navigation-heading' )->parse() ?>

outputLogo( 'p-logo', 'image' ); - echo ''; - $this->outputPortlet( array( + $this->outputSiteNavigation(); + + $siteTools = $this->assemblePortlet( array( 'id' => 'p-sitetools', 'headerMessage' => 'timeless-sitetools', - 'content' => $pileOfTools['general'], - 'class' => 'sidebar-chunk' + 'content' => $pileOfTools['general'] ) ); + $this->outputSidebarChunk( 'site-tools', 'timeless-sitetools', $siteTools ); ?>
+ data['catlinks'] ) { + $this->html( 'catlinks' ); + } + $this->html( 'dataAfterContent' ); + ?>
@@ -186,9 +200,9 @@ class TimelessTemplate extends BaseTemplate { } /** - * Outputs a single sidebar portlet of any kind. + * Returns a single sidebar portlet of any kind (monobook style) */ - private function outputPortlet( $box ) { + private function assemblePortlet( $box ) { if ( !$box['content'] ) { return; } @@ -198,35 +212,85 @@ class TimelessTemplate extends BaseTemplate { $box['class'] .= ' mw-portlet'; } - ?> - - '; + echo '

' . $this->getMsg( $headerMessage )->escaped() . '

'; + echo ''; } /** @@ -305,24 +369,30 @@ class TimelessTemplate extends BaseTemplate { */ private function outputSiteNavigation() { $sidebar = $this->getSidebar(); + $content = ''; $sidebar['SEARCH'] = false; // Already hardcoded into header $sidebar['TOOLBOX'] = false; // Parsed as part of pageTools - $sidebar['LANGUAGES'] = false; // PUT THIS ON THE OTHER SIDE + $sidebar['LANGUAGES'] = false; // Forcibly removed to separate chunk foreach ( $sidebar as $boxName => $box ) { if ( $boxName === false ) { continue; } - $this->outputPortlet( $box, true ); + $content .= $this->assemblePortlet( $box, true ); } + + $this->outputSidebarChunk( 'site-navigation', 'navigation', $content ); } + /** + * Outputs user links portlet for header + */ private function outputUserLinks() { $user = $this->getSkin()->getUser(); ?> - getSkin()->getTitle(); @@ -399,6 +482,18 @@ class TimelessTemplate extends BaseTemplate { 'id' => 't-pagelog' ); } + $pileOfTools['more'] = array( + 'text' => $this->getMsg( 'timeless-more' )->escaped(), + 'id' => 'ca-more', + 'class' => 'dropdown-toggle' + ); + if ( $this->data['language_urls'] ) { + $pileOfTools['languages'] = array( + 'text' => $this->getMsg( 'timeless-languages' )->escaped(), + 'id' => 'ca-languages', + 'class' => 'dropdown-toggle' + ); + } /* This is really dumb, but there is no sane way to do this. */ foreach ( $pileOfTools as $navKey => $navBlock ) { @@ -406,7 +501,7 @@ class TimelessTemplate extends BaseTemplate { if ( in_array( $navKey, array( 'watch', 'unwatch' ) ) ) { $currentSet = 'namespaces'; - } elseif ( in_array( $navKey, array( 'edit', 'view', 'history', 'contributions', 'addsection' ) ) ) { + } elseif ( in_array( $navKey, array( 'edit', 'view', 'history', 'contributions', 'addsection', 'more', 'languages' ) ) ) { $currentSet = 'page-primary'; } elseif ( in_array( $navKey, array( 'delete', 'rename', 'protect', 'unprotect', 'viewsource', 'move' ) ) ) { $currentSet = 'page-secondary'; @@ -486,23 +581,27 @@ class TimelessTemplate extends BaseTemplate { /* Assemble the html because why not... */ if ( $count ) { - $catList = ''; } } if ( $catList ) { - echo $catList; + $this->outputSidebarChunk( 'catlinks-sidebar', $catHeader, $catList ); } } private function assembleCatList( $list, $id, $message ) { - $catList = '

' . $this->getMsg( $message )->escaped() . '

'; - $catList .= ''; return $catList; } + /* + * Output interlanguage links block + */ private function outputInterlanguageLinks() { if ( $this->data['language_urls'] ) { - $msgObj = $this->getMsg( 'otherlanguages' ); - $this->outputPortlet( array( - 'id' => 'p-lang', - 'header' => $msgObj->exists() ? $msgObj->text() : 'otherlanguages', - 'generated' => false, - 'content' => $this->data['language_urls'], - 'class' => 'sidebar-chunk' - ) ); + $msgObj = $this->getMsg( 'otherlanguages' )->escaped(); + $content = $this->assemblePortlet( array( + 'id' => 'p-lang', + 'header' => $msgObj, + 'generated' => false, + 'content' => $this->data['language_urls'] + ) ); + + $this->outputSidebarChunk( 'other-languages', 'timeless-languages', $content ); } } } diff --git a/i18n/en.json b/i18n/en.json index a05e9c2..770b61e 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -3,19 +3,23 @@ "authors": [ "Isarra" ] }, "skinname-timeless": "Timeless", - "timeless-desc": "A timeless skin designed after the Winter prototype by Brandon Harris.", + "timeless-desc": "A timeless skin designed after the Winter prototype by Brandon Harris, and various WMFy styles.", "timeless-search-placeholder": "Search approximately {{NUMBEROFPAGES}} pages", "timeless-loggedin": "Your account", "timeless-anonymous": "Anonymous", + "timeless-loggedinas": "Logged in as $1", + "timeless-notloggedin": "Not logged in", "timeless-userpage": "User page", "timeless-talkpage": "User talk", "timeless-pagelog": "Page logs", + "timeless-more": "More", "timeless-sitetools": "Wiki tools", "timeless-pageactions": "Page tools", "timeless-userpagetools": "User tools", "timeless-pagemisc": "More", "timeless-namespaces": "Namespaces", "timeless-pagetools": "Page actions", + "timeless-languages": "Languages", "timeless-sitetitle": "{{MediaWiki:Sitetitle}}" } diff --git a/i18n/qqq.json b/i18n/qqq.json index db69086..65a0af4 100644 --- a/i18n/qqq.json +++ b/i18n/qqq.json @@ -10,14 +10,18 @@ "timeless-search-placeholder": "Main search input placeholder text", "timeless-loggedin": "Label for logged in users' user menu (if their username is too long to fit)", "timeless-anonymous": "Label for anonymous (not logged in) user menu\n{{Identical|Anonymous}}", + "timeless-loggedinas": "Note for personal menu for logged in users noting their current username\n\nParameters:\n* $1 - username", + "timeless-notloggedin": "Note for personal menu for anonymous users clarifying that they are not logged in", "timeless-userpage": "User page/profile link label in the personal menu\n{{Identical|User page}}", "timeless-talkpage": "Talk page link label in the personal menu", "timeless-pagelog": "Label for special:log link for the page", + "timeless-more": "Label for the more tools dropdown menu in the page actions toolbar", "timeless-sitetools": "Label for general site tools menu in sidebar", "timeless-pageactions": "Label for some page actions", "timeless-userpagetools": "Label for actions associated with a userpage", "timeless-pagemisc": "Label for more tools\n{{Identical|More}}", "timeless-namespaces": "Label for page namespaces and watch tools\n{{Identical|Namespace}}", "timeless-pagetools": "Label for other page tools", + "timeless-languages": "Label for the other languages dropdown", "timeless-sitetitle": "{{ignore}}\nSite title for site banner" } diff --git a/resources/images/arrow-down-white.png b/resources/images/arrow-down-white.png deleted file mode 100644 index 5953d0e7776dc898b7a7e0eb52019a7b595224c8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 227 zcmeAS@N?(olHy`uVBq!ia0vp^Vn8gw!3HFS-u9~jDVAa<&kznEsNqQI0P;BtJR*yM z>aT+^qm#z$3ZS55iEBhjaDG}zd16s2LwR|*US?i)adKios$PCk`s{Z$Qb0uso-U3d z7QJuJp5|;Y5OBSit}OKCh*D5m)&(yX*4+|CcXx3#&({$tn$BE2@5-;-*q0K?Z&ZCJ zu{|$8ZP~B6^yw$53$t%_O`iF-!MsMkzNhL(_Li1#Xa5R@G=&i7==*OOrvB`TobshJ Q7ibrQr>mdKI;Vst06P;+-~a#s diff --git a/resources/images/arrow-down-white.svg b/resources/images/arrow-down-white.svg deleted file mode 100644 index 39a3daf..0000000 --- a/resources/images/arrow-down-white.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/resources/images/cat-grey.png b/resources/images/cat-grey.png new file mode 100644 index 0000000000000000000000000000000000000000..0179759ac71fbdbcf0ca559ab2cf68404939e65f GIT binary patch literal 28718 zcmXtg1z6NgwD+GzKsr_gq`N~prAxZIBwo5xq`N~vx}>{Hx}{S>=|%)ZK;#>~doK?b z&&ux3oH^%LL!^qb%yTqiGzfy8%gIWrK@eO5_@#u348FqpieDJ~f#@nBr-2GS{7@|- zz`vh4$?Cd-$1gqof|H=n@&aFc;U=ZyrtWCv=4t9;33+;Yvf4P0u}s5Uop(9G@qd(q@c zt3$P$^|iGDZY3s+e)`AXj*n>wkU@C5j&?~&iNTDuhB#`|y05E~wTwY*0Nj154)ahg z^SDKWuENdv$%$m`rGMMd@UUf}Yg<@1fSEVe)_&*rIMEq$5=4Mvew;Bv zJCK+MGa*X&kQmP$(g|olBR}7AFcrDGnVDITOPj&-+fD*0=f_LY$A-t#md)ylK+UlxyCn+NciCxI)&V`5?=c)$3=3D)<6U6K+f zLXz@!vqD@I|K^)x&#B#Fh=;lvMLKBl27&Hajh|JU4(=E8kP zM)WT6JY4iIh5zv)OMH1bkFS5GJ~~xM^SJj~>`Pt&@HRMG2iZ?r2QpV_4!)b9#0AcO z&|#KtU_Nf}c|<2-O~H>d`zeHV;YH$=6D~<wyKeD3OO!1-n<^tp(qYy*5CLm&DIQ$8P+UwyOMc|qw#AW zDKrfS1yqQ_wgZ3b3|D+t;r*0ch3WTrzj<@_@Gl5mfg1P2#l?kBH??|HTeC~sC!aq* ze<%vSX)Egy|bhR8^#bPDYSR(W#_K*w@TQ!L14^b((S|=eXAAVNA3)h7CNgJ(BwqS-H zM)WRyTnd!bBPgHb6Hq=?@zMB()J#a`6R1H6p4y}$emWVsxi@G*2^T(HoDvamfrcw) z;LYPkB7#kQLyZd;w=GX-aP+O;PJ@~Rd2JQz#O)&r!Eah>6%*_j#+ zz4>}1=tYyZq}@$m4hPDfs1PF=F|^S2EPHi7$Wb8i@N8mYv=D z5=zKtp#0ClL9NAc)8lb{^TE)=&TiaucZ}e$A4`;(c&BE7u`CR}Y8PEC*7{?zD*3mF4ra1sB%Iq!o-jMFwf=RLX0TByuFAP z-p~H}wbo)#B@upMYr zM}{Q3vkX|n-)0M>I!G^>>7zxQQHs}Y2W#6M3eHDC`L}+^Y_;{EQdPyWQ8YrNpFIY;iicWH?mWqX5;)D8d4JHh<9es-sDg!Cm z&zLMjs5N@VBLLwHO;Fo$?p7qv`aJt;=5NyU(!EzlM zA0{-^Uf4?t(vai9#l^J!m0~L{$ z5i}7ofDr{Z9REr?j!ano{nd;NDkO%7)i6;YT+58Uy}g}A=%41^Q++bmr!&f zk7vahp|iHIyO5>@+J>2gMZO?%l`z$DZ`?@9YJvfTyh%jrY-N3qQ5-mqTU^6T)RT6n zr*>LVQBgva`~${)5+g78 z+*|f%QFZSuN0j&my7;T(AAFb_-uu~x4uTK<`UI!0`Oufc8chTMH-?t6GNZeuz0>83 zQ!e+XS`?8D2I0+SSyEpA)j6b$vh{XpH>i$^D{fKbww^ZRgPH3k6%`n2DOow}S0(m` zW1XYJ!FknJ#1ER?E(elQnqh>*$Ha_8N(RkTB5oxy+eD_|VslY&Gv#sXnWV-LI?yV< zmb7nLsU%t@-iL#XIVun!F?^}(la&S~2C~)6?tQ)b&hNG>N_QoW9w+iK1Y^rP9^3Xi zo>ANzbA`pdyYJ~(3(fv{_kUK?#711D77W6mS#@PL|8HkIUNnu(u-$@DY|<#y=y?$N zmw^F9Xuex(r|V|pTXJu6eSJ{1VaFaB43^M%p3q9GWKLNeG-UBY>sH}Vz#e@B!st8syeb(L5Le%qn)$Z5h->FA-h}@YZ-1MD9o=ub^ z!v%Y@V;v_)(l#F`D(~@%q#Nn4x$=lbi=*fOc5ZSN+Ea6-GP_xze2a;;U|~qjw3Eb( zw;~I#-2AJy8jo)NiGiLx(}#04+iv4(60I11;;tvFt68l^`xVMebmaK11h3=9016fv zqWN0C^$a8w`2j}srYqs(9pD;D_cn*m!uxN}^FDq)2wp)t3pV!p5xO=p5kr?KYr%sq z^$L$6Q&aLasdQqLBxM>)lr=XR07?@R7)~VG^G7uM$>gY-9bFLz3#+Sh#;<-36l*R9 zl~&Oioj!6}3od7NjnL+kR3MN)KD<-T60mea1w!9_PFBikQ};JY1WnG!R2#f*j3k%r~WQh$KkBBieV_A?9a3SX4UOTm6 z#bHlEJceWNvUBsq@iq=A3}wgPu!@-k+B>UoVaLO%80PjpdHeoO{gZO(4eIXzTp->b?eAwSENI?dFB#LJ6EM)GRyOjNm1wVk2ioB(vRTCv1R-8k ziG8)JxMts-c)w&|WR$ay^CjmGd04hyavC9y|H~xKB@zbQNN!8TXXY_a_%D?6EgZxb zH{Rxk^)pB+*RT!tO{5Y2ZYmHzMpu}BCC5n5Ql$*a9xluXodpzt%BVeEE8oE{-}nH#dj0POl|d4x6!Vq=buJq>+-WIHu3cv^U>$XGi-hMC@Qn@QB7tS3v9*-narTJJl!QX9IXptB23k%!xM~^Ftu@4!EV;k&NJ};J(#KT0+K@G=w zL7|aOD(pP2+5V45z`8n@*X*x8|9Rwgt9=NzN89>Y!9!t8%9w-;ef$Fq!G@Ze)#c}R z@jJkfyS;>1r6_U079r*Abnve4w7AsyC?{T7xI6-8c;U5XTj`R%Y!;K@GKgTZ#PfZI zkWcfTLU3ES7%|MG^QC#rDYHxEkfqem`-e8^$ncFS)Y@;jtT*>ZM@M5*;x7JweuQsT z)N~&KLeI+A@bXKY0Lf~!3H#^He|N`}pm6{G?Y!UU@|``d>0#|vHd#hMDqs2*D&b59 zp#8JI$8@BeLFDYIl~~BUB^zByj~y4SLuQ7xb<-J$sZ7qgH~@)D7S4nX2uFD7xHF{{ z^z?{6iu|&|82Z@leOaUO%y^OiDEte*MZhTo+U5+qcn zf!5y9p}$B>QAcIYl&i*(b9iVo&dNN!S37U(Oj(1I*O|>R>`Y@$pDKn%ZddE=pflz` z<1i@U=I+h_c%gTTrARChMUhF&TsoWaZ{jK(86lEY5+P2`Bstn-4a!6lR>SrX_zz;V z#IfZsU%uR^uC6Xf#>^r}vpn7SG+jGKU0ae9i59Qvx`d4r@3JVmRmQP6$E_l?)`W`{ zxW0%IXiAyCw=`zZ<+HGVdFzo{BUsJk>m;(YM}d!4majs8e>L}(DrY|fylh5%w8&EB z>>vwHxp0a6G`vK4`ckcm$hFmgm^yghm-U(AXNB<4YrC=_juIsCpJ}S9m;m+MGK&{3 zETOUwrI4fMsGaxPPQ6ye*EAo>(q&^75*5vj1wupHmPPj)yliGnOphS`II0(V)ok5= zf&|GK$l67L+gOc+wFFCICnL^s^$ z8Km^_-P#qe?Vzajg@xjeN`I*6K2TBan!kSY4JTnSucf8Mo~!;ua`W%(SK9bp1DVh$ z{_DZCLG~;>bwwdULPD3}IMRxWKxQ^JB9ciZdJUDa%fDoB{6L8+Lo!kk)6&)^$ent3 zcjLr&(%L|>iae{B*r>(PQG0bN9fQzMGQsgRobH8bQ;x10i&HK%xqjKtS41cHx^={$$kU~>ctescmNxfe_ztAVDSY+ky zLHIuE(7qa=J1N_g^`?QeolFqfctt7yMx*=`y`TNp&!0|)$D$5vtuv;Uoh>VVWd4t@ zg~1FTKY<~!V232w#snWYb2iw9tH&CNdgW|#l^XUWq}H=u1#$56XH2!*w4B!@*+fAq zYAK_2@2srK$!_)8(7H;W^cy{t;vYYLv?G5l1u~}AKz}7|Re~43U`woL8!Y>ouMK|p|)QAUsyf}G7HA%&htyxC&0)k49-34{){Dmoh3ToVE5yRUw`|$@2 zq6$hCl{|yY4D~kbc<}&q1HivBGc(gpl%FHyousR;&*Uw-y{hzD!pg2aO-ee0r;3@8 zJc#`BU^nwHTG{hR$pRKbib6~hApEAC)W3f`Tmjz@-3bJ^8GImf8^R;9T z`}X)rhlhtjK`NEIe%!=Of7=<0KYAtX^XlKbw2=@ZQn>#6d)tmY3Fo1gb}&3e*!L$# zCoL4n5^BgF$~4s(9ox@d^#u&znEJARHLY3Ps=fQ<{uye?mZes6`>^!Js_rGj6`%j> zE%5XKes$fUa&-X)VEmG!2HEF2bMTTx`ezt66wsHavl@&5%toQ>{(&BmM5E0~Y2(5`7$*gTHBR%PB(h30OwH0l5$JTx<|$CLH6roDQT zQr;wRwb*oVu^Z6`gthS@DS$Uk&CK8-G<{;}6I7>{@fotzw*S1-aN|Ldo!oB7)&7m; z-LUo=-uw42z{=gd>A?T$WuQb_%8N|&3O~5RlM}a9-g!9x4wUd;4EXdl+#DbNJVdwU zU2U5x7)DevQZkSC0Y1jO#Gpw@X7xg^I8NquwZ(ul!&T~@)o|?aw$xz%gy!OiNgGZ~ z-LU)*@;Z?*94yk3^M-;w^AMMZG|W(SZ&Jqok2(6WUOE}6`8{klA~I{5gVvfjKY%O| zp<(B(@#~Mg8Qo6X$c;9m$t%q88^lQ>BBBd0;23j6{M)T-4PL&lSmh{{6cj-cY|xRf z-rf<`axp{<7H>-MtvlA~t$UDSBz7S^bOyQ7Mlv=~oob&U1ZN6iN5kkmXSq9Sp- zf7VTQ&@&zlTtPi>be1FAKd-2lXGhLuv~W)7Wr88u%qUrb+~phbx0(o@Ds@0`Y{A()>m4pTRtuM{frO=N1i9nVMx zH>PjSC3Sr=vb@U)P5tDE(T`8iRRAA^-KVauP7|z)xob*@;*7ZS?C!5y*LaZ@di8o} z0Lid8Ga(ZLWtGu?%ht9O7K4>AycX+x31MQ$54O!MA!}%4WHs^%Bbv7@7Xzx_NaAQO zxk9OFY%895qj7efJig05>@4N$or=-z=HXGUQe-s1KwJ4-*~Fi%$fHmru${#Aw4M`VWg#)@lOqA{UNk# zTrBv}4Th^OTpW&)`lP{r7?WKZpRV9DS&EoV?YcpOcb4RGNoa&uiH+v#`z_6L`xR`{MD*@9cH=%_Dc6C;Z3k|* zW}?ao11Ia}S;slyL_HO}`jN0yp=t!^2%-5i`;o5e=hF893e}}PiJy14xb+Bj@!OJ~ z%Q4`{6|0T4x$ZMhve#+QM{txp*)>e_?>1hrYQ7kfqQZ^*^5>6Nu#u9TczyjC|M^w4 zV^@9tRd9v8aPErl%o5Xqqn#V}zpcS&d;iI-NhC+^Cfiu`i6{aoRniwP>ekW*)hH+= zWCvlkj;O%YYHYBi_%y)>NEbE%GQ=E%^j%tSh2j9?|qS4rW7A4&}UA$*t4XBAhapA znkyZvEw7{bGR3kZA1ccx&Ww*ARp@AG2g=GA;+@s<{|)j{s`1AKY9Qkv)pN1F8@9s7 z5A0eDUD(FI@4_7kHL{s_!xj^2U@_!PqGhZtIClU`CKHrE916VqfPmsev+#?6S0QG2 z8v}pjtBV=sqRpaWmPg*Fu<%Lg;y!WC4#uX>5vk@h=2eE<~5kSV@ke;XxLh;90i-7cS%Gfv?8tAt?wp=1ui zXnuQE;y_)k)PJ7BT3n4WH#NIk)w!rT795`$?(Dq(`)@*vNI|%ckxUEO?y#y^V%Rz_ z70%q;96M4nN^>6JgB`}F~EE#@4& zc=0|h0yFw_lPPr?tXhKzkm7oXPmF|v;)L~;Rpxf9@TJmK3KJzyE}yJ{URG8X{+BbX zd1sppbNmD+J`A7}Dw7Q41GKU;JgJpjtU10k7xhxofBUN%zKdZ~lvf&6O8cdpIBI0* znf8LD1XrWhpiK;i1Zwa6JiahD_s+)h@-mlkm*(4cy}}xlXNd6h*~)JiQz;t|u~P_r zFy88&A3vT?mn0~bc?oUczkL4iwMp}JWRYEc>Qa_0wVs|3H1^W6;&@ZqJmy76f{pe@ z`=rq0ljR0RYe`3k@7wqH4|^L&XJ;ioK0XI=ahPi>E0H#t(m<5FN~Dqz)6`sBSU`Gs zct8`vLEsV>qkY_@c@3D7&6JD-<*;fr$x^-)xkIH@tym0qM?{Lt?g2%%{Uk1dUZ}i! ztoy#^>VI)^>xdz>n;{{Vx&knapdaDP-(v$KFp3|de~fwun#vfAl}o!@lbmE6#icpK%w2*1CHY2nLnLHp^T)XYE!)zbTZjqAN93JN2py##{wFRfr`N53Ajk4Yz_7|7 zNDJMs@A<(4oB-YC^E@;7=LrQ44oWR=Y=nUq=P&Xq&GN_94r zb-4N^)H58qAipT%>B)NyNMWJ*aNG|S`XYG9NKdaX_x-=N-?!jzs2h z7)6nMQi!jQ&-{O{qaOl9zgjg|{1^`P5Fg4+NKGY>RKxTJG^~7TUp=x_qs^R#ijM*M@;{7PbD2p5)7`|yWmXLZ!5>d} zi?h0ES0blS>vZ_Eh~&ar^B5t|g@{l*I`o8ry|N+@_#SwOA2@S#s#Kf~u6<_I-wI2C z{Um8`Z`aUGOa0d3sBY|kO^~cyYNM%H<|a_((`AH2Q8de4HOpX4LveQ$0 z2nscYEo@)R_vvvosNp*WT{Rc9Y(@KfQbUfVfzXM=&t+!(;}?rxHRk>#ZnrW^$S!Vb z5yADs=4z?PMihlI4+m!FK*>LU{=66DQx=YwYPP+E&Mt2Ks=;?pEjj!|EhkTo{dwiA zU5EV~fa2y-+v>_n^30O5$w?)7Y{bmg{)m?`I*h$0*xDC*5qSw1?8B!E&y*{wn!f-jY5$3iTPrb`i9shpdeTMDQ)L(4ZMnq)a2J3Dl+1`E~Itf2+;gZr0d znig=o>qf-XvCGcBDNgF8WQ@QPR zypd{}%x_~$@>|Y#S2k`Z%N*B3u`dsL9`Ab|z+wZNx!v_yGb-P{yX z$;8ovo&wT1m-i22dwW)2mF)_#2Z!nx`%^V3tW8ZnC{yD$eme!FBsprK2B54KFg^8R zkE7>{528u4zxaiI^W)Sbmc*{qE1cX}T#eU>jKr@OfldgpjhTv$euL*hK*1Cf zBGbl~x&U&A@m-LL7pWO*RC8 z_78ky6sQRYD{!m2+{I~4FSbx4kz&{xiH=}(tFI5%;hp1|^$jgU?njEdxsb&E1_qyXQIC#_FotnnTOch1Wco0_9S(s*~mW zk$DFzOIlGgf^2njV~Qrv(Rzd_ZVj7Qz=7|Z1vDC^ zD@wY}V(Oyzy=zuB(b{S%&&+-w%V{uEG5v2AW>|a958Do$`xNC;261eUCOchY!}XKLq~^1eAK;z1~NFY!}~d9xU4I5z;s1eGG)S-Sr&%fewo=foczu z6ks`I@ue8Em8mG%GZc|+#J#{IMh4xSAxbTRU~Xll3^`c*dZti@os$#3wq??PoDx++ zlS9tD16QyOxOxNI7ykPE4n$hgYc3=$rJ)@;nP?;bn}U+3#>GYp1&KbLBo_Z}~QPAXS__7_2geR#u>26N~_*I40II>o46>-4PQ)GLq$kV}WI6 z*RMj-u(9EXmT6Ff(m(A?YNc2c6;~!$bL%Y(aG;UjLr_}PqNerCQb_eE6=@bDrCpYU z!u@lY7XSN+%twB%$tn&YtRDM{0KwKE)(dJ(3;b+FHx_`KXx2CeKW#!k-4tbPZ0y+^ zN1%KpqQ^+9qp)@1HIDy6;G+8%1G`xHQA}SN4t5CW5dBFjnj*1oI;4-c^m34H=m zDw2%kZ-ToV&4CkEewhdGJ*{nQBDL^C!6zmnJT?Y$>W?3$qtiHEn|+sl0j~vCLK=f2 zu+w8UemTJ(bx^FhNGoen@*xu{U8QOT_E*=rTu95=zxEe5FA@?)%p$hFVxy_zRFWWT-|r z%2ALU$Z{Iz9dP)Jb`^J;3|E||SY>K$8N zSmuIZFg}Hwz;KsF<$xeCFQvzePRX~;t~n4M_}}Pl;sK^^B#9^<7#aBt_UcuQ-7zi` z$f8hDQORN>0@OlIiTRY*0G;2mxm`6 zE>PHh=SCslG#Ndj%tXh(7Qi&{ZhR~)L$x${&eH_Ee-+IxEv0ifE6mhx$4TV5`acVT zKz=L+43+Ng?zL#PZhG;o_9|Ivf~iYi_{kyHL3%Po|0YfwtC33~a7LuF9Z@~H*_ct` z&2$M7pw6q=r&*N>l4l@)`57RxC_MuMNk|N=e^f*iwH&I+I}Og;9-J^!*>`(?`BNvY zIL7PwvL?5>yG5Aga6uU4OFi>;em(^T1pY!>Q@Si2;TCRWVBl7&#vog)Mn2AIWNaL+ zhpzBqGZ7uykZkU4WmNCMmdQtc4H zyAoiCAI;7t75~Xgbr@~mXBD_CgxQ;Zz&2n_#|Xf@$4v)!LY?te+EBY#1=Y&6` zHg!go3qEz{J;XE9<}uL;Ut6zXG=NT^zj*&m%p-RAx0lEMHE16p93`L!GC+B1Whv;; zXTZkZyv`bg@;uz#%YZ>V1_YH6J}W<h6vMl9SWhxADcvN&DX5nne*H#-Nak%NdpCxZxo_@MiAj)!#DE zHo>&SySlm{qyckKbOC?=)D7=n{s7Ka2_9ybicU6UZK+DV=`T#AVqVVntQI|Jx|U3n zC1^bIDNcrwlK@bFa7 z%?@iG?`m)$@|^v3*7RtA+FfXq>$c3SzTjX(_Uutqzn5l(?^3fC^sp;g?}l`FC*%I{ z;Nq0^f7W-q|7{Q0Z^GUEz1(W^F^Cw20SH5rD9fFCt;_T`Ky)!gjDmwOe)tWjnapiI zf%I{X_kXuv&77Q60wII}3lq}{=r)?4#JS@64D3?lNf6G6N6PebvL+Vn9Zf!U@i}U}rBiGs7 zJhayHK3Be2t+u_L@jb}j{F@P)NyoIQy znfmY7IGZ7OR1Sy%KG|XdAl@PD_oo&JcR#RzJexc^0-ypLewc}mF8r)VT@aSYpTI~E zoDlP=J4w|N#}4Uyc6{Nb!bc*Ff=MCoP+_!&U(LCJMd)2vFPIt&H=*smUrZmkR>nHLG@a6IX`eh)Nkdl(xW{31){Q5L>iTBj5fEYHzH6@g6Ghjz0Zm`IeBWqyQ62W3&Iy-9l%B}+9OIdn*>lzvu zOz&!X$GdM zQ2g%>OE-XcK@YGGK{1II0uHACd9g%6oiSoRs@yeAu4Wf!Lr`xXE@n7E&i)5e*wWv> zelqXg(Jg%Y#)O51^{)Fe`@HpRy<^}1&rb>?UENX5q^kM<5^jI`xTPVApB@~j^#7>E zfW%bstLV}EK};*GfPVLOKQ|p5odckPCXE*L)iV#l)V22W5gPLYK{y}Sxl0NAv}Or_ z@qq#zy+DQn&(0hG@LHqz^xg2S5dUh7q42BFywi;MNdN4Cr{##@j z=Pcw2>QADk2s8azre69qArK%dT|yLiIDp}vBw@hy<|VFim14?{kM6FI|Njz@3@>O3 zRiX|D5IzU#H)_$3W3+G-`{CX8vGRJ6vPmfjfnXfI!6FlKa{TW<#IudAXfQf6y)P$u zQ$s_Mq?4!}g~*1ZqoZB$u8Zp@{`_g(%>;erGVSM&{&0fnwH4rL%;!G-eTNL?m6p;i z&CR`0+qI!Dbd~(}OqQG2UY2O%>sMtA$jip&8Bk$V!6JjjC;*UR=fZ1xb(Oei&PJ^Y zjVvAoO!Rr+CG5P0pqizu^RvTipSl8iFMoeSrP8^m;q6|0sUIM39lUfr2tfeI{x_yv zrkNL%|7@#DzXfPerDt2FpQhjaCnhW6*$|z9m^`|9Rn}2;rpAI)C;4B!1VFY$_)@C6 zX*3JI^WVRdUt&G}#Hzl&cJHjM4b;}sN&&Z`5CVbba0mvo@7Y@0o2P3XBJcnC-KA<9 z<%1#0B`6pT0zY~~jKBc3%oZ(b9{Cu%2($nX4-a`r(CpXuUIa7)Mv>nrsR)`AFv;N1fI8$7l2uW^MvQ22)Qg ziCP6835bkej{RqO>z{jecT~oMSDH?aI?q(oNx6881TIRQcirUJj9-HE9m(*nuN)5g zAgXuFg)x=S2b=T@gq^Oh6BEm3p&=3!?f|r~Ff)729df72QqzlL&jW1g?c~IM6A$#* zF_5f#XKz0VM2%-)>*1BC=X?I{vYml>g4Fk;_Sc&0lqI+X1HuA@M1+KXVA_nWcX;kv z#ioL6uj;$!;@D9oTy|z^jr6V9_H^X2)XAeJP@ow3^g;S;JxE0r0#LR0e&0K%EZyrs z-wo)Can{`JGN@74+4Vt2CNbM6dMi;g!*5QOcdq^?r%LkWYv0}d<|EnDeL%1g+Z}$l zoJi30!b0kOMbBNu320>qQ^Gf&?!gfyQ=%RKFSQLU?6-@@f18i$#y*F|Cy{t`0|3Oi zf&X68B!9Ip!T(bz_Z3VF!%#Kf5{!|N?=Y&n63bI=x}r%HhN!WuX;9;e@7|SSxJUfJ zuNMFrvtGizBAL{c>IBP`zu##e+Ddy86j&;?Dq&r%Fh{O`o2(H`Qy*~YISUEY#ez1K?U?o#(6gg_jq6>)$9rT|K#pc?Y1|&AKfwz0%bzrwt zee1Z<840LOF?b#=Vq)T7YaO2P-M%*tMzY;^M@*J(ZrtO}1`ZY$)V!RW66JEMs4F+AD4<*5~n%qCA*FWeHj~z`lfsw9Amq1e}Jw_S{xEg68wp4;L-T`5C$8Q zR?G}>S@Y3)6u6wKtgO6eE(y-;!x<#lv5Cfobm2NBoDSq6Po=kSLD1~eUtr2b15=e1 zdTPpfAP7p5lIT(1R$wtbVBz7h*wopnsEVIzuB#>Nc7P2aAxWL=zrXvUcoe;v315IF z^n_&Fd~aBDva_qaV95ky4{JwV4o%sC%&e@G+o9^pZ+M0oZO{_R%bRaMdFO-!#Q<8i zcZUUorc7dGWhGDc78~(9pF=uKbE|#k)$p>w`j|PBu=e$N+w|izNs_A@iYZ}!{%22y zIcE6f4TZgOxf~C;Q`zbQ*o!5QSODlhZ}q#a_xbzhVq#amXfCf-2w=ngDW2( zvSw-DFDLBvGw`=h7hm#dLN#Wa1?M3pM-s>oo@6<8M*`yI8XO$#1mM^auvI5O*Qqmf z#*KC;HN?jah(0#aWo>W9!?wrO$&sJ*>q_7j=t{C&k;a-RLk}X)dlQb?3k3Pe`brkT z4v8&OH(i`1)wY8gE|uagqskbE@{EiOzgf6vYl}yBAW%9sG7{ke zysRa#lJ8wy)Z!#5`Qx@-=#)P>4V!V??B~AE$;!^2>}VNV7ApT~!H(~o40qBx<^uR; zH7LY;Aa7OvzP`5H1i@hvw9xs6cT@8H{rx~#8wI42%I$nZxLE6~N?xi(MJ-(FcS|6w ztT~&@+pkc{LNrekuMiB!JCNvJ(R*cV43lO34BF-R@P7w17B9rHe-SD+p^M_=OXs>4 zt2sq3zc8k&lN{N$V+qMbO4#cfpuXyl_Sg~Q>f}~Z5`1Dw!twVz^MKGV?Z%_ z+X`hSLf{%$%yj@$yFt6zEi26#lP*+EQezgqKWV6KZkFC`caPRJFbJ`=lV_|G8QG4J zBeN`m&K==QVI>yCdX$NQV5k$Al%h4HjKDk%CqoRqe?N!R@k1eKq^D_so~$UzfQ?Km zc*hEKT~RF_bkWhYvh-_J)}hsp67y84AGi6+YHH$vMrR)IyCF9}F)>k*n>h99l2uQ@ zx+iee{(kQb{*T2_!Kg+X8M+;3>v7xc@?Clar&r)_nJ64qyPH9EPx8X@9#?Z zRmC{q35d~X$?+_44?BBDw55c<+Ywg==_udB?x{{3i%^czn#& z1@gH&M!u&_%qL3f{os<`6r9*uFqTN(+Z>@o`=P{EYBF=`MA=3qHs;A+c^10Wx=}?O zd#1ExsY8M>6B85j7Il>ap;~Ms`x;}boK`I>51G_*V>GytpFoToc!(fMXcM>n6HH7_ z=J8p7fB)_&(MKWuV*$*XC8knvlbJEqYT5-qt5gpr7%?%UzQs3XF`!+63!Mq$yT6QM!1unr+*d%h-1IqSK{96s zci&rXGzC5e!a-_f_ynkkwrY>!YVL435h!JvJ3i2>2r zS<#2Xw-1T3l6T;yTP`{{tWSUl+((_Z3+E|_%}b@03sR)r1~}lscoW=Da@m`BaSMX3 zA3NXA23P{f+p1^ zL;6jD4mh^b@Qy3hk9@kQY6{)btZ61F^nY%GsDY7Pb|+{Z;?*cP6vNa&n`E`jLOyhC z=IW|GYQeeH<$EI}dcQJdT~$wV(ku<-v^GOut`AFd@2U;j3V;uMJCVUPv~v2VZ9ivR z_+}0KWQ+r#f;tudkL2TbYGeN{M%8@{6Q?ocrT_khG$;n9$fctAstnG0`nM6&GqXyXK$-1 zC^$c8?HQ^DJsHfrh8(p-S7)+b zmI$q=1wro>a}m9~W{Kd`Wyu^uzyx^89-0tt2S#!^%@X(ZZ1kfzFrv5~+kG^gG zYo4fQ22Q@h=G|h;ff)Jsd(cieUuz_FRR6!0zB`br|NsA9E^g+%Rz`GPBjaWzd)&B2 z-ek*8R(8nVBiTZcSwh)+yJjTWWRHmKm1HNsm(Tb2uW`;juk(66$K&~UJno}5N}!mq zki0?Z2bz)sz#F;`;xq$f9S}FtGBOnY4=w~9zUre#?<7S;Ucb|#gbdHm-v+KJ8Qm_g zzH%t8<|fPn_C)1(BcMXiUH!B1?Q~1^U@*_&H?f0jfm8s+6$R?l05# ziPqX)_pPii{9P53g&^*3!P|cK@>zgA4gyI~lKs5h_%YMu9Q)>M9rDAs`rINPQA=p>S?O;{Ce!tF! zo(fNx6ldk>V@KeNV`Rxr-`h4kDAD9~P4 zZZ@ZVCd@uD_@^nnnCgC%}3v z!tc6RSCk8#Rj0L*0hPB zeEj|Z34QtH)qs`opO=Au*z0#M3Y_bubmAk|yK>9!%pTVUqn_(((QciEOorM=H>Cp! z7@!GqOPz=RvE;Q15ZBfCKvp}y|I(lP^8n52XKsGc@zek0MFU zEfnPqk`zFog&<%$MdAhmLp6}Wg6!hxN@X|j2oTU-wltbN@YyWP2UQya&fRD-$ag;} zbpLz)1CU}t+DnxHXp4gH$&LdV3}Wu?uFIvb!uR3Rrod~P;)jJ|-HKsrrztb!HSC`F za!1yNFMkO}R#!o%9pD{OlWMiOx$FlZ^pp>hegYLu8emLqSK(?J@~;4a zrf%ujZ9nKp0@U-tnLZM^yyZA?%~Kx`tqM=j!(ZeeGo2qMH>Uzv#ye!v8iOud&yU+K z0|G~6pRLB8064@45CfeKLM5f7_5lcXNA}&&1xQUl6*&-aD=_eCfnb|dE#sFRiv{Ze z)(!y_kt6{odph7Q({kW^s92rO^E^)-FBIuaOCND&e!OOOf8U%FKyfW@E78iA{^iZT zRbMQNYa~YKfsrtn!0&^l0|9XIO1n$#*8!eq8bBK_kEYR(Uyoy*$bK1jAQ3%c*9jp# z8YK=yf39x?QZXT`OgrULS(yd!oD5*64gWLn@ z1>vP9d4REJFUOBebaRl~<{otH3jL08ZdS5-G(G;lWAAvmwDh)}y?t+Im1Byv;rhnL z*DNWo!D`T7Og25GZ-3A^WPkxqVPMvxt*jgY_G~)P9#i*KMKA2-0}dGIb~tvbJuPE- zAO-G`W}mnH$Z+S2$J<qE>%C`cBeAwX(Qpm>d1WMI3-DXi%Gc zy#*(L5kM<*b2|Z-bky|NgQ9HD0UGsXIkqw_2Z=@xG-KBvWh{655`1yJI}f3iBr#f< zt2p=Bu4_+c(*nhsLOSSOhp2qPG5iU@DEy9_^}cl5RscxJD`SN^)JUXu>4RP4y~VRu z`UD)XVY-Oud<@u$K5TY%{nvvhDE`i>17nkzNRc~-z5{XV0ppST#L+ocLH`cktu3>8 zHdR49F;}Emf6o*!LyBjSQodJA)q(Z@0>^v zt>O8%>=ylRT>s)KP9MVqfdCM%9}rC)KF60}WI!-KJqA3C0Fd@p@e3Da>-*lRR>FlJ zzis%dXG}8%BW8+Lwx*8>*HaV=Eda+Hpv-vse@>^SK1I4Ea+$bmKyphpdDhow)g zL9EyV=NDL4{gzoFe`Z((f1e)TFh9wUk%6=M@6Jh#>>ckhSp$t5Dp{2Wf{MyX<&=Y< zgvi;!*jLfvxjxVdWO{`uq7$2qKTJ3ax|QhL{r5=2o<-MdDlTicSia*x=>QBzPJwk7 zdE>;}fFr}{!HK=+0Mhuo_T%96H2^|ZWY5;wm1q?!%gdj>;frgi5jlP|P|BX4Fx+pJLEf+-Z+>wG0Hr5Q5A~G`SF*z#W#m}rA(9u0X^Fr{qU)x{*2Q&-+^K@#c zHfKUftz0nOLf_H059n8d4KX_fK(=Wa2L}gv!K~07L$3pnY_}olgV?8@o^>Db{&!T` zGnd5y@l^uia@9)qgLd!(7=eIM(ac>c8SwO;HGWZJL9IDxtMVLi1;OtE z#a|Do5{Pj81J9=-x(SkukNhE02?Q9&+XLysuIb&cf&dFyN!s%0nGZ=EGH`j81wuD2t?!P zG4Gx?D2(i0Ja)YMl;~b?Wu*|rHop1PCeLu0&5F%AnY;;vwe;KJtPlW-kZgXr8Kef? z){UE$?hvH<;)%_FG1buO`#d=~IYT-@!uIMbcfIqx8z}z4Y^||8V8@{jU)kN=4NU47$>2YJ zetl&ao%0h&IeR@H=1CD~KS@bRY5x4rjBip$gvrAw<8}5#^5(d_$xFz<)9|rQqx7^i zo|ES8OEJPKOkdmCc)1A#0;mN#+nHtzF`t1E*=}PiXtA$Ml>VIqdUQW{B=X5JQ$i_b zj3j}!vS9aHfU1PP^C?yOwt1%_UFf1R&9;u`wUyX3seWYE();peu2jRD1ApeDaw2ca z1;%>6B>`9k=zu2uk2Od|2db_C0|{qXKsvAF-Ake-g*bT6G zB8>tgBeFdC^!{!aZnZm&RXw5iaczwBU*rj!Aln{~7)xL3GnRvK-OANjzT);&56K#T zJJfr$^R!A|8q)A}Cpk?mr=;#)wTs1Di2~q7ZWwj+8V! zMbDlLxa2`&h4lJ8^c;GwDXrcS*H^K#XQV3pBYqYRw9B)tf+?H)b7~XHF^K@Y8!`bM zSk>fKsU&l;W`zmObpQH#!A^Kg_?6KX27`H>`OZ-}S1vfqJVS@ZBF<<$BEj?Sin+g; z#a&V1R93)peko-RoM04AUkY4yg1A&SGYFDZcxg!Z<9nd_Taqa`3Q ze@#o3`_+u>&n=c~FC@_xarVn>XLbAIkt#A_8y_&p0F$ox@R^b|JlZb+_|&aQKF$jo@AlsGfmHFDQ7CPx1@gmyF41Su6N>#TV6=CmZ}nja|K7<8&)K* zVZfSn-yU|x$UGOudm6R}gzTnE<61UpbYrFmM0-CHs%0vYrDkAevWcRjv+U-vNu{%C z;oiFGt1G|U3ZC^`QVAwak={RW`}cP@&^$bk{XglhAejrY+$sH(cHik7fq0>Yg@&dC zX;>*$7AzYwQMP3h{V-C0=ie4WT+9#WUi04@dKeCxc_1@*ibT%yu+r))Gww$&%6<}- z#7g^wZFanQZdR@w)`8NCT><8OV<{s4N@OlWKYSu3{kTJ4OO=Hy7_qf_Q0s9cVsL0^ zd4f!d`OO4!t@#f$1d#w*2x24L7#zQD-KzECaH8k{*IGi$s5|tDza&BMrvFHco1jzu z`fF=boRw(C%3vxJWyF2?QB;nfHNF;wBKjmDhZ@?1tws-lUwgQEQo&-k1OYn z95pM?-;^BQ@l^10Ev%CLyI!@p6^#Hsa{}$G$Yd@wxcM*4%dmn5C9N#aZ`54$yf&7T zA( z6b(J(L4L8ySdMOu$0Akc`D{%wbz)JpPAFf~d$)u!&s#-anjYe7=a(0IK{OX}IWl!8 zyayjCjcF4SlUe3x+ODgo|1+?=Mm!ky^%?@{^NCB8SjBNE{W@IbK_K8z;B-dnoT{8M zFnu$D({-h~Dt~7chnv0KnInp$bHat!n+Q%-;00nrG^UmyNzU|qvwH}S+N{qlIQfrm zp|>{=(EiMD(ap+#(`;RjWl9h}H@@7DE@v(1?+Fe5nLWEh@Ag>t`&49D!G~V7w$)C= zf`@glw~>y@FG0bXydz#HK~fkP^q1IFPY(d(-X8FnE+-vDjnCV3-RIN^=L|LriXv$@ zEPlsC^f!jmX><3kzIbhRW_GvPHA$PDQ(`R+G`l~{C9}Ru?xk4sXdHOl$R7<^F#Wc5 z*i(hsagZL>e9e7k`cM+?G`^Wl{dOz7w?hY!K)uiZ^KfNl1xh5$p}R0vfgNK{LRZ!C zM{W9UJ>5_IL(J0rvTNbn1e&gP_}uiNVfSBsyY~-)6>lW|mVRs{bMpCu9p9ql0bpQs zp8B^ABxsJTcD1$ad#eG!G>!ggut&RV=J378S{9lq4x9#1R>e=BI0nFw$X1$lO_iR< zaxNr_LuAE7xVud6CLtz)WgmEj&6}8*Y}XpywstL8WS(1D;e_RJxT_z~>1%5%ucNyx z#c!72)qH+@pIMa4S)+T$Z>p!&41@XLqdp-w**NZX^kf9AH1S`JrbihcV&h@^i#YcI zhF7ZVJfsa3o*#m?4s4UP;UB=V`zdP+`NTjO z@l!lrcwg{tHY>R|zU)761L2F3bwHEd{qR(sdA~=dhL^0Dmo`Ki7%|Bm&Fpwu3a25o zPOR!Y@#-nofd7X?BGvPC3Z2g7#M0Dkh0}&fZu(;Z-Vw}BvZ!(6%ljWLDtm30tyKX% z-;bLd-`KK4I-ZR>*KYt_hw+vGudDL#WKhbB@)QINsz?)u8hQNpXGjR+6!zD~3k)>n)(!J*lk@SCjTlCV& zdDviv*Y&?uRfdMetM$Jv6fWBu1suEGs5m{vqs%|PGT^|0Y20XI=AG_UEjbL00g9=e zVHxmzi`&3C9(_vV6Z#sTnUG2+r19CqlqpWBnb^A z1A$Pttu^8ka^$5jeCqve33U%=lxuA$a)YvdS}t3vqPzbtGHy_%B(9tJ5&APk0@X`82)DkWI_Ec0O1)LHcDQ)XQ)?FJ#H?mLjYh`Jq$5!%qkRAxi2#{h1`gM^ zl5}~tRWA1GtJSn~{bb)t6>{x6VA`k68I*15_mb|@&?W(UzJ#r&pW>7)-ut28Df_C- zle!;0a=rz8><#Ff4_U8fGPifO7jM9vvi6cbH2JTE0Cc)EDgK0oH>&b%0yeNXyDnvfMuf z9nnW?!{g9}H-&;PtK>JQK8O{v7geaL+5Tt7k;9WywCR?-R8mcsBp9l19(#BXMuw9D z)4vKXbULso@2C!JYvag~pJ9aaSxK`pKQc*8;f}$f=tluqKBL z5!-Y8ySHz@GYRX7c+|>sl>Gf#Cbj($YG{!Dzn98j=@)c9yFh(A_G(tW)3jUXYsy6v zv+isY)zd@$lf}-Sx1*$V!`*ky1aRA&R9*Bo{{!m<1hS9ZU0v_tm?!7=_l1xnM_zre z0_a{$l?`sx^VVeyw>g_0smwID6O51#O85cV;laJWCK~o zaOdwot;oT)`=1<(tkJ@yU3<3zBTyd=(M`@`Y|IWF40pJKAHbkOZ}T%Wz; z7-!6WP}JtDi45W|u6fI-9OIH*sCQdm^!iY$CIfGEg}dpto|9O2+=qcoDnk^C4%?;P z)n>h#|K%DSS(3mFa(mX%cDf)Au&74p&3&T66)6eb4Q?&50{UtHru7c{7o z#F2%TMo*clDC?-p%4%|>Vo;l@)?Hz60`0LnsjLUD!^@q%b#a3mu%#xh-0Cf*J48f= z6X>f53#S>ozGmZg)qhpueG-!Jb72>xyQ$h2!NK#3CI61?AP}mEtM3SS8b+NN z%P8778Wdn%)m=3hdJije>B&B4(ES;kj+cdKa+9GYW6$0PjUdGW^S?y}!1)CP*ibwh zp7>c-ZAAl4;n0Mmliy=!1sK5+vZZuljM}oQT~h_U{e-+J6TLb=AD@lu-rW*UxbEsa57vD(W$w%1N`;+}n8LFDus~iTi(k$g zETVp7XZqUQOFW*Y2EmNWyWlp4!tz3;1OIwUFvU^E{L+aL>raS9W+M{6a{h{mYcz0wTfw6DUjSyHdES3{r@oBazK5b=W{0 zUy^gZA0JfSU*LA`NYAB)<%G2*C2h|$SJy;73AAHkNboweOrg?>ZmeM@-K_kL5stta zW2qFUfaUE0+T`T9V1s5)<-~o;@iGkEx|PIN-P$LNPTTla1foL9rrOYvEvYEtMnUJJ zwfEmFjEF|xYNQRVxm)g}QImuO>n2_cO>2EOMt+h5hXc$_&UB}dp=6NSVkYqV~b$!R#w=cge_Y5|tSaYUNcK}5;>MY5+ zQdrO1y+YpVEIBHT&#rFEff)vc;y*0xJ^E7XbscT7DNo>>n-QriF+s0_r}(@ut49BA z^By>nYbPfsXJFZ@>H#spYF6}l9=iR59;+~VbnEc93C)floqf4WHbW~=I89ufAJYsh zHT*LO>wsKTkhA@#Bd4e9^P7N^`VTRG!!GU>=FFrQ4y2A^o zB06H18xu8>T)iQ7=*AVMIrsbYox0j1*< z6B6BYcbszRF@J;S^nJfw+Nj70y$wVH(^W0pw<0`JPRf@Tn3_6K{5$n766sWmfUBq* zV(6m?v_0w-Obfz(ZT*poS7K*G8q$nVAO|AX(<4`DWqL(D>xTG4g2!H;`tv7GzyB6? zt@oZawuLe*-()hm5Sb>_O&?oHXX*HrA;XUcuY)#%$<8ijIvA!=LJN7a9^4X2*bU(S zv)7Js+3CG1@hBs--{&(Sr{6cWu>FL|z_zy~AH z)?u)8NK?avI8$+{P?bHFt$Hi>D8f{3)S{iic$jOL5(+&Vb`%ZkXwt0sHFll+Z4-W{ zrlE}4CR{{(jihSUJoa{!?N^CORUG(C-E}*SYI;q*{fyai-XT32&*|LSCEl2YwJbL2 zPlN564$$gl!?{Hsh?=4pA4iVpPqW^|lcZ;5>W|rAd8>lm-sO|8dV2^CKX(N;IpZ=r ziIFV5&YjP!?JUEwSO_qc+=(HA0Wt8Pd7avqKZ@1ORIt3~Nc!S{mW0nq3#I6mB);3ke(QFP8B zQ|Vy`)T7^~8YjnBLQ%n2wAjmw)n!1|y5FCsAOtVuduu?3_fBWglgHty>WKnGynYV~ z^Gbq!KQ)?-eC*q$a5AbBh~manM{7mPcUFOWAqIUEjwl2^5)ndFh2}{aUw+Y&Tf({T zsB@Tje}k7ZTGGtKHqb3Qg=gDJkUa;<_M!HCEOH(Pg+Tx6tMtcAqHWMWRAcK8Vb-cR z9n($OP%PHI2Xv+0{j*ve@yqQ@P%qGmm62BNq((g-P5$}aO5VwD+|G_3dgwBE{0|@u zH-TbCPNyil@ZVlj?j{j-B}Osj4U3`fyO$606#%qzvK&=LuV{oq1vl&7Q^NJTW_AOW zj6w0Z1(+IdFD?cH5l6L6HKT7iR;9lahh)>f#ZeTG|F)6fH2Zi+*&5cBn&gvBd7mcD zb#NM>(MP)rZ2)y@nsKN#q6kW0vCw|1X?u3-+HEz4@FymWBrsUdr^ZA|ihX1mH6|c57FY{YQnTzl`J$Ebsb;T9}j^{7r{+(DdKMYA- zkBKV7WX&7YIrSa28r|vs*yvRNMIbcA9|c_;eh1&&@$43sN@#=(-t+FK%qr~?Tf@;u zGA0Tbj63XE>+$Azai@N<$1T$v7C9tb(eOkwdGtmdX_ZCnfcBo+9Rwk?*F3f~()J8+ zYHqqqW)TKGkPF?*=CxXH>Wi{{zo@B7LJ#LA8uVEnFMfFZsRSv9c=cOogmmPCC`Z_q z{XN`4QQm$IHOp%POUElq8lVQN416>qN~E{9Qdw*l;4}O|LqB@KRWT!lLrf1zg@(hq z(*oOqE>;Jac@9`C2;7ymvGit7i&gV>&qBz^wx5HF=t93Zxk>%5iOHtmNU~xLKDf#1 zmp>3-@oc8L6Vk({u7R&SiP`t|&pP^{{KVWG(Z?G@f&|r6!v9L|F|_=1yC_~wMlzuh z`+lGPOwrC9Ua%h9ufea~O}*+&_;rZrh1OLmEGot9MkYD4S+lh}esgP*5O@y0x}~9? zc`)s@5HK0NdB*%=9Zxit=%&UuRZ%9N+(=%54WOcBaQD78;k{nI}Pw_Le zTq$?ty|rP(!@D{0IV^W_CNx&=l>bE$6T~ipnbyFSe1b%4fI&yJhERe>9;;?wXKR?U zEz`|t`AXiaOvt;KP-&5lh5u1oV1W3$p<}NA>1H5WFYI=|k&! z6#2g;t1y?i|MA^JA~;+y+7ln=S7))VeOGA(uhRy-8mDL-&rc{d!WVqp~PledT>rXfPy>E(c z(`M>q_Kwf{!0uJXVI_1wlSWMgiMxvlecnES<*)DmcAKG1Wq8EAuh1$z$7913#~7OC zR1OFkjA7_%TM0i?!0s2+$oKjpBd4ig98fsC00vY~Q^a?XBs|w?Zp%hBAsWg#f`fxq ze_i1NmmukZ<>9-ALS<9W&CRuk*D4fIYaTV7mP0kZ$m@q2&^KJ$S%46{i6$* z2luUL1_!&$Gzd-TR!dA87RqBygXQl@TwNtIGZWK7&?)VLZhEg?yZ>BB^sto+C-PqX z?r-p2UWuvnnlHu8A|p6Je4#r5oFotu&DmNLM@bDwKDLdZOJ-7qx?AjjGHYm-T?=$u z4hjBANI*~o3j&Ni=cf7HKkMtZrw2oF5%jDtD$HXCMr#Uxby+FlbVA$y(u1mz5R2uw z$0=EG5S*FYqBuMFV5iPZW|8=1VQ1kwl7$*+Q^zcCLiS4dWvA8f zJZ&(+kIcOhB^CRp^ToZ-`RwuY&SIO&ld(bu$<$;2xJa^9n&V4#W@;cLq}-p9lPf3; zP)Q(FYeFm?A7q@UI9+Ts*;wtMZ#NWO{S;>DxMRp3(?#`=mW6N=@p36R7?RDk|p8eP~Z$X-}F#^q+fr_30(rVF9RN2)G5)Xyt!E+?nM7-cq-%C(;Sj0NXMtE|hin!7nnKG+k4|oS!4;SyyBbc|%J?>;<>YC6 zi5Y_*A=F$lwo+m(^V`Q?74Xr9N2^x94sPBem$2Zk9Z2aT#Q@1R`C9Y+j0P1}db7HR z=@+{?u1nUEeC73wD$uG5$dphkd8zcYT%qw(Zz1ZM?Wy2)A7T^=VhdJEks0}Q1}*#Q z#9Q{VDW+#s>Jr82@)(-U_}0PhowFC^k%khjY53=Zz7|GKpQA!__EUmP(X@vJ7d;Rd z45F}a)N^MBuChC(^VE;T%Ed*7aJ@N$5Iou<{o4c)J4+%xpE#8)Z-}$bN(Lb$fu`Iy zVCdX}?a`;hWiP1f!oy!r?xpSxExu9JJkWxGwGU45UgDf{r + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/clock-grey.png b/resources/images/clock-grey.png new file mode 100644 index 0000000000000000000000000000000000000000..1e5ef28efe42b694e1697678d54aedd216b5f382 GIT binary patch literal 586 zcmV-Q0=4~#P)S=e)u;p<9lg>&jgE!fQ&rsrR^#+3a2!JDI_FLn0uBa)<>7Gn0_Xr{&i^JNa-ga^*4l9zxRelK zhrl*)E+VgtF&jlutQ1ADVvN~P)z`ppRec5=dhhEgqn3V*Mx&R&J>XXe;em7RTWtRm zK(pDr3w-w8e*pTxeP9oGK2xFhzM-mZ;4Fnj-H8JLYwcIyA#et4XIZvh)p83kBJ$=h zSfwKL9k8UTtt#LafU5ScgOv&)^kU9d74SxUexC>M-fOv^0LGZ|>fEdX>Y|mE8jr_i z{zYzj%0Gd%IKHHb*4jz~)M~Z0`1+%&!Xp4xeX?kU#+b(dB62hX3?X!xI-u>nzkMAn zu4w}kRqf6IopUE5asVs?{i~oc)(7e$vTv=uILJ#*QPmyb7O=_G5pP2Xz2r0-z@u1M z9XQVOd^csxY + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/resources/images/editing icons.svg b/resources/images/editing icons.svg new file mode 100644 index 0000000..1007981 --- /dev/null +++ b/resources/images/editing icons.svg @@ -0,0 +1,220 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A + + diff --git a/resources/images/gear-grey.png b/resources/images/gear-grey.png new file mode 100644 index 0000000000000000000000000000000000000000..3127f67374051e47819fd82593d9230d0304d235 GIT binary patch literal 635 zcmV->0)+jEP) zC`D^Q@fEaHq#(=_ButnGs7<*G#bw2=icm|btK5NkfOhV2(L3d4(j>U+S>5^0cYg0T z7r5<4iwJ|k;IR;51OP&aW~bBnIgc-@fKtj!)AZgoL5KzbAAoO+2}``+@84HSd2>6A zn^01prmA*Vn=@yexA}R0x7#sVIsD01(mh851>` zxoN*ct@RRs(;G)_x7&Z1Ij$r*BBE^~+6HjsI+!_@Ql7fl^bUwtoPZr7dfV-G3jk0` zz00!fJu`1sx!3XK!QSRm0H1B=zW_XuQWkE2Qp(d>9|CxUtDU|y#{7t)=x}0WD~;U} zBclCkG5`p}@REr3$}j-CLWq4hz<--DW~P4K4x0cr>= + + + + + + image/svg+xml + + + + + + + + + diff --git a/resources/images/gear-large-grey.png b/resources/images/gear-large-grey.png new file mode 100644 index 0000000000000000000000000000000000000000..0ffcf781eea08f7fbffe41a178ab46d41c632004 GIT binary patch literal 877 zcmV-z1CsoSP)P000>X1^@s6#OZ}&00004b3#c}2nYxW zd|Q(F**ze#FQh+2_UaiLV*s4GEn@ldI|LRAXM zX}b`OJ}mA;5LCpCtA|M4_9=~Ei`?6kSQT7|1a+l|t`uBo)rv@hC15V^)#l!DVPfyS z$$ia3@ZX*P%*;P$X3jbA8z8M3PEJm4bY1rjuoZX(^crKPTk(yxDpIXhGc^H#ts;_X z)weB76bgm5VzJm8kH_DqQmGdJwrwvHkxi=VH{G1gW|w9%nSTLtx!iWwbvJZ&cHZso z?ymX`1LZ0d3T>rQ={C>%ZpSZAtEP3Tu-S~+7IOGM4%_NjFex4#$vG7_ZM&?a17NoVdp^OZQEW36bUx@nd3OS z>r)hlZQCQjaUWFyI*l>^1Vm~V?J&><913N&x4*ytQ8NL6d_LbXKR-VcO6&$O4O}<~yp|$CH?l{gL zQPX8v)>RSt(??Yt$4UC_8%kkW)^L-j;*smRhX)4--_?n+v9T5H?d_KcjxQoIoKB}t z`MHM6SbJK+*b|S(U)#3*74S! + + + + + image/svg+xml + + + + + + + + + + + diff --git a/resources/images/languages-grey.png b/resources/images/languages-grey.png new file mode 100644 index 0000000000000000000000000000000000000000..3c02c75fe5301a6234bc9e2a61ee7e24ad86b5de GIT binary patch literal 789 zcmV+w1M2*VP)K|!rrv`}0GK}~PwJtKk~+Q=;Wvneu=fefu6qGCjdCaIivz80zI zX!(ceTV2j~@9&&@4hQ%jN~KckQmItcV%|z=Ael^-*|yy;B1-{OJC2iI2+))UqS5Fn z5vc^QLPQQPw8Ck?Y&L6?Oo&Jh07%A5{cJXC&l{M}=Z^s>18|1qPXL>I-`_pO-#0uw z-0ykbsy_isv$?8z*LB_AAP63j+zy}>Ko0;IV@6eV%yr$5B2sNx)=m+5*xcOwY637h zlpqM2NZuEb8vuq#ZUN9la>N*uAUP@`O#t?i{30T@s%BO7dLof{KchmDZ2(S5#CCHZ(L8rwt_b_xs0lD<2WNzfw5RDEh2p+UjR6&sz*rX z!Z5r8pvQ5X7RPbwNxrcx>*lnf{7v26-R&fs0X$XJZ^oD%s(Q7xwKW3(nM`I$p-_0M zs`WEArBuG}?^4w^l1>p6iUQeli4N~hCXMdUQe0?7>%epgr5GLo0WFuVrL+?3gLuUIU0ipU25 zCrDOVmQ_C9j*TL61wbZ|NZbPEIh0a)o>y;-ISycqWT)%8&lba(6v;VT_0RMR_h&Q6 TX`5*700000NkvXXu0mjfxoJ-< literal 0 HcmV?d00001 diff --git a/resources/images/languages-grey.svg b/resources/images/languages-grey.svg new file mode 100644 index 0000000..38cfd12 --- /dev/null +++ b/resources/images/languages-grey.svg @@ -0,0 +1,39 @@ + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/resources/images/menu-large-grey.png b/resources/images/menu-large-grey.png new file mode 100644 index 0000000000000000000000000000000000000000..91e3353100ed69d8063cd6584b3bda0b2202d941 GIT binary patch literal 231 zcmeAS@N?(olHy`uVBq!ia0vp^k|4~%1|*NXY)uAIEX7WqAsj$Z!;#Vf2?p zUk71ECym(^ARQ&H5hcO-X(i=}MX3zs<>h*rdD+Fui3O>8`9>b(^AlR_T$%-9CyFt=lz3e7Z>Htc + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/resources/images/page-grey.png b/resources/images/page-grey.png new file mode 100644 index 0000000000000000000000000000000000000000..b9895af88a73e61740dff9733dfb9fcb9ee8bb75 GIT binary patch literal 251 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE-VOR^eP*AeOHKHUqKdq!Zu_%?Hyu4g5GcUV1Ik6yBFTW^#_B$IXprQ&-7sn8b z-nUZ@@-`?4u<$3Deqnz4;?}vq#q;ES0|Xr_C%pKlFgsB}yd$cgOZ<$^$xT5UuJx_# z)3c0qd9YVLXs+J2mve5yW`cTzG{1$&Nwk$Tkz0dGeMvm7(8A5T-G@yGywoNtyzKq literal 0 HcmV?d00001 diff --git a/resources/images/page-grey.svg b/resources/images/page-grey.svg new file mode 100644 index 0000000..d720150 --- /dev/null +++ b/resources/images/page-grey.svg @@ -0,0 +1,35 @@ + + + + + + + image/svg+xml + + + + + + + + + diff --git a/resources/images/pencil-grey.png b/resources/images/pencil-grey.png new file mode 100644 index 0000000000000000000000000000000000000000..a9b58a52782f1870bb49e207dc59f8c1b1cc238c GIT binary patch literal 469 zcmV;`0V@89P)}=U^eGun??mMerK5$OTyJ*qlKAc1^U>sdkye!}l@p@5WlYn6(dP z#A?7>r_(8>y^$HQmjC@ol4PS?F2DXLVI0Q|k0rnhup9)zqqVj$Gia@?iO4yis#*co zfiAEDJdM`Rtn8ett7;QSRCOncq8osAyFH)J=bwR9;2kK0Vb}wh%cxoPn5t@}j{)Rz zxhm|kYWIF73#a^bPvD2lEIcH1Iy4Fn=`V2nA-to$2n40O(wRQ1+ZIWfi@ zrC<$XOp6IKbY)fT0(bs<&sw{dl58S21Ul#HVHkb_A#e{Y01wW&^Ae*Lrqd<&+arD-u3xU#iYhZZxW`djk_Ac(N}Nn6jD00000 LNkvXXu0mjfA~(UD literal 0 HcmV?d00001 diff --git a/resources/images/pencil-grey.svg b/resources/images/pencil-grey.svg new file mode 100644 index 0000000..2e2eea7 --- /dev/null +++ b/resources/images/pencil-grey.svg @@ -0,0 +1,39 @@ + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/resources/images/plus-grey.png b/resources/images/plus-grey.png new file mode 100644 index 0000000000000000000000000000000000000000..99fe7f36a9d0b0b270a4b2e37ee20d80911ae3de GIT binary patch literal 329 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE-VOR^eP*AeOHKHUqKdq!Zu_%?Hyu4g5GcUV1Ik6yBFTW^#_B$IXprT`*E{-7< zy>BO-(a^bv!ntDnm{r-UW|`YU{S literal 0 HcmV?d00001 diff --git a/resources/images/plus-grey.svg b/resources/images/plus-grey.svg new file mode 100644 index 0000000..f586712 --- /dev/null +++ b/resources/images/plus-grey.svg @@ -0,0 +1,48 @@ + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/resources/images/puzzle-grey.png b/resources/images/puzzle-grey.png new file mode 100644 index 0000000000000000000000000000000000000000..707d3f1784fb71e05f99e6599749e2d14d1cdd08 GIT binary patch literal 323 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE-VOR^eP*AeOHKHUqKdq!Zu_%?Hyu4g5GcUV1Ik6yBFTW^#_B$IXprQkwE{-7< zy;p-A`I;Pf=0sJtK5&drwz;hSLG2;)1hqM}z2X<$ccg5VyW%1k;d9}{om*+MX8JYO zvw!6cE#+2VebAxN`MBbJw8iH$ + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/resources/images/star-filled.png b/resources/images/star-filled.png index b1b2318caaa241f326569a7917c292e08d7d36fc..b32f93c70ac66f03b8c07985c10fbfb046e1a5a6 100644 GIT binary patch delta 387 zcmV-}0et?E1n2{hZhvJ-L_t(IjpdZTN@GD3hrc;vA;c#T5iC?zEkv=>A|hJYCZ614 zUtz(<&LXJbW2Djy6Tug-(9+5xsEsb7q_A1o2k@S4R=H}DdsA6>%HRCXcmB*U@D&k4 zScow$7V!=hF^R}N;DF6Mugf!p5SB#b^1rvNsuz8W7wGOVQ-Am%*Wd3j#<&8kWu%o> ztF_TD=iSK7W^>egKWk=lz>ITl0~r61({aw70XJrL?Y+Nkx7!c(dOdvu#u!I{3t%B{ zq#kh%EUW6@w+>^Bi=e-C2 z0%@8?X_`i5v4q?IB;2%!Re0V>}6xY20*xPM7sxQ3bS04u;!zu({b zqlBGK=T@y&I|S~}sAK2call4YIQeb25@gQ8YP7ZLkNq&0})v@vo#Jex+qqotW8v zk(-Eg+wJ!0Wj^=XL{U^Pk#IS8HjkW6r%Qj;P(-o`kId{jun8Q_Ni!>N2-JaNAo1R> zv|6pMs=ny;daEL$Gvj*Rmv-eXhY%J;WOFbWbdw}G&n7!9gitZFry}xJRli*m>OaLV Xw*`M{rnKa800000NkvXXu0mjfYDmp2 diff --git a/resources/images/star.png b/resources/images/star.png index d27efa9926127100dad4bc335b3f96c93ac130d4..99339ceab89c6743d50d4b64b8bce79dc42ad376 100644 GIT binary patch delta 551 zcmV+?0@(eL1&RfbZhr?!L_t(IjpdWiYZFlr$3L^XsZ>;&lfOXFLyHlimx@+UB=%CZ zNH=*|2#EiHcu}5?;IrUIZ~mLBW&O5`SPptv1r;5R{O(<7HRcbWL;f z;5*Hm`OJ6by?GD*#j@6Bs@3Y`Agni_=7Opo0M6|M%1(f_c7Ggr35cpr6$*tX{di}9 z?rz70MPyM``!>;6&{}&6xB|3*Z@`4L_Hw_RE!E29@*&4@G9q#U$N*EoQ4v`LzN+e7 zU=?@_EUD^i5qXo(=Rb;w{t>j+4g*ht(+NeJolfUiI-UN}YPIUXkpyNLIBSeqcL0nr zKY<+ZE&@VeUVlU`dY(5{EEYGWr>EPUPG?+I&#UT9pdGPa9LJe4#;n7pJ2b|8c3t-Z z@ILZi8X6jUK07} zpGu|XfIZ!AcTq&@stRy8DK}A2RYyexVAAuv530Hwz;)g0s=6FANx6v+TSQ{`I4}%6 z1nx)t$%q*nSP+N>9|04_n5)K^Yhf5>BH>@aXwo;_=BU+bUZc@?5QgEMAP8P0RjX7g pqmJXuyCAMR=llNZUz++~)^D1VuO*%4X{!JL002ovPDHLkV1k5d1>XPw delta 558 zcmV+}0@3}71(5}iZhsC*L_t(Ijm?zLYEw}V#(&>!+9KS|#azUdAhdzDJ0G9~1R)D6 zCAnCINVtJNkw&szsh1J8ZmpX(N>N0cav_I%%u zfM-D1>2&V)v-3Rfj&t^6XJ_Y9zv72fE))v8lJ2?fM}L5|wY5yOS{((D^ug6_Woc>Y z+o6E{2hMWt(Pok)r8G?&K@e=lalCA1TaM}Epoar{xzp)PNJ7%GnT>Z{-3Io$gC2{a zr2XjQz&lCTfUCd;zm&zy20A=y+DroPCEdzqvn%@pA&%p^q|0V@6PPeF^?$2Fz3jT? wO0(I#zbF5<24F_aY(dhKD2hHGLFzxXpV_;+EQA?FNdN!<07*qoM6N<$f?3`V@&Et; diff --git a/resources/images/star.svg b/resources/images/star.svg index c8f519e..fa9642b 100644 --- a/resources/images/star.svg +++ b/resources/images/star.svg @@ -1,6 +1,60 @@ - - - - + + + + + image/svg+xml + + + + + + + + + diff --git a/resources/images/talk-grey.png b/resources/images/talk-grey.png new file mode 100644 index 0000000000000000000000000000000000000000..c11e310561efc2f32cba6dee5ea53e36eeb054fc GIT binary patch literal 724 zcmV;_0xSKAP)f#;||ineZ*b}(lb zvZRC6rJ$fX86C8Poq`T+N?j7&(L-QR5Llh+P#Jj;v}1=X=pfa$?E1eQ`mJ@_MLh(4 zmznwIn`hp6X9oWFu+*tcmWN}Tvk&%&xAP6o4DPU9C^f%yP z7={Dsbo$MTK=1uwU>K-fL3{{YbbIyP*X4Vb7jTn8| zY__|q!m+WjJCb^UIiS@!_qkGCCX-3j)zysv9l)$}ZpSj9_rAu=(!g0sjX=)KrhwOy zhMaR>%Awh8Hfd&)(a~$HWa5ySWq{39y!tAs&p9_>W{Ly^lI}+$-aF@-EIQ&|Ns~Yv z$O8|6X*2r)Y?pKl*a%=|R|JOf&nV5PwMNcR3J z{s9~)>F0rjq{q&=7o|n<2s9|^x}*!<`)!hLB@&5uK@jBf`FyjPos@JYTJs2a3JkZQ8Rl|EEebU`TPR#O44~?9WY%i7Ed|nZb)hm!*Ijs=xB2(@VB{= z%zJ;t%zF9dX{qtEW_DB3J?C7m6d=i#o)J{|DdXegyTdSi85N%{6bjj{uC9f@Ev+2! z^2FleVw0I6X*iWi4Xzec5$L_IHM2dEj?c`@jII^-PvR$sAN`_B`MYxf0000 + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/resources/images/user-large-grey.png b/resources/images/user-large-grey.png new file mode 100644 index 0000000000000000000000000000000000000000..edc30fb93f95095045de00cbcac2c28d344bd7d9 GIT binary patch literal 715 zcmV;+0yO=JP)P000>X1^@s6#OZ}&00004b3#c}2nYxW zd8sFq9+o zu3`(t$w5I>#Gy{op@W-H5Gf8~+FTZmP_%{MA|g8I5ESvxpom_FsBpnx-p?g1xsYCt znEKn^`~BYU^B(u^!G8!9rKnUY#n;!@XGG)-Fw&TQ1uO!0Y}>B?6H+V|cUG&_2f(o{ zO4j=O`^PhxjK5V6-3jr1e<1__Nc+BjGptAGNeYF+pfTocr#iqGV}>RtC*QYAhMvS2 zla2rY=vXY4-ZB}sQYp1N0sw%B?CA-^*sRUt4Qk*PTlylXDwCXaLFQ^Q%BwDRp^bV&X=pQ??7&b!SE7IxuJ3 z_G|!IT3Q;_T0d_L1(;8zQrE`D#{NWUUMiL1p6AU27aLQ*5{bkC%d#q)-$ZMDx@nC9 zu6myL%yr$cCk24z<>lj^=e=wK0Cv@CwUYqxrpY61)*lv;wR}GR1}KWi3#HVzMsA;o zj4Guvz)(9}DK!qydSGDSP&S+W(1XoJkG~k3!u=PvtwR6+002ovPDHLkV1n} + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/resources/images/user.png b/resources/images/user.png deleted file mode 100644 index ff9858a63e091640303ef9620c6ea8f8a33a22b8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 704 zcmV;x0zdtUP)@3AC>g2{!e1hF83ZbFAbY)yE^*Lz&jXp=Na z`%mYdd(U_8f6gV0Q7Vl&3b48zK1v$~=vLwky%Ad|_= z1cSk)se!Rr?7FV&$2!n;9kE#K#?-(-Ai&4cdI|=EBhQQkhC-pYlYpU6=*^@veKGTS z$8q+DCh~7EznFP;BFHq&%K)ecy)C8uGYISD%w7ozA?E&P^erco$+PqG^RF$-$^!rq zy&$3m051Ww0Q>~7MMPJLs0;v>W##>T|0^Lx|2wFMfngZ;S65drR;$%@DWyR~4~Xak zfLnu3gb*`C^wc!Xd(mi=*4Eb207^Kt2LR=A`Rn51;w1p6R4OQyN9y?W`4}f=T7TvD*XkrYm|R{l~hLn0000 - - - - - image/svg+xml - - - - - - - - - - - - - - diff --git a/resources/libraries/jquery.mobile.custom.js b/resources/libraries/jquery.mobile.custom.js new file mode 100644 index 0000000..376d183 --- /dev/null +++ b/resources/libraries/jquery.mobile.custom.js @@ -0,0 +1,864 @@ +/* +* jQuery Mobile v1.4.5 +* http://jquerymobile.com +* +* Copyright 2010, 2014 jQuery Foundation, Inc. and other contributors +* Released under the MIT license. +* http://jquery.org/license +* +*/ + +(function ( root, doc, factory ) { + if ( typeof define === "function" && define.amd ) { + // AMD. Register as an anonymous module. + define( [ "jquery" ], function ( $ ) { + factory( $, root, doc ); + return $.mobile; + }); + } else { + // Browser globals + factory( root.jQuery, root, doc ); + } +}( this, document, function ( jQuery, window, document, undefined ) {// This plugin is an experiment for abstracting away the touch and mouse +// events so that developers don't have to worry about which method of input +// the device their document is loaded on supports. +// +// The idea here is to allow the developer to register listeners for the +// basic mouse events, such as mousedown, mousemove, mouseup, and click, +// and the plugin will take care of registering the correct listeners +// behind the scenes to invoke the listener at the fastest possible time +// for that device, while still retaining the order of event firing in +// the traditional mouse environment, should multiple handlers be registered +// on the same element for different events. +// +// The current version exposes the following virtual events to jQuery bind methods: +// "vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel" + +(function( $, window, document, undefined ) { + +var dataPropertyName = "virtualMouseBindings", + touchTargetPropertyName = "virtualTouchID", + virtualEventNames = "vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel".split( " " ), + touchEventProps = "clientX clientY pageX pageY screenX screenY".split( " " ), + mouseHookProps = $.event.mouseHooks ? $.event.mouseHooks.props : [], + mouseEventProps = $.event.props.concat( mouseHookProps ), + activeDocHandlers = {}, + resetTimerID = 0, + startX = 0, + startY = 0, + didScroll = false, + clickBlockList = [], + blockMouseTriggers = false, + blockTouchTriggers = false, + eventCaptureSupported = "addEventListener" in document, + $document = $( document ), + nextTouchID = 1, + lastTouchID = 0, threshold, + i; + +$.vmouse = { + moveDistanceThreshold: 10, + clickDistanceThreshold: 10, + resetTimerDuration: 1500 +}; + +function getNativeEvent( event ) { + + while ( event && typeof event.originalEvent !== "undefined" ) { + event = event.originalEvent; + } + return event; +} + +function createVirtualEvent( event, eventType ) { + + var t = event.type, + oe, props, ne, prop, ct, touch, i, j, len; + + event = $.Event( event ); + event.type = eventType; + + oe = event.originalEvent; + props = $.event.props; + + // addresses separation of $.event.props in to $.event.mouseHook.props and Issue 3280 + // https://github.com/jquery/jquery-mobile/issues/3280 + if ( t.search( /^(mouse|click)/ ) > -1 ) { + props = mouseEventProps; + } + + // copy original event properties over to the new event + // this would happen if we could call $.event.fix instead of $.Event + // but we don't have a way to force an event to be fixed multiple times + if ( oe ) { + for ( i = props.length, prop; i; ) { + prop = props[ --i ]; + event[ prop ] = oe[ prop ]; + } + } + + // make sure that if the mouse and click virtual events are generated + // without a .which one is defined + if ( t.search(/mouse(down|up)|click/) > -1 && !event.which ) { + event.which = 1; + } + + if ( t.search(/^touch/) !== -1 ) { + ne = getNativeEvent( oe ); + t = ne.touches; + ct = ne.changedTouches; + touch = ( t && t.length ) ? t[0] : ( ( ct && ct.length ) ? ct[ 0 ] : undefined ); + + if ( touch ) { + for ( j = 0, len = touchEventProps.length; j < len; j++) { + prop = touchEventProps[ j ]; + event[ prop ] = touch[ prop ]; + } + } + } + + return event; +} + +function getVirtualBindingFlags( element ) { + + var flags = {}, + b, k; + + while ( element ) { + + b = $.data( element, dataPropertyName ); + + for ( k in b ) { + if ( b[ k ] ) { + flags[ k ] = flags.hasVirtualBinding = true; + } + } + element = element.parentNode; + } + return flags; +} + +function getClosestElementWithVirtualBinding( element, eventType ) { + var b; + while ( element ) { + + b = $.data( element, dataPropertyName ); + + if ( b && ( !eventType || b[ eventType ] ) ) { + return element; + } + element = element.parentNode; + } + return null; +} + +function enableTouchBindings() { + blockTouchTriggers = false; +} + +function disableTouchBindings() { + blockTouchTriggers = true; +} + +function enableMouseBindings() { + lastTouchID = 0; + clickBlockList.length = 0; + blockMouseTriggers = false; + + // When mouse bindings are enabled, our + // touch bindings are disabled. + disableTouchBindings(); +} + +function disableMouseBindings() { + // When mouse bindings are disabled, our + // touch bindings are enabled. + enableTouchBindings(); +} + +function startResetTimer() { + clearResetTimer(); + resetTimerID = setTimeout( function() { + resetTimerID = 0; + enableMouseBindings(); + }, $.vmouse.resetTimerDuration ); +} + +function clearResetTimer() { + if ( resetTimerID ) { + clearTimeout( resetTimerID ); + resetTimerID = 0; + } +} + +function triggerVirtualEvent( eventType, event, flags ) { + var ve; + + if ( ( flags && flags[ eventType ] ) || + ( !flags && getClosestElementWithVirtualBinding( event.target, eventType ) ) ) { + + ve = createVirtualEvent( event, eventType ); + + $( event.target).trigger( ve ); + } + + return ve; +} + +function mouseEventCallback( event ) { + var touchID = $.data( event.target, touchTargetPropertyName ), + ve; + + if ( !blockMouseTriggers && ( !lastTouchID || lastTouchID !== touchID ) ) { + ve = triggerVirtualEvent( "v" + event.type, event ); + if ( ve ) { + if ( ve.isDefaultPrevented() ) { + event.preventDefault(); + } + if ( ve.isPropagationStopped() ) { + event.stopPropagation(); + } + if ( ve.isImmediatePropagationStopped() ) { + event.stopImmediatePropagation(); + } + } + } +} + +function handleTouchStart( event ) { + + var touches = getNativeEvent( event ).touches, + target, flags, t; + + if ( touches && touches.length === 1 ) { + + target = event.target; + flags = getVirtualBindingFlags( target ); + + if ( flags.hasVirtualBinding ) { + + lastTouchID = nextTouchID++; + $.data( target, touchTargetPropertyName, lastTouchID ); + + clearResetTimer(); + + disableMouseBindings(); + didScroll = false; + + t = getNativeEvent( event ).touches[ 0 ]; + startX = t.pageX; + startY = t.pageY; + + triggerVirtualEvent( "vmouseover", event, flags ); + triggerVirtualEvent( "vmousedown", event, flags ); + } + } +} + +function handleScroll( event ) { + if ( blockTouchTriggers ) { + return; + } + + if ( !didScroll ) { + triggerVirtualEvent( "vmousecancel", event, getVirtualBindingFlags( event.target ) ); + } + + didScroll = true; + startResetTimer(); +} + +function handleTouchMove( event ) { + if ( blockTouchTriggers ) { + return; + } + + var t = getNativeEvent( event ).touches[ 0 ], + didCancel = didScroll, + moveThreshold = $.vmouse.moveDistanceThreshold, + flags = getVirtualBindingFlags( event.target ); + + didScroll = didScroll || + ( Math.abs( t.pageX - startX ) > moveThreshold || + Math.abs( t.pageY - startY ) > moveThreshold ); + + if ( didScroll && !didCancel ) { + triggerVirtualEvent( "vmousecancel", event, flags ); + } + + triggerVirtualEvent( "vmousemove", event, flags ); + startResetTimer(); +} + +function handleTouchEnd( event ) { + if ( blockTouchTriggers ) { + return; + } + + disableTouchBindings(); + + var flags = getVirtualBindingFlags( event.target ), + ve, t; + triggerVirtualEvent( "vmouseup", event, flags ); + + if ( !didScroll ) { + ve = triggerVirtualEvent( "vclick", event, flags ); + if ( ve && ve.isDefaultPrevented() ) { + // The target of the mouse events that follow the touchend + // event don't necessarily match the target used during the + // touch. This means we need to rely on coordinates for blocking + // any click that is generated. + t = getNativeEvent( event ).changedTouches[ 0 ]; + clickBlockList.push({ + touchID: lastTouchID, + x: t.clientX, + y: t.clientY + }); + + // Prevent any mouse events that follow from triggering + // virtual event notifications. + blockMouseTriggers = true; + } + } + triggerVirtualEvent( "vmouseout", event, flags); + didScroll = false; + + startResetTimer(); +} + +function hasVirtualBindings( ele ) { + var bindings = $.data( ele, dataPropertyName ), + k; + + if ( bindings ) { + for ( k in bindings ) { + if ( bindings[ k ] ) { + return true; + } + } + } + return false; +} + +function dummyMouseHandler() {} + +function getSpecialEventObject( eventType ) { + var realType = eventType.substr( 1 ); + + return { + setup: function(/* data, namespace */) { + // If this is the first virtual mouse binding for this element, + // add a bindings object to its data. + + if ( !hasVirtualBindings( this ) ) { + $.data( this, dataPropertyName, {} ); + } + + // If setup is called, we know it is the first binding for this + // eventType, so initialize the count for the eventType to zero. + var bindings = $.data( this, dataPropertyName ); + bindings[ eventType ] = true; + + // If this is the first virtual mouse event for this type, + // register a global handler on the document. + + activeDocHandlers[ eventType ] = ( activeDocHandlers[ eventType ] || 0 ) + 1; + + if ( activeDocHandlers[ eventType ] === 1 ) { + $document.bind( realType, mouseEventCallback ); + } + + // Some browsers, like Opera Mini, won't dispatch mouse/click events + // for elements unless they actually have handlers registered on them. + // To get around this, we register dummy handlers on the elements. + + $( this ).bind( realType, dummyMouseHandler ); + + // For now, if event capture is not supported, we rely on mouse handlers. + if ( eventCaptureSupported ) { + // If this is the first virtual mouse binding for the document, + // register our touchstart handler on the document. + + activeDocHandlers[ "touchstart" ] = ( activeDocHandlers[ "touchstart" ] || 0) + 1; + + if ( activeDocHandlers[ "touchstart" ] === 1 ) { + $document.bind( "touchstart", handleTouchStart ) + .bind( "touchend", handleTouchEnd ) + + // On touch platforms, touching the screen and then dragging your finger + // causes the window content to scroll after some distance threshold is + // exceeded. On these platforms, a scroll prevents a click event from being + // dispatched, and on some platforms, even the touchend is suppressed. To + // mimic the suppression of the click event, we need to watch for a scroll + // event. Unfortunately, some platforms like iOS don't dispatch scroll + // events until *AFTER* the user lifts their finger (touchend). This means + // we need to watch both scroll and touchmove events to figure out whether + // or not a scroll happenens before the touchend event is fired. + + .bind( "touchmove", handleTouchMove ) + .bind( "scroll", handleScroll ); + } + } + }, + + teardown: function(/* data, namespace */) { + // If this is the last virtual binding for this eventType, + // remove its global handler from the document. + + --activeDocHandlers[ eventType ]; + + if ( !activeDocHandlers[ eventType ] ) { + $document.unbind( realType, mouseEventCallback ); + } + + if ( eventCaptureSupported ) { + // If this is the last virtual mouse binding in existence, + // remove our document touchstart listener. + + --activeDocHandlers[ "touchstart" ]; + + if ( !activeDocHandlers[ "touchstart" ] ) { + $document.unbind( "touchstart", handleTouchStart ) + .unbind( "touchmove", handleTouchMove ) + .unbind( "touchend", handleTouchEnd ) + .unbind( "scroll", handleScroll ); + } + } + + var $this = $( this ), + bindings = $.data( this, dataPropertyName ); + + // teardown may be called when an element was + // removed from the DOM. If this is the case, + // jQuery core may have already stripped the element + // of any data bindings so we need to check it before + // using it. + if ( bindings ) { + bindings[ eventType ] = false; + } + + // Unregister the dummy event handler. + + $this.unbind( realType, dummyMouseHandler ); + + // If this is the last virtual mouse binding on the + // element, remove the binding data from the element. + + if ( !hasVirtualBindings( this ) ) { + $this.removeData( dataPropertyName ); + } + } + }; +} + +// Expose our custom events to the jQuery bind/unbind mechanism. + +for ( i = 0; i < virtualEventNames.length; i++ ) { + $.event.special[ virtualEventNames[ i ] ] = getSpecialEventObject( virtualEventNames[ i ] ); +} + +// Add a capture click handler to block clicks. +// Note that we require event capture support for this so if the device +// doesn't support it, we punt for now and rely solely on mouse events. +if ( eventCaptureSupported ) { + document.addEventListener( "click", function( e ) { + var cnt = clickBlockList.length, + target = e.target, + x, y, ele, i, o, touchID; + + if ( cnt ) { + x = e.clientX; + y = e.clientY; + threshold = $.vmouse.clickDistanceThreshold; + + // The idea here is to run through the clickBlockList to see if + // the current click event is in the proximity of one of our + // vclick events that had preventDefault() called on it. If we find + // one, then we block the click. + // + // Why do we have to rely on proximity? + // + // Because the target of the touch event that triggered the vclick + // can be different from the target of the click event synthesized + // by the browser. The target of a mouse/click event that is synthesized + // from a touch event seems to be implementation specific. For example, + // some browsers will fire mouse/click events for a link that is near + // a touch event, even though the target of the touchstart/touchend event + // says the user touched outside the link. Also, it seems that with most + // browsers, the target of the mouse/click event is not calculated until the + // time it is dispatched, so if you replace an element that you touched + // with another element, the target of the mouse/click will be the new + // element underneath that point. + // + // Aside from proximity, we also check to see if the target and any + // of its ancestors were the ones that blocked a click. This is necessary + // because of the strange mouse/click target calculation done in the + // Android 2.1 browser, where if you click on an element, and there is a + // mouse/click handler on one of its ancestors, the target will be the + // innermost child of the touched element, even if that child is no where + // near the point of touch. + + ele = target; + + while ( ele ) { + for ( i = 0; i < cnt; i++ ) { + o = clickBlockList[ i ]; + touchID = 0; + + if ( ( ele === target && Math.abs( o.x - x ) < threshold && Math.abs( o.y - y ) < threshold ) || + $.data( ele, touchTargetPropertyName ) === o.touchID ) { + // XXX: We may want to consider removing matches from the block list + // instead of waiting for the reset timer to fire. + e.preventDefault(); + e.stopPropagation(); + return; + } + } + ele = ele.parentNode; + } + } + }, true); +} +})( jQuery, window, document ); + +(function( $ ) { + $.mobile = {}; +}( jQuery )); + + (function( $, undefined ) { + var support = { + touch: "ontouchend" in document + }; + + $.mobile.support = $.mobile.support || {}; + $.extend( $.support, support ); + $.extend( $.mobile.support, support ); + }( jQuery )); + + +(function( $, window, undefined ) { + var $document = $( document ), + supportTouch = $.mobile.support.touch, + scrollEvent = "touchmove scroll", + touchStartEvent = supportTouch ? "touchstart" : "mousedown", + touchStopEvent = supportTouch ? "touchend" : "mouseup", + touchMoveEvent = supportTouch ? "touchmove" : "mousemove"; + + // setup new event shortcuts + $.each( ( "touchstart touchmove touchend " + + "tap taphold " + + "swipe swipeleft swiperight " + + "scrollstart scrollstop" ).split( " " ), function( i, name ) { + + $.fn[ name ] = function( fn ) { + return fn ? this.bind( name, fn ) : this.trigger( name ); + }; + + // jQuery < 1.8 + if ( $.attrFn ) { + $.attrFn[ name ] = true; + } + }); + + function triggerCustomEvent( obj, eventType, event, bubble ) { + var originalType = event.type; + event.type = eventType; + if ( bubble ) { + $.event.trigger( event, undefined, obj ); + } else { + $.event.dispatch.call( obj, event ); + } + event.type = originalType; + } + + // also handles scrollstop + $.event.special.scrollstart = { + + enabled: true, + setup: function() { + + var thisObject = this, + $this = $( thisObject ), + scrolling, + timer; + + function trigger( event, state ) { + scrolling = state; + triggerCustomEvent( thisObject, scrolling ? "scrollstart" : "scrollstop", event ); + } + + // iPhone triggers scroll after a small delay; use touchmove instead + $this.bind( scrollEvent, function( event ) { + + if ( !$.event.special.scrollstart.enabled ) { + return; + } + + if ( !scrolling ) { + trigger( event, true ); + } + + clearTimeout( timer ); + timer = setTimeout( function() { + trigger( event, false ); + }, 50 ); + }); + }, + teardown: function() { + $( this ).unbind( scrollEvent ); + } + }; + + // also handles taphold + $.event.special.tap = { + tapholdThreshold: 750, + emitTapOnTaphold: true, + setup: function() { + var thisObject = this, + $this = $( thisObject ), + isTaphold = false; + + $this.bind( "vmousedown", function( event ) { + isTaphold = false; + if ( event.which && event.which !== 1 ) { + return false; + } + + var origTarget = event.target, + timer; + + function clearTapTimer() { + clearTimeout( timer ); + } + + function clearTapHandlers() { + clearTapTimer(); + + $this.unbind( "vclick", clickHandler ) + .unbind( "vmouseup", clearTapTimer ); + $document.unbind( "vmousecancel", clearTapHandlers ); + } + + function clickHandler( event ) { + clearTapHandlers(); + + // ONLY trigger a 'tap' event if the start target is + // the same as the stop target. + if ( !isTaphold && origTarget === event.target ) { + triggerCustomEvent( thisObject, "tap", event ); + } else if ( isTaphold ) { + event.preventDefault(); + } + } + + $this.bind( "vmouseup", clearTapTimer ) + .bind( "vclick", clickHandler ); + $document.bind( "vmousecancel", clearTapHandlers ); + + timer = setTimeout( function() { + if ( !$.event.special.tap.emitTapOnTaphold ) { + isTaphold = true; + } + triggerCustomEvent( thisObject, "taphold", $.Event( "taphold", { target: origTarget } ) ); + }, $.event.special.tap.tapholdThreshold ); + }); + }, + teardown: function() { + $( this ).unbind( "vmousedown" ).unbind( "vclick" ).unbind( "vmouseup" ); + $document.unbind( "vmousecancel" ); + } + }; + + // Also handles swipeleft, swiperight + $.event.special.swipe = { + + // More than this horizontal displacement, and we will suppress scrolling. + scrollSupressionThreshold: 30, + + // More time than this, and it isn't a swipe. + durationThreshold: 1000, + + // Swipe horizontal displacement must be more than this. + horizontalDistanceThreshold: 30, + + // Swipe vertical displacement must be less than this. + verticalDistanceThreshold: 30, + + getLocation: function ( event ) { + var winPageX = window.pageXOffset, + winPageY = window.pageYOffset, + x = event.clientX, + y = event.clientY; + + if ( event.pageY === 0 && Math.floor( y ) > Math.floor( event.pageY ) || + event.pageX === 0 && Math.floor( x ) > Math.floor( event.pageX ) ) { + + // iOS4 clientX/clientY have the value that should have been + // in pageX/pageY. While pageX/page/ have the value 0 + x = x - winPageX; + y = y - winPageY; + } else if ( y < ( event.pageY - winPageY) || x < ( event.pageX - winPageX ) ) { + + // Some Android browsers have totally bogus values for clientX/Y + // when scrolling/zooming a page. Detectable since clientX/clientY + // should never be smaller than pageX/pageY minus page scroll + x = event.pageX - winPageX; + y = event.pageY - winPageY; + } + + return { + x: x, + y: y + }; + }, + + start: function( event ) { + var data = event.originalEvent.touches ? + event.originalEvent.touches[ 0 ] : event, + location = $.event.special.swipe.getLocation( data ); + return { + time: ( new Date() ).getTime(), + coords: [ location.x, location.y ], + origin: $( event.target ) + }; + }, + + stop: function( event ) { + var data = event.originalEvent.touches ? + event.originalEvent.touches[ 0 ] : event, + location = $.event.special.swipe.getLocation( data ); + return { + time: ( new Date() ).getTime(), + coords: [ location.x, location.y ] + }; + }, + + handleSwipe: function( start, stop, thisObject, origTarget ) { + if ( stop.time - start.time < $.event.special.swipe.durationThreshold && + Math.abs( start.coords[ 0 ] - stop.coords[ 0 ] ) > $.event.special.swipe.horizontalDistanceThreshold && + Math.abs( start.coords[ 1 ] - stop.coords[ 1 ] ) < $.event.special.swipe.verticalDistanceThreshold ) { + var direction = start.coords[0] > stop.coords[ 0 ] ? "swipeleft" : "swiperight"; + + triggerCustomEvent( thisObject, "swipe", $.Event( "swipe", { target: origTarget, swipestart: start, swipestop: stop }), true ); + triggerCustomEvent( thisObject, direction,$.Event( direction, { target: origTarget, swipestart: start, swipestop: stop } ), true ); + return true; + } + return false; + + }, + + // This serves as a flag to ensure that at most one swipe event event is + // in work at any given time + eventInProgress: false, + + setup: function() { + var events, + thisObject = this, + $this = $( thisObject ), + context = {}; + + // Retrieve the events data for this element and add the swipe context + events = $.data( this, "mobile-events" ); + if ( !events ) { + events = { length: 0 }; + $.data( this, "mobile-events", events ); + } + events.length++; + events.swipe = context; + + context.start = function( event ) { + + // Bail if we're already working on a swipe event + if ( $.event.special.swipe.eventInProgress ) { + return; + } + $.event.special.swipe.eventInProgress = true; + + var stop, + start = $.event.special.swipe.start( event ), + origTarget = event.target, + emitted = false; + + context.move = function( event ) { + if ( !start || event.isDefaultPrevented() ) { + return; + } + + stop = $.event.special.swipe.stop( event ); + if ( !emitted ) { + emitted = $.event.special.swipe.handleSwipe( start, stop, thisObject, origTarget ); + if ( emitted ) { + + // Reset the context to make way for the next swipe event + $.event.special.swipe.eventInProgress = false; + } + } + // prevent scrolling + if ( Math.abs( start.coords[ 0 ] - stop.coords[ 0 ] ) > $.event.special.swipe.scrollSupressionThreshold ) { + event.preventDefault(); + } + }; + + context.stop = function() { + emitted = true; + + // Reset the context to make way for the next swipe event + $.event.special.swipe.eventInProgress = false; + $document.off( touchMoveEvent, context.move ); + context.move = null; + }; + + $document.on( touchMoveEvent, context.move ) + .one( touchStopEvent, context.stop ); + }; + $this.on( touchStartEvent, context.start ); + }, + + teardown: function() { + var events, context; + + events = $.data( this, "mobile-events" ); + if ( events ) { + context = events.swipe; + delete events.swipe; + events.length--; + if ( events.length === 0 ) { + $.removeData( this, "mobile-events" ); + } + } + + if ( context ) { + if ( context.start ) { + $( this ).off( touchStartEvent, context.start ); + } + if ( context.move ) { + $document.off( touchMoveEvent, context.move ); + } + if ( context.stop ) { + $document.off( touchStopEvent, context.stop ); + } + } + } + }; + $.each({ + scrollstop: "scrollstart", + taphold: "tap", + swipeleft: "swipe.left", + swiperight: "swipe.right" + }, function( event, sourceEvent ) { + + $.event.special[ event ] = { + setup: function() { + $( this ).bind( sourceEvent, $.noop ); + }, + teardown: function() { + $( this ).unbind( sourceEvent ); + } + }; + }); + +})( jQuery, this ); + + +})); diff --git a/resources/mobile.js b/resources/mobile.js new file mode 100644 index 0000000..b90ca19 --- /dev/null +++ b/resources/mobile.js @@ -0,0 +1,53 @@ +/* Popout menus (header) */ + +$( function() { + var toggleTime = 200; + + // Open the various menus + $( '#user-tools h2' ).on( 'click', function( e ) { + if ( $( window ).width() < 851 ) { + $( '#p-personal-inner, #menus-cover' ).fadeToggle( toggleTime ); + } + } ); + $( '#site-navigation h2' ).on( 'click', function( e ) { + if ( $( window ).width() < 851 ) { + $( '#site-navigation .sidebar-inner, #menus-cover' ).fadeToggle( toggleTime ); + } + } ); + $( '#site-tools h2' ).on( 'click', function( e ) { + if ( $( window ).width() < 851 ) { + $( '#site-tools .sidebar-inner, #menus-cover' ).fadeToggle( toggleTime ); + } + } ); + $( '#ca-more' ).on( 'click', function( e ) { + $( '#page-tools .sidebar-inner' ).css( "top", $( '#ca-more' ).offset().top + 25 ); + if ( $( window ).width() < 851 ) { + $( '#page-tools .sidebar-inner, #menus-cover' ).fadeToggle( toggleTime ); + } + } ); + $( '#ca-languages' ).on( 'click', function( e ) { + $( '#other-languages .sidebar-inner' ).css( "top", $( '#ca-languages' ).offset().top + 25 ); + if ( $( window ).width() < 851 ) { + $( '#other-languages .sidebar-inner, #menus-cover' ).fadeToggle( toggleTime ); + } + } ); + + // Close menus on click outside + $( document ).click( function( e ) { + if ( $( e.target ).closest( '#menus-cover' ).length > 0 ) { + $( '#p-personal-inner' ).fadeOut( toggleTime ); + $( '.sidebar-inner' ).fadeOut( toggleTime ); + $( '#menus-cover' ).fadeOut( toggleTime ); + } + } ); + + // Include alternative closing method for ios + $( window ).on( 'swiperight', function( e ) { + if ( $( window ).width() < 851 ) { + $( '#p-personal-inner' ).fadeOut( toggleTime ); + $( '.sidebar-inner' ).fadeOut( toggleTime ); + $( '#menus-cover' ).fadeOut( toggleTime ); + } + } ); +} ); + diff --git a/resources/screen-common.less b/resources/screen-common.less index 54def45..cc66e55 100644 --- a/resources/screen-common.less +++ b/resources/screen-common.less @@ -4,19 +4,27 @@ html, body { - font-family: @fonts; margin: 0; padding: 0; +} +body { + font-family: @fonts; color: @text; background: @background-dark; - font-size: .95em; line-height: 1.4; + font-size: @font-size; } + #mw-content { + .box; background: @background; + padding: 1em @content-padding 3em; + overflow: auto; + position: relative; } #mw-content-container { background: @background2; + word-wrap: break-word; } #mw-footer-container { border-top: solid 1px @background-dark2; @@ -33,17 +41,179 @@ body { #p-logo { text-align: center; + margin: auto; +} +.mw-wiki-logo { + display: block; + content: ''; width: 11em; + height: 11em; + background-repeat: no-repeat; + background-position: 50% 50%; + margin: auto; +} +#p-logo-text { + width: @column-left-size; + text-align: center; + line-height: 1; - a.mw-wiki-logo { + a { + padding: .2em 1em; + color: @text; + font-family: @fonts-secondary; + font-variant: small-caps; + font-size: 1.75em; display: block; - content: ''; - width: 11em; - height: 11em; - background-repeat: no-repeat; - background-position: 50% 50%; + + /* 13+ character names */ + &.long { + font-size: 1.45em; + padding: 0; + line-height: .8; + } + } +} + +/* Search */ + +#simpleSearch { + box-shadow: inset 0 2px 4px 0 rgba(0, 0, 0, 0.05); + background: @background; + position: relative; + border: solid 1px @grey; +} +#searchInput { + border: none; + margin: 0; + height: 2.1em; + padding: .4em 4.5em .2em 2em; + box-shadow: none; + background: transparent; + width: 100%; + min-height: 0; +} +#searchButton, +#mw-searchButton { + position: absolute; + top: 0; + right: 1.5em; + width: 2.5em; + height: 2.5em; + .icon; + .background-image-svg('images/search-ltr.svg', 'images/search-ltr.png'); + background-position: 50% 40%; + box-shadow: none; +} + +/* Dropdown stuff */ + +.pokey, +.pokey::after { + border-bottom: 10px solid @grey-bright; + border-left: 10px solid transparent; + border-right: 10px solid transparent; + content: ""; + height: 0px; + position: absolute; + transform: rotate(360deg); // to force some smoothing in annoying browsers + width: 0px; + z-index: 2; +} +.pokey { + top: 1.85em; + right: 1px; + display: none; +} +.pokey::after { + border-bottom-color: #FFFFFF; + right: -10px; + top: 2px; +} + +.dropdown-toggle { + .dropdown-header(); +} + +/* Footer */ + +#mw-footer { + padding-top: .5em; + padding-bottom: 1em; + + ul, + li { + margin: 1em 0; + list-style: none; + padding: 0; + } + #footer-icons { + float: right; + margin: 0 0 0 1em; + + li { + margin: 0 0 1em 0; + } + } +} +#footer-places li { + display: inline; + padding-right: 1em; +} + +/* Content */ + +#mw-content-container { + border-bottom: solid 4px @green; +} +#page-header-links { + div, + ul, + li { + list-style: none; + display: inline-block; + margin: 0; + padding: 0; + line-height: 1.5; + } + li { + margin: .25em 0 1.5em; + border-bottom: solid 3px @background; + + &:hover { + border-bottom-color: @grey; + } + &.selected { + border-bottom-color: @blue; + + a { + color: @text; + } + } + } +} +#p-namespaces { + float: left; + + li { + margin-right: 1em; } } +#p-pagetools { + float: right; + + li { + margin-left: 1em; + } +} + +#ca-watch a { + .ca-icon(); + .background-image-svg('images/star.svg', 'images/star.png'); +} +#ca-unwatch a { + .ca-icon(); + .background-image-svg('images/star-filled.svg', 'images/star-filled.png'); +} /* Misc */ @@ -51,6 +221,7 @@ a { text-decoration: none; color: @blue; + &:hover, &:visited { color: @blue-dark; } @@ -59,6 +230,7 @@ a.new, .new a { color: @red; + &:hover, &:visited { color: @red-dark; } @@ -66,6 +238,14 @@ a.new, .mw-editsection { font-family: @fonts; + + a { + .background-image-svg('images/pencil-grey.svg', 'images/pencil-grey.png'); + background-repeat: no-repeat; + background-position: 0 0; + display: inline-block; + padding: .5em 0 .25em 1.75em; + } } .mw-editsection-bracket { display: none; @@ -73,6 +253,10 @@ a.new, .visual-clear { clear: both; } +.mw-indicators { + float: right; + margin: .75em 0 0 1em; +} #mw-content { h1, h2, h3, h4, h5, h6, dt { font-weight: normal; @@ -218,12 +402,41 @@ table.wikitable > * > tr > th { border: none; } +/* Color bars */ + +.color-bar { + width: 100%; +} +@color-height: 4px; +.color-left { + height: @color-height; + background: @red-dark; + width: 50%; + float: left; +} +.color-right { + display: inline-block; + height: @color-height; + background: @green-dark; + width: 50%; + float: right; +} +.color-middle-container { + max-width: @content-width; + margin: 0 auto -@color-height; + position: relative; +} +.color-middle { + height: @color-height; + background: @blue-dark; + margin-left: @column-left-size + 1em; + margin-right: @column-right-size + 1em; +} /* Hidden stuff */ #p-namespaces h3, #p-pagetools h3, -#mw-site-navigation h2, #p-search h3 { .hidden; } diff --git a/resources/screen-desktop-full.less b/resources/screen-desktop-full.less new file mode 100644 index 0000000..a9c4e50 --- /dev/null +++ b/resources/screen-desktop-full.less @@ -0,0 +1,19 @@ +@import "variables.less"; + +#mw-site-navigation { + .column-left(); +} + +#mw-content { + margin-left: @column-left-size; + margin-right: @column-right-size; +} + +#mw-related-navigation { + .column-right(); +} + +// Redundant content category list +#catlinks { + display: none; +} diff --git a/resources/screen-desktop-mid.less b/resources/screen-desktop-mid.less new file mode 100644 index 0000000..9768e7f --- /dev/null +++ b/resources/screen-desktop-mid.less @@ -0,0 +1,19 @@ +@import "variables.less"; + +#mw-site-navigation, +#mw-related-navigation { + .column-left(); +} + +#mw-related-navigation { + margin-top: 2em; +} + +#mw-content { + margin-left: @column-left-size; +} + +// Redundant content category list +#catlinks { + display: none; +} diff --git a/resources/screen-desktop-small.less b/resources/screen-desktop-small.less new file mode 100644 index 0000000..5553043 --- /dev/null +++ b/resources/screen-desktop-small.less @@ -0,0 +1,127 @@ +@import "variables.less"; + +// Redundant sidebar category list and stuff + +#mw-content-block { + padding: 0; +} +#mw-content { + border-width: 0 0 1px; + clear: both; +} + +.categories-bottom(); + + +// Header navigation + +.sidebar-chunk { + display: inline-block; + position: relative; + + h2 { + display: inline-block; + } +} +.sidebar-inner, +#p-logo { + display: none !important; +} + +// Have these cover the fixed header color-bar using the mw-header-nav-hack (with its own color-bar at the bottom) +#mw-site-navigation, +#mw-related-navigation { + display: inline-block; + position: relative; + z-index: 99; + + h2 { + font-weight: normal; + font-family: @fonts-secondary; + font-size: 1.25em; + padding: .5em 0 .2em; + margin: 0; + + .dropdown-header(); + } +} +.sidebar-chunk:hover { + .pokey, + .sidebar-inner { + display: block !important; + } +} + +#mw-header-nav-hack { + border-top: solid 2px @grey-bright; + display: block; + position: absolute; + z-index: 98; + background: @background; + width: 100%; +} +#mw-header-nav-hack .color-bar { + margin-top: 2.5em; // Height of expected menu header contents +} + +#mw-site-navigation { + float: left; + margin-left: 2em; + + .sidebar-chunk { + margin: 0 1em 0 0; + } + .sidebar-inner { + .dropdown-menu( left ); + } +} +#mw-related-navigation { + float: right; + margin-right: 2em; + + .sidebar-chunk { + margin: 0 0 0 1em; + } + .sidebar-inner { + .dropdown-menu(); + top: 2.95em !important; // to override mobile positioning + } +} + +// Consistency + +#mw-header { + padding: 0 2em; +} +#p-logo-text a { + padding-left: 0; + text-align: left; +} + +#mw-footer { + padding: 0 @content-padding; +} + +// Personal menu + +#p-personal { + float: right; + + h2 span { + display: none; + } + h2:after { + margin-left: -.65em; + } + .dropdown { + right: -1em; + } + } + +#user-tools { + width: 6em; +} +#p-search { + margin-right: 6em; +} + diff --git a/resources/screen-desktop.less b/resources/screen-desktop.less index b5acdb0..8be7343 100644 --- a/resources/screen-desktop.less +++ b/resources/screen-desktop.less @@ -1,25 +1,21 @@ @import "variables.less"; +// Override menu display from mobile +// This also requires !importants where they hover and stuff +.dropdown, +.sidebar-inner { + display: block !important; +} + .ts-inner { - max-width: 100em; - padding: 0 3em; + max-width: @content-width; + padding: 0 1em; margin: auto; } -#p-logo-text, -#mw-site-navigation { - width: 12em; - float: left; -} -#p-search, -#mw-content, -#mw-header-container .color-middle { - margin-left: 12em; - margin-right: 15em; -} -#mw-related-navigation, -#user-tools { - width: 15em; - float: right; +#mw-content-container { + .background-image-svg('images/cat-grey.svg', 'images/cat-grey.png'); + background-repeat: no-repeat; + background-position: center 15em; } /* Header */ @@ -32,54 +28,63 @@ background: @background; color: @text; padding: 0.5em 0 0; + min-height: @fixed-header-height; + box-sizing: border-box; +} +#p-logo-text { + width: @column-left-size; + float: left; +} +#p-search { + margin-left: @column-left-size; + margin-right: @column-right-size; +} +#user-tools { + width: @column-right-size; + float: right; +} +#mw-header-nav-hack, +#mw-header-hack { + position: fixed; + z-index: 97; + top: @fixed-header-height; box-shadow: 0 3px 3px 2px rgba(0, 0, 0, 0.075), 0 0 2px rgba(0, 0, 0, 0.2); - min-height: 2.85em; +} +#mw-header-nav-hack { + display: none; } /* Add offset to make anchor links work with the fixed header */ :target:before { content: ""; display: block; - height: 2.85em; - margin: -2.85em 0 0; -} - -@color-height: 4px; -.color-left { - float:left; - height: @color-height; - background: @red-dark; - width: 50%; -} -.color-right { - display: inline-block; - height: @color-height; - background: @green-dark; - width: 50%; - float:right; -} -.color-middle { - height: @color-height; - background: @blue-dark; - margin-top: .4em; - margin-bottom: -@color-height; - position: relative; + height: @fixed-header-height; + margin: -@fixed-header-height 0 0; } .dropdown { - display: none; + display: none !important; } #p-personal { display: inline-block; position: relative; padding-left: 1.5em; - padding-right: 2em; line-height: 1; + + .dropdown { + .dropdown-menu(); + top: 2.95em; + right: -2em; + } + .pokey { + top: 2.125em; + } } -#p-personal h3 { - margin: 0 0 -1em; - padding: .7em 0 1.25em 25px; + +#p-personal h2 { + margin: 0; + padding: .7em 0 0 25px; font-family: @fonts-secondary; font-weight: normal; font-size: 1.1em; @@ -87,251 +92,24 @@ background-position: 0 7px; background-repeat: no-repeat; - &:after { - display: inline-block; - content: ''; - width: 22px; - height: 12px; - .background-image-svg('images/arrow-down-grey.svg', 'images/arrow-down-grey.png'); - background-position: center center; - background-repeat: no-repeat; - } - &:hover { - cursor: pointer; - } + .dropdown-header(); } - -#p-logo-text { - width: 11em; - text-align: center; - line-height: 1; - - a { - padding: .2em 0; - color: @text; - font-family: @fonts-secondary; - font-variant: small-caps; - font-size: 1.75em; - display: block; - - /* 13+ character names */ - &.long { - font-size: 1.45em; - padding: 0; - line-height: .8; - } +#p-personal:hover { + .pokey, + .dropdown { + display: block !important; } } -/* Search */ - -#simpleSearch { - box-shadow: inset 0 2px 4px 0 rgba(0, 0, 0, 0.05); - background: @background; - position: relative; - border: solid 1px @grey; -} -#searchInput { - border: none; - margin: 0; - height: 2.1em; - padding: .4em 4.5em .2em 2em; - box-shadow: none; - background: transparent; - width: 100%; - min-height: 0; -} -#searchButton, -#mw-searchButton { - position: absolute; - top: 0; - right: 1.5em; - width: 2.5em; - height: 2.5em; - .icon; - .background-image-svg('images/search-ltr.svg', 'images/search-ltr.png'); - background-position: 50% 40%; - box-shadow: none; -} - -/* Dropdowns */ - -#p-personal:hover .dropdown { - display: block; -} - -.dropdown { - .box; - background: #fff; - box-shadow: 0 2px 3px 1px rgba(0, 0, 0, 0.05); - position: absolute; - padding: 20px 2em 0; - min-width: 6em; - top: 2.95em; - right: 0; - overflow: visible; - line-height: 1.1; - z-index: 1; - - ul, - li { - list-style: none; - margin: 0; - padding: 0; - } - ul { - margin-bottom: 2em; - } - li { - margin: 0 0 .35em; - } -} -.pokey, -.pokey::after { - border-bottom: 10px solid #E6E6E6; - border-left: 10px solid transparent; - border-right: 10px solid transparent; - content: ""; - height: 0px; - position: absolute; - transform: rotate(360deg); // to force some smoothing - width: 0px; -} -.pokey { - right: 28px; - top: -10px; -} -.pokey::after { - border-bottom-color: #FFFFFF; - right: -10px; - top: 2px; +#page-header-links #ca-more, +#page-header-links #ca-languages, +.sidebar-chunk h2 { + display: none; } /* Content */ #mw-content-container { - margin-top: 3em; - padding-bottom: .5em; - border-bottom: solid 4px @green; -} -#mw-content { - .box; - background: @background; - padding: 1em 2em 3em; - overflow: hidden; -} -#page-header-links { - div, - ul, - li { - list-style: none; - display: inline-block; - margin: 0; - padding: 0; - } - li { - margin: .25em 0 1.5em; - - &:hover { - border-bottom: solid 3px @grey; - } - &.selected { - border-bottom: solid 3px @blue; - - a { - color: @text; - } - } - } - #p-namespaces { - float: left; - - li { - margin-right: 1em; - } - } - #p-pagetools { - float: right; - - li { - margin-left: 1em; - } - } -} -#ca-watch a, -#ca-unwatch a { - .icon; - display: inline-block; - width: 1.4em; - height: 1.4em; - box-sizing: border-box; -} -#ca-watch a { - .background-image-svg('images/star.svg', 'images/star.png'); -} -#ca-unwatch a { - .background-image-svg('images/star-filled.svg', 'images/star-filled.png'); -} - -/* Sidebars */ - -#mw-site-navigation .sidebar-chunk, -#mw-related-navigation .sidebar-chunk { - .box; - padding: 1.5em 1.5em 0; - margin: 1em; - line-height: 1.1; - - ul, - li { - list-style: none; - margin: 0; - padding: 0; - } - h3 { - font-weight: normal; - font-size: 1em; - margin: .25em 0 .75em 0; - padding-bottom: .15em; - border-bottom: solid 2px @grey; - } - ul { - margin-bottom: 2em; - } - li { - margin: 0 0 .35em; - } -} - -#mw-site-navigation .sidebar-chunk { - margin-left: 0; -} -#mw-related-navigation .sidebar-chunk { - margin-right: 0; -} - -/* Footer */ - -#mw-footer { - padding-top: .5em; + margin-top: @fixed-header-height; padding-bottom: 1em; - - ul, - li { - margin: 1em 0; - list-style: none; - padding: 0; - } -} -#footer-places li { - display: inline; - padding-right: 1em; -} -#footer-icons { - float: right; - margin: 0 0 0 1em; - - li { - margin: 0 0 1em 0; - } } diff --git a/resources/screen-misc.less b/resources/screen-misc.less new file mode 100644 index 0000000..05658de --- /dev/null +++ b/resources/screen-misc.less @@ -0,0 +1,24 @@ +@import "variables.less"; + +// Let's add some unnecessary white space. Or grey, as it were. In the dumbest possible way. + +@media screen and (min-width: 1425px) { + .color-middle-container, + .ts-inner { + padding: 0 3em; + } + .color-middle { + margin-left: @column-left-size; + margin-right: @column-right-size; + } +} + +@media screen and (min-width: 1250px) and (max-width: 1339px) { + .ts-inner { + padding: 0 3em; + } + .color-middle { + margin-left: @column-left-size + 3em; + margin-right: @column-right-size + 3em; + } +} diff --git a/resources/screen-mobile.less b/resources/screen-mobile.less index 61c088f..5a2a372 100644 --- a/resources/screen-mobile.less +++ b/resources/screen-mobile.less @@ -1 +1,244 @@ @import "variables.less"; + +/* Layout */ + +#mw-footer { + padding: 0 @content-padding; +} +.color-middle { + margin: auto; + width: 34%; +} + +.categories-bottom(); +#catlinks { + padding-bottom: 2em; + border-top: solid 3px @grey; +} + +#page-header-links #ca-view, +#mw-header-nav-hack, +#page-tools h2, +#p-logo { + display: none; +} + +#mw-header-container { + background: @background; + padding: 3.75em @content-padding .35em; +} + +#mw-header-hack { + position: relative; + z-index: 1; + box-shadow: 0 3px 3px 2px rgba(0, 0, 0, 0.075), 0 0 2px rgba(0, 0, 0, 0.2); +} + +/* Dropdowns */ + +.sidebar-inner, +.dropdown { + display: none; +} + +.sidebar-inner, +.dropdown { + .nav-block(); + background: @background; + box-shadow: 0 2px 3px 1px rgba(0, 0, 0, 0.05); + position: absolute; + padding: 2em 2.5em 1em; + margin: 0; + min-width: 9.153em; + max-width: 80%; + top: 3.25em; + right: 0; + overflow: visible; + z-index: 100; + + h3 { + margin: .5em 0 1.5em; + } + ul { + margin: 1em 0 2em; + } + li { + margin: 0 0 .75em; + } +} + +#menus-cover { + display: none; + position: fixed; + top: 0; + left: 0; + z-index: 99; + width: 100%; + height: 100%; + background: @background2; + opacity: .8; + overflow: hidden; +} + +/* Dropdown toggles */ + +#user-tools h2, +.sidebar-chunk h2 { + .dropdown-header(); + margin: 0; + width: 30px; + height: 30px; + position: absolute; + top: 1em; + padding-bottom: 0; + font-size: 1em; + background-repeat: no-repeat; + background-position: 50% 50%; + + span { + display: inline-block; + .icon(); + } + &:after { + position: absolute; + top: .65em; + left: 23px; + } +} +#user-tools h2 { + right: @content-padding + .5em; + .background-image-svg('images/user-large-grey.svg', 'images/user-large-grey.png'); +} +#site-navigation { + h2 { + left: @content-padding; + .background-image-svg('images/menu-large-grey.svg', 'images/menu-large-grey.png'); + } + .sidebar-inner { + left: 0; + right: auto; + } +} +#site-tools h2 { + right: 7em; + .background-image-svg('images/gear-large-grey.svg', 'images/gear-large-grey.png'); +} + +/* Logo */ + +#p-logo-text { + position: absolute; + top: .75em; + left: 6em; + text-align: left; + + a { + padding-left: 0; + } +} + +/* Page actions */ + +#p-namespaces li { + margin-right: 1.5em; +} +#p-pagetools li { + margin-left: 1.5em; + + &#ca-languages { + margin-left: 1em; + } +} + +#page-header-links a { + .ca-icon(); +} +#ca-edit a { + .background-image-svg('images/pencil-grey.svg', 'images/pencil-grey.png'); +} +#ca-history a { + .background-image-svg('images/clock-grey.svg', 'images/clock-grey.png'); +} +#ca-talk a { + .background-image-svg('images/talk-grey.svg', 'images/talk-grey.png'); +} +#t-contributions a { + .background-image-svg('images/puzzle-grey.svg', 'images/puzzle-grey.png'); +} +#ca-addsection a { + .background-image-svg('images/plus-grey.svg', 'images/plus-grey.png'); +} +*[id^='ca-nstab-'] a { + .background-image-svg('images/page-grey.svg', 'images/page-grey.png'); +} + +#ca-more, +#ca-languages { + &:after { + margin-left: -.35em; + } + + span { + .ca-icon(); + } +} +#ca-more span { + .background-image-svg('images/gear-grey.svg', 'images/gear-grey.png'); +} +#ca-languages span { + .background-image-svg('images/languages-grey.svg', 'images/languages-grey.png'); +} + +/* Full-width thumbnails */ + +div.thumb { + float: none; +} +.thumb { + margin: 1em auto; +} +.tright { + margin-left: 0; + padding-left: 0; +} +.tleft { + margin-right: 0; + padding-right: 0; +} +.thumbinner { + padding: 1em 1.5em; + width: 100% !important; + box-sizing: border-box; +} +.thumbimage { + display: block; + margin: 0 auto .5em; +} + +#mw-content { + overflow: auto; + border: none; +} +#mw-content-block { + background: @background; +} + +/* Keep images from overflowing */ + +#mw-content a > img { + height: auto !important; + max-width: 100% !important; +} + +/* Table of contents */ + +#toc, .toc, .mw-warning { + width: 100%; + box-sizing: border-box; +} + +/* Misc */ + +.nomobile { + display: none; +} diff --git a/resources/variables.less b/resources/variables.less index 5ea87bc..6657dfa 100644 --- a/resources/variables.less +++ b/resources/variables.less @@ -1,5 +1,7 @@ @import "mediawiki.mixins"; +// Colours + @text: #013; @background: #fff; @background2: #f3f3f3; @@ -33,6 +35,7 @@ // Flair + // Fonts are chosen for consistent metrics, not necessarily overall prettiness. // This will NEED fixes for different languages. @fonts-secondary: 'Linux Libertine', 'Times New Roman', serif; @@ -40,8 +43,21 @@ @border: .2em; @radius: .2em; +@font-size: .95em; + +// Widths + +@column-left-size: 14em; +@column-right-size: 16em; + +@content-width: 100em; +@content-padding: 2em; + +@fixed-header-height: 3.125em; + + -/* Misc */ +// Miscellaneous functions // To hide objects, but keep them accessible for screen-readers .hidden() { @@ -53,11 +69,11 @@ .icon() { text-indent: -99999px; border: none; - background: transparent; + background-color: transparent; background-repeat: no-repeat; } -.box { +.box() { background: @background3; border: solid @grey-bright; border-width: 1px 1px @border; @@ -65,3 +81,115 @@ box-shadow: 0 1px 2px 1px rgba(0, 0, 0, 0.02); overflow: auto; } + +// Icons for the page actions menus +.ca-icon() { + .icon; + display: inline-block; + width: 20px; + height: 20px; + box-sizing: border-box; + margin-bottom: -.5em; +} + +// Navigation column blocks + +.nav-block() { + .box(); + padding: 1.5em 1.5em 0; + margin: 1em 0; + line-height: 1.1; + + ul, + li { + list-style: none; + margin: 0; + padding: 0; + } + h3 { + font-weight: normal; + font-size: 1em; + margin: .25em 0 .75em 0; + padding-bottom: .15em; + border-bottom: solid 2px @grey; + } + ul { + margin-bottom: 2em; + } + li { + margin: 0 0 .35em; + } +} + +.column-right() { + width: @column-right-size; + float: right; + clear: right; + padding-left: 1em; + box-sizing: border-box; + + .sidebar-chunk { + .nav-block(); + } +} +.column-left() { + width: @column-left-size; + float: left; + clear: left; + padding-right: 1em; + box-sizing: border-box; + + .sidebar-chunk { + .nav-block(); + } +} + +// Dropdowns +.dropdown-header() { + cursor: pointer; + margin-bottom: -1em; + padding-bottom: 1em; + + &:after { + display: inline-block; + content: ''; + width: 22px; + height: 12px; + .background-image-svg('images/arrow-down-grey.svg', 'images/arrow-down-grey.png'); + background-position: center center; + background-repeat: no-repeat; + } +} +.dropdown-menu( @direction: right ) { + .nav-block(); + background: @background; + box-shadow: 0 2px 3px 1px rgba(0, 0, 0, 0.05); + position: absolute; + padding: 20px 2em 0; + margin: 0; + min-width: 9.153em; + top: 2.95em; + @{direction}: -1em; + overflow: visible; + z-index: 1; +} + +// Categories on bottom of page + +.categories-bottom() { + #catlinks-sidebar { + display: none; + } + + #catlinks { + margin: 0 @content-padding; + padding: 1.5em 0 .5em; + + li { + border-left: none; + } + div { + margin: 0 0 .35em; + } + } +} diff --git a/skin.json b/skin.json index 109d740..6b0e276 100644 --- a/skin.json +++ b/skin.json @@ -1,7 +1,7 @@ { "name": "Timeless", - "version": "0.3", - "author": "Isarra", + "version": "0.6", + "author": "Isarra Yos", "url": "https://www.mediawiki.org/wiki/Skin:Timeless", "descriptionmsg": "timeless-desc", "namemsg": "skinname-timeless", @@ -30,18 +30,40 @@ "media": "screen" }, "resources/screen-desktop.less": { - "media": "screen and (min-width: 751px)" + "media": "screen and (min-width: 851px)" + }, + "resources/screen-desktop-full.less": { + "media": "screen and (min-width: 1340px)" + }, + "resources/screen-desktop-mid.less": { + "media": "screen and (min-width: 1100px) and (max-width: 1339px)" + }, + "resources/screen-desktop-small.less": { + "media": "screen and (min-width: 851px) and (max-width: 1099px)" }, "resources/screen-mobile.less": { - "media": "screen and (max-width: 750px)" + "media": "screen and (max-width: 850px)" } } }, + "skins.timeless.misc": { + "position": "top", + "styles": [ + "resources/screen-misc.less" + ] + }, "skins.timeless.js": { "position": "bottom", "scripts": [ "resources/main.js" ] + }, + "skins.timeless.mobile": { + "position": "bottom", + "scripts": [ + "resources/libraries/jquery.mobile.custom.js", + "resources/mobile.js" + ] } }, "ResourceFileModulePaths": {