mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-10 00:42:41 +01:00
Allow profile menus to be collapsed and expanded
Summary: Ref T10054. I think this gets everything except: - circles on icons; - I spent ~15 minutes poking at animations but wasn't able to get anything that looked reasonable whatsoever. Test Plan: - Collapsed menus. - Expanded menus. Reviewers: chad Reviewed By: chad Maniphest Tasks: T10054 Differential Revision: https://secure.phabricator.com/D15056
This commit is contained in:
parent
bf18b59f5f
commit
0a554c2ed5
11 changed files with 329 additions and 42 deletions
|
@ -7,7 +7,7 @@
|
||||||
*/
|
*/
|
||||||
return array(
|
return array(
|
||||||
'names' => array(
|
'names' => array(
|
||||||
'core.pkg.css' => 'c61091b0',
|
'core.pkg.css' => '7fce81fc',
|
||||||
'core.pkg.js' => '573e6664',
|
'core.pkg.js' => '573e6664',
|
||||||
'darkconsole.pkg.js' => 'e7393ebb',
|
'darkconsole.pkg.js' => 'e7393ebb',
|
||||||
'differential.pkg.css' => '2de124c9',
|
'differential.pkg.css' => '2de124c9',
|
||||||
|
@ -143,7 +143,7 @@ return array(
|
||||||
'rsrc/css/phui/phui-object-item-list-view.css' => '26c30d3f',
|
'rsrc/css/phui/phui-object-item-list-view.css' => '26c30d3f',
|
||||||
'rsrc/css/phui/phui-pager.css' => 'bea33d23',
|
'rsrc/css/phui/phui-pager.css' => 'bea33d23',
|
||||||
'rsrc/css/phui/phui-pinboard-view.css' => '2495140e',
|
'rsrc/css/phui/phui-pinboard-view.css' => '2495140e',
|
||||||
'rsrc/css/phui/phui-profile-menu.css' => 'a26fa598',
|
'rsrc/css/phui/phui-profile-menu.css' => '72d69773',
|
||||||
'rsrc/css/phui/phui-property-list-view.css' => '27b2849e',
|
'rsrc/css/phui/phui-property-list-view.css' => '27b2849e',
|
||||||
'rsrc/css/phui/phui-remarkup-preview.css' => '1a8f2591',
|
'rsrc/css/phui/phui-remarkup-preview.css' => '1a8f2591',
|
||||||
'rsrc/css/phui/phui-spacing.css' => '042804d6',
|
'rsrc/css/phui/phui-spacing.css' => '042804d6',
|
||||||
|
@ -500,6 +500,7 @@ return array(
|
||||||
'rsrc/js/core/phtize.js' => 'd254d646',
|
'rsrc/js/core/phtize.js' => 'd254d646',
|
||||||
'rsrc/js/phui/behavior-phui-dropdown-menu.js' => '54733475',
|
'rsrc/js/phui/behavior-phui-dropdown-menu.js' => '54733475',
|
||||||
'rsrc/js/phui/behavior-phui-object-box-tabs.js' => '2bfa2836',
|
'rsrc/js/phui/behavior-phui-object-box-tabs.js' => '2bfa2836',
|
||||||
|
'rsrc/js/phui/behavior-phui-profile-menu.js' => 'bf2c93d6',
|
||||||
'rsrc/js/phuix/PHUIXActionListView.js' => 'b5c256b8',
|
'rsrc/js/phuix/PHUIXActionListView.js' => 'b5c256b8',
|
||||||
'rsrc/js/phuix/PHUIXActionView.js' => '8cf6d262',
|
'rsrc/js/phuix/PHUIXActionView.js' => '8cf6d262',
|
||||||
'rsrc/js/phuix/PHUIXAutocomplete.js' => '21dc9144',
|
'rsrc/js/phuix/PHUIXAutocomplete.js' => '21dc9144',
|
||||||
|
@ -648,6 +649,7 @@ return array(
|
||||||
'javelin-behavior-pholio-mock-view' => 'fbe497e7',
|
'javelin-behavior-pholio-mock-view' => 'fbe497e7',
|
||||||
'javelin-behavior-phui-dropdown-menu' => '54733475',
|
'javelin-behavior-phui-dropdown-menu' => '54733475',
|
||||||
'javelin-behavior-phui-object-box-tabs' => '2bfa2836',
|
'javelin-behavior-phui-object-box-tabs' => '2bfa2836',
|
||||||
|
'javelin-behavior-phui-profile-menu' => 'bf2c93d6',
|
||||||
'javelin-behavior-policy-control' => 'ae45872f',
|
'javelin-behavior-policy-control' => 'ae45872f',
|
||||||
'javelin-behavior-policy-rule-editor' => '5e9f347c',
|
'javelin-behavior-policy-rule-editor' => '5e9f347c',
|
||||||
'javelin-behavior-project-boards' => 'ba4fa35c',
|
'javelin-behavior-project-boards' => 'ba4fa35c',
|
||||||
|
@ -817,7 +819,7 @@ return array(
|
||||||
'phui-object-item-list-view-css' => '26c30d3f',
|
'phui-object-item-list-view-css' => '26c30d3f',
|
||||||
'phui-pager-css' => 'bea33d23',
|
'phui-pager-css' => 'bea33d23',
|
||||||
'phui-pinboard-view-css' => '2495140e',
|
'phui-pinboard-view-css' => '2495140e',
|
||||||
'phui-profile-menu-css' => 'a26fa598',
|
'phui-profile-menu-css' => '72d69773',
|
||||||
'phui-property-list-view-css' => '27b2849e',
|
'phui-property-list-view-css' => '27b2849e',
|
||||||
'phui-remarkup-preview-css' => '1a8f2591',
|
'phui-remarkup-preview-css' => '1a8f2591',
|
||||||
'phui-spacing-css' => '042804d6',
|
'phui-spacing-css' => '042804d6',
|
||||||
|
@ -1772,6 +1774,11 @@ return array(
|
||||||
'javelin-util',
|
'javelin-util',
|
||||||
'javelin-request',
|
'javelin-request',
|
||||||
),
|
),
|
||||||
|
'bf2c93d6' => array(
|
||||||
|
'javelin-behavior',
|
||||||
|
'javelin-stratcom',
|
||||||
|
'javelin-dom',
|
||||||
|
),
|
||||||
'bff6884b' => array(
|
'bff6884b' => array(
|
||||||
'javelin-install',
|
'javelin-install',
|
||||||
'javelin-dom',
|
'javelin-dom',
|
||||||
|
|
|
@ -191,14 +191,29 @@ final class CelerityDefaultPostprocessor
|
||||||
// Background color for "dark" themes.
|
// Background color for "dark" themes.
|
||||||
'page.background.dark' => '#ebecee',
|
'page.background.dark' => '#ebecee',
|
||||||
|
|
||||||
|
// NOTE: We can't just do these with an alpha channel because the
|
||||||
|
// fixed items in the footer may render on top of other items, so the
|
||||||
|
// backgrounds must be opaque.
|
||||||
|
|
||||||
|
// This is the base background color.
|
||||||
'menu.profile.background' => '#525868',
|
'menu.profile.background' => '#525868',
|
||||||
|
|
||||||
|
// This is premultiplied 7.5% alpha.
|
||||||
|
'menu.profile.background.hover' => '#4c5160',
|
||||||
|
|
||||||
|
// This is premultiplied 15% alpha.
|
||||||
|
'menu.profile.background.selected' => '#464b59',
|
||||||
|
|
||||||
'menu.profile.text' => '#c6c7cb',
|
'menu.profile.text' => '#c6c7cb',
|
||||||
'menu.profile.text.selected' => '#ffffff',
|
'menu.profile.text.selected' => '#ffffff',
|
||||||
'menu.profile.icon' => '#ffffff',
|
|
||||||
'menu.profile.icon.disabled' => '#b9bcc2',
|
'menu.profile.icon.disabled' => '#b9bcc2',
|
||||||
|
|
||||||
'menu.main.height' => '44px',
|
'menu.main.height' => '44px',
|
||||||
|
|
||||||
|
'menu.profile.width' => '240px',
|
||||||
|
'menu.profile.width.collapsed' => '80px',
|
||||||
|
'menu.profile.item.height' => '46px',
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ abstract class PhabricatorProjectController extends PhabricatorController {
|
||||||
|
|
||||||
private $project;
|
private $project;
|
||||||
private $profileMenu;
|
private $profileMenu;
|
||||||
|
private $profilePanelEngine;
|
||||||
|
|
||||||
protected function setProject(PhabricatorProject $project) {
|
protected function setProject(PhabricatorProject $project) {
|
||||||
$this->project = $project;
|
$this->project = $project;
|
||||||
|
@ -98,14 +99,8 @@ abstract class PhabricatorProjectController extends PhabricatorController {
|
||||||
|
|
||||||
protected function getProfileMenu() {
|
protected function getProfileMenu() {
|
||||||
if (!$this->profileMenu) {
|
if (!$this->profileMenu) {
|
||||||
$project = $this->getProject();
|
$engine = $this->getProfilePanelEngine();
|
||||||
if ($project) {
|
if ($engine) {
|
||||||
$viewer = $this->getViewer();
|
|
||||||
|
|
||||||
$engine = id(new PhabricatorProjectProfilePanelEngine())
|
|
||||||
->setViewer($viewer)
|
|
||||||
->setProfileObject($project);
|
|
||||||
|
|
||||||
$this->profileMenu = $engine->buildNavigation();
|
$this->profileMenu = $engine->buildNavigation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -131,4 +126,24 @@ abstract class PhabricatorProjectController extends PhabricatorController {
|
||||||
return $crumbs;
|
return $crumbs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function getProfilePanelEngine() {
|
||||||
|
if (!$this->profilePanelEngine) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
$project = $this->getProject();
|
||||||
|
if ($project) {
|
||||||
|
$engine = id(new PhabricatorProjectProfilePanelEngine())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->setProfileObject($project);
|
||||||
|
$this->profilePanelEngine = $engine;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $this->profilePanelEngine;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function setProfilePanelEngine(
|
||||||
|
PhabricatorProjectProfilePanelEngine $engine) {
|
||||||
|
$this->profilePanelEngine = $engine;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,10 +12,13 @@ final class PhabricatorProjectPanelController
|
||||||
$viewer = $this->getViewer();
|
$viewer = $this->getViewer();
|
||||||
$project = $this->getProject();
|
$project = $this->getProject();
|
||||||
|
|
||||||
return id(new PhabricatorProjectProfilePanelEngine())
|
$engine = id(new PhabricatorProjectProfilePanelEngine())
|
||||||
->setProfileObject($project)
|
->setProfileObject($project)
|
||||||
->setController($this)
|
->setController($this);
|
||||||
->buildResponse();
|
|
||||||
|
$this->setProfilePanelEngine($engine);
|
||||||
|
|
||||||
|
return $engine->buildResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ abstract class PhabricatorProfilePanelEngine extends Phobject {
|
||||||
private $profileObject;
|
private $profileObject;
|
||||||
private $panels;
|
private $panels;
|
||||||
private $controller;
|
private $controller;
|
||||||
|
private $navigation;
|
||||||
|
|
||||||
public function setViewer(PhabricatorUser $viewer) {
|
public function setViewer(PhabricatorUser $viewer) {
|
||||||
$this->viewer = $viewer;
|
$this->viewer = $viewer;
|
||||||
|
@ -147,6 +148,10 @@ abstract class PhabricatorProfilePanelEngine extends Phobject {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function buildNavigation() {
|
public function buildNavigation() {
|
||||||
|
if ($this->navigation) {
|
||||||
|
return $this->navigation;
|
||||||
|
}
|
||||||
|
|
||||||
$nav = id(new AphrontSideNavFilterView())
|
$nav = id(new AphrontSideNavFilterView())
|
||||||
->setIsProfileMenu(true)
|
->setIsProfileMenu(true)
|
||||||
->setBaseURI(new PhutilURI($this->getPanelURI('')));
|
->setBaseURI(new PhutilURI($this->getPanelURI('')));
|
||||||
|
@ -185,14 +190,15 @@ abstract class PhabricatorProfilePanelEngine extends Phobject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$configure_item = $this->newConfigureMenuItem();
|
$more_items = $this->newAutomaticMenuItems($nav);
|
||||||
if ($configure_item) {
|
foreach ($more_items as $item) {
|
||||||
$nav->addMenuItem($configure_item);
|
$nav->addMenuItem($item);
|
||||||
}
|
}
|
||||||
|
|
||||||
$nav->selectFilter(null);
|
$nav->selectFilter(null);
|
||||||
|
|
||||||
return $nav;
|
$this->navigation = $nav;
|
||||||
|
return $this->navigation;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getPanels() {
|
private function getPanels() {
|
||||||
|
@ -301,26 +307,112 @@ abstract class PhabricatorProfilePanelEngine extends Phobject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function newConfigureMenuItem() {
|
private function newAutomaticMenuItems(AphrontSideNavFilterView $nav) {
|
||||||
if (!$this->isPanelEngineConfigurable()) {
|
$items = array();
|
||||||
return null;
|
|
||||||
|
// NOTE: We're adding a spacer item for the fixed footer, so that if the
|
||||||
|
// menu taller than the page content you can still scroll down the page far
|
||||||
|
// enough to access the last item without the content being obscured by the
|
||||||
|
// fixed items.
|
||||||
|
$items[] = id(new PHUIListItemView())
|
||||||
|
->setHideInApplicationMenu(true)
|
||||||
|
->addClass('phui-profile-menu-spacer');
|
||||||
|
|
||||||
|
if ($this->isPanelEngineConfigurable()) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
$object = $this->getProfileObject();
|
||||||
|
|
||||||
|
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||||
|
$viewer,
|
||||||
|
$object,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT);
|
||||||
|
|
||||||
|
$expanded_edit_icon = id(new PHUIIconView())
|
||||||
|
->addClass('phui-list-item-icon')
|
||||||
|
->addClass('phui-profile-menu-visible-when-expanded')
|
||||||
|
->setIconFont('fa-pencil');
|
||||||
|
|
||||||
|
$collapsed_edit_icon = id(new PHUIIconView())
|
||||||
|
->addClass('phui-list-item-icon')
|
||||||
|
->addClass('phui-profile-menu-visible-when-collapsed')
|
||||||
|
->setIconFont('fa-pencil')
|
||||||
|
->addSigil('has-tooltip')
|
||||||
|
->setMetadata(
|
||||||
|
array(
|
||||||
|
'tip' => pht('Edit Menu'),
|
||||||
|
'align' => 'E',
|
||||||
|
));
|
||||||
|
|
||||||
|
$items[] = id(new PHUIListItemView())
|
||||||
|
->setName('Edit Menu')
|
||||||
|
->setKey('panel.configure')
|
||||||
|
->addIcon($expanded_edit_icon)
|
||||||
|
->addIcon($collapsed_edit_icon)
|
||||||
|
->addClass('phui-profile-menu-footer')
|
||||||
|
->addClass('phui-profile-menu-footer-1')
|
||||||
|
->setHref($this->getPanelURI('configure/'))
|
||||||
|
->setDisabled(!$can_edit)
|
||||||
|
->setWorkflow(!$can_edit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$collapse_id = celerity_generate_unique_node_id();
|
||||||
|
|
||||||
$viewer = $this->getViewer();
|
$viewer = $this->getViewer();
|
||||||
$object = $this->getProfileObject();
|
|
||||||
|
|
||||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
$collapse_key =
|
||||||
$viewer,
|
PhabricatorUserPreferences::PREFERENCE_PROFILE_MENU_COLLAPSED;
|
||||||
$object,
|
|
||||||
PhabricatorPolicyCapability::CAN_EDIT);
|
|
||||||
|
|
||||||
return id(new PHUIListItemView())
|
$preferences = $viewer->loadPreferences();
|
||||||
->setName('Configure Menu')
|
$is_collapsed = $preferences->getPreference($collapse_key, false);
|
||||||
->setKey('panel.configure')
|
|
||||||
->setIcon('fa-gear')
|
if ($is_collapsed) {
|
||||||
->setHref($this->getPanelURI('configure/'))
|
$nav->addClass('phui-profile-menu-collapsed');
|
||||||
->setDisabled(!$can_edit)
|
} else {
|
||||||
->setWorkflow(!$can_edit);
|
$nav->addClass('phui-profile-menu-expanded');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($viewer->isLoggedIn()) {
|
||||||
|
$settings_uri = '/settings/adjust/?key='.$collapse_key;
|
||||||
|
} else {
|
||||||
|
$settings_uri = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Javelin::initBehavior(
|
||||||
|
'phui-profile-menu',
|
||||||
|
array(
|
||||||
|
'menuID' => $nav->getMainID(),
|
||||||
|
'collapseID' => $collapse_id,
|
||||||
|
'isCollapsed' => $is_collapsed,
|
||||||
|
'settingsURI' => $settings_uri,
|
||||||
|
));
|
||||||
|
|
||||||
|
$collapse_icon = id(new PHUIIconView())
|
||||||
|
->addClass('phui-list-item-icon')
|
||||||
|
->addClass('phui-profile-menu-visible-when-expanded')
|
||||||
|
->setIconFont('fa-angle-left');
|
||||||
|
|
||||||
|
$expand_icon = id(new PHUIIconView())
|
||||||
|
->addClass('phui-list-item-icon')
|
||||||
|
->addClass('phui-profile-menu-visible-when-collapsed')
|
||||||
|
->addSigil('has-tooltip')
|
||||||
|
->setMetadata(
|
||||||
|
array(
|
||||||
|
'tip' => pht('Expand'),
|
||||||
|
'align' => 'E',
|
||||||
|
))
|
||||||
|
->setIconFont('fa-angle-right');
|
||||||
|
|
||||||
|
$items[] = id(new PHUIListItemView())
|
||||||
|
->setName('Collapse')
|
||||||
|
->addIcon($collapse_icon)
|
||||||
|
->addIcon($expand_icon)
|
||||||
|
->setID($collapse_id)
|
||||||
|
->addClass('phui-profile-menu-footer')
|
||||||
|
->addClass('phui-profile-menu-footer-2')
|
||||||
|
->setHideInApplicationMenu(true)
|
||||||
|
->setHref('#');
|
||||||
|
|
||||||
|
return $items;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getConfigureURI() {
|
public function getConfigureURI() {
|
||||||
|
|
|
@ -41,6 +41,8 @@ final class PhabricatorUserPreferences extends PhabricatorUserDAO {
|
||||||
const PREFERENCE_RESOURCE_POSTPROCESSOR = 'resource-postprocessor';
|
const PREFERENCE_RESOURCE_POSTPROCESSOR = 'resource-postprocessor';
|
||||||
const PREFERENCE_DESKTOP_NOTIFICATIONS = 'desktop-notifications';
|
const PREFERENCE_DESKTOP_NOTIFICATIONS = 'desktop-notifications';
|
||||||
|
|
||||||
|
const PREFERENCE_PROFILE_MENU_COLLAPSED = 'profile-menu.collapsed';
|
||||||
|
|
||||||
// These are in an unusual order for historic reasons.
|
// These are in an unusual order for historic reasons.
|
||||||
const MAILTAG_PREFERENCE_NOTIFY = 0;
|
const MAILTAG_PREFERENCE_NOTIFY = 0;
|
||||||
const MAILTAG_PREFERENCE_EMAIL = 1;
|
const MAILTAG_PREFERENCE_EMAIL = 1;
|
||||||
|
|
|
@ -27,6 +27,7 @@ final class AphrontSideNavFilterView extends AphrontView {
|
||||||
private $crumbs;
|
private $crumbs;
|
||||||
private $classes = array();
|
private $classes = array();
|
||||||
private $menuID;
|
private $menuID;
|
||||||
|
private $mainID;
|
||||||
private $isProfileMenu;
|
private $isProfileMenu;
|
||||||
private $footer = array();
|
private $footer = array();
|
||||||
|
|
||||||
|
@ -168,6 +169,13 @@ final class AphrontSideNavFilterView extends AphrontView {
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getMainID() {
|
||||||
|
if (!$this->mainID) {
|
||||||
|
$this->mainID = celerity_generate_unique_node_id();
|
||||||
|
}
|
||||||
|
return $this->mainID;
|
||||||
|
}
|
||||||
|
|
||||||
public function render() {
|
public function render() {
|
||||||
if ($this->menu->getItems()) {
|
if ($this->menu->getItems()) {
|
||||||
if (!$this->baseURI) {
|
if (!$this->baseURI) {
|
||||||
|
@ -212,7 +220,7 @@ final class AphrontSideNavFilterView extends AphrontView {
|
||||||
$local_id = null;
|
$local_id = null;
|
||||||
$background_id = null;
|
$background_id = null;
|
||||||
$local_menu = null;
|
$local_menu = null;
|
||||||
$main_id = celerity_generate_unique_node_id();
|
$main_id = $this->getMainID();
|
||||||
|
|
||||||
if ($this->flexible) {
|
if ($this->flexible) {
|
||||||
$drag_id = celerity_generate_unique_node_id();
|
$drag_id = celerity_generate_unique_node_id();
|
||||||
|
|
|
@ -75,8 +75,11 @@ final class PHUIApplicationMenuView extends Phobject {
|
||||||
$profile_menu = $this->getProfileMenu();
|
$profile_menu = $this->getProfileMenu();
|
||||||
if ($profile_menu) {
|
if ($profile_menu) {
|
||||||
foreach ($profile_menu->getMenu()->getItems() as $item) {
|
foreach ($profile_menu->getMenu()->getItems() as $item) {
|
||||||
|
if ($item->getHideInApplicationMenu()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
$item = clone $item;
|
$item = clone $item;
|
||||||
$item->setRenderNameAsTooltip(false);
|
|
||||||
$view->addMenuItem($item);
|
$view->addMenuItem($item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,17 @@ final class PHUIListItemView extends AphrontTagView {
|
||||||
private $aural;
|
private $aural;
|
||||||
private $profileImage;
|
private $profileImage;
|
||||||
private $indented;
|
private $indented;
|
||||||
|
private $hideInApplicationMenu;
|
||||||
|
private $icons = array();
|
||||||
|
|
||||||
|
public function setHideInApplicationMenu($hide) {
|
||||||
|
$this->hideInApplicationMenu = $hide;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHideInApplicationMenu() {
|
||||||
|
return $this->hideInApplicationMenu;
|
||||||
|
}
|
||||||
|
|
||||||
public function setDropdownMenu(PhabricatorActionListView $actions) {
|
public function setDropdownMenu(PhabricatorActionListView $actions) {
|
||||||
Javelin::initBehavior('phui-dropdown-menu');
|
Javelin::initBehavior('phui-dropdown-menu');
|
||||||
|
@ -150,6 +161,15 @@ final class PHUIListItemView extends AphrontTagView {
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function addIcon(PHUIIconView $icon) {
|
||||||
|
$this->icons[] = $icon;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIcons() {
|
||||||
|
return $this->icons;
|
||||||
|
}
|
||||||
|
|
||||||
protected function getTagName() {
|
protected function getTagName() {
|
||||||
return 'li';
|
return 'li';
|
||||||
}
|
}
|
||||||
|
@ -274,6 +294,8 @@ final class PHUIListItemView extends AphrontTagView {
|
||||||
$classes[] = 'phui-list-item-indented';
|
$classes[] = 'phui-list-item-indented';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$icons = $this->getIcons();
|
||||||
|
|
||||||
return javelin_tag(
|
return javelin_tag(
|
||||||
$this->href ? 'a' : 'div',
|
$this->href ? 'a' : 'div',
|
||||||
array(
|
array(
|
||||||
|
@ -285,6 +307,7 @@ final class PHUIListItemView extends AphrontTagView {
|
||||||
array(
|
array(
|
||||||
$aural,
|
$aural,
|
||||||
$icon,
|
$icon,
|
||||||
|
$icons,
|
||||||
$this->renderChildren(),
|
$this->renderChildren(),
|
||||||
$name,
|
$name,
|
||||||
));
|
));
|
||||||
|
|
|
@ -16,12 +16,17 @@
|
||||||
display: table-cell;
|
display: table-cell;
|
||||||
position: relative;
|
position: relative;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
width: 240px;
|
width: {$menu.profile.width};
|
||||||
max-width: 240px;
|
max-width: {$menu.profile.width};
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.device-desktop .phui-profile-menu-collapsed .phabricator-nav-local {
|
||||||
|
width: {$menu.profile.width.collapsed};
|
||||||
|
max-width: {$menu.profile.width.collapsed};
|
||||||
|
}
|
||||||
|
|
||||||
.device-desktop .phui-profile-menu .phabricator-nav-content {
|
.device-desktop .phui-profile-menu .phabricator-nav-content {
|
||||||
display: table-cell;
|
display: table-cell;
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
|
@ -47,23 +52,47 @@
|
||||||
line-height: 22px;
|
line-height: 22px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
|
||||||
|
/* NOTE: We must have an opaque background on these items so the footer
|
||||||
|
items appear opaque when the render over normal items. */
|
||||||
|
background: {$menu.profile.background};
|
||||||
}
|
}
|
||||||
|
|
||||||
.phui-profile-menu .phabricator-side-menu .phui-list-item-icon,
|
.phui-profile-menu .phabricator-side-menu .phui-list-item-icon,
|
||||||
.phui-profile-menu .phabricator-side-menu
|
.phui-profile-menu .phabricator-side-menu
|
||||||
.phui-list-item-href .phui-icon-view {
|
.phui-list-item-href .phui-icon-view {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 13px;
|
|
||||||
top: 12px;
|
top: 12px;
|
||||||
|
left: 13px;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
width: 22px;
|
width: 22px;
|
||||||
height: 22px;
|
height: 22px;
|
||||||
line-height: 22px;
|
line-height: 22px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: {$menu.profile.icon};
|
color: {$menu.profile.text};
|
||||||
background-size: 100%;
|
background-size: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.phui-profile-menu .phui-profile-menu-collapsed .phui-list-item-href {
|
||||||
|
text-align: center;
|
||||||
|
padding: 42px 8px 12px;
|
||||||
|
font-size: 11px;
|
||||||
|
line-height: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.phui-profile-menu .phui-profile-menu-collapsed .phui-list-item-name {
|
||||||
|
display: block;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.phui-profile-menu .phui-profile-menu-collapsed .phui-list-item-icon,
|
||||||
|
.phui-profile-menu .phui-profile-menu-collapsed
|
||||||
|
.phui-list-item-href .phui-icon-view {
|
||||||
|
top: 10px;
|
||||||
|
left: 29px;
|
||||||
|
}
|
||||||
|
|
||||||
.phui-profile-menu .phabricator-side-menu
|
.phui-profile-menu .phabricator-side-menu
|
||||||
.phui-list-item-disabled
|
.phui-list-item-disabled
|
||||||
.phui-list-item-icon {
|
.phui-list-item-icon {
|
||||||
|
@ -76,7 +105,16 @@
|
||||||
|
|
||||||
.device-desktop .phui-profile-menu .phabricator-side-menu
|
.device-desktop .phui-profile-menu .phabricator-side-menu
|
||||||
.phui-list-item-href:hover {
|
.phui-list-item-href:hover {
|
||||||
background-color: rgba(0, 0, 0, 0.075);
|
background-color: {$menu.profile.background.hover};
|
||||||
|
color: {$menu.profile.text.selected};
|
||||||
|
}
|
||||||
|
|
||||||
|
.phui-profile-menu .phabricator-side-menu
|
||||||
|
.phui-list-item-selected
|
||||||
|
.phui-list-item-icon,
|
||||||
|
.device-desktop .phui-profile-menu .phabricator-side-menu
|
||||||
|
.phui-list-item-href:hover
|
||||||
|
.phui-list-item-icon {
|
||||||
color: {$menu.profile.text.selected};
|
color: {$menu.profile.text.selected};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,7 +123,7 @@
|
||||||
.device-desktop .phui-profile-menu .phabricator-side-menu
|
.device-desktop .phui-profile-menu .phabricator-side-menu
|
||||||
.phui-list-item-selected
|
.phui-list-item-selected
|
||||||
.phui-list-item-href:hover {
|
.phui-list-item-href:hover {
|
||||||
background-color: rgba(0, 0, 0, 0.150);
|
background-color: {$menu.profile.background.selected};
|
||||||
color: {$menu.profile.text.selected};
|
color: {$menu.profile.text.selected};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,3 +145,56 @@
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: {$menu.profile.text};
|
color: {$menu.profile.text};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.phui-profile-menu .phabricator-side-menu .phui-profile-menu-spacer {
|
||||||
|
box-sizing: border-box;
|
||||||
|
height: {$menu.profile.item.height};
|
||||||
|
}
|
||||||
|
|
||||||
|
.phui-profile-menu .phabricator-side-menu .phui-profile-menu-footer {
|
||||||
|
position: fixed;
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: {$menu.profile.width};
|
||||||
|
bottom: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.phui-profile-menu .phabricator-side-menu .phui-profile-menu-footer-1 {
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.phui-profile-menu .phabricator-side-menu .phui-profile-menu-footer-2 {
|
||||||
|
left: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.phui-profile-menu .phui-profile-menu-collapsed .phui-profile-menu-footer {
|
||||||
|
width: 40px;
|
||||||
|
height: {$menu.profile.item.height};
|
||||||
|
bottom: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.phui-profile-menu .phui-profile-menu-collapsed .phui-profile-menu-footer-1 {
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.phui-profile-menu .phui-profile-menu-collapsed .phui-profile-menu-footer-2 {
|
||||||
|
left: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.phui-profile-menu .phui-profile-menu-collapsed .phui-profile-menu-footer
|
||||||
|
.phui-list-item-name {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.phui-profile-menu .phui-profile-menu-collapsed .phui-profile-menu-footer
|
||||||
|
.phui-list-item-icon {
|
||||||
|
top: 10px;
|
||||||
|
left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.phui-profile-menu .phui-profile-menu-expanded
|
||||||
|
.phui-profile-menu-visible-when-collapsed,
|
||||||
|
.phui-profile-menu .phui-profile-menu-collapsed
|
||||||
|
.phui-profile-menu-visible-when-expanded {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
28
webroot/rsrc/js/phui/behavior-phui-profile-menu.js
Normal file
28
webroot/rsrc/js/phui/behavior-phui-profile-menu.js
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
/**
|
||||||
|
* @provides javelin-behavior-phui-profile-menu
|
||||||
|
* @requires javelin-behavior
|
||||||
|
* javelin-stratcom
|
||||||
|
* javelin-dom
|
||||||
|
*/
|
||||||
|
|
||||||
|
JX.behavior('phui-profile-menu', function(config) {
|
||||||
|
var menu_node = JX.$(config.menuID);
|
||||||
|
var collapse_node = JX.$(config.collapseID);
|
||||||
|
|
||||||
|
var is_collapsed = config.isCollapsed;
|
||||||
|
|
||||||
|
JX.DOM.listen(collapse_node, 'click', null, function(e) {
|
||||||
|
is_collapsed = !is_collapsed;
|
||||||
|
JX.DOM.alterClass(menu_node, 'phui-profile-menu-collapsed', is_collapsed);
|
||||||
|
JX.DOM.alterClass(menu_node, 'phui-profile-menu-expanded', !is_collapsed);
|
||||||
|
|
||||||
|
if (config.settingsURI) {
|
||||||
|
new JX.Request(config.settingsURI)
|
||||||
|
.setData({value: (is_collapsed ? 1 : 0)})
|
||||||
|
.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
e.kill();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
Loading…
Reference in a new issue