diff --git a/resources/celerity/map.php b/resources/celerity/map.php --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -93,6 +93,7 @@ 'rsrc/css/application/policy/policy-transaction-detail.css' => '82100a43', 'rsrc/css/application/policy/policy.css' => '957ea14c', 'rsrc/css/application/ponder/ponder-view.css' => '7b0df4da', + 'rsrc/css/application/project/project-card-view.css' => 'ee1ce91d', 'rsrc/css/application/project/project-view.css' => '99a5023b', 'rsrc/css/application/releeph/releeph-core.css' => '9b3c5733', 'rsrc/css/application/releeph/releeph-preview-branch.css' => 'b7a6f4a5', @@ -134,7 +135,7 @@ 'rsrc/css/phui/phui-form-view.css' => '4a1a0f5e', 'rsrc/css/phui/phui-form.css' => '0b98e572', 'rsrc/css/phui/phui-header-view.css' => 'd53cc835', - 'rsrc/css/phui/phui-hovercard.css' => '5684c081', + 'rsrc/css/phui/phui-hovercard.css' => 'de1a2119', 'rsrc/css/phui/phui-icon-set-selector.css' => '1ab67aad', 'rsrc/css/phui/phui-icon.css' => '3f33ab57', 'rsrc/css/phui/phui-image-mask.css' => '5a8b09c8', @@ -809,7 +810,7 @@ 'phui-form-view-css' => '4a1a0f5e', 'phui-header-view-css' => 'd53cc835', 'phui-hovercard' => '1bd28176', - 'phui-hovercard-view-css' => '5684c081', + 'phui-hovercard-view-css' => 'de1a2119', 'phui-icon-set-selector-css' => '1ab67aad', 'phui-icon-view-css' => '3f33ab57', 'phui-image-mask-css' => '5a8b09c8', @@ -843,6 +844,7 @@ 'policy-edit-css' => '815c66f7', 'policy-transaction-detail-css' => '82100a43', 'ponder-view-css' => '7b0df4da', + 'project-card-view-css' => 'ee1ce91d', 'project-view-css' => '99a5023b', 'releeph-core' => '9b3c5733', 'releeph-preview-branch' => 'b7a6f4a5', diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2862,6 +2862,7 @@ 'PhabricatorProjectBoardImportController' => 'applications/project/controller/PhabricatorProjectBoardImportController.php', 'PhabricatorProjectBoardReorderController' => 'applications/project/controller/PhabricatorProjectBoardReorderController.php', 'PhabricatorProjectBoardViewController' => 'applications/project/controller/PhabricatorProjectBoardViewController.php', + 'PhabricatorProjectCardView' => 'applications/project/view/PhabricatorProjectCardView.php', 'PhabricatorProjectColorsConfigOptionType' => 'applications/project/config/PhabricatorProjectColorsConfigOptionType.php', 'PhabricatorProjectColumn' => 'applications/project/storage/PhabricatorProjectColumn.php', 'PhabricatorProjectColumnDetailController' => 'applications/project/controller/PhabricatorProjectColumnDetailController.php', @@ -3816,6 +3817,7 @@ 'ProjectDefaultJoinCapability' => 'applications/project/capability/ProjectDefaultJoinCapability.php', 'ProjectDefaultViewCapability' => 'applications/project/capability/ProjectDefaultViewCapability.php', 'ProjectEditConduitAPIMethod' => 'applications/project/conduit/ProjectEditConduitAPIMethod.php', + 'ProjectHovercardEngineExtension' => 'applications/project/events/ProjectHovercardEngineExtension.php', 'ProjectQueryConduitAPIMethod' => 'applications/project/conduit/ProjectQueryConduitAPIMethod.php', 'ProjectRemarkupRule' => 'applications/project/remarkup/ProjectRemarkupRule.php', 'ProjectRemarkupRuleTestCase' => 'applications/project/remarkup/__tests__/ProjectRemarkupRuleTestCase.php', @@ -5672,7 +5674,7 @@ 'PHUIHandleView' => 'AphrontView', 'PHUIHeaderView' => 'AphrontTagView', 'PHUIHovercardUIExample' => 'PhabricatorUIExample', - 'PHUIHovercardView' => 'AphrontView', + 'PHUIHovercardView' => 'AphrontTagView', 'PHUIIconCircleView' => 'AphrontTagView', 'PHUIIconExample' => 'PhabricatorUIExample', 'PHUIIconView' => 'AphrontTagView', @@ -7272,6 +7274,7 @@ 'PhabricatorProjectBoardImportController' => 'PhabricatorProjectBoardController', 'PhabricatorProjectBoardReorderController' => 'PhabricatorProjectBoardController', 'PhabricatorProjectBoardViewController' => 'PhabricatorProjectBoardController', + 'PhabricatorProjectCardView' => 'AphrontTagView', 'PhabricatorProjectColorsConfigOptionType' => 'PhabricatorConfigJSONOptionType', 'PhabricatorProjectColumn' => array( 'PhabricatorProjectDAO', @@ -8449,6 +8452,7 @@ 'ProjectDefaultJoinCapability' => 'PhabricatorPolicyCapability', 'ProjectDefaultViewCapability' => 'PhabricatorPolicyCapability', 'ProjectEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', + 'ProjectHovercardEngineExtension' => 'PhabricatorHovercardEngineExtension', 'ProjectQueryConduitAPIMethod' => 'ProjectConduitAPIMethod', 'ProjectRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'ProjectRemarkupRuleTestCase' => 'PhabricatorTestCase', diff --git a/src/applications/project/events/ProjectHovercardEngineExtension.php b/src/applications/project/events/ProjectHovercardEngineExtension.php new file mode 100644 --- /dev/null +++ b/src/applications/project/events/ProjectHovercardEngineExtension.php @@ -0,0 +1,55 @@ +getViewer(); + $phids = mpull($objects, 'getPHID'); + + $projects = id(new PhabricatorProjectQuery()) + ->setViewer($viewer) + ->withPHIDs($phids) + ->needImages(true) + ->execute(); + $projects = mpull($projects, null, 'getPHID'); + + return array( + 'projects' => $projects, + ); + } + + public function renderHovercard( + PHUIHovercardView $hovercard, + PhabricatorObjectHandle $handle, + $object, + $data) { + $viewer = $this->getViewer(); + + $project = idx($data['projects'], $object->getPHID()); + if (!$project) { + return; + } + + $project_card = id(new PhabricatorProjectCardView()) + ->setProject($project) + ->setViewer($viewer); + + $hovercard->appendChild($project_card); + } + +} diff --git a/src/applications/project/view/PhabricatorProjectCardView.php b/src/applications/project/view/PhabricatorProjectCardView.php new file mode 100644 --- /dev/null +++ b/src/applications/project/view/PhabricatorProjectCardView.php @@ -0,0 +1,84 @@ +project = $project; + return $this; + } + + public function setViewer(PhabricatorUser $viewer) { + $this->viewer = $viewer; + return $this; + } + + public function setTag($tag) { + $this->tag = $tag; + return $this; + } + + protected function getTagName() { + if ($this->tag) { + return $this->tag; + } + return 'div'; + } + + protected function getTagAttributes() { + $classes = array(); + $classes[] = 'project-card-view'; + + $color = $this->project->getColor(); + $classes[] = 'project-card-'.$color; + + return array( + 'class' => implode($classes, ' '), + ); + } + + protected function getTagContent() { + + $project = $this->project; + $viewer = $this->viewer; + require_celerity_resource('project-card-view-css'); + + $icon = $project->getDisplayIconIcon(); + $icon_name = $project->getDisplayIconName(); + $tag = id(new PHUITagView()) + ->setIcon($icon) + ->setName($icon_name) + ->addClass('project-view-header-tag') + ->setType(PHUITagView::TYPE_SHADE); + + $header = id(new PHUIHeaderView()) + ->setHeader(array($project->getName(), $tag)) + ->setUser($viewer) + ->setPolicyObject($project) + ->setImage($project->getProfileImageURI()); + + if ($project->getStatus() == PhabricatorProjectStatus::STATUS_ACTIVE) { + $header->setStatus('fa-check', 'bluegrey', pht('Active')); + } else { + $header->setStatus('fa-ban', 'red', pht('Archived')); + } + + $description = null; + + $card = phutil_tag( + 'div', + array( + 'class' => 'project-card-inner', + ), + array( + $header, + $description, + )); + + return $card; + } + +} diff --git a/src/view/phui/PHUIHovercardView.php b/src/view/phui/PHUIHovercardView.php --- a/src/view/phui/PHUIHovercardView.php +++ b/src/view/phui/PHUIHovercardView.php @@ -4,7 +4,7 @@ * The default one-for-all hovercard. We may derive from this one to create * more specialized ones. */ -final class PHUIHovercardView extends AphrontView { +final class PHUIHovercardView extends AphrontTagView { /** * @var PhabricatorObjectHandle @@ -70,7 +70,16 @@ return $this; } - public function render() { + protected function getTagAttributes() { + $classes = array(); + $classes[] = 'phui-hovercard-wrapper'; + + return array( + 'class' => implode(' ', $classes), + ); + } + + protected function getTagContent() { if (!$this->handle) { throw new PhutilInvalidStateException('setObjectHandle'); } @@ -80,14 +89,17 @@ require_celerity_resource('phui-hovercard-view-css'); + // If we're a fully custom Hovercard, skip the common UI + $children = $this->renderChildren(); + if ($children) { + return $children; + } + $title = array( id(new PHUISpacesNamespaceContextView()) ->setUser($viewer) ->setObject($this->getObject()), - pht( - '%s: %s', - $handle->getTypeName(), - $this->title ? $this->title : $handle->getName()), + $this->title ? $this->title : $handle->getName(), ); $header = new PHUIHeaderView(); @@ -182,14 +194,14 @@ } $hovercard = phutil_tag_div( - 'phui-hovercard-container', + 'phui-hovercard-container grouped', array( phutil_tag_div('phui-hovercard-head', $header), phutil_tag_div('phui-hovercard-body grouped', $body), $tail, )); - return phutil_tag_div('phui-hovercard-wrapper', $hovercard); + return $hovercard; } } diff --git a/webroot/rsrc/css/application/project/project-card-view.css b/webroot/rsrc/css/application/project/project-card-view.css new file mode 100644 --- /dev/null +++ b/webroot/rsrc/css/application/project/project-card-view.css @@ -0,0 +1,150 @@ +/** + * @provides project-card-view-css + */ + +.project-card-view { + margin: 0 12px 16px 0; + text-align: left; + background: #fff; + border: 1px solid {$lightblueborder}; + border-radius: 3px; + box-shadow: {$dropshadow}; + width: 380px; +} + +.project-card-view .phui-header-shell { + margin: 0; + padding: 12px 12px 16px 12px; + border: none; + border-radius: 3px; +} + +.project-card-view .phui-header-shell .phui-header-image { + border: 3px solid #fff; + border-radius: 3px; +} + +.project-card-view .phui-header-shell .phui-header-header { + font-size: 18px; + font-family: 'Aleo', {$fontfamily}; + width: 290px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + display: block; +} + +.project-card-view .phui-header-shell .phui-header-col1 { + vertical-align: top; + width: 64px; +} + +.project-card-view .phui-header-subheader { + font-size: {$normalfontsize}; + margin-top: 12px; +} + +.project-card-view .phui-header-header .phui-tag-view { + display: block; + font-weight: normal; + color: {$bluetext}; + font-size: {$normalfontsize}; + font-family: {$fontfamily}; + margin-top: 8px; +} + +.project-card-view .phui-header-header .phui-tag-view .phui-tag-core { + padding: 0; +} + +.project-card-view .phui-header-header .phui-tag-view .phui-icon-view { + margin-left: 0; + color: {$bluetext}; +} + + +/* Colors */ + +.project-card-view.project-card-red { + border-color: {$sh-redborder}; +} + +.project-card-view.project-card-red .phui-header-shell { + background: linear-gradient(to bottom, {$sh-redbackground} 44px, #fff 44px); +} + +.project-card-view.project-card-orange { + border-color: {$sh-orangeborder}; +} + +.project-card-view.project-card-orange .phui-header-shell { + background: linear-gradient(to bottom, {$sh-orangebackground} 44px, #fff 44px); +} + +.project-card-view.project-card-yellow { + border-color: {$sh-yellowborder}; +} + +.project-card-view.project-card-yellow .phui-header-shell { + background: linear-gradient(to bottom, {$sh-yellowbackground} 44px, #fff 44px); +} + +.project-card-view.project-card-green { + border-color: {$sh-greenborder}; +} + +.project-card-view.project-card-green .phui-header-shell { + background: linear-gradient(to bottom, {$sh-greenbackground} 44px, #fff 44px); +} + +.project-card-view.project-card-blue { + border-color: {$sh-blueborder}; +} + +.project-card-view.project-card-blue .phui-header-shell { + background: linear-gradient(to bottom, {$sh-bluebackground} 44px, #fff 44px); +} + +.project-card-view.project-card-indigo { + border-color: {$sh-indigoborder}; +} + +.project-card-view.project-card-indigo .phui-header-shell { + background: linear-gradient(to bottom, {$sh-indigobackground} 44px, #fff 44px); +} + +.project-card-view.project-card-violet { + border-color: {$sh-violetborder}; +} + +.project-card-view.project-card-violet .phui-header-shell { + background: linear-gradient(to bottom, {$sh-violetbackground} 44px, #fff 44px); +} + +.project-card-view.project-card-pink { + border-color: {$sh-pinkborder}; +} + +.project-card-view.project-card-pink .phui-header-shell { + background: linear-gradient(to bottom, {$sh-pinkbackground} 44px, #fff 44px); +} + +.project-card-view.project-card-grey { + border-color: {$sh-greyborder}; +} + +.project-card-view.project-card-grey .phui-header-shell { + background: linear-gradient(to bottom, {$sh-greybackground} 44px, #fff 44px); +} + +.project-card-view.project-card-checkered { + border-color: {$sh-greyborder}; +} + +.project-card-view.project-card-checkered .phui-header-shell { + background-color: #fff; + background-image: linear-gradient(45deg, {$sh-greybackground} 25%, transparent 25%, transparent 75%, {$sh-greybackground} 75%, {$sh-greybackground}), + linear-gradient(45deg, {$sh-greybackground} 25%, transparent 25%, transparent 75%, {$sh-greybackground} 75%, {$sh-greybackground}); + background-size: 16px 16px; + background-position:0 0, 8px 8px; +} diff --git a/webroot/rsrc/css/phui/phui-hovercard.css b/webroot/rsrc/css/phui/phui-hovercard.css --- a/webroot/rsrc/css/phui/phui-hovercard.css +++ b/webroot/rsrc/css/phui/phui-hovercard.css @@ -7,20 +7,17 @@ } .phui-hovercard-wrapper { - float: left; width: 400px; } .device-phone .phui-hovercard-wrapper { - float: left; width: 300px; } .phui-hovercard-container { - float: left; width: 100%; box-shadow: {$dropshadow}; - border: 1px solid {$blueborder}; + border: 1px solid {$lightblueborder}; border-radius: 3px; background-color: #fff; } @@ -33,7 +30,7 @@ } .phui-hovercard-head .phui-header-header { - font-size: 14px; + font-size: {$biggerfontsize}; } .phui-hovercard-head .phui-tag-type-state {