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

Configure Feed

Select the types of activity you want to include in your feed.

Add concept of "skins" to phame, and add a phacility skin

Summary:
introduce an abstract "PhameBlogSkin" class and instantiate two versions -- PhabricatorBlogSkin (Default) and PhacilityBlogSkin.

Most notable hack is including the directory /rsrc/images/phacility - this lets things "work" without messing around with the phacility.com CSS and instead just cutting and pasting most of the file.

Test Plan: played around with Phame a bunch. In particular, created a blog with a custom domain and the phacility skin. Verified it looked good and individual posts looked okay.

Reviewers: epriestley

Reviewed By: epriestley

CC: aran, Korvin

Maniphest Tasks: T1373

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

+878 -307
+56 -6
src/__celerity_resource_map__.php
··· 462 462 'disk' => '/rsrc/image/nyan.gif', 463 463 'type' => 'gif', 464 464 ), 465 + '/rsrc/image/phacility/phacility_logo.jpg' => 466 + array( 467 + 'hash' => '88000de28b8741acc584b24560bd3d4f', 468 + 'uri' => '/res/88000de2/rsrc/image/phacility/phacility_logo.jpg', 469 + 'disk' => '/rsrc/image/phacility/phacility_logo.jpg', 470 + 'type' => 'jpg', 471 + ), 472 + '/rsrc/image/phacility/sprites.png' => 473 + array( 474 + 'hash' => 'b018a070d120f689a2beb8ece67e1b1e', 475 + 'uri' => '/res/b018a070/rsrc/image/phacility/sprites.png', 476 + 'disk' => '/rsrc/image/phacility/sprites.png', 477 + 'type' => 'png', 478 + ), 479 + '/rsrc/image/phacility/tactile_noise.png' => 480 + array( 481 + 'hash' => '7fb4ca90b8b0919153770b6badb982f0', 482 + 'uri' => '/res/7fb4ca90/rsrc/image/phacility/tactile_noise.png', 483 + 'disk' => '/rsrc/image/phacility/tactile_noise.png', 484 + 'type' => 'png', 485 + ), 465 486 '/rsrc/image/search.png' => 466 487 array( 467 488 'hash' => 'ff7da044e6f923b8f569dec11f97e5e5', ··· 2182 2203 ), 2183 2204 'disk' => '/rsrc/js/javelin/lib/Workflow.js', 2184 2205 ), 2206 + 'jquery-js' => 2207 + array( 2208 + 'uri' => '/res/7f0dd213/rsrc/js/application/phame/skins/phacility/jquery/jquery.min.js', 2209 + 'type' => 'js', 2210 + 'requires' => 2211 + array( 2212 + ), 2213 + 'disk' => '/rsrc/js/application/phame/skins/phacility/jquery/jquery.min.js', 2214 + ), 2185 2215 'maniphest-batch-editor' => 2186 2216 array( 2187 2217 'uri' => '/res/fb15d744/rsrc/css/application/maniphest/batch-editor.css', ··· 2888 2918 ), 2889 2919 'disk' => '/rsrc/js/application/uiexample/ReactorSendPropertiesExample.js', 2890 2920 ), 2891 - 'phame-blog-detail-css' => 2921 + 'phacility-bootstrap-css' => 2892 2922 array( 2893 - 'uri' => '/res/5a0e24ab/rsrc/css/application/phame/blog-detail.css', 2923 + 'uri' => '/res/28f0ad0e/rsrc/css/application/phame/skins/phacility/bootstrap/bootstrap.min.css', 2894 2924 'type' => 'css', 2895 2925 'requires' => 2896 2926 array( 2897 2927 ), 2898 - 'disk' => '/rsrc/css/application/phame/blog-detail.css', 2928 + 'disk' => '/rsrc/css/application/phame/skins/phacility/bootstrap/bootstrap.min.css', 2899 2929 ), 2900 - 'phame-blog-post-list-css' => 2930 + 'phacility-css' => 2901 2931 array( 2902 - 'uri' => '/res/371237fa/rsrc/css/application/phame/blog-post-list.css', 2932 + 'uri' => '/res/f55275c2/rsrc/css/application/phame/skins/phacility/phacility.css', 2903 2933 'type' => 'css', 2904 2934 'requires' => 2905 2935 array( 2936 + 0 => 'phacility-bootstrap-css', 2906 2937 ), 2907 - 'disk' => '/rsrc/css/application/phame/blog-post-list.css', 2938 + 'disk' => '/rsrc/css/application/phame/skins/phacility/phacility.css', 2939 + ), 2940 + 'phacility-js' => 2941 + array( 2942 + 'uri' => '/res/f441bc88/rsrc/js/application/phame/skins/phacility/bootstrap/bootstrap.min.js', 2943 + 'type' => 'js', 2944 + 'requires' => 2945 + array( 2946 + 0 => 'jquery-js', 2947 + ), 2948 + 'disk' => '/rsrc/js/application/phame/skins/phacility/bootstrap/bootstrap.min.js', 2949 + ), 2950 + 'phame-css' => 2951 + array( 2952 + 'uri' => '/res/2d18adca/rsrc/css/application/phame/phame.css', 2953 + 'type' => 'css', 2954 + 'requires' => 2955 + array( 2956 + ), 2957 + 'disk' => '/rsrc/css/application/phame/phame.css', 2908 2958 ), 2909 2959 'phriction-document-css' => 2910 2960 array(
+4
src/__phutil_library_map__.php
··· 602 602 'PhabricatorAuditStatusConstants' => 'applications/audit/constants/PhabricatorAuditStatusConstants.php', 603 603 'PhabricatorAuthController' => 'applications/auth/controller/PhabricatorAuthController.php', 604 604 'PhabricatorBaseEnglishTranslation' => 'infrastructure/internationalization/PhabricatorBaseEnglishTranslation.php', 605 + 'PhabricatorBlogSkin' => 'applications/phame/view/skins/PhabricatorBlogSkin.php', 605 606 'PhabricatorBuiltinPatchList' => 'infrastructure/storage/patch/PhabricatorBuiltinPatchList.php', 606 607 'PhabricatorCacheDAO' => 'applications/cache/storage/PhabricatorCacheDAO.php', 607 608 'PhabricatorCalendarBrowseController' => 'applications/calendar/controller/PhabricatorCalendarBrowseController.php', ··· 1155 1156 'PhameBlogListBaseController' => 'applications/phame/controller/blog/list/PhameBlogListBaseController.php', 1156 1157 'PhameBlogListView' => 'applications/phame/view/PhameBlogListView.php', 1157 1158 'PhameBlogQuery' => 'applications/phame/query/PhameBlogQuery.php', 1159 + 'PhameBlogSkin' => 'applications/phame/view/skins/PhameBlogSkin.php', 1158 1160 'PhameBlogViewController' => 'applications/phame/controller/blog/PhameBlogViewController.php', 1159 1161 'PhameBloggerPostListController' => 'applications/phame/controller/post/list/PhameBloggerPostListController.php', 1160 1162 'PhameController' => 'applications/phame/controller/PhameController.php', ··· 1784 1786 'PhabricatorAuditReplyHandler' => 'PhabricatorMailReplyHandler', 1785 1787 'PhabricatorAuthController' => 'PhabricatorController', 1786 1788 'PhabricatorBaseEnglishTranslation' => 'PhabricatorTranslation', 1789 + 'PhabricatorBlogSkin' => 'PhameBlogSkin', 1787 1790 'PhabricatorBuiltinPatchList' => 'PhabricatorSQLPatchList', 1788 1791 'PhabricatorCacheDAO' => 'PhabricatorLiskDAO', 1789 1792 'PhabricatorCalendarBrowseController' => 'PhabricatorCalendarController', ··· 2280 2283 'PhameBlogListBaseController' => 'PhameController', 2281 2284 'PhameBlogListView' => 'AphrontView', 2282 2285 'PhameBlogQuery' => 'PhabricatorOffsetPagedQuery', 2286 + 'PhameBlogSkin' => 'AphrontView', 2283 2287 'PhameBlogViewController' => 'PhameController', 2284 2288 'PhameBloggerPostListController' => 'PhamePostListBaseController', 2285 2289 'PhameController' => 'PhabricatorController',
+7 -3
src/aphront/configuration/AphrontApplicationConfiguration.php
··· 153 153 154 154 // 2 basic cases 155 155 // -- looking at a list of blog posts, path is nothing or '/' 156 - // -- looking at an actual blog post, path is like /btrahan/post_title 156 + // -- we have to fudge the URI in this case 157 + // -- looking at an actual blog post, path is like 158 + // /phame/posts/<author>/post_title 159 + // NOTE: it is possible to get other phame pages, we just do 160 + // not link to them at this time. 157 161 if (!$path || $path == '/') { 158 162 $path = $blog->getViewURI(); 159 - } else { 160 - $path = '/phame/posts/'.trim($path, '/').'/'; 161 163 } 164 + 165 + PhameBlog::setRequestBlog($blog); 162 166 163 167 $celerity = CelerityAPI::getStaticResourceResponse(); 164 168 $celerity->setUseFullURI(true);
+20
src/applications/phame/controller/PhameController.php
··· 21 21 */ 22 22 abstract class PhameController extends PhabricatorController { 23 23 private $showSideNav; 24 + private $showChrome = true; 25 + private $deviceReady = false; 24 26 25 27 protected function setShowSideNav($value) { 26 28 $this->showSideNav = (bool) $value; ··· 30 32 return $this->showSideNav; 31 33 } 32 34 35 + protected function setShowChrome($show_chrome) { 36 + $this->showChrome = $show_chrome; 37 + return $this; 38 + } 39 + private function getShowChrome() { 40 + return $this->showChrome; 41 + } 42 + 43 + public function setDeviceReady($device_ready) { 44 + $this->deviceReady = $device_ready; 45 + return $this; 46 + } 47 + public function getDeviceReady() { 48 + return $this->deviceReady; 49 + } 50 + 33 51 public function buildStandardPageResponse($view, array $data) { 34 52 35 53 $page = $this->buildStandardPageView(); ··· 38 56 $page->setBaseURI('/phame/'); 39 57 $page->setTitle(idx($data, 'title')); 40 58 $page->setGlyph("\xe2\x9c\xa9"); 59 + $page->setShowChrome($this->getShowChrome()); 60 + $page->setDeviceReady($this->getDeviceReady()); 41 61 42 62 if ($this->showSideNav()) { 43 63 $nav = $this->renderSideNavFilterView($this->getSideNavFilter());
+9
src/applications/phame/controller/blog/PhameBlogEditController.php
··· 123 123 $description = $request->getStr('description'); 124 124 $blogger_arr = $request->getArr('bloggers'); 125 125 $custom_domain = $request->getStr('custom_domain'); 126 + $skin = $request->getStr('skin'); 126 127 127 128 if (empty($blogger_arr)) { 128 129 $error = 'Bloggers must be nonempty.'; ··· 155 156 } 156 157 $blog->setDomain($custom_domain); 157 158 } 159 + $blog->setSkin($skin); 158 160 159 161 if (empty($errors)) { 160 162 $blog->save(); ··· 230 232 ->setCaption('Must include at least one dot (.), e.g. '. 231 233 'blog.example.com') 232 234 ->setError($e_custom_domain) 235 + ) 236 + ->appendChild( 237 + id(new AphrontFormSelectControl()) 238 + ->setLabel('Skin') 239 + ->setName('skin') 240 + ->setValue($blog->getSkin()) 241 + ->setOptions(PhameBlog::getSkinOptionsForSelect()) 233 242 ) 234 243 ->appendChild( 235 244 id(new AphrontFormSubmitControl())
+19 -28
src/applications/phame/controller/blog/PhameBlogViewController.php
··· 99 99 $posts = array(); 100 100 } 101 101 102 - $actions = array('view'); 103 - $is_admin = false; 104 - // TODO -- make this check use a policy 105 - if (isset($bloggers[$user->getPHID()])) { 106 - $actions[] = 'edit'; 107 - $is_admin = true; 108 - } 109 - 102 + $notice = array(); 110 103 if ($request->getExists('new')) { 111 - $notice = $this->buildNoticeView() 112 - ->setTitle('Successfully created your blog.') 113 - ->appendChild('Time to write some posts.'); 104 + $notice = 105 + array( 106 + 'title' => 'Successfully created your blog.', 107 + 'body' => 'Time to write some posts.' 108 + ); 114 109 } else if ($request->getExists('edit')) { 115 - $notice = $this->buildNoticeView() 116 - ->setTitle('Successfully edited your blog.') 117 - ->appendChild('Time to write some posts.'); 118 - } else { 119 - $notice = null; 110 + $notice = 111 + array( 112 + 'title' => 'Successfully edited your blog.', 113 + 'body' => 'Time to write some posts.' 114 + ); 120 115 } 121 116 122 - $panel = id(new PhamePostListView()) 123 - ->setBlogStyle(true) 117 + $skin = $blog->getSkinRenderer(); 118 + $skin 124 119 ->setUser($this->getRequest()->getUser()) 120 + ->setNotice($notice) 125 121 ->setBloggers($bloggers) 126 122 ->setPosts($posts) 127 - ->setActions($actions) 128 - ->setDraftList(false); 129 - 130 - $details = id(new PhameBlogDetailView()) 131 - ->setUser($user) 132 - ->setBloggers($bloggers) 133 123 ->setBlog($blog) 134 - ->setIsAdmin($is_admin); 124 + ->setRequestURI($this->getRequest()->getRequestURI()); 135 125 136 126 $this->setShowSideNav(false); 127 + $this->setShowChrome($skin->getShowChrome()); 128 + $this->setDeviceReady($skin->getDeviceReady()); 129 + $skin->setIsExternalDomain($blog->getDomain() == $request->getHost()); 137 130 138 131 return $this->buildStandardPageResponse( 139 132 array( 140 - $notice, 141 - $details, 142 - $panel, 133 + $skin 143 134 ), 144 135 array( 145 136 'title' => $blog->getName(),
+1
src/applications/phame/controller/post/PhamePostEditController.php
··· 299 299 </div> 300 300 </div>'; 301 301 302 + require_celerity_resource('phame-css'); 302 303 Javelin::initBehavior( 303 304 'phame-post-preview', 304 305 array(
+3 -1
src/applications/phame/controller/post/PhamePostPreviewController.php
··· 39 39 ->setPhameTitle($phame_title) 40 40 ->setDateModified(time()); 41 41 42 + $blogger = PhabricatorObjectHandleData::loadOneHandle($user->getPHID()); 43 + 42 44 $post_html = id(new PhamePostDetailView()) 43 45 ->setUser($user) 44 - ->setBlogger($user) 46 + ->setBlogger($blogger) 45 47 ->setPost($post) 46 48 ->setIsPreview(true) 47 49 ->render();
+44 -18
src/applications/phame/controller/post/PhamePostViewController.php
··· 90 90 91 91 if ($post) { 92 92 $this->setPhameTitle($post->getPhameTitle()); 93 - $blogger = id(new PhabricatorUser())->loadOneWhere( 94 - 'phid = %s', $post->getBloggerPHID()); 93 + $blogger = PhabricatorObjectHandleData::loadOneHandle( 94 + $post->getBloggerPHID(), 95 + $user); 95 96 if (!$blogger) { 96 97 return new Aphront404Response(); 97 98 } ··· 100 101 } else if ($this->getBloggerName() && $this->getPhameTitle()) { 101 102 $phame_title = $this->getPhameTitle(); 102 103 $phame_title = PhabricatorSlug::normalize($phame_title); 103 - $blogger = id(new PhabricatorUser())->loadOneWhere( 104 + $blogger_user = id(new PhabricatorUser())->loadOneWhere( 104 105 'username = %s', 105 106 $this->getBloggerName()); 107 + if (!$blogger_user) { 108 + return new Aphront404Response(); 109 + } 110 + $blogger = PhabricatorObjectHandleData::loadOneHandle( 111 + $blogger_user->getPHID(), 112 + $user); 106 113 if (!$blogger) { 107 114 return new Aphront404Response(); 108 115 } ··· 128 135 } 129 136 130 137 if ($post->isDraft()) { 131 - $notice = $this->buildNoticeView() 132 - ->setTitle('You are previewing a draft.') 133 - ->setErrors(array( 134 - 'Only you can see this draft until you publish it.', 135 - 'If you chose a comment widget it will show up when you publish.', 136 - )); 138 + $notice = array( 139 + 'title' => 'You are previewing a draft.', 140 + 'body' => 'Only you can see this draft until you publish it. '. 141 + 'If you chose a comment widget it will show up when '. 142 + 'you publish.' 143 + ); 137 144 } else if ($request->getExists('saved')) { 138 145 $new_link = phutil_render_tag( 139 146 'a', ··· 143 150 ), 144 151 'write another blog post' 145 152 ); 146 - $notice = $this->buildNoticeView() 147 - ->appendChild('<p>Saved post successfully.</p>') 148 - ->appendChild('Seek even more phame and '.$new_link); 153 + $notice = array( 154 + 'title' => 'Saved post successfully.', 155 + 'body' => 'Seek even more phame and '.$new_link.'.' 156 + ); 149 157 } else { 150 - $notice = null; 158 + $notice = array(); 159 + } 160 + 161 + $actions = array('more'); 162 + if ($post->getBloggerPHID() == $user->getPHID()) { 163 + $actions[] = 'edit'; 151 164 } 152 165 153 - $page = id(new PhamePostDetailView()) 166 + $blog = PhameBlog::getRequestBlog(); 167 + if ($blog) { 168 + $skin = $blog->getSkinRenderer(); 169 + $skin->setBlog($blog); 170 + $skin->setIsExternalDomain(true); 171 + } else { 172 + $skin = new PhabricatorBlogSkin(); 173 + } 174 + $skin 154 175 ->setUser($user) 155 176 ->setRequestURI($request->getRequestURI()) 156 - ->setBlogger($blogger) 157 - ->setPost($post); 177 + ->setBloggers(array($blogger->getPHID() => $blogger)) 178 + ->setPosts(array($post)) 179 + ->setNotice($notice) 180 + ->setShowPostComments(true) 181 + ->setActions($actions); 158 182 159 183 $this->setShowSideNav(false); 184 + $this->setShowChrome($skin->getShowChrome()); 185 + $this->setDeviceReady($skin->getDeviceReady()); 186 + 160 187 return $this->buildStandardPageResponse( 161 188 array( 162 - $notice, 163 - $page, 189 + $skin 164 190 ), 165 191 array( 166 192 'title' => $post->getTitle(),
+1 -1
src/applications/phame/controller/post/list/PhameAllPostListController.php
··· 80 80 $query->withVisibility(PhamePost::VISIBILITY_PUBLISHED); 81 81 $this->setPhamePostQuery($query); 82 82 83 - $this->setActions(array('view')); 83 + $this->setActions(array()); 84 84 85 85 $page_title = 'All Posts'; 86 86 $this->setPageTitle($page_title);
+5 -3
src/applications/phame/controller/post/list/PhamePostListBaseController.php
··· 71 71 } 72 72 73 73 protected function buildPostListPageResponse() { 74 - $pager = $this->getPager(); 75 - $query = $this->getPhamePostQuery(); 76 - $posts = $query->executeWithOffsetPager($pager); 74 + $request = $this->getRequest(); 75 + $pager = $this->getPager(); 76 + $query = $this->getPhamePostQuery(); 77 + $posts = $query->executeWithOffsetPager($pager); 77 78 78 79 $bloggers = $this->loadBloggersFromPosts($posts); 79 80 ··· 82 83 ->setBloggers($bloggers) 83 84 ->setPosts($posts) 84 85 ->setActions($this->getActions()) 86 + ->setRequestURI($request->getRequestURI()) 85 87 ->setDraftList($this->isDraft()); 86 88 87 89 return $this->buildStandardPageResponse(
+41
src/applications/phame/storage/PhameBlog.php
··· 21 21 */ 22 22 final class PhameBlog extends PhameDAO { 23 23 24 + const SKIN_DEFAULT = 'PhabricatorBlogSkin'; 25 + 24 26 protected $id; 25 27 protected $phid; 26 28 protected $name; ··· 29 31 protected $configData; 30 32 protected $creatorPHID; 31 33 34 + private $skin; 35 + 32 36 private $bloggerPHIDs; 33 37 private $bloggers; 38 + 39 + static private $requestBlog; 34 40 35 41 public function getConfiguration() { 36 42 return array( ··· 44 50 public function generatePHID() { 45 51 return PhabricatorPHID::generateNewPHID( 46 52 PhabricatorPHIDConstants::PHID_TYPE_BLOG); 53 + } 54 + 55 + public function getSkinRenderer() { 56 + $skin = $this->getSkin(); 57 + 58 + return new $skin(); 47 59 } 48 60 49 61 /** ··· 142 154 return $this->bloggers; 143 155 } 144 156 157 + public function getSkin() { 158 + $config = coalesce($this->getConfigData(), array()); 159 + return idx($config, 'skin', self::SKIN_DEFAULT); 160 + } 161 + 162 + public function setSkin($skin) { 163 + $config = coalesce($this->getConfigData(), array()); 164 + $config['skin'] = $skin; 165 + return $this->setConfigData($config); 166 + } 167 + 168 + static public function getSkinOptionsForSelect() { 169 + $classes = id(new PhutilSymbolLoader()) 170 + ->setAncestorClass('PhameBlogSkin') 171 + ->setType('class') 172 + ->setConcreteOnly(true) 173 + ->selectSymbolsWithoutLoading(); 174 + 175 + return ipull($classes, 'name', 'name'); 176 + } 177 + 145 178 public function getPostListURI() { 146 179 return $this->getActionURI('posts'); 147 180 } ··· 164 197 165 198 private function getActionURI($action) { 166 199 return '/phame/blog/'.$action.'/'.$this->getPHID().'/'; 200 + } 201 + 202 + public static function setRequestBlog(PhameBlog $blog) { 203 + self::$requestBlog = $blog; 204 + } 205 + 206 + public static function getRequestBlog() { 207 + return self::$requestBlog; 167 208 } 168 209 }
+40 -30
src/applications/phame/view/PhameBlogDetailView.php
··· 22 22 final class PhameBlogDetailView extends AphrontView { 23 23 24 24 private $user; 25 - 26 - private $isAdmin; 27 25 private $blog; 28 26 private $bloggers; 29 27 30 - public function setIsAdmin($is_admin) { 31 - $this->isAdmin = $is_admin; 32 - return $this; 33 - } 34 - private function getIsAdmin() { 35 - return $this->isAdmin; 36 - } 37 - 38 28 public function setUser(PhabricatorUser $user) { 39 29 $this->user = $user; 40 30 return $this; ··· 60 50 return $this->blog; 61 51 } 62 52 63 - 64 53 public function render() { 65 54 require_celerity_resource('phabricator-remarkup-css'); 66 - require_celerity_resource('phame-blog-detail-css'); 67 55 68 56 $user = $this->getUser(); 69 57 $blog = $this->getBlog(); 70 58 $bloggers = $this->getBloggers(); 71 59 $name = phutil_escape_html($blog->getName()); 72 60 $description = phutil_escape_html($blog->getDescription()); 73 - $bloggers_txt = implode(' &middot; ', mpull($bloggers, 'renderLink')); 74 - $panel = id(new AphrontPanelView()) 75 - ->addClass('blog-detail') 76 - ->setHeader($name) 77 - ->setCaption($description) 78 - ->setWidth(AphrontPanelView::WIDTH_FORM) 79 - ->appendChild('Current bloggers: '.$bloggers_txt); 80 61 81 - if ($this->getIsAdmin()) { 82 - $panel->addButton( 62 + $detail = phutil_render_tag( 63 + 'div', 64 + array( 65 + 'class' => 'blog-detail' 66 + ), 67 + phutil_render_tag( 68 + 'div', 69 + array( 70 + 'class' => 'header', 71 + ), 83 72 phutil_render_tag( 84 - 'a', 85 - array( 86 - 'href' => $blog->getEditURI(), 87 - 'class' => 'button grey', 88 - ), 89 - 'Edit Blog') 90 - ); 73 + 'h1', 74 + array(), 75 + $name 76 + ) 77 + ). 78 + phutil_render_tag( 79 + 'div', 80 + array( 81 + 'class' => 'description' 82 + ), 83 + $description 84 + ). 85 + phutil_render_tag( 86 + 'div', 87 + array( 88 + 'class' => 'bloggers' 89 + ), 90 + 'Current bloggers: '.$this->getBloggersHTML($bloggers) 91 + ) 92 + ); 93 + 94 + return $detail; 95 + } 96 + 97 + private function getBloggersHTML(array $bloggers) { 98 + assert_instances_of($bloggers, 'PhabricatorObjectHandle'); 91 99 100 + $arr = array(); 101 + foreach ($bloggers as $blogger) { 102 + $arr[] = '<strong>'.phutil_escape_html($blogger->getName()).'</strong>'; 92 103 } 93 104 94 - return $panel->render(); 105 + return implode(' &middot; ', $arr); 95 106 } 96 - 97 107 }
+23 -47
src/applications/phame/view/PhameBlogListView.php
··· 64 64 return $panel->render(); 65 65 } 66 66 67 - $table_data = array(); 67 + $view = new PhabricatorObjectItemListView(); 68 68 foreach ($blogs as $blog) { 69 - $view_link = phutil_render_tag( 70 - 'a', 71 - array( 72 - 'href' => $blog->getViewURI(), 73 - ), 74 - phutil_escape_html($blog->getName())); 75 69 $bloggers = $blog->getBloggers(); 70 + 71 + $item = id(new PhabricatorObjectItemView()) 72 + ->setHeader($blog->getName()) 73 + ->setHref($blog->getViewURI()) 74 + ->addDetail( 75 + 'Bloggers', 76 + implode(', ', mpull($bloggers, 'renderLink'))) 77 + ->addDetail( 78 + 'Custom Domain', 79 + $blog->getDomain()); 80 + 76 81 if (isset($bloggers[$user->getPHID()])) { 77 - $edit = phutil_render_tag( 78 - 'a', 79 - array( 80 - 'class' => 'button small grey', 81 - 'href' => $blog->getEditURI(), 82 - ), 83 - 'Edit'); 84 - } else { 85 - $edit = null; 82 + $item->addAttribute( 83 + phutil_render_tag( 84 + 'a', 85 + array( 86 + 'class' => 'button small grey', 87 + 'href' => $blog->getEditURI(), 88 + ), 89 + 'Edit')); 86 90 } 87 - $view = phutil_render_tag( 88 - 'a', 89 - array( 90 - 'class' => 'button small grey', 91 - 'href' => $blog->getViewURI(), 92 - ), 93 - 'View'); 94 - $table_data[] = 95 - array( 96 - $view_link, 97 - implode(', ', mpull($blog->getBloggers(), 'renderLink')), 98 - $view, 99 - $edit, 100 - ); 91 + 92 + $view->addItem($item); 101 93 } 102 94 103 - $table = new AphrontTableView($table_data); 104 - $table->setHeaders( 105 - array( 106 - 'Name', 107 - 'Bloggers', 108 - '', 109 - '', 110 - )); 111 - $table->setColumnClasses( 112 - array( 113 - null, 114 - null, 115 - 'action', 116 - 'action', 117 - )); 118 - 119 95 $panel->setCreateButton('Create a Blog', '/phame/blog/new/'); 120 96 $panel->setHeader($this->getHeader()); 121 - $panel->appendChild($table); 97 + $panel->appendChild($view); 122 98 123 99 return $panel->render(); 124 100 }
+206 -75
src/applications/phame/view/PhamePostDetailView.php
··· 20 20 * @group phame 21 21 */ 22 22 final class PhamePostDetailView extends AphrontView { 23 + 24 + private $user; 23 25 private $post; 26 + private $blog; 24 27 private $blogger; 28 + private $actions = array(); 25 29 private $requestURI; 26 - private $user; 27 30 private $isPreview; 31 + private $showComments; 32 + private $shouldShorten; 28 33 29 - public function setIsPreview($is_preview) { 30 - $this->isPreview = $is_preview; 34 + public function setShouldShorten($should_shorten) { 35 + $this->shouldShorten = $should_shorten; 31 36 return $this; 32 37 } 33 - private function isPreview() { 34 - return $this->isPreview; 38 + public function getShouldShorten() { 39 + return $this->shouldShorten; 35 40 } 36 41 37 42 public function setUser(PhabricatorUser $user) { ··· 42 47 return $this->user; 43 48 } 44 49 50 + public function setPost(PhamePost $post) { 51 + $this->post = $post; 52 + return $this; 53 + } 54 + private function getPost() { 55 + return $this->post; 56 + } 57 + 58 + public function setBlog(PhameBlog $blog) { 59 + $this->blog = $blog; 60 + return $this; 61 + } 62 + private function getBlog() { 63 + return $this->blog; 64 + } 65 + 66 + public function setBlogger(PhabricatorObjectHandle $blogger) { 67 + $this->blogger = $blogger; 68 + return $this; 69 + } 70 + private function getBlogger() { 71 + return $this->blogger; 72 + } 73 + 74 + public function setActions(array $actions) { 75 + $this->actions = $actions; 76 + return $this; 77 + } 78 + private function getActions() { 79 + if ($this->actions) { 80 + return $this->actions; 81 + } 82 + return array(); 83 + } 84 + 45 85 public function setRequestURI(PhutilURI $uri) { 46 86 $uri = PhabricatorEnv::getProductionURI($uri->setQueryParams(array())); 47 87 $this->requestURI = $uri; ··· 51 91 return $this->requestURI; 52 92 } 53 93 54 - public function setBlogger(PhabricatorUser $blogger) { 55 - $this->blogger = $blogger; 94 + public function setIsPreview($is_preview) { 95 + $this->isPreview = $is_preview; 56 96 return $this; 57 97 } 58 - private function getBlogger() { 59 - return $this->blogger; 98 + private function isPreview() { 99 + return $this->isPreview; 60 100 } 61 101 62 - public function setPost(PhamePost $post) { 63 - $this->post = $post; 102 + public function setShowComments($show_comments) { 103 + $this->showComments = $show_comments; 64 104 return $this; 65 105 } 66 - private function getPost() { 67 - return $this->post; 106 + private function getShowComments() { 107 + return $this->showComments; 68 108 } 69 109 70 110 public function render() { 71 111 require_celerity_resource('phabricator-remarkup-css'); 112 + require_celerity_resource('phame-css'); 72 113 73 114 $user = $this->getUser(); 74 115 $blogger = $this->getBlogger(); 75 116 $post = $this->getPost(); 76 - $engine = PhabricatorMarkupEngine::newPhameMarkupEngine(); 77 - $body = $engine->markupText($post->getBody()); 78 - if ($post->isDraft()) { 79 - $uri = '/phame/draft/'; 80 - $label = 'Back to Your Drafts'; 81 - } else { 82 - $uri = '/phame/posts/'.$blogger->getUsername().'/'; 83 - $label = 'More Posts by '.phutil_escape_html($blogger->getUsername()); 117 + $actions = $this->getActions(); 118 + $noun = $post->isDraft() ? 'Draft' : 'Post'; 119 + $buttons = array(); 120 + 121 + foreach ($actions as $action) { 122 + switch ($action) { 123 + case 'view': 124 + $uri = $post->getViewURI($blogger->getName()); 125 + $label = 'View '.$noun; 126 + break; 127 + case 'edit': 128 + $uri = $post->getEditURI(); 129 + $label = 'Edit '.$noun; 130 + break; 131 + case 'more': 132 + if ($post->isDraft()) { 133 + $uri = '/phame/draft/'; 134 + $label = 'Back to Your Drafts'; 135 + } else { 136 + $uri = '/phame/posts/'.$blogger->getName().'/'; 137 + $label = 'More Posts by '.phutil_escape_html($blogger->getName()); 138 + } 139 + break; 140 + default: 141 + break; 142 + } 143 + $button = phutil_render_tag( 144 + 'a', 145 + array( 146 + 'href' => $uri, 147 + 'class' => 'grey button', 148 + ), 149 + $label); 150 + $buttons[] = $button; 84 151 } 85 - $button = phutil_render_tag( 86 - 'a', 87 - array( 88 - 'href' => $uri, 89 - 'class' => 'grey button', 90 - ), 91 - $label 92 - ); 152 + 153 + $button_html = ''; 154 + if ($buttons) { 155 + $button_html = phutil_render_tag( 156 + 'div', 157 + array( 158 + 'class' => 'buttons' 159 + ), 160 + implode('', $buttons) 161 + ); 162 + } 93 163 94 164 $publish_date = $post->getDatePublished(); 95 165 if ($publish_date) { ··· 101 171 phabricator_datetime($post->getDateModified(), 102 172 $user); 103 173 } 104 - $caption .= ' by '.phutil_render_tag( 105 - 'a', 106 - array( 107 - 'href' => new PhutilURI('/p/'.$blogger->getUsername().'/'), 108 - ), 109 - phutil_escape_html($blogger->getUsername()) 110 - ).'.'; 174 + $caption .= ' by <b>'. 175 + phutil_escape_html($blogger->getName()).'</b>.'; 176 + 177 + $shortened = false; 178 + $body_text = $post->getBody(); 179 + if ($this->getShouldShorten()) { 180 + $body_length = phutil_utf8_strlen($body_text); 181 + $body_text = phutil_utf8_shorten($body_text, 5000); 182 + $shortened = $body_length > phutil_utf8_strlen($body_text); 183 + } 184 + $engine = PhabricatorMarkupEngine::newPhameMarkupEngine(); 185 + $body = $engine->markupText($body_text); 111 186 112 - if ($this->isPreview()) { 113 - $width = AphrontPanelView::WIDTH_FULL; 114 - } else { 115 - $width = AphrontPanelView::WIDTH_WIDE; 187 + $comments = null; 188 + if ($this->getShowComments()) { 189 + switch ($post->getCommentsWidget()) { 190 + case 'facebook': 191 + $comments = $this->renderFacebookComments(); 192 + break; 193 + case 'disqus': 194 + $comments = $this->renderDisqusComments(); 195 + break; 196 + case 'none': 197 + default: 198 + $comments = null; 199 + break; 200 + } 116 201 } 117 - $panel = id(new AphrontPanelView()) 118 - ->setHeader(phutil_escape_html($post->getTitle())) 119 - ->appendChild('<div class="phabricator-remarkup">'.$body.'</div>') 120 - ->setWidth($width) 121 - ->addButton($button) 122 - ->setCaption($caption); 123 - if ($user->getPHID() == $post->getBloggerPHID()) { 124 - if ($post->isDraft()) { 125 - $label = 'Edit Draft'; 126 - } else { 127 - $label = 'Edit Post'; 202 + 203 + $more_to_do = null; 204 + if (!$comments) { 205 + 206 + if ($shortened) { 207 + $more_to_do = 208 + phutil_render_tag( 209 + 'div', 210 + array( 211 + 'class' => 'more-and-comments' 212 + ), 213 + phutil_render_tag( 214 + 'a', 215 + array( 216 + 'href' => $post->getViewURI() 217 + ), 218 + '&#8594; Read More' 219 + ) 220 + ); 221 + 222 + } else if ($post->getCommentsWidget() && 223 + $post->getCommentsWidget() != 'none') { 224 + $more_to_do = 225 + phutil_render_tag( 226 + 'div', 227 + array( 228 + 'class' => 'more-and-comments' 229 + ), 230 + phutil_render_tag( 231 + 'a', 232 + array( 233 + 'href' => $post->getViewURI() 234 + ), 235 + '&#8594; Comment' 236 + ) 237 + ); 128 238 } 129 - $button = phutil_render_tag( 130 - 'a', 239 + } 240 + 241 + $post_html = 242 + phutil_render_tag( 243 + 'div', 131 244 array( 132 - 'href' => $post->getEditURI(), 133 - 'class' => 'grey button', 245 + 'class' => 'blog-post' 134 246 ), 135 - $label); 136 - $panel->addButton($button); 137 - } 138 - switch ($post->getCommentsWidget()) { 139 - case 'facebook': 140 - $comments = $this->renderFacebookComments(); 141 - break; 142 - case 'disqus': 143 - $comments = $this->renderDisqusComments(); 144 - break; 145 - case 'none': 146 - default: 147 - $comments = null; 148 - break; 149 - } 150 - $panel->appendChild($comments); 247 + phutil_render_tag( 248 + 'div', 249 + array( 250 + 'class' => 'header', 251 + ), 252 + $button_html . 253 + phutil_render_tag( 254 + 'h1', 255 + array(), 256 + phutil_render_tag('a', 257 + array( 258 + 'href' => $post->getViewURI($blogger->getName()) 259 + ), 260 + phutil_escape_html($post->getTitle()) 261 + ) 262 + ). 263 + phutil_render_tag( 264 + 'div', 265 + array( 266 + 'class' => 'last-updated' 267 + ), 268 + $caption 269 + ) 270 + ). 271 + phutil_render_tag( 272 + 'div', 273 + array( 274 + 'class' => 'phabricator-remarkup' 275 + ), 276 + $body 277 + ). 278 + $comments.$more_to_do 279 + ); 151 280 152 - return $panel->render(); 281 + return $post_html; 153 282 } 154 283 155 284 private function renderFacebookComments() { ··· 161 290 $fb_root = phutil_render_tag('div', 162 291 array( 163 292 'id' => 'fb-root', 164 - ) 293 + ), 294 + '' 165 295 ); 166 296 167 297 $c_uri = '//connect.facebook.net/en_US/all.js#xfbml=1&appId='.$fb_id; ··· 181 311 'class' => 'fb-comments', 182 312 'data-href' => $this->getRequestURI(), 183 313 'data-num-posts' => 5, 184 - 'data-width' => 1080, 314 + 'data-width' => 1080, // we hack this to fluid in css 185 315 'data-colorscheme' => 'dark', 186 - ) 316 + ), 317 + '' 187 318 ); 188 319 189 320 return '<hr />' . $fb_root . $fb_js . $fb_comments;
+41 -59
src/applications/phame/view/PhamePostListView.php
··· 24 24 private $user; 25 25 private $posts; 26 26 private $bloggers; 27 - private $actions; 27 + private $actions = array(); 28 28 private $draftList; 29 - private $blogStyle; 29 + private $requestURI; 30 + private $showPostComments; 31 + 32 + public function setShowPostComments($show_post_comments) { 33 + $this->showPostComments = $show_post_comments; 34 + return $this; 35 + } 36 + private function getShowPostComments() { 37 + return $this->showPostComments; 38 + } 39 + 40 + public function setRequestURI($request_uri) { 41 + $this->requestURI = $request_uri; 42 + return $this; 43 + } 44 + public function getRequestURI() { 45 + return $this->requestURI; 46 + } 30 47 31 48 public function setDraftList($draft_list) { 32 49 $this->draftList = $draft_list; ··· 72 89 return $this; 73 90 } 74 91 private function getActions() { 75 - if ($this->actions) { 76 - return $this->actions; 77 - } 78 - return array(); 79 - } 80 - 81 - public function setBlogStyle($style) { 82 - $this->blogStyle = $style; 83 - return $this; 84 - } 85 - private function getBlogStyle() { 86 - return $this->blogStyle; 92 + return $this->actions; 87 93 } 88 94 89 95 public function render() { 90 - $user = $this->getUser(); 91 - $posts = $this->getPosts(); 92 - $bloggers = $this->getBloggers(); 93 - $noun = $this->getPostNoun(); 94 - // TODO -- change this from a boolean to a string 95 - // this string will represent a more specific "style" below 96 - $blog_style = $this->getBlogStyle(); 96 + $user = $this->getUser(); 97 + $posts = $this->getPosts(); 98 + $bloggers = $this->getBloggers(); 99 + $noun = $this->getPostNoun(); 97 100 98 101 if (empty($posts)) { 99 102 $panel = id(new AphrontPanelView()) ··· 103 106 sprintf('/phame/%s/new', strtolower($noun))); 104 107 return $panel->render(); 105 108 } 109 + 106 110 require_celerity_resource('phabricator-remarkup-css'); 107 - if ($blog_style) { 108 - require_celerity_resource('phame-blog-post-list-css'); 109 - } 111 + require_celerity_resource('phame-css'); 110 112 111 113 $engine = PhabricatorMarkupEngine::newPhameMarkupEngine(); 112 114 $html = array(); ··· 114 116 foreach ($posts as $post) { 115 117 $blogger_phid = $post->getBloggerPHID(); 116 118 $blogger = $bloggers[$blogger_phid]; 117 - $blogger_link = $blogger->renderLink(); 118 - $updated = phabricator_datetime($post->getDateModified(), 119 - $user); 120 - $body = $engine->markupText($post->getBody()); 121 - $panel = id(new AphrontPanelView()) 122 - ->setHeader(phutil_escape_html($post->getTitle())) 123 - ->setCaption('Last updated '.$updated.' by '.$blogger_link.'.') 124 - ->appendChild('<div class="phabricator-remarkup">'.$body.'</div>'); 125 - if ($blog_style) { 126 - $panel->addClass('blog-post-list'); 127 - } 128 - foreach ($actions as $action) { 129 - switch ($action) { 130 - case 'view': 131 - $uri = $post->getViewURI($blogger->getName()); 132 - $label = 'View '.$noun; 133 - break; 134 - case 'edit': 135 - $uri = $post->getEditURI(); 136 - $label = 'Edit '.$noun; 137 - break; 138 - default: 139 - break; 140 - } 141 - $button = phutil_render_tag( 142 - 'a', 143 - array( 144 - 'href' => $uri, 145 - 'class' => 'grey button', 146 - ), 147 - $label); 148 - $panel->addButton($button); 149 - } 119 + $detail = id(new PhamePostDetailView()) 120 + ->setUser($user) 121 + ->setPost($post) 122 + ->setBlogger($blogger) 123 + ->setActions($actions) 124 + ->setRequestURI($this->getRequestURI()) 125 + ->setShowComments($this->getShowPostComments()); 150 126 151 - $html[] = $panel->render(); 127 + $html[] = $detail->render(); 152 128 } 153 129 154 - return implode('', $html); 130 + return phutil_render_tag( 131 + 'div', 132 + array( 133 + 'class' => 'blog-post-list' 134 + ), 135 + implode('', $html) 136 + ); 155 137 } 156 138 }
+44
src/applications/phame/view/skins/PhabricatorBlogSkin.php
··· 1 + <?php 2 + 3 + /* 4 + * Copyright 2012 Facebook, Inc. 5 + * 6 + * Licensed under the Apache License, Version 2.0 (the "License"); 7 + * you may not use this file except in compliance with the License. 8 + * You may obtain a copy of the License at 9 + * 10 + * http://www.apache.org/licenses/LICENSE-2.0 11 + * 12 + * Unless required by applicable law or agreed to in writing, software 13 + * distributed under the License is distributed on an "AS IS" BASIS, 14 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 + * See the License for the specific language governing permissions and 16 + * limitations under the License. 17 + */ 18 + 19 + /** 20 + * @group phame 21 + */ 22 + final class PhabricatorBlogSkin extends PhameBlogSkin { 23 + 24 + public function __construct() { 25 + $this->setShowChrome(true); 26 + } 27 + 28 + protected function renderHeader() { 29 + return ''; 30 + } 31 + 32 + protected function renderFooter() { 33 + return ''; 34 + } 35 + 36 + protected function renderBody() { 37 + require_celerity_resource('phame-css'); 38 + 39 + return 40 + $this->renderNotice() . 41 + $this->renderPosts() . 42 + $this->renderBlogDetails(); 43 + } 44 + }
+200
src/applications/phame/view/skins/PhameBlogSkin.php
··· 1 + <?php 2 + 3 + /* 4 + * Copyright 2012 Facebook, Inc. 5 + * 6 + * Licensed under the Apache License, Version 2.0 (the "License"); 7 + * you may not use this file except in compliance with the License. 8 + * You may obtain a copy of the License at 9 + * 10 + * http://www.apache.org/licenses/LICENSE-2.0 11 + * 12 + * Unless required by applicable law or agreed to in writing, software 13 + * distributed under the License is distributed on an "AS IS" BASIS, 14 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 + * See the License for the specific language governing permissions and 16 + * limitations under the License. 17 + */ 18 + 19 + /** 20 + * @group phame 21 + */ 22 + abstract class PhameBlogSkin extends AphrontView { 23 + 24 + private $user; 25 + private $blog; 26 + private $bloggers; 27 + private $posts; 28 + private $actions; 29 + private $notice; 30 + private $showChrome; 31 + private $deviceReady; 32 + private $isExternalDomain; 33 + private $requestURI; 34 + private $showPostComments; 35 + 36 + public function setUser(PhabricatorUser $user) { 37 + $this->user = $user; 38 + return $this; 39 + } 40 + public function getUser() { 41 + return $this->user; 42 + } 43 + 44 + public function setBlog(PhameBlog $blog) { 45 + $this->blog = $blog; 46 + return $this; 47 + } 48 + public function getBlog() { 49 + return $this->blog; 50 + } 51 + 52 + public function setBloggers(array $bloggers) { 53 + assert_instances_of($bloggers, 'PhabricatorObjectHandle'); 54 + $this->bloggers = $bloggers; 55 + return $this; 56 + } 57 + public function getBloggers() { 58 + return $this->bloggers; 59 + } 60 + 61 + public function setPosts(array $posts) { 62 + assert_instances_of($posts, 'PhamePost'); 63 + $this->posts = $posts; 64 + return $this; 65 + } 66 + protected function getPosts() { 67 + return $this->posts; 68 + } 69 + 70 + public function setActions($actions) { 71 + $this->actions = $actions; 72 + return $this; 73 + } 74 + public function getActions() { 75 + return $this->actions; 76 + } 77 + 78 + public function setNotice(array $notice) { 79 + $this->notice = $notice; 80 + return $this; 81 + } 82 + protected function getNotice() { 83 + return $this->notice; 84 + } 85 + 86 + public function setIsExternalDomain($is_external_domain) { 87 + $this->isExternalDomain = $is_external_domain; 88 + return $this; 89 + } 90 + protected function getIsExternalDomain() { 91 + return $this->isExternalDomain; 92 + } 93 + 94 + public function setRequestURI($request_uri) { 95 + $this->requestURI = $request_uri; 96 + return $this; 97 + } 98 + private function getRequestURI() { 99 + return $this->requestURI; 100 + } 101 + 102 + protected function setShowChrome($show_chrome) { 103 + $this->showChrome = $show_chrome; 104 + return $this; 105 + } 106 + public function getShowChrome() { 107 + return $this->showChrome; 108 + } 109 + 110 + protected function setDeviceReady($device_ready) { 111 + $this->deviceReady = $device_ready; 112 + return $this; 113 + } 114 + public function getDeviceReady() { 115 + return $this->deviceReady; 116 + } 117 + 118 + public function setShowPostComments($show_post_comments) { 119 + $this->showPostComments = $show_post_comments; 120 + return $this; 121 + } 122 + public function getShowPostComments() { 123 + return $this->showPostComments; 124 + } 125 + 126 + 127 + public function __construct() { 128 + // set any options here 129 + } 130 + 131 + public function render() { 132 + return 133 + $this->renderHeader(). 134 + $this->renderBody(). 135 + $this->renderFooter(); 136 + } 137 + 138 + abstract protected function renderHeader(); 139 + abstract protected function renderBody(); 140 + abstract protected function renderFooter(); 141 + 142 + final public function renderPosts() { 143 + $list = id(new PhamePostListView()) 144 + ->setUser($this->getUser()) 145 + ->setPosts($this->getPosts()) 146 + ->setBloggers($this->getBloggers()) 147 + ->setRequestURI($this->getRequestURI()) 148 + ->setShowPostComments($this->getShowPostComments()) 149 + ->setDraftList(false); 150 + 151 + return $list->render(); 152 + } 153 + 154 + final protected function renderBlogDetails() { 155 + $details = array(); 156 + 157 + $blog = $this->getBlog(); 158 + if ($blog) { 159 + $detail = id(new PhameBlogDetailView()) 160 + ->setUser($this->getUser()) 161 + ->setBlog($this->getBlog()) 162 + ->setBloggers($this->getBloggers()); 163 + $details[] = $detail->render(); 164 + } 165 + 166 + // TODO - more cool boxes for the right hand column...! 167 + 168 + return implode('', $details); 169 + } 170 + 171 + final protected function renderNotice() { 172 + $notice_html = ''; 173 + if ($this->getIsExternalDomain()) { 174 + return $notice_html; 175 + } 176 + 177 + $notice = $this->getNotice(); 178 + if ($notice) { 179 + $header = $notice['title']; 180 + $details = $notice['body']; 181 + $notice_html = phutil_render_tag( 182 + 'div', 183 + array( 184 + 'class' => 'notice' 185 + ), 186 + phutil_render_tag( 187 + 'h3', 188 + array(), 189 + $header 190 + ).phutil_render_tag( 191 + 'h4', 192 + array(), 193 + $details 194 + ) 195 + ); 196 + } 197 + return $notice_html; 198 + } 199 + 200 + }
-18
webroot/rsrc/css/application/phame/blog-detail.css
··· 1 - /** 2 - * @provides phame-blog-detail-css 3 - */ 4 - 5 - .blog-detail { 6 - clear: right; 7 - float: right; 8 - width: 20%; 9 - margin: 16px 16px 16px 0px; 10 - padding: 12px 8px 12px 8px; 11 - } 12 - 13 - .device-tablet .blog-detail, 14 - .device-phone .blog-detail { 15 - float: none; 16 - margin: 16px auto; 17 - width: 90%; 18 - }
-18
webroot/rsrc/css/application/phame/blog-post-list.css
··· 1 - /** 2 - * @provides phame-blog-post-list-css 3 - */ 4 - 5 - .blog-post-list { 6 - clear: left; 7 - float: left; 8 - width: 70%; 9 - margin: 16px 0px 16px 16px; 10 - padding: 12px 8px 12px 8px; 11 - } 12 - 13 - .device-tablet .blog-post-list, 14 - .device-phone .blog-post-list { 15 - float: none; 16 - width: 90%; 17 - margin: 16px auto; 18 - }
+114
webroot/rsrc/css/application/phame/phame.css
··· 1 + /** 2 + * @provides phame-css 3 + */ 4 + 5 + .notice { 6 + background: #F3F3FF; 7 + border: 1px solid #008; 8 + margin: 16px 16px 4px 26px; 9 + } 10 + .notice h3 { 11 + background: #E3E3FF; 12 + padding: 8px; 13 + } 14 + 15 + .notice h4 { 16 + font-weight: normal; 17 + padding: 8px; 18 + } 19 + 20 + .phame-post-preview-header { 21 + margin: 0px 0px 16px 0px; 22 + } 23 + 24 + .blog-post-list { 25 + clear: left; 26 + float: left; 27 + width: 70%; 28 + margin: 16px 0px 16px 16px; 29 + padding: 0px 8px 12px 8px; 30 + } 31 + 32 + .device-tablet .blog-post-list, 33 + .device-phone .blog-post-list { 34 + float: none; 35 + width: 90%; 36 + margin: 16px auto; 37 + } 38 + 39 + .blog-post-list-full { 40 + clear: left; 41 + float: left; 42 + margin: 16px 0px 0px 0px; 43 + padding: 0px 16px 0px 16px; 44 + } 45 + 46 + .device-tablet .blog-post-list-full, 47 + .device-phone .blog-post-list-full { 48 + float: none; 49 + margin: 16px auto; 50 + } 51 + 52 + .blog-detail { 53 + float: right; 54 + clear: right; 55 + width: 20%; 56 + margin: 16px 16px 16px 0px; 57 + } 58 + 59 + .device-tablet .blog-detail, 60 + .device-phone .blog-detail { 61 + float: none; 62 + margin: 16px auto; 63 + width: 90%; 64 + } 65 + 66 + .blog-detail .description { 67 + margin: 16px 0px 16px 0px; 68 + } 69 + 70 + .blog-detail .bloggers { 71 + font-size: 11px; 72 + } 73 + 74 + .blog-post, 75 + .blog-detail { 76 + border: 1px solid #DBDBDB; 77 + background: #F9F9F9; 78 + padding: 20px; 79 + } 80 + 81 + .blog-post { 82 + margin: 0px 0px 20px 0px; 83 + } 84 + 85 + .blog-post .header { 86 + padding: 0px 0px 16px 0px; 87 + } 88 + 89 + .blog-post .header h1 { 90 + clear: none; 91 + } 92 + 93 + .blog-post .header .last-updated { 94 + color: #666; 95 + clear: none; 96 + font-size: 11px; 97 + } 98 + 99 + .blog-post .header .buttons { 100 + float: right; 101 + } 102 + .blog-post .header .buttons a { 103 + margin: 0px 0px 0px 12px; 104 + } 105 + 106 + .more-and-comments { 107 + padding: 12px 0px 12px 0px; 108 + } 109 + 110 + .fb-comments, 111 + .fb-comments span, 112 + .fb-comments iframe[style] { 113 + width: 100% !important; 114 + }