@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator

Improve desktop and mobile layouts for new "CommitGridView"

Summary:
Ref T13552. The current layout doesn't work particularly well on desktops or devices.

We have some device/desktop table layout code, but it isn't generic. We also have property list layout code, but it isn't generic either.

Provide generic layout elements ("Fuel", from "Phabricator UI Layout" to "PHUIL"?) and narrowly specialize their display behavior. Then swap the ListItemView stuff to use it.

Test Plan:
Saw slightly better responsive behavior:

{F7637457}

Maniphest Tasks: T13552

Differential Revision: https://secure.phabricator.com/D21418

+392 -20
+4
resources/celerity/map.php
··· 121 121 'rsrc/css/font/font-awesome.css' => '3883938a', 122 122 'rsrc/css/font/font-lato.css' => '23631304', 123 123 'rsrc/css/font/phui-font-icon-base.css' => '303c9b87', 124 + 'rsrc/css/fuel/fuel-grid.css' => 'd87031e7', 125 + 'rsrc/css/fuel/fuel-map.css' => 'd6e31510', 124 126 'rsrc/css/layout/phabricator-source-code-view.css' => '03d7ac28', 125 127 'rsrc/css/phui/button/phui-button-bar.css' => 'a4aa75c4', 126 128 'rsrc/css/phui/button/phui-button-simple.css' => '1ff278aa', ··· 574 576 'diviner-shared-css' => '4bd263b0', 575 577 'font-fontawesome' => '3883938a', 576 578 'font-lato' => '23631304', 579 + 'fuel-grid-css' => 'd87031e7', 580 + 'fuel-map-css' => 'd6e31510', 577 581 'global-drag-and-drop-css' => '1d2713a4', 578 582 'harbormaster-css' => '8dfe16b2', 579 583 'herald-css' => '648d39e2',
+14
src/__phutil_library_map__.php
··· 1305 1305 'FlagDeleteConduitAPIMethod' => 'applications/flag/conduit/FlagDeleteConduitAPIMethod.php', 1306 1306 'FlagEditConduitAPIMethod' => 'applications/flag/conduit/FlagEditConduitAPIMethod.php', 1307 1307 'FlagQueryConduitAPIMethod' => 'applications/flag/conduit/FlagQueryConduitAPIMethod.php', 1308 + 'FuelComponentView' => 'view/fuel/FuelComponentView.php', 1309 + 'FuelGridCellView' => 'view/fuel/FuelGridCellView.php', 1310 + 'FuelGridRowView' => 'view/fuel/FuelGridRowView.php', 1311 + 'FuelGridView' => 'view/fuel/FuelGridView.php', 1312 + 'FuelMapItemView' => 'view/fuel/FuelMapItemView.php', 1313 + 'FuelMapView' => 'view/fuel/FuelMapView.php', 1314 + 'FuelView' => 'view/fuel/FuelView.php', 1308 1315 'FundBacker' => 'applications/fund/storage/FundBacker.php', 1309 1316 'FundBackerCart' => 'applications/fund/phortune/FundBackerCart.php', 1310 1317 'FundBackerEditor' => 'applications/fund/editor/FundBackerEditor.php', ··· 7439 7446 'FlagDeleteConduitAPIMethod' => 'FlagConduitAPIMethod', 7440 7447 'FlagEditConduitAPIMethod' => 'FlagConduitAPIMethod', 7441 7448 'FlagQueryConduitAPIMethod' => 'FlagConduitAPIMethod', 7449 + 'FuelComponentView' => 'FuelView', 7450 + 'FuelGridCellView' => 'FuelView', 7451 + 'FuelGridRowView' => 'FuelView', 7452 + 'FuelGridView' => 'FuelComponentView', 7453 + 'FuelMapItemView' => 'AphrontView', 7454 + 'FuelMapView' => 'FuelComponentView', 7455 + 'FuelView' => 'AphrontView', 7442 7456 'FundBacker' => array( 7443 7457 'FundDAO', 7444 7458 'PhabricatorPolicyInterface',
+11 -9
src/applications/diffusion/view/DiffusionCommitGraphView.php
··· 164 164 $this->addAuditAction($item_view, $hash); 165 165 166 166 if ($show_auditors) { 167 - $auditor_list = $item_view->newPropertyList(); 167 + $auditor_list = $item_view->newMapView(); 168 168 if ($commit) { 169 169 $auditors = $this->newAuditorList($commit, $handles); 170 - $auditor_list->addProperty(pht('Auditors'), $auditors); 170 + $auditor_list->newItem() 171 + ->setName(pht('Auditors')) 172 + ->setValue($auditors); 171 173 } 172 174 } 173 175 174 - $property_list = $item_view->newPropertyList(); 176 + $property_list = $item_view->newMapView(); 175 177 176 178 if ($commit) { 177 179 $author_view = $this->getCommitAuthorView($commit); 178 180 if ($author_view) { 179 - $property_list->addProperty( 180 - pht('Author'), 181 - $this->getCommitAuthorView($commit)); 181 + $property_list->newItem() 182 + ->setName(pht('Author')) 183 + ->setValue($author_view); 182 184 } 183 185 } 184 186 ··· 189 191 $revision = head($revisions); 190 192 $handle = $handles[$revision->getPHID()]; 191 193 192 - $property_list->addProperty( 193 - pht('Revision'), 194 - $handle->renderLink()); 194 + $property_list->newItem() 195 + ->setName(pht('Revision')) 196 + ->setValue($handle->renderLink()); 195 197 } 196 198 } 197 199 }
+35
src/view/fuel/FuelComponentView.php
··· 1 + <?php 2 + 3 + abstract class FuelComponentView 4 + extends FuelView { 5 + 6 + private $classes = array(); 7 + 8 + final public function addClass($class) { 9 + $this->classes[] = $class; 10 + return $this; 11 + } 12 + 13 + private function getClasses() { 14 + return $this->classes; 15 + } 16 + 17 + final protected function newComponentTag( 18 + $tag, 19 + array $attributes, 20 + $content) { 21 + 22 + $classes = $this->getClasses(); 23 + if (isset($attributes['class'])) { 24 + $classes[] = $attributes['class']; 25 + } 26 + 27 + if ($classes) { 28 + $classes = implode(' ', $classes); 29 + $attributes['class'] = $classes; 30 + } 31 + 32 + return javelin_tag($tag, $attributes, $content); 33 + } 34 + 35 + }
+28
src/view/fuel/FuelGridCellView.php
··· 1 + <?php 2 + 3 + final class FuelGridCellView 4 + extends FuelView { 5 + 6 + private $content; 7 + 8 + public function setContent($content) { 9 + $this->content = $content; 10 + return $this; 11 + } 12 + 13 + public function getContent() { 14 + return $this->content; 15 + } 16 + 17 + public function render() { 18 + $content = $this->getContent(); 19 + 20 + return phutil_tag( 21 + 'div', 22 + array( 23 + 'class' => 'fuel-grid-cell', 24 + ), 25 + $content); 26 + } 27 + 28 + }
+32
src/view/fuel/FuelGridRowView.php
··· 1 + <?php 2 + 3 + final class FuelGridRowView 4 + extends FuelView { 5 + 6 + private $cells = array(); 7 + 8 + public function newCell() { 9 + $cell = new FuelGridCellView(); 10 + $this->cells[] = $cell; 11 + return $cell; 12 + } 13 + 14 + public function render() { 15 + $cells = $this->cells; 16 + 17 + $classes = array(); 18 + $classes[] = 'fuel-grid-row'; 19 + 20 + $classes[] = sprintf( 21 + 'fuel-grid-cell-count-%d', 22 + count($cells)); 23 + 24 + return phutil_tag( 25 + 'div', 26 + array( 27 + 'class' => implode(' ', $classes), 28 + ), 29 + $cells); 30 + } 31 + 32 + }
+41
src/view/fuel/FuelGridView.php
··· 1 + <?php 2 + 3 + final class FuelGridView 4 + extends FuelComponentView { 5 + 6 + private $rows = array(); 7 + 8 + public function newRow() { 9 + $row = new FuelGridRowView(); 10 + $this->rows[] = $row; 11 + return $row; 12 + } 13 + 14 + public function render() { 15 + require_celerity_resource('fuel-grid-css'); 16 + 17 + $rows = $this->rows; 18 + 19 + $body = phutil_tag( 20 + 'div', 21 + array( 22 + 'class' => 'fuel-grid-body', 23 + ), 24 + $rows); 25 + 26 + $grid = phutil_tag( 27 + 'div', 28 + array( 29 + 'class' => 'fuel-grid', 30 + ), 31 + $body); 32 + 33 + return $this->newComponentTag( 34 + 'div', 35 + array( 36 + 'class' => 'fuel-grid-component', 37 + ), 38 + $grid); 39 + } 40 + 41 + }
+54
src/view/fuel/FuelMapItemView.php
··· 1 + <?php 2 + 3 + final class FuelMapItemView 4 + extends AphrontView { 5 + 6 + private $name; 7 + private $value; 8 + 9 + public function setName($name) { 10 + $this->name = $name; 11 + return $this; 12 + } 13 + 14 + public function getName() { 15 + return $this->name; 16 + } 17 + 18 + public function setValue($value) { 19 + $this->value = $value; 20 + return $this; 21 + } 22 + 23 + public function getValue() { 24 + return $this->value; 25 + } 26 + 27 + public function render() { 28 + $value = $this->getValue(); 29 + 30 + $view = array(); 31 + 32 + $view[] = phutil_tag( 33 + 'div', 34 + array( 35 + 'class' => 'fuel-map-name', 36 + ), 37 + $this->getName()); 38 + 39 + $view[] = phutil_tag( 40 + 'div', 41 + array( 42 + 'class' => 'fuel-map-value', 43 + ), 44 + $value); 45 + 46 + return phutil_tag( 47 + 'div', 48 + array( 49 + 'class' => 'fuel-map-pair', 50 + ), 51 + $view); 52 + } 53 + 54 + }
+45
src/view/fuel/FuelMapView.php
··· 1 + <?php 2 + 3 + final class FuelMapView 4 + extends FuelComponentView { 5 + 6 + private $items = array(); 7 + 8 + public function newItem() { 9 + $item = new FuelMapItemView(); 10 + $this->items[] = $item; 11 + return $item; 12 + } 13 + 14 + public function render() { 15 + require_celerity_resource('fuel-map-css'); 16 + 17 + $items = $this->items; 18 + 19 + if (!$items) { 20 + return null; 21 + } 22 + 23 + $body = phutil_tag( 24 + 'div', 25 + array( 26 + 'class' => 'fuel-map-items', 27 + ), 28 + $items); 29 + 30 + $map = phutil_tag( 31 + 'div', 32 + array( 33 + 'class' => 'fuel-map', 34 + ), 35 + $body); 36 + 37 + return $this->newComponentTag( 38 + 'div', 39 + array( 40 + 'class' => 'fuel-map-component', 41 + ), 42 + $map); 43 + } 44 + 45 + }
+10
src/view/fuel/FuelView.php
··· 1 + <?php 2 + 3 + abstract class FuelView 4 + extends AphrontView { 5 + 6 + final protected function canAppendChild() { 7 + return false; 8 + } 9 + 10 + }
+18 -11
src/view/phui/PHUIObjectItemView.php
··· 30 30 private $coverImage; 31 31 private $description; 32 32 private $clickable; 33 - private $propertyLists = array(); 33 + private $mapViews = array(); 34 34 35 35 private $selectableName; 36 36 private $selectableValue; ··· 220 220 return $action; 221 221 } 222 222 223 - public function newPropertyList() { 224 - $list = new PHUIPropertyListView(); 225 - $this->propertyLists[] = $list; 223 + public function newMapView() { 224 + $list = id(new FuelMapView()) 225 + ->addClass('fuel-map-property-list'); 226 + $this->mapViews[] = $list; 226 227 return $list; 227 228 } 228 229 ··· 612 613 ''); 613 614 } 614 615 615 - $property_lists = null; 616 - if ($this->propertyLists) { 617 - $property_lists[] = phutil_tag( 618 - 'div', 619 - array(), 620 - $this->propertyLists); 616 + $map_views = null; 617 + if ($this->mapViews) { 618 + $grid = id(new FuelGridView()) 619 + ->addClass('fuel-grid-property-list'); 620 + 621 + $row = $grid->newRow(); 622 + foreach ($this->mapViews as $map_view) { 623 + $row->newCell() 624 + ->setContent($map_view); 625 + } 626 + 627 + $map_views = $grid; 621 628 } 622 629 623 630 $content = phutil_tag( ··· 628 635 array( 629 636 $subhead, 630 637 $attrs, 631 - $property_lists, 638 + $map_views, 632 639 $this->renderChildren(), 633 640 )); 634 641
+29
webroot/rsrc/css/fuel/fuel-grid.css
··· 1 + /** 2 + * @provides fuel-grid-css 3 + */ 4 + 5 + .device-desktop .fuel-grid { 6 + display: table; 7 + table-layout: fixed; 8 + } 9 + 10 + .device-desktop .fuel-grid-body { 11 + display: table-row-group; 12 + } 13 + 14 + .device-desktop .fuel-grid-row { 15 + display: table-row; 16 + } 17 + 18 + .device-desktop .fuel-grid-cell { 19 + display: table-cell; 20 + vertical-align: top; 21 + } 22 + 23 + .device-desktop .fuel-grid-cell-count-2 > .fuel-grid-cell { 24 + width: 50%; 25 + } 26 + 27 + .fuel-grid-property-list > .fuel-grid { 28 + width: 100%; 29 + }
+71
webroot/rsrc/css/fuel/fuel-map.css
··· 1 + /** 2 + * @provides fuel-map-css 3 + */ 4 + 5 + .device-desktop .fuel-map { 6 + display: table; 7 + table-layout: fixed; 8 + } 9 + 10 + .device-desktop .fuel-map-items { 11 + display: table-row-group; 12 + } 13 + 14 + .device-desktop .fuel-map-pair { 15 + display: table-row; 16 + } 17 + 18 + .device-desktop .fuel-map-name, 19 + .device-desktop .fuel-map-value { 20 + display: table-cell; 21 + vertical-align: top; 22 + } 23 + 24 + .fuel-map-property-list { 25 + margin: 4px; 26 + } 27 + 28 + .fuel-map-property-list > .fuel-map { 29 + overflow: hidden; 30 + width: 100%; 31 + max-width: 100%; 32 + } 33 + 34 + .fuel-map-property-list > .fuel-map > .fuel-map-items > .fuel-map-pair > 35 + .fuel-map-name, 36 + .fuel-map-property-list > .fuel-map > .fuel-map-items > .fuel-map-pair > 37 + .fuel-map-value { 38 + padding: 2px 4px; 39 + white-space: nowrap; 40 + } 41 + 42 + .fuel-map-property-list > .fuel-map > .fuel-map-items > .fuel-map-pair > 43 + .fuel-map-name { 44 + color: {$bluetext}; 45 + } 46 + 47 + .fuel-map-property-list > .fuel-map > .fuel-map-items > .fuel-map-pair > 48 + .fuel-map-value { 49 + color: {$lightgreytext}; 50 + } 51 + 52 + .device-desktop 53 + .fuel-map-property-list > .fuel-map > .fuel-map-items > .fuel-map-pair > 54 + .fuel-map-name { 55 + text-align: right; 56 + min-width: 80px; 57 + width: 80px; 58 + } 59 + 60 + .device-desktop 61 + .fuel-map-property-list > .fuel-map > .fuel-map-items > .fuel-map-pair > 62 + .fuel-map-value { 63 + text-overflow: ellipsis; 64 + overflow: hidden; 65 + } 66 + 67 + .device 68 + .fuel-map-property-list > .fuel-map > .fuel-map-items > .fuel-map-pair > 69 + .fuel-map-value { 70 + padding-left: 12px; 71 + }