From d3fd790574921be6d3d560ca0e6eda65e82d828e Mon Sep 17 00:00:00 2001 From: epriestley Date: Sat, 11 Aug 2012 07:06:12 -0700 Subject: [PATCH] Add basic support for new navigation menu Summary: Add a new left-side application menu. This menu shows which application you're in and provides a quick way to get to other applications. On desktops, menus are always shown but the app menu can be collapsed to be very small. On tablets, navigation buttons allow you to choose between the menus and the content. On phones, navigation buttons allow you to choose between the app menu, the local menu, and the content. This needs some code and UI cleanup, but has no effect yet so I think it's okay to land as-is, I'll clean it up a bit as I start integrating it. I want to play around with it a bit and see if it's good/useful or horrible anyway. Test Plan: Will include screenshots. Reviewers: vrana, btrahan, chad Reviewed By: btrahan CC: aran, alanh Maniphest Tasks: T1569 Differential Revision: https://secure.phabricator.com/D3223 --- src/__celerity_resource_map__.php | 39 ++- src/__phutil_library_map__.php | 2 + .../PhabricatorApplicationAudit.php | 4 + .../base/PhabricatorApplication.php | 4 + .../PhabricatorApplicationDifferential.php | 4 + .../PhabricatorApplicationDiffusion.php | 4 + .../PhabricatorApplicationManiphest.php | 4 + .../controller/ManiphestController.php | 5 + .../PhabricatorApplicationApplications.php | 4 + .../PhabricatorApplicationSettings.php | 1 + ...abricatorPeopleAdjustSettingController.php | 34 +++ .../storage/PhabricatorUserPreferences.php | 3 + .../PhabricatorApplicationPhriction.php | 4 + src/view/layout/AphrontSideNavFilterView.php | 25 ++ src/view/layout/AphrontSideNavView.php | 206 ++++++++++++--- .../rsrc/css/aphront/phabricator-nav-view.css | 224 +++++++++++++++- webroot/rsrc/image/app/app_applications.png | Bin 0 -> 463 bytes webroot/rsrc/image/button_apps.png | Bin 0 -> 463 bytes webroot/rsrc/image/button_content.png | Bin 0 -> 326 bytes webroot/rsrc/image/button_menu.png | Bin 0 -> 147 bytes .../js/application/core/behavior-device.js | 2 + .../core/behavior-phabricator-nav.js | 245 +++++++++++++----- .../application/core/behavior-toggle-class.js | 2 +- 23 files changed, 705 insertions(+), 111 deletions(-) create mode 100644 src/applications/people/controller/PhabricatorPeopleAdjustSettingController.php create mode 100644 webroot/rsrc/image/app/app_applications.png create mode 100644 webroot/rsrc/image/button_apps.png create mode 100755 webroot/rsrc/image/button_content.png create mode 100755 webroot/rsrc/image/button_menu.png diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php index 7c715ca5c1..0c7ae3b8ea 100644 --- a/src/__celerity_resource_map__.php +++ b/src/__celerity_resource_map__.php @@ -7,6 +7,13 @@ */ celerity_register_resource_map(array( + '/rsrc/image/app/app_applications.png' => + array( + 'hash' => '0e83b7bea93bf92777e546ae6c7ac1cb', + 'uri' => '/res/0e83b7be/rsrc/image/app/app_applications.png', + 'disk' => '/rsrc/image/app/app_applications.png', + 'type' => 'png', + ), '/rsrc/image/app/app_audit.png' => array( 'hash' => '53340003d1daf306b64ed5ebb08bc204', @@ -140,6 +147,27 @@ celerity_register_resource_map(array( 'disk' => '/rsrc/image/bolt.png', 'type' => 'png', ), + '/rsrc/image/button_apps.png' => + array( + 'hash' => 'cc29f793afd01b15af613562225118f3', + 'uri' => '/res/cc29f793/rsrc/image/button_apps.png', + 'disk' => '/rsrc/image/button_apps.png', + 'type' => 'png', + ), + '/rsrc/image/button_content.png' => + array( + 'hash' => '87cc5797352097b4b3d7541e6c46f032', + 'uri' => '/res/87cc5797/rsrc/image/button_content.png', + 'disk' => '/rsrc/image/button_content.png', + 'type' => 'png', + ), + '/rsrc/image/button_menu.png' => + array( + 'hash' => '5742857c7734d9d25be1125f5737fe0e', + 'uri' => '/res/5742857c/rsrc/image/button_menu.png', + 'disk' => '/rsrc/image/button_menu.png', + 'type' => 'png', + ), '/rsrc/image/credit_cards.png' => array( 'hash' => '681448de424ea159b6ea68af04c046ae', @@ -1153,7 +1181,7 @@ celerity_register_resource_map(array( ), 'javelin-behavior-device' => array( - 'uri' => '/res/bec84986/rsrc/js/application/core/behavior-device.js', + 'uri' => '/res/37669d1a/rsrc/js/application/core/behavior-device.js', 'type' => 'js', 'requires' => array( @@ -1614,7 +1642,7 @@ celerity_register_resource_map(array( ), 'javelin-behavior-phabricator-nav' => array( - 'uri' => '/res/adaae8ae/rsrc/js/application/core/behavior-phabricator-nav.js', + 'uri' => '/res/cb8979b2/rsrc/js/application/core/behavior-phabricator-nav.js', 'type' => 'js', 'requires' => array( @@ -1623,6 +1651,9 @@ celerity_register_resource_map(array( 2 => 'javelin-dom', 3 => 'javelin-magical-init', 4 => 'javelin-vector', + 5 => 'javelin-request', + 6 => 'javelin-util', + 7 => 'javelin-fx', ), 'disk' => '/rsrc/js/application/core/behavior-phabricator-nav.js', ), @@ -1819,7 +1850,7 @@ celerity_register_resource_map(array( ), 'javelin-behavior-toggle-class' => array( - 'uri' => '/res/35b86b96/rsrc/js/application/core/behavior-toggle-class.js', + 'uri' => '/res/fa818e0f/rsrc/js/application/core/behavior-toggle-class.js', 'type' => 'js', 'requires' => array( @@ -2533,7 +2564,7 @@ celerity_register_resource_map(array( ), 'phabricator-nav-view-css' => array( - 'uri' => '/res/3443576d/rsrc/css/aphront/phabricator-nav-view.css', + 'uri' => '/res/82636b80/rsrc/css/aphront/phabricator-nav-view.css', 'type' => 'css', 'requires' => array( diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 6f8afa6705..cf538cb35b 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -882,6 +882,7 @@ phutil_register_library_map(array( 'PhabricatorPasteListController' => 'applications/paste/controller/PhabricatorPasteListController.php', 'PhabricatorPasteQuery' => 'applications/paste/query/PhabricatorPasteQuery.php', 'PhabricatorPasteViewController' => 'applications/paste/controller/PhabricatorPasteViewController.php', + 'PhabricatorPeopleAdjustSettingController' => 'applications/people/controller/PhabricatorPeopleAdjustSettingController.php', 'PhabricatorPeopleController' => 'applications/people/controller/PhabricatorPeopleController.php', 'PhabricatorPeopleEditController' => 'applications/people/controller/PhabricatorPeopleEditController.php', 'PhabricatorPeopleLdapController' => 'applications/people/controller/PhabricatorPeopleLdapController.php', @@ -1964,6 +1965,7 @@ phutil_register_library_map(array( 'PhabricatorPasteListController' => 'PhabricatorPasteController', 'PhabricatorPasteQuery' => 'PhabricatorCursorPagedPolicyQuery', 'PhabricatorPasteViewController' => 'PhabricatorPasteController', + 'PhabricatorPeopleAdjustSettingController' => 'PhabricatorPeopleController', 'PhabricatorPeopleController' => 'PhabricatorController', 'PhabricatorPeopleEditController' => 'PhabricatorPeopleController', 'PhabricatorPeopleLdapController' => 'PhabricatorPeopleController', diff --git a/src/applications/audit/application/PhabricatorApplicationAudit.php b/src/applications/audit/application/PhabricatorApplicationAudit.php index 02b15ab5e9..d71aa0e350 100644 --- a/src/applications/audit/application/PhabricatorApplicationAudit.php +++ b/src/applications/audit/application/PhabricatorApplicationAudit.php @@ -42,6 +42,10 @@ final class PhabricatorApplicationAudit extends PhabricatorApplication { ); } + public function getCoreApplicationOrder() { + return 0.130; + } + public function loadStatus(PhabricatorUser $user) { $status = array(); diff --git a/src/applications/base/PhabricatorApplication.php b/src/applications/base/PhabricatorApplication.php index d91f15f3f9..64d53542ae 100644 --- a/src/applications/base/PhabricatorApplication.php +++ b/src/applications/base/PhabricatorApplication.php @@ -62,6 +62,10 @@ abstract class PhabricatorApplication { return true; } + public function getCoreApplicationOrder() { + return null; + } + /* -( URI Routing )-------------------------------------------------------- */ diff --git a/src/applications/differential/application/PhabricatorApplicationDifferential.php b/src/applications/differential/application/PhabricatorApplicationDifferential.php index 72de852a8d..4354c800a4 100644 --- a/src/applications/differential/application/PhabricatorApplicationDifferential.php +++ b/src/applications/differential/application/PhabricatorApplicationDifferential.php @@ -66,6 +66,10 @@ final class PhabricatorApplicationDifferential extends PhabricatorApplication { ); } + public function getCoreApplicationOrder() { + return 0.100; + } + public function loadStatus(PhabricatorUser $user) { $revisions = id(new DifferentialRevisionQuery()) ->withResponsibleUsers(array($user->getPHID())) diff --git a/src/applications/diffusion/application/PhabricatorApplicationDiffusion.php b/src/applications/diffusion/application/PhabricatorApplicationDiffusion.php index 1db129df93..fc5a47aaf9 100644 --- a/src/applications/diffusion/application/PhabricatorApplicationDiffusion.php +++ b/src/applications/diffusion/application/PhabricatorApplicationDiffusion.php @@ -72,5 +72,9 @@ final class PhabricatorApplicationDiffusion extends PhabricatorApplication { ); } + public function getCoreApplicationOrder() { + return 0.120; + } + } diff --git a/src/applications/maniphest/application/PhabricatorApplicationManiphest.php b/src/applications/maniphest/application/PhabricatorApplicationManiphest.php index 5982b69a60..1c5976d56b 100644 --- a/src/applications/maniphest/application/PhabricatorApplicationManiphest.php +++ b/src/applications/maniphest/application/PhabricatorApplicationManiphest.php @@ -34,6 +34,10 @@ final class PhabricatorApplicationManiphest extends PhabricatorApplication { return celerity_get_resource_uri('/rsrc/image/app/app_maniphest.png'); } + public function getCoreApplicationOrder() { + return 0.110; + } + public function getFactObjectsForAnalysis() { return array( new ManiphestTask(), diff --git a/src/applications/maniphest/controller/ManiphestController.php b/src/applications/maniphest/controller/ManiphestController.php index 471b229fac..224c940fcb 100644 --- a/src/applications/maniphest/controller/ManiphestController.php +++ b/src/applications/maniphest/controller/ManiphestController.php @@ -84,6 +84,11 @@ abstract class ManiphestController extends PhabricatorController { $nav->addLabel('Reports'); $nav->addFilter('report', 'Reports', '/maniphest/report/'); + $nav->setFlexNav(true); + $nav->setShowApplicationMenu(true); + $nav->setCurrentApplication($this->getCurrentApplication()); + $nav->setUser($this->getRequest()->getUser()); + return $nav; } diff --git a/src/applications/meta/application/PhabricatorApplicationApplications.php b/src/applications/meta/application/PhabricatorApplicationApplications.php index f9360be2cf..60f3e106f0 100644 --- a/src/applications/meta/application/PhabricatorApplicationApplications.php +++ b/src/applications/meta/application/PhabricatorApplicationApplications.php @@ -26,6 +26,10 @@ final class PhabricatorApplicationApplications extends PhabricatorApplication { return 'Manage Applications'; } + public function getIconURI() { + return celerity_get_resource_uri('/rsrc/image/app/app_applications.png'); + } + public function getRoutes() { return array( '/applications/' => array( diff --git a/src/applications/people/application/PhabricatorApplicationSettings.php b/src/applications/people/application/PhabricatorApplicationSettings.php index 70f9508e3f..65c2468415 100644 --- a/src/applications/people/application/PhabricatorApplicationSettings.php +++ b/src/applications/people/application/PhabricatorApplicationSettings.php @@ -34,6 +34,7 @@ final class PhabricatorApplicationSettings extends PhabricatorApplication { return array( '/settings/' => array( '(?:page/(?P[^/]+)/)?' => 'PhabricatorUserSettingsController', + 'adjust/' => 'PhabricatorPeopleAdjustSettingController', ), ); } diff --git a/src/applications/people/controller/PhabricatorPeopleAdjustSettingController.php b/src/applications/people/controller/PhabricatorPeopleAdjustSettingController.php new file mode 100644 index 0000000000..b147af1a9e --- /dev/null +++ b/src/applications/people/controller/PhabricatorPeopleAdjustSettingController.php @@ -0,0 +1,34 @@ +getRequest(); + $user = $request->getUser(); + + $prefs = $user->loadPreferences(); + $prefs->setPreference( + $request->getStr('key'), + $request->getStr('value')); + $prefs->save(); + + return id(new AphrontAjaxResponse())->setContent(array()); + } +} diff --git a/src/applications/people/storage/PhabricatorUserPreferences.php b/src/applications/people/storage/PhabricatorUserPreferences.php index 2d4941207b..5f6691ca1d 100644 --- a/src/applications/people/storage/PhabricatorUserPreferences.php +++ b/src/applications/people/storage/PhabricatorUserPreferences.php @@ -33,6 +33,9 @@ final class PhabricatorUserPreferences extends PhabricatorUserDAO { const PREFERENCE_DIFFUSION_VIEW = 'diffusion-view'; const PREFERENCE_DIFFUSION_SYMBOLS = 'diffusion-symbols'; + const PREFERENCE_NAV_COLLAPSED = 'nav-collapsed'; + const PREFERENCE_NAV_WIDTH = 'nav-width'; + protected $userPHID; protected $preferences = array(); diff --git a/src/applications/phriction/application/PhabricatorApplicationPhriction.php b/src/applications/phriction/application/PhabricatorApplicationPhriction.php index 02c0d67a41..080cdd6863 100644 --- a/src/applications/phriction/application/PhabricatorApplicationPhriction.php +++ b/src/applications/phriction/application/PhabricatorApplicationPhriction.php @@ -53,5 +53,9 @@ final class PhabricatorApplicationPhriction extends PhabricatorApplication { ); } + public function getCoreApplicationOrder() { + return 0.140; + } + } diff --git a/src/view/layout/AphrontSideNavFilterView.php b/src/view/layout/AphrontSideNavFilterView.php index de662f2d35..a8ebba4c53 100644 --- a/src/view/layout/AphrontSideNavFilterView.php +++ b/src/view/layout/AphrontSideNavFilterView.php @@ -42,6 +42,24 @@ final class AphrontSideNavFilterView extends AphrontView { private $selectedFilter = false; private $flexNav; private $flexible; + private $showApplicationMenu; + private $user; + private $currentApplication; + + public function setCurrentApplication(PhabricatorApplication $current) { + $this->currentApplication = $current; + return $this; + } + + public function setUser(PhabricatorUser $user) { + $this->user = $user; + return $this; + } + + public function setShowApplicationMenu($show_application_menu) { + $this->showApplicationMenu = $show_application_menu; + return $this; + } public function setFlexNav($flex_nav) { $this->flexNav = $flex_nav; @@ -129,6 +147,13 @@ final class AphrontSideNavFilterView extends AphrontView { $view = new AphrontSideNavView(); $view->setFlexNav($this->flexNav); $view->setFlexible($this->flexible); + $view->setShowApplicationMenu($this->showApplicationMenu); + if ($this->user) { + $view->setUser($this->user); + } + if ($this->currentApplication) { + $view->setCurrentApplication($this->currentApplication); + } foreach ($this->items as $item) { list($type, $key, $name) = $item; switch ($type) { diff --git a/src/view/layout/AphrontSideNavView.php b/src/view/layout/AphrontSideNavView.php index 6a43eee791..f4a0bedb2f 100644 --- a/src/view/layout/AphrontSideNavView.php +++ b/src/view/layout/AphrontSideNavView.php @@ -18,9 +18,27 @@ final class AphrontSideNavView extends AphrontView { - protected $items = array(); - protected $flexNav; - protected $isFlexible; + private $items = array(); + private $flexNav; + private $isFlexible; + private $showApplicationMenu; + private $user; + private $currentApplication; + + public function setUser(PhabricatorUser $user) { + $this->user = $user; + return $this; + } + + public function setShowApplicationMenu($show_application_menu) { + $this->showApplicationMenu = $show_application_menu; + return $this; + } + + public function setCurrentApplication(PhabricatorApplication $current) { + $this->currentApplication = $current; + return $this; + } public function addNavItem($item) { $this->items[] = $item; @@ -42,20 +60,60 @@ final class AphrontSideNavView extends AphrontView { $view->appendChild($this->items); if ($this->flexNav) { + $user = $this->user; + require_celerity_resource('phabricator-nav-view-css'); - $nav_id = celerity_generate_unique_node_id(); - $drag_id = celerity_generate_unique_node_id(); + $nav_classes = array(); + $nav_classes[] = 'phabricator-nav'; + + $app_id = celerity_generate_unique_node_id(); + $nav_id = null; + $drag_id = null; $content_id = celerity_generate_unique_node_id(); + $collapse_id = null; + $expand_id = null; + $main_id = celerity_generate_unique_node_id(); + + $apps = $this->renderApplications(); + + $key = PhabricatorUserPreferences::PREFERENCE_NAV_COLLAPSED; + if ($user->loadPreferences()->getPreference($key)) { + $nav_classes[] = 'phabricator-nav-app-collapsed'; + } + + $collapse_id = celerity_generate_unique_node_id(); + $expand_id = celerity_generate_unique_node_id(); + + $collapse_button = phutil_render_tag( + 'a', + array( + 'href' => '#', + 'class' => 'phabricator-nav-app-button-collapse', + 'id' => $collapse_id, + ), + '« Collapse'); + $expand_button = phutil_render_tag( + 'a', + array( + 'href' => '#', + 'class' => 'phabricator-nav-app-button-expand', + 'id' => $expand_id, + ), + '»'); + + $app_menu = phutil_render_tag( + 'div', + array( + 'class' => 'phabricator-nav-col phabricator-nav-app', + 'id' => $app_id, + ), + $apps->render()). + $expand_button. + $collapse_button; if ($this->flexible) { - Javelin::initBehavior( - 'phabricator-nav', - array( - 'navID' => $nav_id, - 'dragID' => $drag_id, - 'contentID' => $content_id, - )); + $drag_id = celerity_generate_unique_node_id(); $flex_bar = phutil_render_tag( 'div', array( @@ -67,24 +125,66 @@ final class AphrontSideNavView extends AphrontView { $flex_bar = null; } - return - '
'. - phutil_render_tag( - 'div', - array( - 'class' => 'phabricator-nav-col', - 'id' => $nav_id, - ), - $view->render()). - $flex_bar. - phutil_render_tag( - 'div', - array( - 'class' => 'phabricator-nav-content', - 'id' => $content_id, - ), - $this->renderChildren()). + $nav_menu = null; + if ($this->items) { + $local_id = celerity_generate_unique_node_id(); + $nav_classes[] = 'has-local-nav'; + $local_menu = phutil_render_tag( + 'div', + array( + 'class' => 'phabricator-nav-col phabricator-nav-local', + 'id' => $local_id, + ), + $view->render()); + } + + Javelin::initBehavior( + 'phabricator-nav', + array( + 'mainID' => $main_id, + 'appID' => $app_id, + 'localID' => $local_id, + 'dragID' => $drag_id, + 'contentID' => $content_id, + 'collapseID' => $collapse_id, + 'expandID' => $expand_id, + 'collapseKey' => $key, + )); + + $header_part = + '
'. + '
'. + ''. + ''. + '
'. + ''. '
'; + + return $header_part.phutil_render_tag( + 'div', + array( + 'class' => implode(' ', $nav_classes), + 'id' => $main_id, + ), + $app_menu. + $local_menu. + $flex_bar. + phutil_render_tag( + 'div', + array( + 'class' => 'phabricator-nav-content', + 'id' => $content_id, + ), + $this->renderChildren())); } else { require_celerity_resource('aphront-side-nav-view-css'); @@ -103,4 +203,52 @@ final class AphrontSideNavView extends AphrontView { } } + private function renderApplications() { + $core = array(); + $current = $this->currentApplication; + + $meta = null; + + $applications = PhabricatorApplication::getAllInstalledApplications(); + foreach ($applications as $application) { + if ($application instanceof PhabricatorApplicationApplications) { + $meta = $application; + continue; + } + if ($application->getCoreApplicationOrder() !== null) { + $core[] = $application; + } + } + + $core = msort($core, 'getCoreApplicationOrder'); + if ($meta) { + $core[] = $meta; + } + $core = mpull($core, null, 'getPHID'); + + if ($current && empty($core[$current->getPHID()])) { + array_unshift($core, $this->current); + } + + $apps = array(); + foreach ($core as $phid => $application) { + $classes = array(); + $classes[] = 'phabricator-nav-app-item'; + if ($current && $phid == $current->getPHID()) { + $classes[] = 'phabricator-nav-app-item-selected'; + } + + $apps[] = phutil_render_tag( + 'a', + array( + 'class' => implode(' ', $classes), + 'href' => $application->getBaseURI(), + 'style' => 'background-image: url('.$application->getIconURI().')', + ), + phutil_escape_html($application->getName())); + } + + return id(new AphrontNullView())->appendChild($apps); + } + } diff --git a/webroot/rsrc/css/aphront/phabricator-nav-view.css b/webroot/rsrc/css/aphront/phabricator-nav-view.css index fecb298970..65a54e1dd2 100644 --- a/webroot/rsrc/css/aphront/phabricator-nav-view.css +++ b/webroot/rsrc/css/aphront/phabricator-nav-view.css @@ -11,11 +11,9 @@ top: 44px; left: 0; bottom: 0; - width: 179px; - background: #e3e3e3; border-right: 1px solid #999c9e; - box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.20); + box-shadow: inset -3px 0 4px rgba(0, 0, 0, 0.05); overflow-y: auto; overflow-x: hidden; @@ -23,6 +21,21 @@ white-space: nowrap; } +.phabricator-nav-app { + width: 149px; + background: #d2d2d2; +} + +.phabricator-nav-local { + width: 179px; + background: #ececec; +} + +.device-tablet .phabricator-nav-local, +.device-phone .phabricator-nav-local { + width: 299px; +} + .phabricator-nav-drag { position: fixed; top: 44px; @@ -37,7 +50,7 @@ border-width: 0 1px 0 1px; border-color: #fff #999c9e #fff #999c9e; - box-shadow: inset -1px 0px 2px rgba(0, 0, 0, 0.15); + box-shadow: inset -1px 0px 1px rgba(0, 0, 0, 0.15); background-image: url(/rsrc/image/divot.png); background-position: center; @@ -54,10 +67,30 @@ display: block; } -.phabricator-nav-content { - margin-left: 180px; +.phabricator-nav-local { + left: 150px; } +.device-desktop .phabricator-nav-app-collapsed .phabricator-nav-local { + left: 34px; +} + +.phabricator-nav-content { + margin-left: 150px; +} + +.has-local-nav .phabricator-nav-content { + margin-left: 330px; +} + +.device-desktop .phabricator-nav-app-collapsed .phabricator-nav-content { + margin-left: 32px; +} + +.device-desktop .has-local-nav.phabricator-nav-app-collapsed + .phabricator-nav-content { + margin-left: 212px; +} .phabricator-nav-col span { display: block; @@ -74,10 +107,183 @@ } .phabricator-nav-col a.aphront-side-nav-selected { - background: #a1bbe5; + background-color: #a1bbe5; } -.phabricator-nav-col a:hover { - background: #3875d7; +.device-desktop .phabricator-nav-col a:hover { + background-color: #3875d7; color: #ffffff; } + +a.phabricator-nav-app-item { + color: #222222; + font-weight: normal; + padding: 4px; + padding-left: 37px; + vertical-align: middle; + line-height: 25px; + + border-width: 1px 0px; + border-style: solid; + border-color: transparent; + + background-size: auto 25px; + background-position: 4px 4px; + background-repeat: no-repeat; +} + +a.phabricator-nav-app-item-selected { + background-color: #f3f3f3; + box-shadow: inset 0 0 2px rgba(0, 0, 0, 0.20); + border-color: #b0b0b0; +} + + +a.phabricator-nav-app-button-expand, +a.phabricator-nav-app-button-collapse { + position: fixed; + display: none; + left: 0; + bottom: 0; + padding: 4px; + z-index: 2; + background: #d9d9d9; + line-height: 14px; + border-top: 1px solid #a9a9a9; + text-align: center; + font-size: 11px; + box-shadow: inset -1px -1px 3px rgba(0, 0, 0, 0.1); + color: #696969; + text-decoration: none; +} + +.phabricator-nav-app-button-collapse { + width: 141px; +} + +.phabricator-nav-app-button-expand { + width: 25px; + display: none; +} + +.device-desktop .phabricator-nav-app-button-expand, +.device-desktop .phabricator-nav-app-button-collapse { + display: block; +} + +.device-desktop .phabricator-nav-app-collapsed .phabricator-nav-app { + width: 33px; +} + +.phabricator-nav-app-collapsed .phabricator-nav-app-button-collapse { + display: none; +} + +.device-desktop .phabricator-nav-app-collapsed + .phabricator-nav-app-button-expand { + display: block; +} + +.device-desktop .phabricator-nav-head { + display: none; +} + +.device-tablet .phabricator-nav-col, +.device-phone .phabricator-nav-col { + position: absolute; + top: 0px; +} + +.device-tablet .phabricator-nav-app, +.device-phone .phabricator-nav-app { + left: -450px; +} + +.device-tablet .phabricator-nav-local, +.device-phone .phabricator-nav-local { + left: -300px; +} + +.device-phone .phabricator-nav-head-tablet { + display: none; +} + +.device-tablet .phabricator-nav-head-phone { + display: none; +} + +.device-tablet .phabricator-nav, +.device-phone .phabricator-nav { + overflow-x: hidden; + position: relative; +} + +.device-tablet .phabricator-nav-content, +.device-phone .phabricator-nav-content { + width: 100%; +} + +.device-tablet .phabricator-nav-content, +.device-phone .phabricator-nav-content { + margin-left: 0; + position: relative; +} + +.phabricator-nav-head { + display: block; + position: relative; + height: 43px; + background: #e6e6e6; + overflow: hidden; + border-bottom: 1px solid #9d9d9d; + text-align: center; + box-shadow: inset 0 0px 3px rgba(0, 0, 0, 0.30), + 0px 1px 2px rgba(0, 0, 0, 0.10); + z-index: 3; +} + +.nav-button { + background-color: #f3f3f3; + height: 32px; + width: 40px; + margin: 5px 0px; + display: inline-block; + border: 1px solid #999999; + box-shadow: inset -1px -1px 3px rgba(0, 0, 0, 0.10); + background-repeat: no-repeat; +} + +.nav-button-selected { + background-color: #c9c9c9; + box-shadow: inset 1px 1px 3px rgba(0, 0, 0, 0.20); +} + +.nav-button + .nav-button { + margin-left: -1px; +} + +.nav-button-w { + border-radius: 6px 0 0 6px; +} + +.nav-button-e { + border-radius: 0 6px 6px 0; +} + +.nav-button-apps { + background-image: url(/rsrc/image/button_apps.png); + background-size: 24px auto; + background-position: center; +} + +.nav-button-menu { + background-image: url(/rsrc/image/button_menu.png); + background-size: 24px auto; + background-position: center; +} + +.nav-button-content { + background-image: url(/rsrc/image/button_content.png); + background-size: 24px auto; + background-position: center; +} diff --git a/webroot/rsrc/image/app/app_applications.png b/webroot/rsrc/image/app/app_applications.png new file mode 100644 index 0000000000000000000000000000000000000000..ff13f2866e9978ce965a2d4300b91d7bd67da188 GIT binary patch literal 463 zcmV;=0WkiFP)nfJ4tA~ruLJFX>p(l81WTXyWtTKYABI+!N5eOzhd^wFM802T51$Kp$jpYzqX_O$o+fSmFGVj!nE%{hNx8b3R=JiCR1@5XUs`>%k-wgf+cAMs-e~ve)(i;NT2)|98LG#c6 zM>2Vi#CzbvQ_qHyRFp6j=A%joo>Jk6om;p9!39g~9J%&zbevD!Xv?*+a7snrWr1Cj zGkf8zSedUK^3bu_1}v`3jHp@JT|?egDP+=Y&;I+{@(W@TvXgxEB3J+b002ovPDHLk FV1jr5#Nz+} literal 0 HcmV?d00001 diff --git a/webroot/rsrc/image/button_apps.png b/webroot/rsrc/image/button_apps.png new file mode 100644 index 0000000000000000000000000000000000000000..ff13f2866e9978ce965a2d4300b91d7bd67da188 GIT binary patch literal 463 zcmV;=0WkiFP)nfJ4tA~ruLJFX>p(l81WTXyWtTKYABI+!N5eOzhd^wFM802T51$Kp$jpYzqX_O$o+fSmFGVj!nE%{hNx8b3R=JiCR1@5XUs`>%k-wgf+cAMs-e~ve)(i;NT2)|98LG#c6 zM>2Vi#CzbvQ_qHyRFp6j=A%joo>Jk6om;p9!39g~9J%&zbevD!Xv?*+a7snrWr1Cj zGkf8zSedUK^3bu_1}v`3jHp@JT|?egDP+=Y&;I+{@(W@TvXgxEB3J+b002ovPDHLk FV1jr5#Nz+} literal 0 HcmV?d00001 diff --git a/webroot/rsrc/image/button_content.png b/webroot/rsrc/image/button_content.png new file mode 100755 index 0000000000000000000000000000000000000000..3ae1bf4fc98578f3de2361ce068fe35b536c0890 GIT binary patch literal 326 zcmV-M0lEH(P)_0S_CQbSeBrucklXq*#ylG+5)*%OI zMmd0MmRSPo1Q4g0C16qj@u1wUE5Mr&K;p{=imC;W4b&Hb3O3CG2{b~|ERaDXz->Buxs4|QaoRCS9c0Y@p2q933YSe`Pgs?Et8nMcMyr$0=#%GF-(B$ zpOvK?PJ6FVq17GCvHzk;$}GEr0}&z(!6WMFP^@6SNyA@MQYV7eE4ez6*$C zPYe)XUFZDnB1oJiz`M>x{IyOQCGhNeKPNZ_2#~JNg$t0bn-Hk$%;PEFJ1FWChaQNce`iZ_S5W*Z#Wp4