diff --git a/scripts/celerity/generate_sprites.php b/scripts/celerity/generate_sprites.php index a6f2b109b5..b44e61f1e3 100755 --- a/scripts/celerity/generate_sprites.php +++ b/scripts/celerity/generate_sprites.php @@ -1,261 +1,264 @@ #!/usr/bin/env php setTagline('regenerate CSS sprite sheets'); $args->setSynopsis(<<parseStandardArguments(); $args->parse( array( array( 'name' => 'source', 'param' => 'directory', 'help' => 'Directory with sprite sources.', ) )); $srcroot = $args->getArg('source'); if (!$srcroot) { throw new Exception( "You must specify a source directory with '--source'."); } $webroot = dirname(phutil_get_library_root('phabricator')).'/webroot/rsrc'; $webroot = Filesystem::readablePath($webroot); function glx($x) { return (60 + (48 * $x)); } function gly($y) { return (110 + (48 * $y)); } $sheet = new PhutilSpriteSheet(); $at = '@'; $sheet->setCSSHeader(<<setSourceFile($srcroot.'/menu_normal_1x.png') ->setSourceSize(26, 26); $menu_hover_template = id(new PhutilSprite()) ->setSourceFile($srcroot.'/menu_hover_1x.png') ->setSourceSize(26, 26); $menu_selected_template = id(new PhutilSprite()) ->setSourceFile($srcroot.'/menu_selected_1x.png') ->setSourceSize(26, 26); $menu_map = array( '' => $menu_normal_template, '-selected' => $menu_selected_template, ':hover' => $menu_hover_template, ); $icon_map = array( 'help' => array(4, 19), 'settings' => array(0, 28), 'logout' => array(3, 6), 'notifications' => array(5, 20), 'task' => array(1, 15), ); foreach ($icon_map as $icon => $coords) { list($x, $y) = $coords; foreach ($menu_map as $suffix => $template) { $sheet->addSprite( id(clone $template) ->setSourcePosition(glx($x), gly($y)) ->setTargetCSS('.main-menu-item-icon-'.$icon.$suffix)); } } $app_template_large = id(new PhutilSprite()) ->setSourceFile($srcroot.'/application_large_1x.png') ->setSourceSize(60, 60); $app_template_large_hover = id(new PhutilSprite()) ->setSourceFile($srcroot.'/application_large_hover_1x.png') ->setSourceSize(60, 60); $app_template_small = id(new PhutilSprite()) ->setSourceFile($srcroot.'/menu_normal_1x.png') ->setSourceSize(30, 30); $app_template_small_hover = id(new PhutilSprite()) ->setSourceFile($srcroot.'/menu_hover_1x.png') ->setSourceSize(30, 30); $app_template_small_selected = id(new PhutilSprite()) ->setSourceFile($srcroot.'/menu_selected_1x.png') ->setSourceSize(30, 30); $app_source_map = array( '-large' => array($app_template_large, 2), // For the application launch view, we only show hover state on the desktop // because it looks glitchy on touch devices. We show the hover state when // the surrounding is hovered, not the icon itself. '-large /* hover */' => array( $app_template_large_hover, 2, '.device-desktop .phabricator-application-launch-container:hover '), '' => array($app_template_small, 1), // Show hover state only for the desktop. ':hover' => array( $app_template_small_hover, 1, '.device-desktop ', ), '-selected' => array($app_template_small_selected, 1), ); $app_map = array( 'differential' => array(9, 1), 'fact' => array(2, 4), 'mail' => array(0, 1), 'diffusion' => array(7, 13), 'slowvote' => array(1, 4), 'phriction' => array(1, 7), 'maniphest' => array(3, 24), 'flags' => array(6, 26), 'settings' => array(9, 11), 'applications' => array(0, 34), 'default' => array(9, 9), 'people' => array(3, 0), 'ponder' => array(4, 35), 'calendar' => array(5, 4), 'files' => array(6, 3), 'projects' => array(7, 35), 'daemons' => array(7, 6), 'herald' => array(1, 5), 'countdown' => array(7, 5), 'conduit' => array(7, 30), 'feed' => array(3, 11), 'paste' => array(9, 2), 'audit' => array(8, 19), 'uiexample' => array(7, 28), 'phpast' => array(6, 31), 'owners' => array(5, 32), 'phid' => array(9, 25), 'diviner' => array(1, 35), 'repositories' => array(8, 13), 'phame' => array(8, 4), 'macro' => array(0, 31), ); $xadj = -1; foreach ($app_map as $icon => $coords) { list($x, $y) = $coords; foreach ($app_source_map as $suffix => $spec) { list($template, $scale) = $spec; if (isset($spec[2])) { $prefix = $spec[2]; } else { $prefix = ''; } $sheet->addSprite( id(clone $template) ->setSourcePosition(($xadj + glx($x)) * $scale, gly($y) * $scale) ->setTargetCSS($prefix.'.app-'.$icon.$suffix)); } } $action_template = id(new PhutilSprite()) ->setSourcePosition(0, 0) ->setSourceSize(16, 16); $action_map = array( 'file' => 'icon/page_white_text.png', 'fork' => 'icon/arrow_branch.png', 'edit' => 'icon/page_white_edit.png', 'flag-0' => 'icon/flag-0.png', 'flag-1' => 'icon/flag-1.png', 'flag-2' => 'icon/flag-2.png', 'flag-3' => 'icon/flag-3.png', 'flag-4' => 'icon/flag-4.png', 'flag-5' => 'icon/flag-5.png', 'flag-6' => 'icon/flag-6.png', 'flag-7' => 'icon/flag-7.png', 'flag-ghost' => 'icon/flag-ghost.png', 'subscribe-auto' => 'icon/unsubscribe.png', 'subscribe-add' => 'icon/subscribe.png', 'subscribe-delete' => 'icon/unsubscribe.png', 'new' => 'icon/page_white_put.png', 'world' => 'icon/world.png', - 'delete' => 'icon/delete.png', + 'delete' => 'icon/page_delete.png', + 'move' => 'icon/page_go.png', + 'preview' => 'icon/page_world.png', + 'unpublish' => 'icon/page_error.png', ); foreach ($action_map as $icon => $source) { $sheet->addSprite( id(clone $action_template) ->setSourceFile($srcroot.$source) ->setTargetCSS('.action-'.$icon)); } $remarkup_template = id(new PhutilSprite()) ->setSourcePosition(0, 0) ->setSourceSize(14, 14); $remarkup_icons = array( 'b', 'code', 'i', 'image', 'ol', 'tag', 'tt', 'ul', 'help', ); foreach ($remarkup_icons as $icon) { $sheet->addSprite( id(clone $remarkup_template) ->setSourceFile($srcroot.'remarkup/text_'.$icon.'.png') ->setTargetCSS('.remarkup-assist-'.$icon)); } $sheet->generateImage($webroot.'/image/autosprite.png'); $sheet->generateCSS($webroot.'/css/autosprite.css'); echo "Done.\n"; diff --git a/src/applications/phame/application/PhabricatorApplicationPhame.php b/src/applications/phame/application/PhabricatorApplicationPhame.php index 5867f9d194..84ca525a9c 100644 --- a/src/applications/phame/application/PhabricatorApplicationPhame.php +++ b/src/applications/phame/application/PhabricatorApplicationPhame.php @@ -1,77 +1,78 @@ array( '' => 'PhamePostListController', 'live/(?P[^/]+)/(?P.*)' => 'PhameBlogLiveController', 'post/' => array( '(?:(?Pdraft|all)/)?' => 'PhamePostListController', 'blogger/(?P[\w\.-_]+)/' => 'PhamePostListController', 'delete/(?P[^/]+)/' => 'PhamePostDeleteController', 'edit/(?:(?P[^/]+)/)?' => 'PhamePostEditController', 'view/(?P\d+)/' => 'PhamePostViewController', 'publish/(?P\d+)/' => 'PhamePostPublishController', 'unpublish/(?P\d+)/' => 'PhamePostUnpublishController', 'notlive/(?P\d+)/' => 'PhamePostNotLiveController', 'preview/' => 'PhamePostPreviewController', 'framed/(?P\d+)/' => 'PhamePostFramedController', 'new/' => 'PhamePostNewController', + 'move/(?P\d+)/' => 'PhamePostNewController' ), 'blog/' => array( '(?:(?Puser|all)/)?' => 'PhameBlogListController', 'delete/(?P[^/]+)/' => 'PhameBlogDeleteController', 'edit/(?P[^/]+)/' => 'PhameBlogEditController', 'view/(?P[^/]+)/' => 'PhameBlogViewController', 'new/' => 'PhameBlogEditController', ), 'posts/' => array( '(?P\w+)/(?P.+/)' => 'PhamePostViewController', ), ), ); } } diff --git a/src/applications/phame/controller/blog/PhameBlogEditController.php b/src/applications/phame/controller/blog/PhameBlogEditController.php index 35cddc9b52..4b953d2bd0 100644 --- a/src/applications/phame/controller/blog/PhameBlogEditController.php +++ b/src/applications/phame/controller/blog/PhameBlogEditController.php @@ -1,208 +1,208 @@ id = idx($data, 'id'); } public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); if ($this->id) { $blog = id(new PhameBlogQuery()) ->setViewer($user) ->withIDs(array($this->id)) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_EDIT )) ->executeOne(); if (!$blog) { return new Aphront404Response(); } $submit_button = pht('Save Changes'); $page_title = pht('Edit Blog'); $cancel_uri = $this->getApplicationURI('blog/view/'.$blog->getID().'/'); } else { $blog = id(new PhameBlog()) ->setCreatorPHID($user->getPHID()); $blog->setViewPolicy(PhabricatorPolicies::POLICY_USER); $blog->setEditPolicy(PhabricatorPolicies::POLICY_USER); $blog->setJoinPolicy(PhabricatorPolicies::POLICY_USER); $submit_button = pht('Create Blog'); $page_title = pht('Create Blog'); $cancel_uri = $this->getApplicationURI(); } $e_name = true; $e_custom_domain = null; $errors = array(); if ($request->isFormPost()) { $name = $request->getStr('name'); $description = $request->getStr('description'); $custom_domain = $request->getStr('custom_domain'); $skin = $request->getStr('skin'); if (empty($name)) { $errors[] = 'You must give the blog a name.'; $e_name = 'Required'; } else { $e_name = null; } $blog->setName($name); $blog->setDescription($description); - $blog->setDomain($custom_domain); + $blog->setDomain(nonempty($custom_domain, null)); $blog->setSkin($skin); if (!empty($custom_domain)) { $error = $blog->validateCustomDomain($custom_domain); if ($error) { $errors[] = $error; $e_custom_domain = 'Invalid'; } } $blog->setViewPolicy($request->getStr('can_view')); $blog->setEditPolicy($request->getStr('can_edit')); $blog->setJoinPolicy($request->getStr('can_join')); // Don't let users remove their ability to edit blogs. PhabricatorPolicyFilter::mustRetainCapability( $user, $blog, PhabricatorPolicyCapability::CAN_EDIT); if (!$errors) { try { $blog->save(); return id(new AphrontRedirectResponse()) ->setURI($this->getApplicationURI('blog/view/'.$blog->getID().'/')); } catch (AphrontQueryDuplicateKeyException $ex) { $errors[] = 'Domain must be unique.'; $e_custom_domain = 'Not Unique'; } } } $policies = id(new PhabricatorPolicyQuery()) ->setViewer($user) ->setObject($blog) ->execute(); $form = id(new AphrontFormView()) ->setUser($user) ->setFlexible(true) ->appendChild( id(new AphrontFormTextControl()) ->setLabel('Name') ->setName('name') ->setValue($blog->getName()) ->setID('blog-name') ->setError($e_name) ) ->appendChild( id(new PhabricatorRemarkupControl()) ->setLabel('Description') ->setName('description') ->setValue($blog->getDescription()) ->setID('blog-description') ) ->appendChild( id(new AphrontFormPolicyControl()) ->setUser($user) ->setCapability(PhabricatorPolicyCapability::CAN_VIEW) ->setPolicyObject($blog) ->setPolicies($policies) ->setName('can_view')) ->appendChild( id(new AphrontFormPolicyControl()) ->setUser($user) ->setCapability(PhabricatorPolicyCapability::CAN_EDIT) ->setPolicyObject($blog) ->setPolicies($policies) ->setName('can_edit')) ->appendChild( id(new AphrontFormPolicyControl()) ->setUser($user) ->setCapability(PhabricatorPolicyCapability::CAN_JOIN) ->setPolicyObject($blog) ->setPolicies($policies) ->setName('can_join')) ->appendChild( id(new AphrontFormTextControl()) ->setLabel('Custom Domain') ->setName('custom_domain') ->setValue($blog->getDomain()) ->setCaption('Must include at least one dot (.), e.g. '. 'blog.example.com') ->setError($e_custom_domain) ) ->appendChild( id(new AphrontFormSelectControl()) ->setLabel('Skin') ->setName('skin') ->setValue($blog->getSkin()) ->setOptions(PhameBlog::getSkinOptionsForSelect()) ) ->appendChild( id(new AphrontFormSubmitControl()) ->addCancelButton($cancel_uri) ->setValue($submit_button) ); if ($errors) { $error_view = id(new AphrontErrorView()) ->setTitle('Form Errors') ->setErrors($errors); } else { $error_view = null; } $header = id(new PhabricatorHeaderView()) ->setHeader($page_title); $nav = $this->renderSideNavFilterView(); $nav->selectFilter($this->id ? null : 'blog/new'); $nav->appendChild( array( $header, $error_view, $form, )); return $this->buildApplicationPage( $nav, array( 'title' => $page_title, )); } } diff --git a/src/applications/phame/controller/blog/PhameBlogViewController.php b/src/applications/phame/controller/blog/PhameBlogViewController.php index 7533d0b86b..8475cee454 100644 --- a/src/applications/phame/controller/blog/PhameBlogViewController.php +++ b/src/applications/phame/controller/blog/PhameBlogViewController.php @@ -1,172 +1,172 @@ id = $data['id']; } public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $blog = id(new PhameBlogQuery()) ->setViewer($user) ->withIDs(array($this->id)) ->executeOne(); if (!$blog) { return new Aphront404Response(); } $pager = id(new AphrontCursorPagerView()) ->readFromRequest($request); $posts = id(new PhamePostQuery()) ->setViewer($user) ->withBlogPHIDs(array($blog->getPHID())) ->executeWithCursorPager($pager); $nav = $this->renderSideNavFilterView(null); $header = id(new PhabricatorHeaderView()) ->setHeader($blog->getName()); $handle_phids = array_merge( mpull($posts, 'getBloggerPHID'), mpull($posts, 'getBlogPHID')); $this->loadHandles($handle_phids); $actions = $this->renderActions($blog, $user); $properties = $this->renderProperties($blog, $user); $post_list = $this->renderPostList( $posts, $user, pht('This blog has no visible posts.')); $nav->appendChild( array( $header, $actions, $properties, $post_list, )); return $this->buildApplicationPage( $nav, array( 'device' => true, 'title' => $blog->getName(), )); } private function renderProperties(PhameBlog $blog, PhabricatorUser $user) { $properties = new PhabricatorPropertyListView(); $properties->addProperty( pht('Skin'), phutil_escape_html($blog->getSkin())); $properties->addProperty( pht('Domain'), phutil_escape_html($blog->getDomain())); $descriptions = PhabricatorPolicyQuery::renderPolicyDescriptions( $user, $blog); $properties->addProperty( pht('Visible To'), $descriptions[PhabricatorPolicyCapability::CAN_VIEW]); $properties->addProperty( pht('Editable By'), $descriptions[PhabricatorPolicyCapability::CAN_EDIT]); $properties->addProperty( pht('Joinable By'), $descriptions[PhabricatorPolicyCapability::CAN_JOIN]); $engine = id(new PhabricatorMarkupEngine()) ->setViewer($user) ->addObject($blog, PhameBlog::MARKUP_FIELD_DESCRIPTION) ->process(); $properties->addTextContent( '
'. $engine->getOutput($blog, PhameBlog::MARKUP_FIELD_DESCRIPTION). '
'); return $properties; } private function renderActions(PhameBlog $blog, PhabricatorUser $user) { $actions = id(new PhabricatorActionListView()) ->setObject($blog) ->setUser($user); $can_edit = PhabricatorPolicyFilter::hasCapability( $user, $blog, PhabricatorPolicyCapability::CAN_EDIT); $can_join = PhabricatorPolicyFilter::hasCapability( $user, $blog, PhabricatorPolicyCapability::CAN_JOIN); $actions->addAction( id(new PhabricatorActionView()) ->setIcon('new') - ->setHref($this->getApplicationURI('post/new/?blog='.$blog->getID())) + ->setHref($this->getApplicationURI('post/edit/?blog='.$blog->getID())) ->setName(pht('Write Post')) ->setDisabled(!$can_join) ->setWorkflow(!$can_join)); $actions->addAction( id(new PhabricatorActionView()) ->setIcon('world') ->setHref($this->getApplicationURI('live/'.$blog->getID().'/')) ->setName(pht('View Live'))); $actions->addAction( id(new PhabricatorActionView()) ->setIcon('edit') ->setHref($this->getApplicationURI('blog/edit/'.$blog->getID().'/')) ->setName('Edit Blog') ->setDisabled(!$can_edit) ->setWorkflow(!$can_edit)); $actions->addAction( id(new PhabricatorActionView()) ->setIcon('delete') ->setHref($this->getApplicationURI('blog/delete/'.$blog->getID().'/')) ->setName('Delete Blog') ->setDisabled(!$can_edit) ->setWorkflow(true)); return $actions; } } diff --git a/src/applications/phame/controller/post/PhamePostNewController.php b/src/applications/phame/controller/post/PhamePostNewController.php index 6393c2d9b0..60b7056e67 100644 --- a/src/applications/phame/controller/post/PhamePostNewController.php +++ b/src/applications/phame/controller/post/PhamePostNewController.php @@ -1,77 +1,140 @@ id = idx($data, 'id'); + } + public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); + $post = null; + $view_uri = null; + if ($this->id) { + $post = id(new PhamePostQuery()) + ->setViewer($user) + ->withIDs(array($this->id)) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->executeOne(); + if (!$post) { + return new Aphront404Response(); + } + + $view_uri = '/post/view/'.$post->getID().'/'; + $view_uri = $this->getApplicationURI($view_uri); + + if ($request->isFormPost()) { + $blog = id(new PhameBlogQuery()) + ->setViewer($user) + ->withIDs(array($request->getInt('blog'))) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_JOIN, + )) + ->executeOne(); + + if ($blog) { + $post->setBlogPHID($blog->getPHID()); + $post->save(); + + return id(new AphrontRedirectResponse())->setURI($view_uri); + } + } + + $title = pht('Move Post'); + } else { + $title = pht('Create Post'); + } + $blogs = id(new PhameBlogQuery()) ->setViewer($user) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_JOIN, )) ->execute(); $nav = $this->renderSideNavFilterView(); $nav->selectFilter('post/new'); $nav->appendChild( - id(new PhabricatorHeaderView())->setHeader( - pht('Create Post'))); + id(new PhabricatorHeaderView())->setHeader($title)); if (!$blogs) { $notification = id(new AphrontErrorView()) ->setSeverity(AphrontErrorView::SEVERITY_NODATA) ->appendChild( pht('You do not have permission to join any blogs. Create a blog '. 'first, then you can post to it.')); $nav->appendChild($notification); } else { $options = mpull($blogs, 'getName', 'getID'); + asort($options); + + $selected_value = null; + if ($post && $post->getBlog()) { + $selected_value = $post->getBlog()->getID(); + } $form = id(new AphrontFormView()) ->setUser($user) - ->setMethod('GET') ->setFlexible(true) - ->setAction($this->getApplicationURI('post/edit/')) ->appendChild( id(new AphrontFormSelectControl()) ->setLabel('Blog') ->setName('blog') - ->setOptions($options)) - ->appendChild( - id(new AphrontFormSubmitControl()) - ->setValue('Continue')); + ->setOptions($options) + ->setValue($selected_value)); + + if ($post) { + $form + ->appendChild( + id(new AphrontFormSubmitControl()) + ->setValue(pht('Move Post')) + ->addCancelButton($view_uri)); + } else { + $form + ->setAction($this->getApplicationURI('post/edit/')) + ->setMethod('GET') + ->appendChild( + id(new AphrontFormSubmitControl()) + ->setValue(pht('Continue'))); + } $nav->appendChild($form); } return $this->buildApplicationPage( $nav, array( - 'title' => 'Create Post', + 'title' => $title, 'device' => true, )); } } diff --git a/src/applications/phame/controller/post/PhamePostNotLiveController.php b/src/applications/phame/controller/post/PhamePostNotLiveController.php index 9676a11ad8..8d5cb3715b 100644 --- a/src/applications/phame/controller/post/PhamePostNotLiveController.php +++ b/src/applications/phame/controller/post/PhamePostNotLiveController.php @@ -1,79 +1,79 @@ id = $data['id']; } public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $post = id(new PhamePostQuery()) ->setViewer($user) ->withIDs(array($this->id)) ->executeOne(); if (!$post) { return new Aphront404Response(); } $reasons = array(); if (!$post->getBlog()) { $reasons[] = '

'.pht('You can not view the live version of this post because it '. - 'is not associated with a blog. Edit the post and choose a blog to '. - 'publish it to.').'

'; + 'is not associated with a blog. Move the post to a blog in order to '. + 'view it live.').'

'; } if ($post->isDraft()) { $reasons[] = '

'.pht('You can not view the live version of this post because it '. 'is still a draft. Use "Preview/Publish" to publish the post.').'

'; } if ($reasons) { $cancel_uri = $this->getApplicationURI('/post/view/'.$post->getID().'/'); $dialog = id(new AphrontDialogView()) ->setUser($user) ->setTitle(pht('Post Not Live')) ->addCancelButton($cancel_uri); foreach ($reasons as $reason) { $dialog->appendChild($reason); } return id(new AphrontDialogResponse())->setDialog($dialog); } // No reason this can't go live, maybe an old link. Kick them live and see // what happens. $blog = $post->getBlog(); $live_uri = 'http://'.$blog->getDomain().'/'.$post->getPhameTitle(); return id(new AphrontRedirectResponse())->setURI($live_uri); } } diff --git a/src/applications/phame/controller/post/PhamePostViewController.php b/src/applications/phame/controller/post/PhamePostViewController.php index affbfbda81..626a1704c4 100644 --- a/src/applications/phame/controller/post/PhamePostViewController.php +++ b/src/applications/phame/controller/post/PhamePostViewController.php @@ -1,204 +1,209 @@ id = $data['id']; } public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $post = id(new PhamePostQuery()) ->setViewer($user) ->withIDs(array($this->id)) ->executeOne(); if (!$post) { return new Aphront404Response(); } + $nav = $this->renderSideNavFilterView(); + + $nav->appendChild( + id(new PhabricatorHeaderView()) + ->setHeader($post->getTitle())); + if ($post->isDraft()) { - $notice = array( - 'title' => 'You are previewing a draft.', - 'body' => 'Only you can see this draft until you publish it. '. - 'If you chose a comment widget it will show up when '. - 'you publish.' - ); - } else if ($request->getExists('saved')) { - $new_link = phutil_render_tag( - 'a', - array( - 'href' => '/phame/post/new/', - 'class' => 'button green', - ), - 'write another blog post' - ); - $notice = array( - 'title' => 'Saved post successfully.', - 'body' => 'Seek even more phame and '.$new_link.'.' - ); - } else { - $notice = array(); + $nav->appendChild( + id(new AphrontErrorView()) + ->setSeverity(AphrontErrorView::SEVERITY_NOTICE) + ->setTitle(pht('Draft Post')) + ->appendChild( + pht('Only you can see this draft until you publish it. '. + 'Use "Preview / Publish" to publish this post.'))); + } + + if (!$post->getBlog()) { + $nav->appendChild( + id(new AphrontErrorView()) + ->setSeverity(AphrontErrorView::SEVERITY_WARNING) + ->setTitle(pht('Not On A Blog')) + ->appendChild( + pht('This post is not associated with a blog (the blog may have '. + 'been deleted). Use "Move Post" to move it to a new blog.'))); } $this->loadHandles( array( $post->getBlogPHID(), $post->getBloggerPHID(), )); - $nav = $this->renderSideNavFilterView(null); - - $header = id(new PhabricatorHeaderView())->setHeader($post->getTitle()); - $actions = $this->renderActions($post, $user); $properties = $this->renderProperties($post, $user); $nav->appendChild( array( - $header, $actions, $properties, )); return $this->buildApplicationPage( $nav, array( 'title' => $post->getTitle(), 'device' => true, )); } private function renderActions( PhamePost $post, PhabricatorUser $user) { $actions = id(new PhabricatorActionListView()) ->setObject($post) ->setUser($user); $can_edit = PhabricatorPolicyFilter::hasCapability( $user, $post, PhabricatorPolicyCapability::CAN_EDIT); $id = $post->getID(); $actions->addAction( id(new PhabricatorActionView()) ->setIcon('edit') ->setHref($this->getApplicationURI('post/edit/'.$id.'/')) ->setName('Edit Post') ->setDisabled(!$can_edit) ->setWorkflow(!$can_edit)); - $blog = $post->getBlog(); - $can_view_live = $blog && !$post->isDraft(); - - if ($can_view_live) { - $live_uri = 'live/'.$blog->getID().'/post/'.$post->getPhameTitle(); - } else { - $live_uri = 'post/notlive/'.$post->getID().'/'; - } - $live_uri = $this->getApplicationURI($live_uri); - $actions->addAction( id(new PhabricatorActionView()) - ->setIcon('world') - ->setHref($live_uri) - ->setName(pht('View Live')) - ->setDisabled(!$can_view_live) - ->setWorkflow(!$can_view_live)); + ->setIcon('move') + ->setHref($this->getApplicationURI('post/move/'.$id.'/')) + ->setName('Move Post') + ->setDisabled(!$can_edit) + ->setWorkflow(!$can_edit)); if ($post->isDraft()) { $actions->addAction( id(new PhabricatorActionView()) - ->setIcon('world') + ->setIcon('preview') ->setHref($this->getApplicationURI('post/publish/'.$id.'/')) ->setName(pht('Preview / Publish'))); } else { $actions->addAction( id(new PhabricatorActionView()) - ->setIcon('delete') + ->setIcon('unpublish') ->setHref($this->getApplicationURI('post/unpublish/'.$id.'/')) ->setName(pht('Unpublish')) ->setWorkflow(true)); } $actions->addAction( id(new PhabricatorActionView()) ->setIcon('delete') ->setHref($this->getApplicationURI('post/delete/'.$id.'/')) ->setName('Delete Post') ->setDisabled(!$can_edit) ->setWorkflow(true)); + $blog = $post->getBlog(); + $can_view_live = $blog && !$post->isDraft(); + + if ($can_view_live) { + $live_uri = 'live/'.$blog->getID().'/post/'.$post->getPhameTitle(); + } else { + $live_uri = 'post/notlive/'.$post->getID().'/'; + } + $live_uri = $this->getApplicationURI($live_uri); + + $actions->addAction( + id(new PhabricatorActionView()) + ->setIcon('world') + ->setHref($live_uri) + ->setName(pht('View Live')) + ->setDisabled(!$can_view_live) + ->setWorkflow(!$can_view_live)); + return $actions; } private function renderProperties( PhamePost $post, PhabricatorUser $user) { $properties = new PhabricatorPropertyListView(); $descriptions = PhabricatorPolicyQuery::renderPolicyDescriptions( $user, $post); $properties->addProperty( pht('Blog'), $post->getBlogPHID() ? $this->getHandle($post->getBlogPHID())->renderLink() : null); $properties->addProperty( pht('Blogger'), $this->getHandle($post->getBloggerPHID())->renderLink()); $properties->addProperty( pht('Visible To'), $descriptions[PhabricatorPolicyCapability::CAN_VIEW]); $properties->addProperty( pht('Published'), $post->isDraft() ? pht('Draft') : phabricator_datetime($post->getDatePublished(), $user)); $engine = id(new PhabricatorMarkupEngine()) ->setViewer($user) ->addObject($post, PhamePost::MARKUP_FIELD_BODY) ->process(); $properties->addTextContent( '
'. $engine->getOutput($post, PhamePost::MARKUP_FIELD_BODY). '
'); return $properties; } } diff --git a/src/view/form/AphrontErrorView.php b/src/view/form/AphrontErrorView.php index f68dc129cd..dce3e9a974 100644 --- a/src/view/form/AphrontErrorView.php +++ b/src/view/form/AphrontErrorView.php @@ -1,108 +1,107 @@ title = $title; return $this; } public function setSeverity($severity) { $this->severity = $severity; return $this; } public function setErrors(array $errors) { $this->errors = $errors; return $this; } public function setID($id) { $this->id = $id; return $this; } final public function render() { require_celerity_resource('aphront-error-view-css'); $errors = $this->errors; if ($errors) { $list = array(); foreach ($errors as $error) { $list[] = phutil_render_tag( 'li', array(), phutil_escape_html($error)); } $list = phutil_render_tag( 'ul', array( 'class' => 'aphront-error-view-list', ), implode("\n", $list)); } else { $list = null; } $title = $this->title; if (strlen($title)) { $title = phutil_render_tag( 'h1', array( 'class' => 'aphront-error-view-head', ), phutil_escape_html($title)); } else { $title = null; } $this->severity = nonempty($this->severity, self::SEVERITY_ERROR); $more_classes = array(); $more_classes[] = 'aphront-error-severity-'.$this->severity; $more_classes = implode(' ', $more_classes); - return + return phutil_render_tag( + 'div', + array( + 'id' => $this->id, + 'class' => 'aphront-error-view '.$more_classes, + ), + $title. phutil_render_tag( 'div', array( - 'id' => $this->id, - 'class' => 'aphront-error-view '.$more_classes, + 'class' => 'aphront-error-view-body', ), - $title. - phutil_render_tag( - 'div', - array( - 'class' => 'aphront-error-view-body', - ), - $this->renderChildren(). - $list)); + $this->renderChildren(). + $list)); } } diff --git a/webroot/rsrc/css/aphront/error-view.css b/webroot/rsrc/css/aphront/error-view.css index 02056f45cf..21f6e36156 100644 --- a/webroot/rsrc/css/aphront/error-view.css +++ b/webroot/rsrc/css/aphront/error-view.css @@ -1,68 +1,69 @@ /** * @provides aphront-error-view-css */ .aphront-error-view { margin: 1em 2%; box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.1); border-style: solid; border-width: 1px; } .aphront-error-view-body { padding: 0.5em 1em; font-size: 12px; line-height: 1.6em; } .aphront-error-view-head { font-size: 13px; padding: 0.5em 1em; font-weight: bold; color: #333333; } .aphront-error-view-list { margin: 0.2em 0 0.2em 2em; list-style: disc; } .aphront-error-severity-error { border-color: #aa0000; background: #fff3f3; } .aphront-error-severity-error .aphront-error-view-head { background: #ffe3e3; } .aphront-error-severity-warning { border-color: #888800; background: #ffffee; } .aphront-error-severity-warning .aphront-error-view-head { background: #ffffcc; } .aphront-error-severity-notice { border-color: #000088; background: #f3f3ff; } .aphront-error-severity-notice .aphront-error-view-head { background: #e3e3ff; } .aphront-error-severity-nodata { border-color: #dfdfdf; background: #f3f3f3; color: #666666; box-shadow: 0px 0px 0px #000; } .aphront-error-severity-nodata .aphront-error-view-head { background: #e3e3e3; } + diff --git a/webroot/rsrc/css/autosprite.css b/webroot/rsrc/css/autosprite.css index e26de1e87e..5b93e88883 100644 --- a/webroot/rsrc/css/autosprite.css +++ b/webroot/rsrc/css/autosprite.css @@ -1,797 +1,809 @@ /** * @provides autosprite-css * @generated */ .autosprite { background-image: url(/rsrc/image/autosprite.png); background-repeat: no-repeat; } .main-menu-item-icon-help { background-position: 0px 0px; } .main-menu-item-icon-help-selected { background-position: 0px -27px; } .main-menu-item-icon-help:hover { background-position: 0px -54px; } .main-menu-item-icon-settings { background-position: 0px -81px; } .main-menu-item-icon-settings-selected { background-position: 0px -108px; } .main-menu-item-icon-settings:hover { background-position: 0px -135px; } .main-menu-item-icon-logout { background-position: 0px -162px; } .main-menu-item-icon-logout-selected { background-position: 0px -189px; } .main-menu-item-icon-logout:hover { background-position: 0px -216px; } .main-menu-item-icon-notifications { background-position: 0px -243px; } .main-menu-item-icon-notifications-selected { background-position: 0px -270px; } .main-menu-item-icon-notifications:hover { background-position: 0px -297px; } .main-menu-item-icon-task { background-position: 0px -324px; } .main-menu-item-icon-task-selected { background-position: 0px -351px; } .main-menu-item-icon-task:hover { background-position: 0px -378px; } .app-differential-large { background-position: 0px -405px; } .device-desktop .phabricator-application-launch-container:hover .app-differential-large /* hover */ { background-position: 0px -466px; } .app-differential { background-position: 0px -527px; } .device-desktop .app-differential:hover { background-position: 0px -558px; } .app-differential-selected { background-position: 0px -589px; } .app-fact-large { background-position: 0px -620px; } .device-desktop .phabricator-application-launch-container:hover .app-fact-large /* hover */ { background-position: 0px -681px; } .app-fact { background-position: 0px -742px; } .device-desktop .app-fact:hover { background-position: 0px -773px; } .app-fact-selected { background-position: 0px -804px; } .app-mail-large { background-position: 0px -835px; } .device-desktop .phabricator-application-launch-container:hover .app-mail-large /* hover */ { background-position: 0px -896px; } .app-mail { background-position: 0px -957px; } .device-desktop .app-mail:hover { background-position: 0px -988px; } .app-mail-selected { background-position: 0px -1019px; } .app-diffusion-large { background-position: 0px -1050px; } .device-desktop .phabricator-application-launch-container:hover .app-diffusion-large /* hover */ { background-position: 0px -1111px; } .app-diffusion { background-position: 0px -1172px; } .device-desktop .app-diffusion:hover { background-position: 0px -1203px; } .app-diffusion-selected { background-position: 0px -1234px; } .app-slowvote-large { background-position: 0px -1265px; } .device-desktop .phabricator-application-launch-container:hover .app-slowvote-large /* hover */ { background-position: 0px -1326px; } .app-slowvote { background-position: 0px -1387px; } .device-desktop .app-slowvote:hover { background-position: 0px -1418px; } .app-slowvote-selected { background-position: 0px -1449px; } .app-phriction-large { background-position: 0px -1480px; } .device-desktop .phabricator-application-launch-container:hover .app-phriction-large /* hover */ { background-position: 0px -1541px; } .app-phriction { background-position: 0px -1602px; } .device-desktop .app-phriction:hover { background-position: 0px -1633px; } .app-phriction-selected { background-position: 0px -1664px; } .app-maniphest-large { background-position: 0px -1695px; } .device-desktop .phabricator-application-launch-container:hover .app-maniphest-large /* hover */ { background-position: 0px -1756px; } .app-maniphest { background-position: 0px -1817px; } .device-desktop .app-maniphest:hover { background-position: 0px -1848px; } .app-maniphest-selected { background-position: 0px -1879px; } .app-flags-large { background-position: 0px -1910px; } .device-desktop .phabricator-application-launch-container:hover .app-flags-large /* hover */ { background-position: 0px -1971px; } .app-flags { background-position: 0px -2032px; } .device-desktop .app-flags:hover { background-position: 0px -2063px; } .app-flags-selected { background-position: 0px -2094px; } .app-settings-large { background-position: 0px -2125px; } .device-desktop .phabricator-application-launch-container:hover .app-settings-large /* hover */ { background-position: 0px -2186px; } .app-settings { background-position: 0px -2247px; } .device-desktop .app-settings:hover { background-position: 0px -2278px; } .app-settings-selected { background-position: 0px -2309px; } .app-applications-large { background-position: 0px -2340px; } .device-desktop .phabricator-application-launch-container:hover .app-applications-large /* hover */ { background-position: 0px -2401px; } .app-applications { background-position: 0px -2462px; } .device-desktop .app-applications:hover { background-position: 0px -2493px; } .app-applications-selected { background-position: 0px -2524px; } .app-default-large { background-position: 0px -2555px; } .device-desktop .phabricator-application-launch-container:hover .app-default-large /* hover */ { background-position: 0px -2616px; } .app-default { background-position: 0px -2677px; } .device-desktop .app-default:hover { background-position: 0px -2708px; } .app-default-selected { background-position: 0px -2739px; } .app-people-large { background-position: 0px -2770px; } .device-desktop .phabricator-application-launch-container:hover .app-people-large /* hover */ { background-position: 0px -2831px; } .app-people { background-position: 0px -2892px; } .device-desktop .app-people:hover { background-position: 0px -2923px; } .app-people-selected { background-position: 0px -2954px; } .app-ponder-large { background-position: 0px -2985px; } .device-desktop .phabricator-application-launch-container:hover .app-ponder-large /* hover */ { background-position: 0px -3046px; } .app-ponder { background-position: 0px -3107px; } .device-desktop .app-ponder:hover { background-position: 0px -3138px; } .app-ponder-selected { background-position: 0px -3169px; } .app-calendar-large { background-position: 0px -3200px; } .device-desktop .phabricator-application-launch-container:hover .app-calendar-large /* hover */ { background-position: 0px -3261px; } .app-calendar { background-position: 0px -3322px; } .device-desktop .app-calendar:hover { background-position: 0px -3353px; } .app-calendar-selected { background-position: 0px -3384px; } .app-files-large { background-position: 0px -3415px; } .device-desktop .phabricator-application-launch-container:hover .app-files-large /* hover */ { background-position: 0px -3476px; } .app-files { background-position: 0px -3537px; } .device-desktop .app-files:hover { background-position: 0px -3568px; } .app-files-selected { background-position: 0px -3599px; } .app-projects-large { background-position: 0px -3630px; } .device-desktop .phabricator-application-launch-container:hover .app-projects-large /* hover */ { background-position: 0px -3691px; } .app-projects { background-position: 0px -3752px; } .device-desktop .app-projects:hover { background-position: 0px -3783px; } .app-projects-selected { background-position: 0px -3814px; } .app-daemons-large { background-position: 0px -3845px; } .device-desktop .phabricator-application-launch-container:hover .app-daemons-large /* hover */ { background-position: 0px -3906px; } .app-daemons { background-position: 0px -3967px; } .device-desktop .app-daemons:hover { background-position: 0px -3998px; } .app-daemons-selected { background-position: 0px -4029px; } .app-herald-large { background-position: 0px -4060px; } .device-desktop .phabricator-application-launch-container:hover .app-herald-large /* hover */ { background-position: 0px -4121px; } .app-herald { background-position: 0px -4182px; } .device-desktop .app-herald:hover { background-position: 0px -4213px; } .app-herald-selected { background-position: 0px -4244px; } .app-countdown-large { background-position: 0px -4275px; } .device-desktop .phabricator-application-launch-container:hover .app-countdown-large /* hover */ { background-position: 0px -4336px; } .app-countdown { background-position: 0px -4397px; } .device-desktop .app-countdown:hover { background-position: 0px -4428px; } .app-countdown-selected { background-position: 0px -4459px; } .app-conduit-large { background-position: 0px -4490px; } .device-desktop .phabricator-application-launch-container:hover .app-conduit-large /* hover */ { background-position: 0px -4551px; } .app-conduit { background-position: 0px -4612px; } .device-desktop .app-conduit:hover { background-position: 0px -4643px; } .app-conduit-selected { background-position: 0px -4674px; } .app-feed-large { background-position: 0px -4705px; } .device-desktop .phabricator-application-launch-container:hover .app-feed-large /* hover */ { background-position: 0px -4766px; } .app-feed { background-position: 0px -4827px; } .device-desktop .app-feed:hover { background-position: 0px -4858px; } .app-feed-selected { background-position: 0px -4889px; } .app-paste-large { background-position: 0px -4920px; } .device-desktop .phabricator-application-launch-container:hover .app-paste-large /* hover */ { background-position: 0px -4981px; } .app-paste { background-position: 0px -5042px; } .device-desktop .app-paste:hover { background-position: 0px -5073px; } .app-paste-selected { background-position: 0px -5104px; } .app-audit-large { background-position: 0px -5135px; } .device-desktop .phabricator-application-launch-container:hover .app-audit-large /* hover */ { background-position: 0px -5196px; } .app-audit { background-position: 0px -5257px; } .device-desktop .app-audit:hover { background-position: 0px -5288px; } .app-audit-selected { background-position: 0px -5319px; } .app-uiexample-large { background-position: 0px -5350px; } .device-desktop .phabricator-application-launch-container:hover .app-uiexample-large /* hover */ { background-position: 0px -5411px; } .app-uiexample { background-position: 0px -5472px; } .device-desktop .app-uiexample:hover { background-position: 0px -5503px; } .app-uiexample-selected { background-position: 0px -5534px; } .app-phpast-large { background-position: 0px -5565px; } .device-desktop .phabricator-application-launch-container:hover .app-phpast-large /* hover */ { background-position: 0px -5626px; } .app-phpast { background-position: 0px -5687px; } .device-desktop .app-phpast:hover { background-position: 0px -5718px; } .app-phpast-selected { background-position: 0px -5749px; } .app-owners-large { background-position: 0px -5780px; } .device-desktop .phabricator-application-launch-container:hover .app-owners-large /* hover */ { background-position: 0px -5841px; } .app-owners { background-position: 0px -5902px; } .device-desktop .app-owners:hover { background-position: 0px -5933px; } .app-owners-selected { background-position: 0px -5964px; } .app-phid-large { background-position: 0px -5995px; } .device-desktop .phabricator-application-launch-container:hover .app-phid-large /* hover */ { background-position: 0px -6056px; } .app-phid { background-position: 0px -6117px; } .device-desktop .app-phid:hover { background-position: 0px -6148px; } .app-phid-selected { background-position: 0px -6179px; } .app-diviner-large { background-position: 0px -6210px; } .device-desktop .phabricator-application-launch-container:hover .app-diviner-large /* hover */ { background-position: 0px -6271px; } .app-diviner { background-position: 0px -6332px; } .device-desktop .app-diviner:hover { background-position: 0px -6363px; } .app-diviner-selected { background-position: 0px -6394px; } .app-repositories-large { background-position: 0px -6425px; } .device-desktop .phabricator-application-launch-container:hover .app-repositories-large /* hover */ { background-position: 0px -6486px; } .app-repositories { background-position: 0px -6547px; } .device-desktop .app-repositories:hover { background-position: 0px -6578px; } .app-repositories-selected { background-position: 0px -6609px; } .app-phame-large { background-position: 0px -6640px; } .device-desktop .phabricator-application-launch-container:hover .app-phame-large /* hover */ { background-position: 0px -6701px; } .app-phame { background-position: 0px -6762px; } .device-desktop .app-phame:hover { background-position: 0px -6793px; } .app-phame-selected { background-position: 0px -6824px; } .app-macro-large { background-position: 0px -6855px; } .device-desktop .phabricator-application-launch-container:hover .app-macro-large /* hover */ { background-position: 0px -6916px; } .app-macro { background-position: 0px -6977px; } .device-desktop .app-macro:hover { background-position: 0px -7008px; } .app-macro-selected { background-position: 0px -7039px; } .action-file { background-position: 0px -7070px; } .action-fork { background-position: 0px -7087px; } .action-edit { background-position: 0px -7104px; } .action-flag-0 { background-position: 0px -7121px; } .action-flag-1 { background-position: 0px -7138px; } .action-flag-2 { background-position: 0px -7155px; } .action-flag-3 { background-position: 0px -7172px; } .action-flag-4 { background-position: 0px -7189px; } .action-flag-5 { background-position: 0px -7206px; } .action-flag-6 { background-position: 0px -7223px; } .action-flag-7 { background-position: 0px -7240px; } .action-flag-ghost { background-position: 0px -7257px; } .action-subscribe-auto { background-position: 0px -7274px; } .action-subscribe-add { background-position: 0px -7291px; } .action-subscribe-delete { background-position: 0px -7308px; } .action-new { background-position: 0px -7325px; } .action-world { background-position: 0px -7342px; } .action-delete { background-position: 0px -7359px; } -.remarkup-assist-b { +.action-move { background-position: 0px -7376px; } +.action-preview { + background-position: 0px -7393px; +} + +.action-unpublish { + background-position: 0px -7410px; +} + +.remarkup-assist-b { + background-position: 0px -7427px; +} + .remarkup-assist-code { - background-position: 0px -7391px; + background-position: 0px -7442px; } .remarkup-assist-i { - background-position: 0px -7406px; + background-position: 0px -7457px; } .remarkup-assist-image { - background-position: 0px -7421px; + background-position: 0px -7472px; } .remarkup-assist-ol { - background-position: 0px -7436px; + background-position: 0px -7487px; } .remarkup-assist-tag { - background-position: 0px -7451px; + background-position: 0px -7502px; } .remarkup-assist-tt { - background-position: 0px -7466px; + background-position: 0px -7517px; } .remarkup-assist-ul { - background-position: 0px -7481px; + background-position: 0px -7532px; } .remarkup-assist-help { - background-position: 0px -7496px; + background-position: 0px -7547px; } diff --git a/webroot/rsrc/css/layout/phabricator-action-list-view.css b/webroot/rsrc/css/layout/phabricator-action-list-view.css index 80083e448a..a8d7ce03d2 100644 --- a/webroot/rsrc/css/layout/phabricator-action-list-view.css +++ b/webroot/rsrc/css/layout/phabricator-action-list-view.css @@ -1,80 +1,80 @@ /** * @provides phabricator-action-list-view-css */ .phabricator-action-list-view { background: #ffffff; } .device-desktop .phabricator-action-list-view { border: 1px solid #dcdcdc; padding: .5em 0; float: right; - margin-top: -30px; + margin-top: 0px; margin-right: 1%; width: 20%; border-radius: 2px; font-size: 12px; box-shadow: 0px 1px 4px rgba(0, 0, 0, 0.10); } .device-tablet .phabricator-action-list-view, .device-phone .phabricator-action-list-view { background: #f3f3f3; border-top: 1px solid #dcdcdc; padding: .5em 0; } .phabricator-action-view { padding: 2px 0; position: relative; } .phabricator-action-view button.phabricator-action-view-item { border: none; background: transparent; box-shadow: none; outline: 0; box-shadow: 0; padding: 0; margin: 0; font-weight: normal; color: #3b5998; width: 100%; text-align: left; } .phabricator-action-view button.phabricator-action-view-item, .phabricator-action-view-item { line-height: 20px; padding-left: 34px; display: block; font-size: 12px; } .phabricator-action-view-icon { width: 16px; height: 16px; position: absolute; top: 4px; left: 12px; } .device-desktop .phabricator-action-view-item:hover { background-color: #3875d7; color: #ffffff; text-decoration: none; } .phabricator-action-view-disabled .phabricator-action-view-item, .phabricator-action-view-disabled button.phabricator-action-view-item { color: #888888; } .phabricator-action-view-disabled .phabricator-action-view-item:hover, .phabricator-action-view-disabled button.phabricator-action-view-item:hover { background-color: #dfdfdf; color: #888888; } diff --git a/webroot/rsrc/css/layout/phabricator-property-list-view.css b/webroot/rsrc/css/layout/phabricator-property-list-view.css index 22f3affe7a..dec6656600 100644 --- a/webroot/rsrc/css/layout/phabricator-property-list-view.css +++ b/webroot/rsrc/css/layout/phabricator-property-list-view.css @@ -1,68 +1,92 @@ /** * @provides phabricator-property-list-view-css */ .phabricator-property-list-view { border-color: #dbdbdb; border-style: solid; border-width: 1px 0; background-color: #f9f9f9; } .phabriator-property-list-view-end { clear: both; } .device-desktop .phabricator-property-list-view { padding: 1em 0 0.75em; } .device-tablet .phabricator-property-list-view, .device-phone .phabricator-property-list-view { padding: .5em; } .phabricator-property-key { color: #333333; font-weight: bold; } .device-desktop .phabricator-property-key { width: 12%; margin-left: 1%; text-align: right; float: left; clear: left; margin-bottom: .5em; } .device-tablet .phabricator-property-key, .device-phone .phabricator-property-key { padding-left: .5em; } .phabricator-property-value { color: #333333; } .device-desktop .phabricator-property-value { width: 53%; margin-left: 1%; float: left; margin-bottom: .5em; } .device-tablet .phabricator-property-value, .device-phone .phabricator-property-value { padding-left: 1.5em; margin-bottom: .5em; } .phabricator-property-list-content { background: #fdfdfd; border-bottom: 1px solid #dbdbdb; } .phabricator-property-list-text-content { padding: 12px 18px; } + +/* When we follow an action list view on the Desktop, move down 30px so the + action list can start slightly above the property list. This is an unusual + case where we have something between the header and the action/property + lists and we want to give it space. */ +.device-desktop .phabricator-action-list-view + + .phabricator-property-list-view { + clear: left; + margin-top: 30px; +} + + +/* In the common case where we immediately follow a header, move back up 30px + so we snuggle next to the header. */ +.device-desktop .phabricator-header-view + + .phabricator-action-list-view { + margin-top: -30px; +} + +.device-desktop .phabricator-header-view + + .phabricator-action-list-view + + .phabricator-property-list-view { + margin-top: 0px; +} diff --git a/webroot/rsrc/image/autosprite.png b/webroot/rsrc/image/autosprite.png index 35b9978462..89a7ff31ad 100644 Binary files a/webroot/rsrc/image/autosprite.png and b/webroot/rsrc/image/autosprite.png differ