Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15394446
D15056.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
19 KB
Referenced Files
None
Subscribers
None
D15056.diff
View Options
diff --git a/resources/celerity/map.php b/resources/celerity/map.php
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -7,7 +7,7 @@
*/
return array(
'names' => array(
- 'core.pkg.css' => 'c61091b0',
+ 'core.pkg.css' => '7fce81fc',
'core.pkg.js' => '573e6664',
'darkconsole.pkg.js' => 'e7393ebb',
'differential.pkg.css' => '2de124c9',
@@ -143,7 +143,7 @@
'rsrc/css/phui/phui-object-item-list-view.css' => '26c30d3f',
'rsrc/css/phui/phui-pager.css' => 'bea33d23',
'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-remarkup-preview.css' => '1a8f2591',
'rsrc/css/phui/phui-spacing.css' => '042804d6',
@@ -500,6 +500,7 @@
'rsrc/js/core/phtize.js' => 'd254d646',
'rsrc/js/phui/behavior-phui-dropdown-menu.js' => '54733475',
'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/PHUIXActionView.js' => '8cf6d262',
'rsrc/js/phuix/PHUIXAutocomplete.js' => '21dc9144',
@@ -648,6 +649,7 @@
'javelin-behavior-pholio-mock-view' => 'fbe497e7',
'javelin-behavior-phui-dropdown-menu' => '54733475',
'javelin-behavior-phui-object-box-tabs' => '2bfa2836',
+ 'javelin-behavior-phui-profile-menu' => 'bf2c93d6',
'javelin-behavior-policy-control' => 'ae45872f',
'javelin-behavior-policy-rule-editor' => '5e9f347c',
'javelin-behavior-project-boards' => 'ba4fa35c',
@@ -817,7 +819,7 @@
'phui-object-item-list-view-css' => '26c30d3f',
'phui-pager-css' => 'bea33d23',
'phui-pinboard-view-css' => '2495140e',
- 'phui-profile-menu-css' => 'a26fa598',
+ 'phui-profile-menu-css' => '72d69773',
'phui-property-list-view-css' => '27b2849e',
'phui-remarkup-preview-css' => '1a8f2591',
'phui-spacing-css' => '042804d6',
@@ -1772,6 +1774,11 @@
'javelin-util',
'javelin-request',
),
+ 'bf2c93d6' => array(
+ 'javelin-behavior',
+ 'javelin-stratcom',
+ 'javelin-dom',
+ ),
'bff6884b' => array(
'javelin-install',
'javelin-dom',
diff --git a/src/applications/celerity/postprocessor/CelerityDefaultPostprocessor.php b/src/applications/celerity/postprocessor/CelerityDefaultPostprocessor.php
--- a/src/applications/celerity/postprocessor/CelerityDefaultPostprocessor.php
+++ b/src/applications/celerity/postprocessor/CelerityDefaultPostprocessor.php
@@ -191,14 +191,29 @@
// Background color for "dark" themes.
'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',
+
+ // 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.selected' => '#ffffff',
- 'menu.profile.icon' => '#ffffff',
'menu.profile.icon.disabled' => '#b9bcc2',
'menu.main.height' => '44px',
+ 'menu.profile.width' => '240px',
+ 'menu.profile.width.collapsed' => '80px',
+ 'menu.profile.item.height' => '46px',
+
);
}
diff --git a/src/applications/project/controller/PhabricatorProjectController.php b/src/applications/project/controller/PhabricatorProjectController.php
--- a/src/applications/project/controller/PhabricatorProjectController.php
+++ b/src/applications/project/controller/PhabricatorProjectController.php
@@ -4,6 +4,7 @@
private $project;
private $profileMenu;
+ private $profilePanelEngine;
protected function setProject(PhabricatorProject $project) {
$this->project = $project;
@@ -98,14 +99,8 @@
protected function getProfileMenu() {
if (!$this->profileMenu) {
- $project = $this->getProject();
- if ($project) {
- $viewer = $this->getViewer();
-
- $engine = id(new PhabricatorProjectProfilePanelEngine())
- ->setViewer($viewer)
- ->setProfileObject($project);
-
+ $engine = $this->getProfilePanelEngine();
+ if ($engine) {
$this->profileMenu = $engine->buildNavigation();
}
}
@@ -131,4 +126,24 @@
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;
+ }
+
}
diff --git a/src/applications/project/controller/PhabricatorProjectPanelController.php b/src/applications/project/controller/PhabricatorProjectPanelController.php
--- a/src/applications/project/controller/PhabricatorProjectPanelController.php
+++ b/src/applications/project/controller/PhabricatorProjectPanelController.php
@@ -12,10 +12,13 @@
$viewer = $this->getViewer();
$project = $this->getProject();
- return id(new PhabricatorProjectProfilePanelEngine())
+ $engine = id(new PhabricatorProjectProfilePanelEngine())
->setProfileObject($project)
- ->setController($this)
- ->buildResponse();
+ ->setController($this);
+
+ $this->setProfilePanelEngine($engine);
+
+ return $engine->buildResponse();
}
}
diff --git a/src/applications/search/engine/PhabricatorProfilePanelEngine.php b/src/applications/search/engine/PhabricatorProfilePanelEngine.php
--- a/src/applications/search/engine/PhabricatorProfilePanelEngine.php
+++ b/src/applications/search/engine/PhabricatorProfilePanelEngine.php
@@ -6,6 +6,7 @@
private $profileObject;
private $panels;
private $controller;
+ private $navigation;
public function setViewer(PhabricatorUser $viewer) {
$this->viewer = $viewer;
@@ -147,6 +148,10 @@
}
public function buildNavigation() {
+ if ($this->navigation) {
+ return $this->navigation;
+ }
+
$nav = id(new AphrontSideNavFilterView())
->setIsProfileMenu(true)
->setBaseURI(new PhutilURI($this->getPanelURI('')));
@@ -185,14 +190,15 @@
}
}
- $configure_item = $this->newConfigureMenuItem();
- if ($configure_item) {
- $nav->addMenuItem($configure_item);
+ $more_items = $this->newAutomaticMenuItems($nav);
+ foreach ($more_items as $item) {
+ $nav->addMenuItem($item);
}
$nav->selectFilter(null);
- return $nav;
+ $this->navigation = $nav;
+ return $this->navigation;
}
private function getPanels() {
@@ -301,26 +307,112 @@
}
}
- private function newConfigureMenuItem() {
- if (!$this->isPanelEngineConfigurable()) {
- return null;
+ private function newAutomaticMenuItems(AphrontSideNavFilterView $nav) {
+ $items = array();
+
+ // 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();
- $object = $this->getProfileObject();
- $can_edit = PhabricatorPolicyFilter::hasCapability(
- $viewer,
- $object,
- PhabricatorPolicyCapability::CAN_EDIT);
+ $collapse_key =
+ PhabricatorUserPreferences::PREFERENCE_PROFILE_MENU_COLLAPSED;
+
+ $preferences = $viewer->loadPreferences();
+ $is_collapsed = $preferences->getPreference($collapse_key, false);
+
+ if ($is_collapsed) {
+ $nav->addClass('phui-profile-menu-collapsed');
+ } else {
+ $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,
+ ));
- return id(new PHUIListItemView())
- ->setName('Configure Menu')
- ->setKey('panel.configure')
- ->setIcon('fa-gear')
- ->setHref($this->getPanelURI('configure/'))
- ->setDisabled(!$can_edit)
- ->setWorkflow(!$can_edit);
+ $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() {
diff --git a/src/applications/settings/storage/PhabricatorUserPreferences.php b/src/applications/settings/storage/PhabricatorUserPreferences.php
--- a/src/applications/settings/storage/PhabricatorUserPreferences.php
+++ b/src/applications/settings/storage/PhabricatorUserPreferences.php
@@ -41,6 +41,8 @@
const PREFERENCE_RESOURCE_POSTPROCESSOR = 'resource-postprocessor';
const PREFERENCE_DESKTOP_NOTIFICATIONS = 'desktop-notifications';
+ const PREFERENCE_PROFILE_MENU_COLLAPSED = 'profile-menu.collapsed';
+
// These are in an unusual order for historic reasons.
const MAILTAG_PREFERENCE_NOTIFY = 0;
const MAILTAG_PREFERENCE_EMAIL = 1;
diff --git a/src/view/layout/AphrontSideNavFilterView.php b/src/view/layout/AphrontSideNavFilterView.php
--- a/src/view/layout/AphrontSideNavFilterView.php
+++ b/src/view/layout/AphrontSideNavFilterView.php
@@ -27,6 +27,7 @@
private $crumbs;
private $classes = array();
private $menuID;
+ private $mainID;
private $isProfileMenu;
private $footer = array();
@@ -168,6 +169,13 @@
return $this;
}
+ public function getMainID() {
+ if (!$this->mainID) {
+ $this->mainID = celerity_generate_unique_node_id();
+ }
+ return $this->mainID;
+ }
+
public function render() {
if ($this->menu->getItems()) {
if (!$this->baseURI) {
@@ -212,7 +220,7 @@
$local_id = null;
$background_id = null;
$local_menu = null;
- $main_id = celerity_generate_unique_node_id();
+ $main_id = $this->getMainID();
if ($this->flexible) {
$drag_id = celerity_generate_unique_node_id();
diff --git a/src/view/layout/PHUIApplicationMenuView.php b/src/view/layout/PHUIApplicationMenuView.php
--- a/src/view/layout/PHUIApplicationMenuView.php
+++ b/src/view/layout/PHUIApplicationMenuView.php
@@ -75,8 +75,11 @@
$profile_menu = $this->getProfileMenu();
if ($profile_menu) {
foreach ($profile_menu->getMenu()->getItems() as $item) {
+ if ($item->getHideInApplicationMenu()) {
+ continue;
+ }
+
$item = clone $item;
- $item->setRenderNameAsTooltip(false);
$view->addMenuItem($item);
}
}
diff --git a/src/view/phui/PHUIListItemView.php b/src/view/phui/PHUIListItemView.php
--- a/src/view/phui/PHUIListItemView.php
+++ b/src/view/phui/PHUIListItemView.php
@@ -28,6 +28,17 @@
private $aural;
private $profileImage;
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) {
Javelin::initBehavior('phui-dropdown-menu');
@@ -150,6 +161,15 @@
return $this;
}
+ public function addIcon(PHUIIconView $icon) {
+ $this->icons[] = $icon;
+ return $this;
+ }
+
+ public function getIcons() {
+ return $this->icons;
+ }
+
protected function getTagName() {
return 'li';
}
@@ -274,6 +294,8 @@
$classes[] = 'phui-list-item-indented';
}
+ $icons = $this->getIcons();
+
return javelin_tag(
$this->href ? 'a' : 'div',
array(
@@ -285,6 +307,7 @@
array(
$aural,
$icon,
+ $icons,
$this->renderChildren(),
$name,
));
diff --git a/webroot/rsrc/css/phui/phui-profile-menu.css b/webroot/rsrc/css/phui/phui-profile-menu.css
--- a/webroot/rsrc/css/phui/phui-profile-menu.css
+++ b/webroot/rsrc/css/phui/phui-profile-menu.css
@@ -16,12 +16,17 @@
display: table-cell;
position: relative;
vertical-align: top;
- width: 240px;
- max-width: 240px;
+ width: {$menu.profile.width};
+ max-width: {$menu.profile.width};
margin-top: 0;
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 {
display: table-cell;
margin-left: 0;
@@ -47,23 +52,47 @@
line-height: 22px;
overflow: hidden;
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-href .phui-icon-view {
position: absolute;
- left: 13px;
top: 12px;
+ left: 13px;
font-size: 20px;
width: 22px;
height: 22px;
line-height: 22px;
text-align: center;
- color: {$menu.profile.icon};
+ color: {$menu.profile.text};
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-list-item-disabled
.phui-list-item-icon {
@@ -76,7 +105,16 @@
.device-desktop .phui-profile-menu .phabricator-side-menu
.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};
}
@@ -85,7 +123,7 @@
.device-desktop .phui-profile-menu .phabricator-side-menu
.phui-list-item-selected
.phui-list-item-href:hover {
- background-color: rgba(0, 0, 0, 0.150);
+ background-color: {$menu.profile.background.selected};
color: {$menu.profile.text.selected};
}
@@ -107,3 +145,56 @@
font-size: 12px;
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;
+}
diff --git a/webroot/rsrc/js/phui/behavior-phui-profile-menu.js b/webroot/rsrc/js/phui/behavior-phui-profile-menu.js
new file mode 100644
--- /dev/null
+++ b/webroot/rsrc/js/phui/behavior-phui-profile-menu.js
@@ -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();
+ });
+
+});
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Mar 16, 11:52 PM (5 d, 15 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7389278
Default Alt Text
D15056.diff (19 KB)
Attached To
Mode
D15056: Allow profile menus to be collapsed and expanded
Attached
Detach File
Event Timeline
Log In to Comment