diff --git a/resources/sprite/gradients/dark-menu-label.png b/resources/sprite/gradients/dark-menu-label.png deleted file mode 100644 index 30f94c868a..0000000000 Binary files a/resources/sprite/gradients/dark-menu-label.png and /dev/null differ diff --git a/resources/sprite/gradients/menu-label.png b/resources/sprite/gradients/menu-label.png deleted file mode 100644 index 263b7021ca..0000000000 Binary files a/resources/sprite/gradients/menu-label.png and /dev/null differ diff --git a/resources/sprite/manifest/gradient.json b/resources/sprite/manifest/gradient.json index 4e66b3aa3b..f787402ac7 100644 --- a/resources/sprite/manifest/gradient.json +++ b/resources/sprite/manifest/gradient.json @@ -1,60 +1,50 @@ { "version" : 1, "sprites" : { "gradient-blue-header" : { "name" : "gradient-blue-header", "rule" : ".gradient-blue-header", "hash" : "bcfc1d3e93ea8585af5b5ca52b08e944" }, "gradient-breadcrumbs" : { "name" : "gradient-breadcrumbs", "rule" : ".gradient-breadcrumbs", "hash" : "ed46fe9544216513a3958900c688a808" }, "gradient-dark-grey-header" : { "name" : "gradient-dark-grey-header", "rule" : ".gradient-dark-grey-header", "hash" : "e8762dd2849410a7e4fba8f972f946ff" }, - "gradient-dark-menu-label" : { - "name" : "gradient-dark-menu-label", - "rule" : ".gradient-dark-menu-label, .phabricator-dark-menu .phui-list-item-type-label", - "hash" : "8a11efa454f788aa2419ed8c745dece2" - }, "gradient-green-header" : { "name" : "gradient-green-header", "rule" : ".gradient-green-header", "hash" : "848b563e846e187b688e899a9d838e40" }, "gradient-grey-header" : { "name" : "gradient-grey-header", "rule" : ".gradient-grey-header", "hash" : "1c8f8d61984e3fc5a7e528b9bd4d484a" }, "gradient-lightblue-header" : { "name" : "gradient-lightblue-header", "rule" : ".gradient-lightblue-header", "hash" : "e7753a6ce63c6822a559266eef9e255b" }, - "gradient-menu-label" : { - "name" : "gradient-menu-label", - "rule" : ".gradient-menu-label, .phabricator-side-menu .phui-list-item-type-label", - "hash" : "e2aa8e74c3b2c0b18de34d336d318b5c" - }, "gradient-red-header" : { "name" : "gradient-red-header", "rule" : ".gradient-red-header", "hash" : "070a2e01f611bfaf5207be25eebdd6f2" }, "gradient-yellow-header" : { "name" : "gradient-yellow-header", "rule" : ".gradient-yellow-header", "hash" : "166ee67c5201416cfa598c1eb86bf92a" } }, "scales" : [ 1 ], - "header" : "\/**\n * @provides sprite-gradient-css\n * @generated\n *\/\n\n.sprite-gradient, .phabricator-dark-menu .phui-list-item-type-label, .phabricator-side-menu .phui-list-item-type-label {\n background-image: url(\/rsrc\/image\/sprite-gradient.png);\n background-repeat: repeat-x;\n}\n\n\n", + "header" : "\/**\n * @provides sprite-gradient-css\n * @generated\n *\/\n\n.sprite-gradient {\n background-image: url(\/rsrc\/image\/sprite-gradient.png);\n background-repeat: repeat-x;\n}\n\n\n", "type" : "repeat-x" } diff --git a/src/applications/home/controller/PhabricatorHomeController.php b/src/applications/home/controller/PhabricatorHomeController.php index 561c673fa8..00f8bc386a 100644 --- a/src/applications/home/controller/PhabricatorHomeController.php +++ b/src/applications/home/controller/PhabricatorHomeController.php @@ -1,180 +1,176 @@ buildStandardPageView(); $page->setBaseURI('/'); $page->setTitle(idx($data, 'title')); $page->setGlyph("\xE2\x9A\x92"); $page->appendChild($view); $response = new AphrontWebpageResponse(); return $response->setContent($page->render()); } public function buildNav() { $user = $this->getRequest()->getUser(); $nav = new AphrontSideNavFilterView(); $nav->setBaseURI(new PhutilURI('/')); $applications = id(new PhabricatorApplicationQuery()) ->setViewer($user) ->withInstalled(true) ->withUnlisted(false) ->execute(); foreach ($applications as $key => $application) { if (!$application->shouldAppearInLaunchView()) { // Remove hidden applications (usually internal stuff). unset($applications[$key]); } $invisible = PhabricatorApplication::TILE_INVISIBLE; if ($application->getDefaultTileDisplay($user) == $invisible) { // Remove invisible applications (e.g., admin apps for non-admins). unset($applications[$key]); } } $status = array(); foreach ($applications as $key => $application) { $status[get_class($application)] = $application->loadStatus($user); } $tile_groups = array(); $prefs = $user->loadPreferences()->getPreference( PhabricatorUserPreferences::PREFERENCE_APP_TILES, array()); foreach ($applications as $key => $application) { $display = idx( $prefs, get_class($application), $application->getDefaultTileDisplay($user)); $tile_groups[$display][] = $application; } $tile_groups = array_select_keys( $tile_groups, array( PhabricatorApplication::TILE_FULL, PhabricatorApplication::TILE_SHOW, PhabricatorApplication::TILE_HIDE, )); foreach ($tile_groups as $tile_display => $tile_group) { if (!$tile_group) { continue; } $is_small_tiles = ($tile_display == PhabricatorApplication::TILE_SHOW) || ($tile_display == PhabricatorApplication::TILE_HIDE); if ($is_small_tiles) { $groups = PhabricatorApplication::getApplicationGroups(); $tile_group = mgroup($tile_group, 'getApplicationGroup'); $tile_group = array_select_keys($tile_group, array_keys($groups)); } else { $tile_group = array($tile_group); } $is_hide = ($tile_display == PhabricatorApplication::TILE_HIDE); if ($is_hide) { $show_item_id = celerity_generate_unique_node_id(); $hide_item_id = celerity_generate_unique_node_id(); $show_item = id(new PHUIListItemView()) ->setName(pht('Show More Applications')) ->setHref('#') ->addSigil('reveal-content') ->setID($show_item_id); $hide_item = id(new PHUIListItemView()) ->setName(pht('Show Fewer Applications')) ->setHref('#') ->setStyle('display: none') ->setID($hide_item_id) ->addSigil('reveal-content'); $nav->addMenuItem($show_item); $tile_ids = array($hide_item_id); } foreach ($tile_group as $group => $application_list) { $tiles = array(); foreach ($application_list as $key => $application) { $tile = id(new PhabricatorApplicationLaunchView()) ->setApplication($application) ->setApplicationStatus( idx($status, get_class($application), array())) ->setUser($user); - if ($tile_display == PhabricatorApplication::TILE_FULL) { - $tile->setFullWidth(true); - } - $tiles[] = $tile; } if ($is_small_tiles) { while (count($tiles) % 3) { $tiles[] = id(new PhabricatorApplicationLaunchView()); } $label = id(new PHUIListItemView()) ->setType(PHUIListItemView::TYPE_LABEL) ->setName($groups[$group]); if ($is_hide) { $label_id = celerity_generate_unique_node_id(); $attrs = array(); $label->setStyle('display: none;'); $label->setID($label_id); $tile_ids[] = $label_id; } $nav->addMenuItem($label); } $group_id = celerity_generate_unique_node_id(); $tile_ids[] = $group_id; $nav->addCustomBlock( phutil_tag( 'div', array( 'class' => 'application-tile-group', 'id' => $group_id, 'style' => ($is_hide ? 'display: none' : null), ), mpull($tiles, 'render'))); } if ($is_hide) { Javelin::initBehavior('phabricator-reveal-content'); $show_item->setMetadata( array( 'showIDs' => $tile_ids, 'hideIDs' => array($show_item_id), )); $hide_item->setMetadata( array( 'showIDs' => array($show_item_id), 'hideIDs' => $tile_ids, )); $nav->addMenuItem($hide_item); } } $nav->addFilter( '', pht('Customize Applications...'), '/settings/panel/home/'); $nav->addClass('phabricator-side-menu-home'); $nav->selectFilter(null); return $nav; } } diff --git a/src/applications/meta/view/PhabricatorApplicationLaunchView.php b/src/applications/meta/view/PhabricatorApplicationLaunchView.php index d40e9b482c..3c3f95c339 100644 --- a/src/applications/meta/view/PhabricatorApplicationLaunchView.php +++ b/src/applications/meta/view/PhabricatorApplicationLaunchView.php @@ -1,156 +1,140 @@ fullWidth = $full_width; - return $this; - } public function setApplication(PhabricatorApplication $application) { $this->application = $application; return $this; } public function setApplicationStatus(array $status) { $this->status = $status; return $this; } public function render() { $application = $this->application; require_celerity_resource('phabricator-application-launch-view-css'); require_celerity_resource('sprite-apps-large-css'); $content = array(); $icon = null; $create_button = null; if ($application) { $content[] = phutil_tag( 'span', array( 'class' => 'phabricator-application-launch-name', ), $application->getName()); if ($application->isBeta()) { $content[] = javelin_tag( 'span', array( 'aural' => false, 'class' => 'phabricator-application-beta', ), "\xCE\xB2"); } - if ($this->fullWidth) { - $content[] = phutil_tag( - 'span', - array( - 'class' => 'phabricator-application-launch-description', - ), - $application->getShortDescription()); - } + $content[] = phutil_tag( + 'span', + array( + 'class' => 'phabricator-application-launch-description', + ), + $application->getShortDescription()); $counts = array(); $text = array(); if ($this->status) { foreach ($this->status as $status) { $type = $status->getType(); $counts[$type] = idx($counts, $type, 0) + $status->getCount(); if ($status->getCount()) { $text[] = $status->getText(); } } } $attention = PhabricatorApplicationStatusView::TYPE_NEEDS_ATTENTION; $warning = PhabricatorApplicationStatusView::TYPE_WARNING; if (!empty($counts[$attention]) || !empty($counts[$warning])) { $count = idx($counts, $attention, 0); $count1 = $count2 = ''; if ($count > 0) { $count1 = phutil_tag( 'span', array( 'class' => 'phabricator-application-attention-count', ), $count); } if (!empty($counts[$warning])) { $count2 = phutil_tag( 'span', array( 'class' => 'phabricator-application-warning-count', ), $counts[$warning]); } Javelin::initBehavior('phabricator-tooltips'); $content[] = javelin_tag( 'span', array( 'sigil' => 'has-tooltip', 'meta' => array( 'tip' => implode("\n", $text), 'size' => 240, ), 'class' => 'phabricator-application-launch-attention', ), array($count1, $count2)); } $classes = array(); $classes[] = 'phabricator-application-launch-icon'; $styles = array(); if ($application->getIconURI()) { $styles[] = 'background-image: url('.$application->getIconURI().')'; } else { $icon = $application->getIconName(); $classes[] = 'sprite-apps-large'; - $classes[] = 'apps-'.$icon.'-light-large'; + $classes[] = 'apps-'.$icon.'-dark-large'; } $icon = phutil_tag( 'span', array( 'class' => implode(' ', $classes), 'style' => nonempty(implode('; ', $styles), null), ), ''); } $classes = array(); $classes[] = 'phabricator-application-launch-container'; - if ($this->fullWidth) { - $classes[] = 'application-tile-full'; - } - - $title = null; - if ($application && !$this->fullWidth) { - $title = $application->getShortDescription(); - } + $classes[] = 'application-tile-full'; $app_button = phutil_tag( $application ? 'a' : 'div', array( 'class' => implode(' ', $classes), 'href' => $application ? $application->getBaseURI() : null, - 'title' => $title, ), array( $icon, $content, )); return array($app_button, $create_button); } } diff --git a/src/infrastructure/celerity/CeleritySpriteGenerator.php b/src/infrastructure/celerity/CeleritySpriteGenerator.php index 24f875337d..9c62ae28ba 100644 --- a/src/infrastructure/celerity/CeleritySpriteGenerator.php +++ b/src/infrastructure/celerity/CeleritySpriteGenerator.php @@ -1,703 +1,692 @@ 1, '2x' => 2, ); $sprites = array(); $template = id(new PhutilSprite()) ->setSourceSize(14, 14); $remarkup_icons = $this->getDirectoryList('remarkup_1x'); foreach ($remarkup_icons as $icon) { $prefix = 'remarkup_'; // Strip 'text_' from these file names. $class_name = substr($icon, 5); if ($class_name == 'fullscreen_off') { $tcss = '.remarkup-control-fullscreen-mode .remarkup-assist-fullscreen'; } else { $tcss = '.remarkup-assist-'.$class_name; } $sprite = id(clone $template) ->setName('remarkup-assist-'.$icon) ->setTargetCSS($tcss); foreach ($scales as $scale_key => $scale) { $path = $this->getPath($prefix.$scale_key.'/'.$icon.'.png'); $sprite->setSourceFile($path, $scale); } $sprites[] = $sprite; } $sheet = $this->buildSheet('remarkup', true); $sheet->setScales($scales); foreach ($sprites as $sprite) { $sheet->addSprite($sprite); } return $sheet; } public function buildMiniconsSheet() { $icons = $this->getDirectoryList('minicons_white_1x'); $colors = array( 'white', 'dark', ); $scales = array( '1x' => 1, '2x' => 2, ); $template = id(new PhutilSprite()) ->setSourceSize(16, 16); $sprites = array(); foreach ($colors as $color) { foreach ($icons as $icon) { $prefix = 'minicons_'; if (strlen($color)) { $prefix .= $color.'_'; } $suffix = ''; if (strlen($color)) { $suffix = '-'.$color; } $sprite = id(clone $template) ->setName('minicons-'.$icon.$suffix); $sprite->setTargetCSS('.minicons-'.$icon.$suffix); foreach ($scales as $scale_key => $scale) { $path = $this->getPath($prefix.$scale_key.'/'.$icon.'.png'); $sprite->setSourceFile($path, $scale); } $sprites[] = $sprite; } } $sheet = $this->buildSheet('minicons', true); $sheet->setScales($scales); foreach ($sprites as $sprite) { $sheet->addSprite($sprite); } return $sheet; } public function buildMenuSheet() { $sprites = array(); $sources = array( 'seen_read_all' => array( 'x' => 18, 'y' => 18, 'css' => '.alert-notifications .phabricator-main-menu-alert-icon', ), 'seen_have_unread' => array( 'x' => 18, 'y' => 18, 'css' => '.alert-notifications:hover .phabricator-main-menu-alert-icon', ), 'unseen_any' => array( 'x' => 18, 'y' => 18, 'css' => '.alert-notifications.alert-unread .phabricator-main-menu-alert-icon', ), 'arrow-right' => array( 'x' => 9, 'y' => 31, 'css' => '.phabricator-crumb-divider', ), 'search' => array( 'x' => 24, 'y' => 24, 'css' => '.menu-icon-search', ), 'search_blue' => array( 'x' => 24, 'y' => 24, 'css' => '.menu-icon-search-blue', ), 'new' => array( 'x' => 24, 'y' => 24, 'css' => '.menu-icon-new', ), 'new_blue' => array( 'x' => 24, 'y' => 24, 'css' => '.menu-icon-new-blue', ), 'app' => array( 'x' => 24, 'y' => 24, 'css' => '.menu-icon-app', ), 'app_blue' => array( 'x' => 24, 'y' => 24, 'css' => '.menu-icon-app-blue', ), 'logo' => array( 'x' => 149, 'y' => 26, 'css' => '.phabricator-main-menu-logo-image', ), 'conf-off' => array( 'x' => 18, 'y' => 18, 'css' => '.alert-notifications .phabricator-main-menu-message-icon', ), 'conf-hover' => array( 'x' => 18, 'y' => 18, 'css' => '.alert-notifications:hover .phabricator-main-menu-message-icon', ), 'conf-unseen' => array( 'x' => 18, 'y' => 18, 'css' => '.alert-notifications.message-unread '. '.phabricator-main-menu-message-icon', ), ); $scales = array( '1x' => 1, '2x' => 2, ); $template = new PhutilSprite(); foreach ($sources as $name => $spec) { $sprite = id(clone $template) ->setName($name) ->setSourceSize($spec['x'], $spec['y']) ->setTargetCSS($spec['css']); foreach ($scales as $scale_name => $scale) { $path = 'menu_'.$scale_name.'/'.$name.'.png'; $path = $this->getPath($path); $sprite->setSourceFile($path, $scale); } $sprites[] = $sprite; } $sheet = $this->buildSheet('menu', true); $sheet->setScales($scales); foreach ($sprites as $sprite) { $sheet->addSprite($sprite); } return $sheet; } public function buildTokenSheet() { $icons = $this->getDirectoryList('tokens_1x'); $scales = array( '1x' => 1, '2x' => 2, ); $template = id(new PhutilSprite()) ->setSourceSize(16, 16); $sprites = array(); $prefix = 'tokens_'; foreach ($icons as $icon) { $sprite = id(clone $template) ->setName('tokens-'.$icon) ->setTargetCSS('.tokens-'.$icon); foreach ($scales as $scale_key => $scale) { $path = $this->getPath($prefix.$scale_key.'/'.$icon.'.png'); $sprite->setSourceFile($path, $scale); } $sprites[] = $sprite; } $sheet = $this->buildSheet('tokens', true); $sheet->setScales($scales); foreach ($sprites as $sprite) { $sheet->addSprite($sprite); } return $sheet; } public function buildButtonBarSheet() { $icons = $this->getDirectoryList('button_bar_1x'); $scales = array( '1x' => 1, '2x' => 2, ); $template = id(new PhutilSprite()) ->setSourceSize(14, 14); $sprites = array(); $prefix = 'button_bar_'; foreach ($icons as $icon) { $sprite = id(clone $template) ->setName('buttonbar-'.$icon) ->setTargetCSS('.buttonbar-'.$icon); foreach ($scales as $scale_key => $scale) { $path = $this->getPath($prefix.$scale_key.'/'.$icon.'.png'); $sprite->setSourceFile($path, $scale); } $sprites[] = $sprite; } $sheet = $this->buildSheet('buttonbar', true); $sheet->setScales($scales); foreach ($sprites as $sprite) { $sheet->addSprite($sprite); } return $sheet; } public function buildProjectsSheet() { $icons = $this->getDirectoryList('projects_1x'); $scales = array( '1x' => 1, '2x' => 2, ); $template = id(new PhutilSprite()) ->setSourceSize(50, 50); $sprites = array(); $prefix = 'projects-'; foreach ($icons as $icon) { $sprite = id(clone $template) ->setName($prefix.$icon) ->setTargetCSS('.'.$prefix.$icon); foreach ($scales as $scale_key => $scale) { $path = $this->getPath('projects_'.$scale_key.'/'.$icon.'.png'); $sprite->setSourceFile($path, $scale); } $sprites[] = $sprite; } $sheet = $this->buildSheet('projects', true); $sheet->setScales($scales); foreach ($sprites as $sprite) { $sheet->addSprite($sprite); } return $sheet; } public function buildPaymentsSheet() { $icons = $this->getDirectoryList('payments_2x'); $scales = array( '2x' => 1, ); $template = id(new PhutilSprite()) ->setSourceSize(60, 32); $sprites = array(); $prefix = 'payments_'; foreach ($icons as $icon) { $sprite = id(clone $template) ->setName('payments-'.$icon) ->setTargetCSS('.payments-'.$icon); foreach ($scales as $scale_key => $scale) { $path = $this->getPath($prefix.$scale_key.'/'.$icon.'.png'); $sprite->setSourceFile($path, $scale); } $sprites[] = $sprite; } $sheet = $this->buildSheet('payments', true); $sheet->setScales($scales); foreach ($sprites as $sprite) { $sheet->addSprite($sprite); } return $sheet; } public function buildConpherenceSheet() { $name = 'conpherence'; $icons = $this->getDirectoryList($name.'_1x'); $scales = array( '1x' => 1, '2x' => 2, ); $template = id(new PhutilSprite()) ->setSourceSize(32, 32); $sprites = array(); foreach ($icons as $icon) { $color = preg_match('/_on/', $icon) ? 'on' : 'off'; $prefix = $name.'_'; $sprite = id(clone $template) ->setName($prefix.$icon); $tcss = array(); $tcss[] = '.'.$prefix.$icon; if ($color == 'on') { $class = str_replace('_on', '_off', $prefix.$icon); $tcss[] = '.device-desktop .'.$class.':hover '; } $sprite->setTargetCSS(implode(', ', $tcss)); foreach ($scales as $scale_key => $scale) { $path = $this->getPath($prefix.$scale_key.'/'.$icon.'.png'); $sprite->setSourceFile($path, $scale); } $sprites[] = $sprite; } $sheet = $this->buildSheet($name, true); $sheet->setScales($scales); foreach ($sprites as $sprite) { $sheet->addSprite($sprite); } return $sheet; } public function buildDocsSheet() { $icons = $this->getDirectoryList('docs_1x'); $scales = array( '1x' => 1, '2x' => 2, ); $template = id(new PhutilSprite()) ->setSourceSize(32, 32); $sprites = array(); $prefix = 'docs_'; foreach ($icons as $icon) { $sprite = id(clone $template) ->setName($prefix.$icon) ->setTargetCSS('.'.$prefix.$icon); foreach ($scales as $scale_key => $scale) { $path = $this->getPath($prefix.$scale_key.'/'.$icon.'.png'); $sprite->setSourceFile($path, $scale); } $sprites[] = $sprite; } $sheet = $this->buildSheet('docs', true); $sheet->setScales($scales); foreach ($sprites as $sprite) { $sheet->addSprite($sprite); } return $sheet; } public function buildLoginSheet() { $icons = $this->getDirectoryList('login_1x'); $scales = array( '1x' => 1, '2x' => 2, ); $template = id(new PhutilSprite()) ->setSourceSize(34, 34); $sprites = array(); $prefix = 'login_'; foreach ($icons as $icon) { $sprite = id(clone $template) ->setName('login-'.$icon) ->setTargetCSS('.login-'.$icon); foreach ($scales as $scale_key => $scale) { $path = $this->getPath($prefix.$scale_key.'/'.$icon.'.png'); $sprite->setSourceFile($path, $scale); } $sprites[] = $sprite; } $sheet = $this->buildSheet('login', true); $sheet->setScales($scales); foreach ($sprites as $sprite) { $sheet->addSprite($sprite); } return $sheet; } public function buildGradientSheet() { $gradients = $this->getDirectoryList('gradients'); $template = new PhutilSprite(); $unusual_heights = array( - 'dark-menu-label' => 25, 'breadcrumbs' => 31, - 'menu-label' => 24, 'red-header' => 70, 'blue-header' => 70, 'green-header' => 70, 'yellow-header' => 70, 'grey-header' => 70, 'dark-grey-header' => 70, 'lightblue-header' => 240, ); - $extra_css = array( - 'dark-menu-label' => - ', .phabricator-dark-menu .phui-list-item-type-label', - 'menu-label' => - ', .phabricator-side-menu .phui-list-item-type-label', - ); - $sprites = array(); foreach ($gradients as $gradient) { $path = $this->getPath('gradients/'.$gradient.'.png'); $sprite = id(clone $template) ->setName('gradient-'.$gradient) ->setSourceFile($path) - ->setTargetCSS('.gradient-'.$gradient.idx($extra_css, $gradient)); + ->setTargetCSS('.gradient-'.$gradient); $sprite->setSourceSize(4, idx($unusual_heights, $gradient, 26)); $sprites[] = $sprite; } $sheet = $this->buildSheet( 'gradient', false, - PhutilSpriteSheet::TYPE_REPEAT_X, - ', .phabricator-dark-menu .phui-list-item-type-label, '. - '.phabricator-side-menu .phui-list-item-type-label'); + PhutilSpriteSheet::TYPE_REPEAT_X); foreach ($sprites as $sprite) { $sheet->addSprite($sprite); } return $sheet; } public function buildMainHeaderSheet() { $gradients = $this->getDirectoryList('main_header'); $template = new PhutilSprite(); $sprites = array(); foreach ($gradients as $gradient) { $path = $this->getPath('main_header/'.$gradient.'.png'); $sprite = id(clone $template) ->setName('main-header-'.$gradient) ->setSourceFile($path) ->setTargetCSS('.main-header-'.$gradient); $sprite->setSourceSize(6, 44); $sprites[] = $sprite; } $sheet = $this->buildSheet('main-header', false, PhutilSpriteSheet::TYPE_REPEAT_X); foreach ($sprites as $sprite) { $sheet->addSprite($sprite); } return $sheet; } public function buildAppsSheet() { return $this->buildAppsSheetVariant(1); } public function buildAppsLargeSheet() { return $this->buildAppsSheetVariant(2); } public function buildAppsXLargeSheet() { return $this->buildAppsSheetVariant(3); } private function buildAppsSheetVariant($variant) { if ($variant == 1) { $scales = array( '1x' => 1, '2x' => 2, ); $variant_name = 'apps'; $variant_short = ''; $size_x = 14; $size_y = 14; $colors = array( 'dark' => 'dark', ); } else if ($variant == 2) { $scales = array( '2x' => 1, '4x' => 2, ); $variant_name = 'apps-large'; $variant_short = '-large'; $size_x = 28; $size_y = 28; $colors = array( 'light' => 'lb', 'dark' => 'dark', 'blue' => 'blue', ); } else { $scales = array( '4x' => 1, ); $variant_name = 'apps-xlarge'; $variant_short = '-xlarge'; $size_x = 56; $size_y = 56; $colors = array( 'dark' => 'dark', ); } $apps = $this->getDirectoryList('apps_dark_1x'); $template = id(new PhutilSprite()) ->setSourceSize($size_x, $size_y); $sprites = array(); foreach ($apps as $app) { foreach ($colors as $color => $color_path) { $css = '.apps-'.$app.'-'.$color.$variant_short; if ($color == 'blue' && $variant_name == 'apps-large') { $css .= ', .phabricator-crumb-view:hover .apps-'.$app.'-dark-large'; } $sprite = id(clone $template) ->setName('apps-'.$app.'-'.$color.$variant_short) ->setTargetCSS($css); foreach ($scales as $scale_name => $scale) { $path = $this->getPath( 'apps_'.$color_path.'_'.$scale_name.'/'.$app.'.png'); $sprite->setSourceFile($path, $scale); } $sprites[] = $sprite; } } $sheet = $this->buildSheet($variant_name, count($scales) > 1); $sheet->setScales($scales); foreach ($sprites as $sprite) { $sheet->addSprite($sprite); } return $sheet; } private function getPath($to_path = null) { $root = dirname(phutil_get_library_root('phabricator')); return $root.'/resources/sprite/'.$to_path; } private function getDirectoryList($dir) { $path = $this->getPath($dir); $result = array(); $images = Filesystem::listDirectory($path, $include_hidden = false); foreach ($images as $image) { if (!preg_match('/\.png$/', $image)) { throw new Exception( "Expected file '{$image}' in '{$path}' to be a sprite source ". "ending in '.png'."); } $result[] = substr($image, 0, -4); } return $result; } private function buildSheet( $name, $has_retina, $type = null, $extra_css = '') { $sheet = new PhutilSpriteSheet(); $at = '@'; switch ($type) { case PhutilSpriteSheet::TYPE_STANDARD: default: $type = PhutilSpriteSheet::TYPE_STANDARD; $repeat_rule = 'no-repeat'; break; case PhutilSpriteSheet::TYPE_REPEAT_X: $repeat_rule = 'repeat-x'; break; case PhutilSpriteSheet::TYPE_REPEAT_Y: $repeat_rule = 'repeat-y'; break; } $retina_rules = null; if ($has_retina) { $retina_rules = <<setSheetType($type); $sheet->setCSSHeader(<<