@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.

Implement improved remarkup assistance panel

Summary:
- I made a "?" icon for help/reference.
- The `<>` icon was slightly too wide so I carved it down to 14x14.
- All the icons are in `/Phabriactor/remarkup_icon_sources.psd` if you want to tweak anything.
- Tooltips don't look like the mock but I'll tackle those separately.
- Removed strikethrough.
- Removed tag/image/text size for now since they don't have reasonable JS implementations yet.
- I think everything else is accurate to the mock.

Test Plan:
Normal state:

{F20621, size=full}

Hover + Click states:

{F20622, size=full}

Clicked state:

{F20620, size=full}

Reviewers: chad

Reviewed By: chad

CC: aran

Maniphest Tasks: T1848

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

+170 -112
+25
scripts/celerity/generate_sprites.php
··· 227 227 ->setTargetCSS('.action-'.$icon)); 228 228 } 229 229 230 + 231 + $remarkup_template = id(new PhutilSprite()) 232 + ->setSourcePosition(0, 0) 233 + ->setSourceSize(14, 14); 234 + 235 + $remarkup_icons = array( 236 + 'b', 237 + 'code', 238 + 'i', 239 + 'image', 240 + 'ol', 241 + 'tag', 242 + 'tt', 243 + 'ul', 244 + 'help', 245 + ); 246 + 247 + foreach ($remarkup_icons as $icon) { 248 + $sheet->addSprite( 249 + id(clone $remarkup_template) 250 + ->setSourceFile($srcroot.'remarkup/text_'.$icon.'.png') 251 + ->setTargetCSS('.remarkup-assist-'.$icon)); 252 + } 253 + 254 + 230 255 $sheet->generateImage($webroot.'/image/autosprite.png'); 231 256 $sheet->generateCSS($webroot.'/css/autosprite.css'); 232 257
+30 -30
src/__celerity_resource_map__.php
··· 51 51 ), 52 52 '/rsrc/image/autosprite.png' => 53 53 array( 54 - 'hash' => 'c7f9d2dd752a24c518c0eb426a4853a5', 55 - 'uri' => '/res/c7f9d2dd/rsrc/image/autosprite.png', 54 + 'hash' => '005c7630a31cb2ef6b1782d4eca08cd7', 55 + 'uri' => '/res/005c7630/rsrc/image/autosprite.png', 56 56 'disk' => '/rsrc/image/autosprite.png', 57 57 'type' => 'png', 58 58 ), ··· 657 657 ), 658 658 'autosprite-css' => 659 659 array( 660 - 'uri' => '/res/947e1dcf/rsrc/css/autosprite.css', 660 + 'uri' => '/res/6c0c2948/rsrc/css/autosprite.css', 661 661 'type' => 'css', 662 662 'requires' => 663 663 array( ··· 1559 1559 ), 1560 1560 'javelin-behavior-phabricator-remarkup-assist' => 1561 1561 array( 1562 - 'uri' => '/res/5f7ccd02/rsrc/js/application/core/behavior-phabricator-remarkup-assist.js', 1562 + 'uri' => '/res/d3b53e76/rsrc/js/application/core/behavior-phabricator-remarkup-assist.js', 1563 1563 'type' => 'js', 1564 1564 'requires' => 1565 1565 array( ··· 2636 2636 ), 2637 2637 'phabricator-remarkup-css' => 2638 2638 array( 2639 - 'uri' => '/res/47c16585/rsrc/css/core/remarkup.css', 2639 + 'uri' => '/res/66b4cd42/rsrc/css/core/remarkup.css', 2640 2640 'type' => 'css', 2641 2641 'requires' => 2642 2642 array( ··· 3003 3003 ), array( 3004 3004 'packages' => 3005 3005 array( 3006 - '782b1e3f' => 3006 + '1da0b408' => 3007 3007 array( 3008 3008 'name' => 'core.pkg.css', 3009 3009 'symbols' => ··· 3032 3032 21 => 'phabricator-flag-css', 3033 3033 22 => 'aphront-error-view-css', 3034 3034 ), 3035 - 'uri' => '/res/pkg/782b1e3f/core.pkg.css', 3035 + 'uri' => '/res/pkg/1da0b408/core.pkg.css', 3036 3036 'type' => 'css', 3037 3037 ), 3038 3038 '3a455e4f' => ··· 3199 3199 'reverse' => 3200 3200 array( 3201 3201 'aphront-attached-file-view-css' => '7839ae2d', 3202 - 'aphront-crumbs-view-css' => '782b1e3f', 3203 - 'aphront-dialog-view-css' => '782b1e3f', 3204 - 'aphront-error-view-css' => '782b1e3f', 3205 - 'aphront-form-view-css' => '782b1e3f', 3202 + 'aphront-crumbs-view-css' => '1da0b408', 3203 + 'aphront-dialog-view-css' => '1da0b408', 3204 + 'aphront-error-view-css' => '1da0b408', 3205 + 'aphront-form-view-css' => '1da0b408', 3206 3206 'aphront-headsup-action-list-view-css' => '2ba14b3d', 3207 - 'aphront-headsup-view-css' => '782b1e3f', 3208 - 'aphront-list-filter-view-css' => '782b1e3f', 3209 - 'aphront-pager-view-css' => '782b1e3f', 3210 - 'aphront-panel-view-css' => '782b1e3f', 3211 - 'aphront-side-nav-view-css' => '782b1e3f', 3212 - 'aphront-table-view-css' => '782b1e3f', 3213 - 'aphront-tokenizer-control-css' => '782b1e3f', 3214 - 'aphront-tooltip-css' => '782b1e3f', 3215 - 'aphront-typeahead-control-css' => '782b1e3f', 3207 + 'aphront-headsup-view-css' => '1da0b408', 3208 + 'aphront-list-filter-view-css' => '1da0b408', 3209 + 'aphront-pager-view-css' => '1da0b408', 3210 + 'aphront-panel-view-css' => '1da0b408', 3211 + 'aphront-side-nav-view-css' => '1da0b408', 3212 + 'aphront-table-view-css' => '1da0b408', 3213 + 'aphront-tokenizer-control-css' => '1da0b408', 3214 + 'aphront-tooltip-css' => '1da0b408', 3215 + 'aphront-typeahead-control-css' => '1da0b408', 3216 3216 'differential-changeset-view-css' => '2ba14b3d', 3217 3217 'differential-core-view-css' => '2ba14b3d', 3218 3218 'differential-inline-comment-editor' => 'd05e3c0f', ··· 3278 3278 'javelin-workflow' => '3a455e4f', 3279 3279 'maniphest-task-summary-css' => '7839ae2d', 3280 3280 'maniphest-transaction-detail-css' => '7839ae2d', 3281 - 'phabricator-app-buttons-css' => '782b1e3f', 3281 + 'phabricator-app-buttons-css' => '1da0b408', 3282 3282 'phabricator-content-source-view-css' => '2ba14b3d', 3283 - 'phabricator-core-buttons-css' => '782b1e3f', 3284 - 'phabricator-core-css' => '782b1e3f', 3285 - 'phabricator-directory-css' => '782b1e3f', 3283 + 'phabricator-core-buttons-css' => '1da0b408', 3284 + 'phabricator-core-css' => '1da0b408', 3285 + 'phabricator-directory-css' => '1da0b408', 3286 3286 'phabricator-drag-and-drop-file-upload' => 'd05e3c0f', 3287 3287 'phabricator-dropdown-menu' => '3a455e4f', 3288 - 'phabricator-flag-css' => '782b1e3f', 3289 - 'phabricator-jump-nav' => '782b1e3f', 3288 + 'phabricator-flag-css' => '1da0b408', 3289 + 'phabricator-jump-nav' => '1da0b408', 3290 3290 'phabricator-keyboard-shortcut' => '3a455e4f', 3291 3291 'phabricator-keyboard-shortcut-manager' => '3a455e4f', 3292 3292 'phabricator-menu-item' => '3a455e4f', ··· 3294 3294 'phabricator-paste-file-upload' => '3a455e4f', 3295 3295 'phabricator-prefab' => '3a455e4f', 3296 3296 'phabricator-project-tag-css' => '7839ae2d', 3297 - 'phabricator-remarkup-css' => '782b1e3f', 3297 + 'phabricator-remarkup-css' => '1da0b408', 3298 3298 'phabricator-shaped-request' => 'd05e3c0f', 3299 - 'phabricator-standard-page-view' => '782b1e3f', 3299 + 'phabricator-standard-page-view' => '1da0b408', 3300 3300 'phabricator-tooltip' => '3a455e4f', 3301 - 'phabricator-transaction-view-css' => '782b1e3f', 3302 - 'syntax-highlighting-css' => '782b1e3f', 3301 + 'phabricator-transaction-view-css' => '1da0b408', 3302 + 'syntax-highlighting-css' => '1da0b408', 3303 3303 ), 3304 3304 ));
+31 -33
src/view/form/control/PhabricatorRemarkupControl.php
··· 21 21 protected function renderInput() { 22 22 23 23 Javelin::initBehavior('phabricator-remarkup-assist', array()); 24 + Javelin::initBehavior('phabricator-tooltips', array()); 24 25 25 26 $actions = array( 26 27 'b' => array( 27 - 'text' => 'B', 28 + 'tip' => pht('Bold'), 28 29 ), 29 30 'i' => array( 30 - 'text' => 'I', 31 + 'tip' => pht('Italics'), 31 32 ), 32 33 'tt' => array( 33 - 'text' => 'T', 34 - ), 35 - 's' => array( 36 - 'text' => 'S', 34 + 'tip' => pht('Monospaced'), 37 35 ), 38 36 array( 39 37 'spacer' => true, 40 38 ), 41 39 'ul' => array( 42 - 'text' => "\xE2\x80\xA2", 40 + 'tip' => pht('Bulleted List'), 43 41 ), 44 42 'ol' => array( 45 - 'text' => '1.', 43 + 'tip' => pht('Numbered List'), 46 44 ), 47 45 'code' => array( 48 - 'text' => '{}', 49 - ), 50 - array( 51 - 'spacer' => true, 52 - ), 53 - 'mention' => array( 54 - 'text' => '@', 55 - ), 56 - array( 57 - 'spacer' => true, 58 - ), 59 - 'h1' => array( 60 - 'text' => 'H', 61 - ), 62 - array( 63 - 'spacer' => true, 46 + 'tip' => pht('Code Block'), 64 47 ), 65 48 'help' => array( 49 + 'tip' => pht('Help'), 66 50 'align' => 'right', 67 - 'text' => '?', 68 51 'href' => PhabricatorEnv::getDoclink( 69 52 'article/Remarkup_Reference.html'), 70 53 ), ··· 73 56 $buttons = array(); 74 57 foreach ($actions as $action => $spec) { 75 58 if (idx($spec, 'spacer')) { 76 - $buttons[] = '<span> </span>'; 59 + $buttons[] = phutil_render_tag( 60 + 'span', 61 + array( 62 + 'class' => 'remarkup-assist-separator', 63 + ), 64 + ''); 77 65 continue; 78 66 } 79 67 80 68 $classes = array(); 81 - $classes[] = 'button'; 82 - $classes[] = 'grey'; 83 69 $classes[] = 'remarkup-assist-button'; 84 70 if (idx($spec, 'align') == 'right') { 85 71 $classes[] = 'remarkup-assist-right'; ··· 91 77 $mustcapture = true; 92 78 $target = null; 93 79 } else { 94 - $meta = null; 80 + $meta = array(); 95 81 $mustcapture = null; 96 82 $target = '_blank'; 97 83 } 98 84 85 + $tip = idx($spec, 'tip'); 86 + if ($tip) { 87 + $meta['tip'] = $tip; 88 + } 89 + 99 90 $buttons[] = javelin_render_tag( 100 91 'a', 101 92 array( 102 93 'class' => implode(' ', $classes), 103 94 'href' => $href, 104 - 'sigil' => 'remarkup-assist', 95 + 'sigil' => 'remarkup-assist has-tooltip', 105 96 'meta' => $meta, 106 97 'mustcapture' => $mustcapture, 107 98 'target' => $target, ··· 110 101 phutil_render_tag( 111 102 'div', 112 103 array( 113 - 'class' => 'remarkup-assist remarkup-assist-'.$action, 104 + 'class' => 'remarkup-assist autosprite remarkup-assist-'.$action, 114 105 ), 115 - idx($spec, 'text', ''))); 106 + '')); 116 107 } 117 108 118 - $buttons = implode('', $buttons); 109 + $buttons = phutil_render_tag( 110 + 'div', 111 + array( 112 + 'class' => 'remarkup-assist-bar', 113 + ), 114 + implode('', $buttons)); 115 + 116 + $this->setCustomClass('remarkup-assist-textarea'); 119 117 120 118 return javelin_render_tag( 121 119 'div',
+36
webroot/rsrc/css/autosprite.css
··· 747 747 .action-subscribe-delete { 748 748 background-position: 0px -7308px; 749 749 } 750 + 751 + .remarkup-assist-b { 752 + background-position: 0px -7325px; 753 + } 754 + 755 + .remarkup-assist-code { 756 + background-position: 0px -7340px; 757 + } 758 + 759 + .remarkup-assist-i { 760 + background-position: 0px -7355px; 761 + } 762 + 763 + .remarkup-assist-image { 764 + background-position: 0px -7370px; 765 + } 766 + 767 + .remarkup-assist-ol { 768 + background-position: 0px -7385px; 769 + } 770 + 771 + .remarkup-assist-tag { 772 + background-position: 0px -7400px; 773 + } 774 + 775 + .remarkup-assist-tt { 776 + background-position: 0px -7415px; 777 + } 778 + 779 + .remarkup-assist-ul { 780 + background-position: 0px -7430px; 781 + } 782 + 783 + .remarkup-assist-help { 784 + background-position: 0px -7445px; 785 + }
+48 -39
webroot/rsrc/css/core/remarkup.css
··· 247 247 padding: 3px 6px; 248 248 } 249 249 250 - .remarkup-assist-bar { 251 - padding: 2px 0; 250 + 251 + .remarkup-assist-textarea { 252 + border-width: 1px; 253 + border-color: #e5e5e5 #999999 #999999; 254 + 255 + /* Prevent Safari and Chrome users from dragging the textarea any wider, 256 + because the top bar won't resize along with it. */ 257 + resize: vertical; 252 258 } 253 259 254 - a.remarkup-assist-button { 255 - padding-left: 4px; 256 - padding-right: 4px; 257 - padding-bottom: 4px; 258 - margin-bottom: 3px; 260 + .remarkup-assist-bar { 261 + height: 27px; 262 + padding: 0 2px; 259 263 260 - position: relative; 264 + border-width: 1px 1px 0; 265 + border-style: solid; 266 + border-color: #737373 #999999; 267 + 268 + background: #f5f5f5; 261 269 overflow: hidden; 262 - height: 16px; 263 - width: 16px; 264 270 } 265 271 266 - a.remarkup-assist-button + a.remarkup-assist-button { 267 - border-left-width: 0px; 272 + .remarkup-assist-button { 273 + display: block; 274 + padding: 3px; 275 + margin: 2px 1px; 276 + float: left; 277 + 278 + border: 1px solid transparent; 279 + border-radius: 2px; 268 280 } 269 281 270 - .remarkup-assist { 271 - float: left; 272 - height: 16px; 273 - width: 16px; 274 - font-weight: normal; 282 + .remarkup-assist-button:hover { 283 + background: #f7f7f7; 284 + border-color: #c6c6c6; 285 + box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.10); 275 286 } 276 287 277 - .remarkup-assist-right { 278 - float: right; 288 + .remarkup-assist-button:active { 289 + outline: none; 290 + background: #f3f3f3; 291 + box-shadow: inset 1px 1px 1px rgba(0, 0, 0, 0.10); 279 292 } 280 293 281 - .remarkup-assist-b { 282 - font-family: "Georgia", serif; 283 - font-weight: bold; 294 + .remarkup-assist-button:focus { 295 + outline: none; 284 296 } 285 297 286 - .remarkup-assist-i { 287 - font-family: "Georgia", serif; 288 - font-style: italic; 289 - } 298 + .remarkup-assist-separator { 299 + display: block; 300 + float: left; 290 301 291 - .remarkup-assist-code, 292 - .remarkup-assist-tt { 293 - text-align: center; 294 - font-family: monospace; 295 - } 302 + margin: 7px 4px; 303 + height: 14px; 296 304 297 - .remarkup-assist-s { 298 - font-family: "Georgia", serif; 299 - text-decoration: line-through; 305 + width: 0px; 306 + border-right: 1px solid #cccccc; 300 307 } 301 308 302 - .remarkup-assist-ol { 303 - font-family: "Georgia", serif; 309 + .remarkup-assist { 310 + display: block; 311 + width: 14px; 312 + height: 14px; 313 + overflow: hidden; 304 314 } 305 315 306 - .remarkup-assist-h1 { 307 - font-family: "Georgia", serif; 308 - font-weight: bold; 316 + .remarkup-assist-right { 317 + float: right; 309 318 }
webroot/rsrc/image/autosprite.png

This is a binary file and will not be displayed.

-10
webroot/rsrc/js/application/core/behavior-phabricator-remarkup-assist.js
··· 39 39 case 'tt': 40 40 update(area, '`', sel || 'monospaced text', '`'); 41 41 break; 42 - case 's': 43 - update(area, '~~', sel || 'strikethrough text', '~~'); 44 - break; 45 42 case 'ul': 46 43 case 'ol': 47 44 var ch = (action == 'ol') ? ' # ' : ' - '; ··· 58 55 sel = sel.split("\n"); 59 56 sel = " " + sel.join("\n "); 60 57 update(area, ((r.start == 0) ? "" : "\n\n"), sel, "\n\n"); 61 - break; 62 - case 'mention': 63 - update(area, '@', sel || 'username', ''); 64 - break; 65 - case 'h1': 66 - sel = sel || 'Header'; 67 - update(area, ((r.start == 0) ? "" : "\n\n") + "= ", sel, " =\n\n"); 68 58 break; 69 59 } 70 60 }