diff --git a/resources/sprite/manifest/gradient.json b/resources/sprite/manifest/gradient.json index ab96d12c96..c050f77f36 100644 --- a/resources/sprite/manifest/gradient.json +++ b/resources/sprite/manifest/gradient.json @@ -28,7 +28,7 @@ }, "gradient-dark-menu-label" : { "name" : "gradient-dark-menu-label", - "rule" : ".gradient-dark-menu-label", + "rule" : ".gradient-dark-menu-label, .phabricator-dark-menu .phabricator-menu-item-type-label", "hash" : "89a908596142d38fbe61a706694cd321" }, "gradient-green-dark" : { @@ -55,6 +55,6 @@ "scales" : [ 1 ], - "header" : "\/**\n * @provides sprite-gradient-css\n * @generated\n *\/\n\n.sprite-gradient, button, a.button, a.button:visited, input.inputsubmit {\n background-image: url(\/rsrc\/image\/sprite-gradient.png);\n background-repeat: repeat-x;\n}\n\n@media\nonly screen and (min-device-pixel-ratio: 1.5),\nonly screen and (-webkit-min-device-pixel-ratio: 1.5) {\n .sprite-gradient, button, a.button, a.button:visited, input.inputsubmit {\n background-image: url(\/rsrc\/image\/sprite-gradient-X2.png);\n background-size: {X}px {Y}px;\n }\n}", + "header" : "\/**\n * @provides sprite-gradient-css\n * @generated\n *\/\n\n.sprite-gradient, button, a.button, a.button:visited, input.inputsubmit, .phabricator-dark-menu .phabricator-menu-item-type-label {\n background-image: url(\/rsrc\/image\/sprite-gradient.png);\n background-repeat: repeat-x;\n}\n\n@media\nonly screen and (min-device-pixel-ratio: 1.5),\nonly screen and (-webkit-min-device-pixel-ratio: 1.5) {\n .sprite-gradient, button, a.button, a.button:visited, input.inputsubmit, .phabricator-dark-menu .phabricator-menu-item-type-label {\n background-image: url(\/rsrc\/image\/sprite-gradient-X2.png);\n background-size: {X}px {Y}px;\n }\n}", "type" : "repeat-x" } diff --git a/resources/sprite/manifest/menu.json b/resources/sprite/manifest/menu.json index 75c4747934..e008dc5386 100644 --- a/resources/sprite/manifest/menu.json +++ b/resources/sprite/manifest/menu.json @@ -1,6 +1,11 @@ { "version" : 1, "sprites" : { + "app" : { + "name" : "app", + "rule" : ".menu-icon-app", + "hash" : "a389f99d9c00f688e625da71579ee90a" + }, "arrow-right" : { "name" : "arrow-right", "rule" : ".phabricator-crumb-divider", @@ -11,6 +16,11 @@ "rule" : ".phabricator-main-menu-alert-bubble.alert-unread", "hash" : "1145ac8a137a2a22517c1945fe22c517" }, + "eye" : { + "name" : "eye", + "rule" : ".menu-icon-eye", + "hash" : "d598b1acb1933a86eaed3dea3347f7b0" + }, "round_bubble" : { "name" : "round_bubble", "rule" : ".phabricator-main-menu-alert-bubble", diff --git a/resources/sprite/menu_1x/app.png b/resources/sprite/menu_1x/app.png new file mode 100644 index 0000000000..c395e306af Binary files /dev/null and b/resources/sprite/menu_1x/app.png differ diff --git a/resources/sprite/menu_1x/eye.png b/resources/sprite/menu_1x/eye.png new file mode 100644 index 0000000000..a1ccfe2bfd Binary files /dev/null and b/resources/sprite/menu_1x/eye.png differ diff --git a/resources/sprite/menu_2x/app.png b/resources/sprite/menu_2x/app.png new file mode 100644 index 0000000000..f59dc10f14 Binary files /dev/null and b/resources/sprite/menu_2x/app.png differ diff --git a/resources/sprite/menu_2x/eye.png b/resources/sprite/menu_2x/eye.png new file mode 100644 index 0000000000..702d2ca457 Binary files /dev/null and b/resources/sprite/menu_2x/eye.png differ diff --git a/scripts/celerity/generate_sprites.php b/scripts/celerity/generate_sprites.php index a395d5b76e..38b027a2fb 100755 --- a/scripts/celerity/generate_sprites.php +++ b/scripts/celerity/generate_sprites.php @@ -204,6 +204,16 @@ $sheets = array( 'gradient' => $generator->buildGradientSheet(), ); +list($err) = exec_manual('optipng'); +if ($err) { + $have_optipng = false; + echo phutil_console_format( + " WARNING `optipng` not found in PATH.\n". + "Sprites will not be optimized! Install `optipng`!\n"); +} else { + $have_optipng = true; +} + foreach ($sheets as $name => $sheet) { $manifest_path = $root.'/resources/sprite/manifest/'.$name.'.json'; if (!$args->getArg('force')) { @@ -226,7 +236,14 @@ foreach ($sheets as $name => $sheet) { } else { $sheet_name = "sprite-{$name}-X{$scale}.png"; } - $sheet->generateImage("{$webroot}/image/{$sheet_name}", $scale); + + $full_path = "{$webroot}/image/{$sheet_name}"; + $sheet->generateImage($full_path, $scale); + + if ($have_optipng) { + echo "Optimizing...\n"; + phutil_passthru('optipng -o7 -clobber %s', $full_path); + } } } diff --git a/src/infrastructure/celerity/CeleritySpriteGenerator.php b/src/infrastructure/celerity/CeleritySpriteGenerator.php index 4d88b69c99..fe2033efae 100644 --- a/src/infrastructure/celerity/CeleritySpriteGenerator.php +++ b/src/infrastructure/celerity/CeleritySpriteGenerator.php @@ -113,6 +113,16 @@ final class CeleritySpriteGenerator { 'y' => 31, 'css' => '.phabricator-crumb-divider', ), + 'eye' => array( + 'x' => 24, + 'y' => 20, + 'css' => '.menu-icon-eye', + ), + 'app' => array( + 'x' => 24, + 'y' => 20, + 'css' => '.menu-icon-app', + ), ); $scales = array( @@ -177,6 +187,8 @@ final class CeleritySpriteGenerator { 'button.grey_active, a.dropdown-open', 'green-dark' => ', button.green, a.green, a.green:visited', 'green-light' => ', button.green:active, a.green:active', + 'dark-menu-label' + => ', .phabricator-dark-menu .phabricator-menu-item-type-label', ); $sprites = array(); @@ -195,7 +207,8 @@ final class CeleritySpriteGenerator { $sheet = $this->buildSheet( 'gradient', PhutilSpriteSheet::TYPE_REPEAT_X, - ', button, a.button, a.button:visited, input.inputsubmit'); + ', button, a.button, a.button:visited, input.inputsubmit, '. + '.phabricator-dark-menu .phabricator-menu-item-type-label'); foreach ($sprites as $sprite) { $sheet->addSprite($sprite); } diff --git a/src/view/page/menu/PhabricatorMainMenuView.php b/src/view/page/menu/PhabricatorMainMenuView.php index a833960e4d..f9059dc28f 100644 --- a/src/view/page/menu/PhabricatorMainMenuView.php +++ b/src/view/page/menu/PhabricatorMainMenuView.php @@ -7,7 +7,6 @@ final class PhabricatorMainMenuView extends AphrontView { private $controller; private $applicationMenu; - public function setApplicationMenu(PhabricatorMenuView $application_menu) { $this->applicationMenu = $application_menu; return $this; @@ -110,7 +109,9 @@ final class PhabricatorMainMenuView extends AphrontView { self::renderSingleView( array( $this->renderPhabricatorMenuButton($header_id), - $this->renderApplicationMenuButton($header_id), + $application_menu + ? $this->renderApplicationMenuButton($header_id) + : null, $this->renderPhabricatorLogo(), $alerts, $phabricator_menu, @@ -164,7 +165,12 @@ final class PhabricatorMainMenuView extends AphrontView { ), ), ), - ''); + phutil_render_tag( + 'span', + array( + 'class' => 'phabricator-menu-button-icon sprite-menu menu-icon-eye', + ), + '')); } public function renderApplicationMenuButton($header_id) { @@ -180,7 +186,12 @@ final class PhabricatorMainMenuView extends AphrontView { ), ), ), - ''); + phutil_render_tag( + 'span', + array( + 'class' => 'phabricator-menu-button-icon sprite-menu menu-icon-app', + ), + '')); } private function renderPhabricatorMenu() { @@ -221,6 +232,23 @@ final class PhabricatorMainMenuView extends AphrontView { $search = $this->renderSearch(); $view->appendChild($search); + $view + ->newLabel(pht('Home')) + ->addClass('phabricator-core-item-device'); + $view->addMenuItem( + id(new PhabricatorMenuItemView()) + ->addClass('phabricator-core-item-device') + ->setName(pht('Phabricator Home')) + ->setHref('/')); + if ($controller->getCurrentApplication()) { + $application = $controller->getCurrentApplication(); + $view->addMenuItem( + id(new PhabricatorMenuItemView()) + ->addClass('phabricator-core-item-device') + ->setName(pht('%s Home', $application->getName())) + ->setHref($controller->getApplicationURI())); + } + if ($core) { $view->addMenuItem( id(new PhabricatorMenuItemView()) diff --git a/webroot/rsrc/css/application/base/main-menu-view.css b/webroot/rsrc/css/application/base/main-menu-view.css index 2e7de7a188..035eb5636c 100644 --- a/webroot/rsrc/css/application/base/main-menu-view.css +++ b/webroot/rsrc/css/application/base/main-menu-view.css @@ -1,4 +1,4 @@ -/** +<<