1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-25 16:22:43 +01:00

Add an icon+background selector for project images

Summary: Makes it easy to choose distinctive icons for projects.

Test Plan:
{F71018}

{F71020}

{F71019}

{F71021}

Reviewers: btrahan, chad

Reviewed By: chad

CC: chad, aran

Differential Revision: https://secure.phabricator.com/D7333
This commit is contained in:
epriestley 2013-10-17 09:32:34 -07:00
parent 70b7b9a869
commit 4f05736175
21 changed files with 973 additions and 287 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

View file

@ -1,284 +1,284 @@
{
"version" : 1,
"sprites" : {
"projects_8ball" : {
"name" : "projects_8ball",
"rule" : ".projects_8ball",
"projects-8ball" : {
"name" : "projects-8ball",
"rule" : ".projects-8ball",
"hash" : "1571c4d51926d3af7711b825c5816e2e"
},
"projects_alien" : {
"name" : "projects_alien",
"rule" : ".projects_alien",
"projects-alien" : {
"name" : "projects-alien",
"rule" : ".projects-alien",
"hash" : "384f920ae335dca04edaf29663d3a074"
},
"projects_annouce" : {
"name" : "projects_annouce",
"rule" : ".projects_annouce",
"hash" : "38abd2ff32e7c145e44c020ee4e6f2f1"
"projects-announce" : {
"name" : "projects-announce",
"rule" : ".projects-announce",
"hash" : "94329cedd509fc27a6fb577927581118"
},
"projects_art" : {
"name" : "projects_art",
"rule" : ".projects_art",
"projects-art" : {
"name" : "projects-art",
"rule" : ".projects-art",
"hash" : "85c545e5130f00ff1b93c0af0d540974"
},
"projects_award" : {
"name" : "projects_award",
"rule" : ".projects_award",
"projects-award" : {
"name" : "projects-award",
"rule" : ".projects-award",
"hash" : "fad6d89e4938e16f22f3c9db7cf5d696"
},
"projects_bacon" : {
"name" : "projects_bacon",
"rule" : ".projects_bacon",
"projects-bacon" : {
"name" : "projects-bacon",
"rule" : ".projects-bacon",
"hash" : "f6300cdfa5a96a223f53f13dd0d3acc3"
},
"projects_bandaid" : {
"name" : "projects_bandaid",
"rule" : ".projects_bandaid",
"projects-bandaid" : {
"name" : "projects-bandaid",
"rule" : ".projects-bandaid",
"hash" : "c463dffa161997277fc6697155f4085b"
},
"projects_beer" : {
"name" : "projects_beer",
"rule" : ".projects_beer",
"projects-beer" : {
"name" : "projects-beer",
"rule" : ".projects-beer",
"hash" : "81c7580f322d9fb40c77db56cd92d61d"
},
"projects_bomb" : {
"name" : "projects_bomb",
"rule" : ".projects_bomb",
"projects-bomb" : {
"name" : "projects-bomb",
"rule" : ".projects-bomb",
"hash" : "1123da7cc56313891c9979b004cc02f7"
},
"projects_briefcase" : {
"name" : "projects_briefcase",
"rule" : ".projects_briefcase",
"projects-briefcase" : {
"name" : "projects-briefcase",
"rule" : ".projects-briefcase",
"hash" : "9b4b413ddb250ce1d3fbe18a5a5698cd"
},
"projects_bug" : {
"name" : "projects_bug",
"rule" : ".projects_bug",
"projects-bug" : {
"name" : "projects-bug",
"rule" : ".projects-bug",
"hash" : "9678702aed00c4779759ebbdfe97fe48"
},
"projects_calendar" : {
"name" : "projects_calendar",
"rule" : ".projects_calendar",
"projects-calendar" : {
"name" : "projects-calendar",
"rule" : ".projects-calendar",
"hash" : "e7dc5d1b11fc55ed239fcbfe527ed0e7"
},
"projects_cloud" : {
"name" : "projects_cloud",
"rule" : ".projects_cloud",
"projects-cloud" : {
"name" : "projects-cloud",
"rule" : ".projects-cloud",
"hash" : "d38bf58580b3c36fbd3149a13f7d0e5e"
},
"projects_coffee" : {
"name" : "projects_coffee",
"rule" : ".projects_coffee",
"projects-coffee" : {
"name" : "projects-coffee",
"rule" : ".projects-coffee",
"hash" : "a9c10862139d8e7f56c9f892496f9666"
},
"projects_creditcard" : {
"name" : "projects_creditcard",
"rule" : ".projects_creditcard",
"projects-creditcard" : {
"name" : "projects-creditcard",
"rule" : ".projects-creditcard",
"hash" : "db2c179cb4935da8b9950ac30da8c0d1"
},
"projects_death" : {
"name" : "projects_death",
"rule" : ".projects_death",
"projects-death" : {
"name" : "projects-death",
"rule" : ".projects-death",
"hash" : "cdea72dfdcb3fc64873b9fff78addb3c"
},
"projects_desktop" : {
"name" : "projects_desktop",
"rule" : ".projects_desktop",
"projects-desktop" : {
"name" : "projects-desktop",
"rule" : ".projects-desktop",
"hash" : "19d2ef34e3dd53615cdad91eb987d6fe"
},
"projects_dropbox" : {
"name" : "projects_dropbox",
"rule" : ".projects_dropbox",
"projects-dropbox" : {
"name" : "projects-dropbox",
"rule" : ".projects-dropbox",
"hash" : "10231bf468769b96ed40cf983abfa269"
},
"projects_education" : {
"name" : "projects_education",
"rule" : ".projects_education",
"projects-education" : {
"name" : "projects-education",
"rule" : ".projects-education",
"hash" : "ce3d0ca75d519b2ac427a690d30475f8"
},
"projects_experimental" : {
"name" : "projects_experimental",
"rule" : ".projects_experimental",
"projects-experimental" : {
"name" : "projects-experimental",
"rule" : ".projects-experimental",
"hash" : "311ef712f8daca057c20c8fd78fa77ce"
},
"projects_facebook" : {
"name" : "projects_facebook",
"rule" : ".projects_facebook",
"projects-facebook" : {
"name" : "projects-facebook",
"rule" : ".projects-facebook",
"hash" : "16581191e4ce9e0115d447b479c886cb"
},
"projects_facility" : {
"name" : "projects_facility",
"rule" : ".projects_facility",
"projects-facility" : {
"name" : "projects-facility",
"rule" : ".projects-facility",
"hash" : "d8893f9d2b75ec047b6f3898a386055c"
},
"projects_film" : {
"name" : "projects_film",
"rule" : ".projects_film",
"projects-film" : {
"name" : "projects-film",
"rule" : ".projects-film",
"hash" : "57497050fa09ba1533d981a9c1550ba9"
},
"projects_forked" : {
"name" : "projects_forked",
"rule" : ".projects_forked",
"projects-forked" : {
"name" : "projects-forked",
"rule" : ".projects-forked",
"hash" : "f575428e1079981840297bd444e51c43"
},
"projects_games" : {
"name" : "projects_games",
"rule" : ".projects_games",
"projects-games" : {
"name" : "projects-games",
"rule" : ".projects-games",
"hash" : "b802cff3e76051675b37165bd9702088"
},
"projects_ghost" : {
"name" : "projects_ghost",
"rule" : ".projects_ghost",
"projects-ghost" : {
"name" : "projects-ghost",
"rule" : ".projects-ghost",
"hash" : "7c8622cad29bddc5179f6a6d5f15fbe9"
},
"projects_gift" : {
"name" : "projects_gift",
"rule" : ".projects_gift",
"projects-gift" : {
"name" : "projects-gift",
"rule" : ".projects-gift",
"hash" : "f2ca678906a6806f421b60abddaa6cae"
},
"projects_globe" : {
"name" : "projects_globe",
"rule" : ".projects_globe",
"projects-globe" : {
"name" : "projects-globe",
"rule" : ".projects-globe",
"hash" : "87515a83cc0c840804aca594677d1eae"
},
"projects_golf" : {
"name" : "projects_golf",
"rule" : ".projects_golf",
"projects-golf" : {
"name" : "projects-golf",
"rule" : ".projects-golf",
"hash" : "1ee7556fab3d46d925deb00322dad858"
},
"projects_heart" : {
"name" : "projects_heart",
"rule" : ".projects_heart",
"projects-heart" : {
"name" : "projects-heart",
"rule" : ".projects-heart",
"hash" : "3da64839e37ee245333017d0a310cc2e"
},
"projects_intergalactic" : {
"name" : "projects_intergalactic",
"rule" : ".projects_intergalactic",
"projects-intergalactic" : {
"name" : "projects-intergalactic",
"rule" : ".projects-intergalactic",
"hash" : "94dca756cb267bdb4e0ed58467320780"
},
"projects_lock" : {
"name" : "projects_lock",
"rule" : ".projects_lock",
"projects-lock" : {
"name" : "projects-lock",
"rule" : ".projects-lock",
"hash" : "9d4c8ad3a4ac4163f284461da7df2763"
},
"projects_mail" : {
"name" : "projects_mail",
"rule" : ".projects_mail",
"projects-mail" : {
"name" : "projects-mail",
"rule" : ".projects-mail",
"hash" : "963f5ce26c6caf86e72d754f7b6e8865"
},
"projects_martini" : {
"name" : "projects_martini",
"rule" : ".projects_martini",
"projects-martini" : {
"name" : "projects-martini",
"rule" : ".projects-martini",
"hash" : "24d4d5fb5c334621ece4c35a9196471e"
},
"projects_medical" : {
"name" : "projects_medical",
"rule" : ".projects_medical",
"projects-medical" : {
"name" : "projects-medical",
"rule" : ".projects-medical",
"hash" : "e0cb3ef5557321d166e8eb49c10d3599"
},
"projects_mobile" : {
"name" : "projects_mobile",
"rule" : ".projects_mobile",
"projects-mobile" : {
"name" : "projects-mobile",
"rule" : ".projects-mobile",
"hash" : "37dec95d1a4a937743d52acac319c3b6"
},
"projects_music" : {
"name" : "projects_music",
"rule" : ".projects_music",
"projects-music" : {
"name" : "projects-music",
"rule" : ".projects-music",
"hash" : "e7a814194685ac25be0db05b04074607"
},
"projects_news" : {
"name" : "projects_news",
"rule" : ".projects_news",
"projects-news" : {
"name" : "projects-news",
"rule" : ".projects-news",
"hash" : "6861f3ee827d09b0592166514f4941e8"
},
"projects_orgchart" : {
"name" : "projects_orgchart",
"rule" : ".projects_orgchart",
"projects-orgchart" : {
"name" : "projects-orgchart",
"rule" : ".projects-orgchart",
"hash" : "20c51c59788fb2bc8184fdd5687d33dc"
},
"projects_peoples" : {
"name" : "projects_peoples",
"rule" : ".projects_peoples",
"projects-peoples" : {
"name" : "projects-peoples",
"rule" : ".projects-peoples",
"hash" : "c949ba6d09e68317a9a11482e75e5140"
},
"projects_piechart" : {
"name" : "projects_piechart",
"rule" : ".projects_piechart",
"projects-piechart" : {
"name" : "projects-piechart",
"rule" : ".projects-piechart",
"hash" : "051138560e30982a029aa5e4ea87bc17"
},
"projects_poison" : {
"name" : "projects_poison",
"rule" : ".projects_poison",
"projects-poison" : {
"name" : "projects-poison",
"rule" : ".projects-poison",
"hash" : "56ddafd138e421f198b9cb38e5dc7455"
},
"projects_putabirdonit" : {
"name" : "projects_putabirdonit",
"rule" : ".projects_putabirdonit",
"projects-putabirdonit" : {
"name" : "projects-putabirdonit",
"rule" : ".projects-putabirdonit",
"hash" : "ee298fff82c34341b986a3e1b77bea11"
},
"projects_radiate" : {
"name" : "projects_radiate",
"rule" : ".projects_radiate",
"projects-radiate" : {
"name" : "projects-radiate",
"rule" : ".projects-radiate",
"hash" : "9cfb918089b3de8506a5d270a119052c"
},
"projects_savings" : {
"name" : "projects_savings",
"rule" : ".projects_savings",
"projects-savings" : {
"name" : "projects-savings",
"rule" : ".projects-savings",
"hash" : "9e92bc5e64f79d2f4842ac24a8b57fcb"
},
"projects_search" : {
"name" : "projects_search",
"rule" : ".projects_search",
"projects-search" : {
"name" : "projects-search",
"rule" : ".projects-search",
"hash" : "a42c1c31f2929838b0f181f417c0b6a4"
},
"projects_shield" : {
"name" : "projects_shield",
"rule" : ".projects_shield",
"projects-shield" : {
"name" : "projects-shield",
"rule" : ".projects-shield",
"hash" : "40c6e1bec7c07c165668ac45c218847a"
},
"projects_speed" : {
"name" : "projects_speed",
"rule" : ".projects_speed",
"projects-speed" : {
"name" : "projects-speed",
"rule" : ".projects-speed",
"hash" : "2b70c194d07f5a9d95abc51d84fb22ed"
},
"projects_sprint" : {
"name" : "projects_sprint",
"rule" : ".projects_sprint",
"projects-sprint" : {
"name" : "projects-sprint",
"rule" : ".projects-sprint",
"hash" : "655ef9a3043eab23eac1da21baeb36b3"
},
"projects_star" : {
"name" : "projects_star",
"rule" : ".projects_star",
"projects-star" : {
"name" : "projects-star",
"rule" : ".projects-star",
"hash" : "a46e3c18f68bc13a65b410496e27b5d7"
},
"projects_storage" : {
"name" : "projects_storage",
"rule" : ".projects_storage",
"projects-storage" : {
"name" : "projects-storage",
"rule" : ".projects-storage",
"hash" : "bb19baa77bb7596f43f77e5dbbddb006"
},
"projects_tablet" : {
"name" : "projects_tablet",
"rule" : ".projects_tablet",
"projects-tablet" : {
"name" : "projects-tablet",
"rule" : ".projects-tablet",
"hash" : "830dcf6637288ca122c8f5034cae3769"
},
"projects_travel" : {
"name" : "projects_travel",
"rule" : ".projects_travel",
"projects-travel" : {
"name" : "projects-travel",
"rule" : ".projects-travel",
"hash" : "86ec4dcd025879a43435b101fd542a1b"
},
"projects_twitter" : {
"name" : "projects_twitter",
"rule" : ".projects_twitter",
"projects-twitter" : {
"name" : "projects-twitter",
"rule" : ".projects-twitter",
"hash" : "75b8680dd1e4ecce4ca3a39c87e1ed80"
},
"projects_warning" : {
"name" : "projects_warning",
"rule" : ".projects_warning",
"projects-warning" : {
"name" : "projects-warning",
"rule" : ".projects-warning",
"hash" : "3ac48b6f963675e1f4bb4ac75aad936f"
},
"projects_whale" : {
"name" : "projects_whale",
"rule" : ".projects_whale",
"projects-whale" : {
"name" : "projects-whale",
"rule" : ".projects-whale",
"hash" : "569b584c7e80a0a9b965280abd27c723"
}
},

View file

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View file

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

View file

@ -1791,6 +1791,18 @@ celerity_register_resource_map(array(
),
'disk' => '/rsrc/js/core/behavior-history-install.js',
),
'javelin-behavior-icon-composer' =>
array(
'uri' => '/res/0be5c462/rsrc/js/application/files/behavior-icon-composer.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-behavior',
1 => 'javelin-dom',
2 => 'javelin-stratcom',
),
'disk' => '/rsrc/js/application/files/behavior-icon-composer.js',
),
'javelin-behavior-konami' =>
array(
'uri' => '/res/b7bb7c24/rsrc/js/core/behavior-konami.js',
@ -1802,6 +1814,18 @@ celerity_register_resource_map(array(
),
'disk' => '/rsrc/js/core/behavior-konami.js',
),
'javelin-behavior-launch-icon-composer' =>
array(
'uri' => '/res/202488ac/rsrc/js/application/files/behavior-launch-icon-composer.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-behavior',
1 => 'javelin-dom',
2 => 'javelin-workflow',
),
'disk' => '/rsrc/js/application/files/behavior-launch-icon-composer.js',
),
'javelin-behavior-lightbox-attachments' =>
array(
'uri' => '/res/72b4d3a8/rsrc/js/core/behavior-lightbox-attachments.js',
@ -3062,7 +3086,7 @@ celerity_register_resource_map(array(
),
'people-profile-css' =>
array(
'uri' => '/res/d50d9502/rsrc/css/application/people/people-profile.css',
'uri' => '/res/f1da102e/rsrc/css/application/people/people-profile.css',
'type' => 'css',
'requires' =>
array(
@ -4227,7 +4251,7 @@ celerity_register_resource_map(array(
),
'sprite-projects-css' =>
array(
'uri' => '/res/3ff34b69/rsrc/css/sprite-projects.css',
'uri' => '/res/40eacbfb/rsrc/css/sprite-projects.css',
'type' => 'css',
'requires' =>
array(

View file

@ -1209,6 +1209,7 @@ phutil_register_library_map(array(
'PhabricatorFile' => 'applications/files/storage/PhabricatorFile.php',
'PhabricatorFileBundleLoader' => 'applications/files/query/PhabricatorFileBundleLoader.php',
'PhabricatorFileCommentController' => 'applications/files/controller/PhabricatorFileCommentController.php',
'PhabricatorFileComposeController' => 'applications/files/controller/PhabricatorFileComposeController.php',
'PhabricatorFileController' => 'applications/files/controller/PhabricatorFileController.php',
'PhabricatorFileDAO' => 'applications/files/storage/PhabricatorFileDAO.php',
'PhabricatorFileDataController' => 'applications/files/controller/PhabricatorFileDataController.php',
@ -1523,6 +1524,7 @@ phutil_register_library_map(array(
'PhabricatorProjectProfile' => 'applications/project/storage/PhabricatorProjectProfile.php',
'PhabricatorProjectProfileController' => 'applications/project/controller/PhabricatorProjectProfileController.php',
'PhabricatorProjectProfileEditController' => 'applications/project/controller/PhabricatorProjectProfileEditController.php',
'PhabricatorProjectProfilePictureController' => 'applications/project/controller/PhabricatorProjectProfilePictureController.php',
'PhabricatorProjectQuery' => 'applications/project/query/PhabricatorProjectQuery.php',
'PhabricatorProjectSearchEngine' => 'applications/project/query/PhabricatorProjectSearchEngine.php',
'PhabricatorProjectSearchIndexer' => 'applications/project/search/PhabricatorProjectSearchIndexer.php',
@ -3397,6 +3399,7 @@ phutil_register_library_map(array(
3 => 'PhabricatorPolicyInterface',
),
'PhabricatorFileCommentController' => 'PhabricatorFileController',
'PhabricatorFileComposeController' => 'PhabricatorFileController',
'PhabricatorFileController' => 'PhabricatorController',
'PhabricatorFileDAO' => 'PhabricatorLiskDAO',
'PhabricatorFileDataController' => 'PhabricatorFileController',
@ -3739,6 +3742,7 @@ phutil_register_library_map(array(
'PhabricatorProjectProfile' => 'PhabricatorProjectDAO',
'PhabricatorProjectProfileController' => 'PhabricatorProjectController',
'PhabricatorProjectProfileEditController' => 'PhabricatorProjectController',
'PhabricatorProjectProfilePictureController' => 'PhabricatorProjectController',
'PhabricatorProjectQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorProjectSearchEngine' => 'PhabricatorApplicationSearchEngine',
'PhabricatorProjectSearchIndexer' => 'PhabricatorSearchDocumentIndexer',

View file

@ -51,6 +51,7 @@ final class PhabricatorApplicationFiles extends PhabricatorApplication {
'(query/(?P<key>[^/]+)/)?' => 'PhabricatorFileListController',
'upload/' => 'PhabricatorFileUploadController',
'dropupload/' => 'PhabricatorFileDropUploadController',
'compose/' => 'PhabricatorFileComposeController',
'comment/(?P<id>[1-9]\d*)/' => 'PhabricatorFileCommentController',
'delete/(?P<id>[1-9]\d*)/' => 'PhabricatorFileDeleteController',
'info/(?P<phid>[^/]+)/' => 'PhabricatorFileInfoController',

View file

@ -0,0 +1,249 @@
<?php
final class PhabricatorFileComposeController
extends PhabricatorFileController {
public function processRequest() {
$request = $this->getRequest();
$viewer = $request->getUser();
$colors = array(
'red' => pht('Verbillion'),
'orange' => pht('Navel Orange'),
'yellow' => pht('Prim Goldenrod'),
'green' => pht('Lustrous Verdant'),
'blue' => pht('Tropical Deep'),
'sky' => pht('Wide Open Sky'),
'indigo' => pht('Pleated Khaki'),
'violet' => pht('Aged Merlot'),
'charcoal' => pht('Gemstone'),
'backdrop' => pht('Driven Snow'),
);
$manifest = PHUIIconView::getSheetManifest(PHUIIconView::SPRITE_PROJECTS);
if ($request->isFormPost()) {
$icon = $request->getStr('icon');
$color = $request->getStr('color');
if (isset($colors[$color]) && isset($manifest['projects-'.$icon])) {
$root = dirname(phutil_get_library_root('phabricator'));
$icon_file = $root.'/resources/sprite/projects_1x/'.$icon.'.png';
$icon_data = Filesystem::readFile($icon_file);
$data = $this->composeImage($color, $icon_data);
$file = PhabricatorFile::buildFromFileDataOrHash(
$data,
array(
'name' => 'project.png',
));
$content = array(
'phid' => $file->getPHID(),
);
return id(new AphrontAjaxResponse())->setContent($content);
}
}
$value_color = head_key($colors);
$value_icon = head_key($manifest);
$value_icon = substr($value_icon, strlen('projects-'));
require_celerity_resource('people-profile-css');
$buttons = array();
foreach ($colors as $color => $name) {
$buttons[] = javelin_tag(
'button',
array(
'class' => 'grey profile-image-button',
'sigil' => 'has-tooltip compose-select-color',
'style' => 'margin: 0 8px 8px 0',
'meta' => array(
'color' => $color,
'tip' => $name,
),
),
id(new PHUIIconView())
->addClass('compose-background-'.$color));
}
$icons = array();
$icon_quips = array(
'8ball' => pht('Take a Risk'),
'alien' => pht('Foreign Interface'),
'announce' => pht('Louder is Better'),
'art' => pht('Unique Snowflake'),
'award' => pht('Shooting Star'),
'bacon' => pht('Healthy Vegetables'),
'bandaid' => pht('Durable Infrastructure'),
'beer' => pht('Healthy Vegetable Juice'),
'bomb' => pht('Imminent Success'),
'briefcase' => pht('Adventure Pack'),
'bug' => pht('Costumed Egg'),
'calendar' => pht('Everyone Loves Meetings'),
'cloud' => pht('Water Cycle'),
'coffee' => pht('Half-Whip Nonfat Soy Latte'),
'creditcard' => pht('Expense It'),
'death' => pht('Calcium Promotes Bone Health'),
'desktop' => pht('Magical Portal'),
'dropbox' => pht('Cardboard Box'),
'education' => pht('Debt'),
'experimental' => pht('CAUTION: Dangerous Chemicals'),
'facebook' => pht('Popular Social Network'),
'facility' => pht('Pollution Solves Problems'),
'film' => pht('Actual Physical Film'),
'forked' => pht('You Can\'t Eat Soup'),
'games' => pht('Serious Business'),
'ghost' => pht('Haunted'),
'gift' => pht('Surprise!'),
'globe' => pht('Scanner Sweep'),
'golf' => pht('Business Meeting'),
'heart' => pht('Undergoing a Major Surgery'),
'intergalactic' => pht('Jupiter'),
'lock' => pht('Extremely Secret'),
'mail' => pht('Oragami'),
'martini' => pht('Healthy Olive Drink'),
'medical' => pht('Medic!'),
'mobile' => pht('Cellular Telephone'),
'music' => pht("\xE2\x99\xAB"),
'news' => pht('Actual Physical Newspaper'),
'orgchart' => pht('It\'s Good to be King'),
'peoples' => pht('Angel and Devil'),
'piechart' => pht('Actual Physical Pie'),
'poison' => pht('Healthy Bone Juice'),
'putabirdonit' => pht('Put a Bird On It'),
'radiate' => pht('Radiant Beauty'),
'savings' => pht('Oink Oink'),
'search' => pht('Sleuthing'),
'shield' => pht('Royal Crest'),
'speed' => pht('Slow and Steady'),
'sprint' => pht('Fire Exit'),
'star' => pht('The More You Know'),
'storage' => pht('Stack of Pancakes'),
'tablet' => pht('Cellular Telephone For Giants'),
'travel' => pht('Pretty Clearly an Airplane'),
'twitter' => pht('Bird Stencil'),
'warning' => pht('No Caution Required, Everything Looks Safe'),
'whale' => pht('Friendly Walrus'),
);
foreach ($manifest as $icon => $spec) {
$icon = substr($icon, strlen('projects-'));
$icons[] = javelin_tag(
'button',
array(
'class' => 'grey profile-image-button',
'sigil' => 'has-tooltip compose-select-icon',
'style' => 'margin: 0 8px 8px 0',
'meta' => array(
'icon' => $icon,
'tip' => idx($icon_quips, $icon, $icon),
),
),
id(new PHUIIconView())
->setSpriteIcon($icon)
->setSpriteSheet(PHUIIconView::SPRITE_PROJECTS));
}
$dialog_id = celerity_generate_unique_node_id();
$color_input_id = celerity_generate_unique_node_id();;
$icon_input_id = celerity_generate_unique_node_id();
$preview_id = celerity_generate_unique_node_id();
$preview = id(new PHUIIconView())
->setID($preview_id)
->addClass('compose-background-'.$value_color)
->setSpriteIcon($value_icon)
->setSpriteSheet(PHUIIconView::SPRITE_PROJECTS);
$color_input = javelin_tag(
'input',
array(
'type' => 'hidden',
'name' => 'color',
'value' => $value_color,
'id' => $color_input_id,
));
$icon_input = javelin_tag(
'input',
array(
'type' => 'hidden',
'name' => 'icon',
'value' => $value_icon,
'id' => $icon_input_id,
));
Javelin::initBehavior('phabricator-tooltips');
Javelin::initBehavior(
'icon-composer',
array(
'dialogID' => $dialog_id,
'colorInputID' => $color_input_id,
'iconInputID' => $icon_input_id,
'previewID' => $preview_id,
'defaultColor' => $value_color,
'defaultIcon' => $value_icon,
));
$dialog = id(new AphrontDialogView())
->setUser($viewer)
->setFormID($dialog_id)
->setClass('compose-dialog')
->setTitle(pht('Compose Image'))
->appendChild(
phutil_tag(
'div',
array(
'class' => 'compose-header',
),
pht('Choose Background Color')))
->appendChild($buttons)
->appendChild(
phutil_tag(
'div',
array(
'class' => 'compose-header',
),
pht('Choose Icon')))
->appendChild($icons)
->appendChild(
phutil_tag(
'div',
array(
'class' => 'compose-header',
),
pht('Preview')))
->appendChild($preview)
->appendChild($color_input)
->appendChild($icon_input)
->addCancelButton('/')
->addSubmitButton(pht('Save Image'));
return id(new AphrontDialogResponse())->setDialog($dialog);
}
private function composeImage($color, $icon_data) {
$icon_img = imagecreatefromstring($icon_data);
$map = CelerityResourceTransformer::getCSSVariableMap();
$color_string = idx($map, $color, '#ff00ff');
$color_const = hexdec(trim($color_string, '#'));
$canvas = imagecreatetruecolor(50, 50);
imagefill($canvas, 0, 0, $color_const);
imagecopy($canvas, $icon_img, 0, 0, 0, 0, 50, 50);
return PhabricatorImageTransformer::saveImageDataInAnyFormat(
$canvas,
'image/png');
}
}

View file

@ -42,6 +42,8 @@ final class PhabricatorApplicationProject extends PhabricatorApplication {
=> 'PhabricatorProjectMembersEditController',
'view/(?P<id>[1-9]\d*)/(?:(?P<page>\w+)/)?'
=> 'PhabricatorProjectProfileController',
'picture/(?P<id>[1-9]\d*)/' =>
'PhabricatorProjectProfilePictureController',
'create/' => 'PhabricatorProjectCreateController',
'update/(?P<id>[1-9]\d*)/(?P<action>[^/]+)/'
=> 'PhabricatorProjectUpdateController',

View file

@ -216,6 +216,14 @@ final class PhabricatorProjectProfileController
->setDisabled(!$can_edit)
->setWorkflow(!$can_edit));
$view->addAction(
id(new PhabricatorActionView())
->setName(pht('Edit Picture'))
->setIcon('image')
->setHref($this->getApplicationURI("picture/{$id}/"))
->setDisabled(!$can_edit)
->setWorkflow(!$can_edit));
$action = null;
if (!$project->isUserMember($viewer->getPHID())) {

View file

@ -29,14 +29,9 @@ final class PhabricatorProjectProfileEditController
}
$profile = $project->getProfile();
$img_src = $profile->getProfileImageURI();
$options = PhabricatorProjectStatus::getStatusMap();
$supported_formats = PhabricatorFile::getTransformableImageFormats();
$e_name = true;
$e_image = null;
$errors = array();
if ($request->isFormPost()) {
@ -89,37 +84,6 @@ final class PhabricatorProjectProfileEditController
$e_name = null;
}
$default_image = $request->getExists('default_image');
if ($default_image) {
$profile->setProfileImagePHID(null);
} else if (!empty($_FILES['image'])) {
$err = idx($_FILES['image'], 'error');
if ($err != UPLOAD_ERR_NO_FILE) {
$file = PhabricatorFile::newFromPHPUpload(
$_FILES['image'],
array(
'authorPHID' => $user->getPHID(),
));
$okay = $file->isTransformableImage();
if ($okay) {
$xformer = new PhabricatorImageTransformer();
$xformed = $xformer->executeThumbTransform(
$file,
$x = 50,
$y = 50);
$profile->setProfileImagePHID($xformed->getPHID());
$xformed->attachToObject($user, $project->getPHID());
} else {
$e_image = pht('Not Supported');
$errors[] =
pht('This server only supports these image formats:').' '.
implode(', ', $supported_formats).'.';
}
}
}
if (!$errors) {
$project->save();
$profile->setProjectPHID($project->getPHID());
@ -150,7 +114,6 @@ final class PhabricatorProjectProfileEditController
->setID('project-edit-form')
->setUser($user)
->setAction($action)
->setEncType('multipart/form-data')
->appendChild(
id(new AphrontFormTextControl())
->setLabel(pht('Name'))
@ -198,22 +161,6 @@ final class PhabricatorProjectProfileEditController
->setPolicyObject($project)
->setPolicies($policies)
->setCapability(PhabricatorPolicyCapability::CAN_JOIN))
->appendChild(
id(new AphrontFormMarkupControl())
->setLabel(pht('Profile Image'))
->setValue(
phutil_tag(
'img',
array(
'src' => $img_src,
))))
->appendChild(
id(new AphrontFormImageControl())
->setLabel(pht('Change Image'))
->setName('image')
->setError($e_image)
->setCaption(
pht('Supported formats:').' '.implode(', ', $supported_formats)))
->appendChild(
id(new AphrontFormSubmitControl())
->addCancelButton('/project/view/'.$project->getID().'/')

View file

@ -0,0 +1,274 @@
<?php
final class PhabricatorProjectProfilePictureController
extends PhabricatorProjectController {
private $id;
public function willProcessRequest(array $data) {
$this->id = $data['id'];
}
public function processRequest() {
$request = $this->getRequest();
$viewer = $request->getUser();
$project = id(new PhabricatorProjectQuery())
->setViewer($viewer)
->withIDs(array($this->id))
->needProfiles(true)
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
))
->executeOne();
if (!$project) {
return new Aphront404Response();
}
$project_uri = $this->getApplicationURI('view/'.$project->getID().'/');
$supported_formats = PhabricatorFile::getTransformableImageFormats();
$e_file = true;
$errors = array();
if ($request->isFormPost()) {
$phid = $request->getStr('phid');
$is_default = false;
if ($phid == PhabricatorPHIDConstants::PHID_VOID) {
$phid = null;
$is_default = true;
} else if ($phid) {
$file = id(new PhabricatorFileQuery())
->setViewer($viewer)
->withPHIDs(array($phid))
->executeOne();
} else {
if ($request->getFileExists('picture')) {
$file = PhabricatorFile::newFromPHPUpload(
$_FILES['picture'],
array(
'authorPHID' => $viewer->getPHID(),
));
} else {
$e_file = pht('Required');
$errors[] = pht(
'You must choose a file when uploading a new project picture.');
}
}
if (!$errors && !$is_default) {
if (!$file->isTransformableImage()) {
$e_file = pht('Not Supported');
$errors[] = pht(
'This server only supports these image formats: %s.',
implode(', ', $supported_formats));
} else {
$xformer = new PhabricatorImageTransformer();
$xformed = $xformer->executeProfileTransform(
$file,
$width = 50,
$min_height = 50,
$max_height = 50);
}
}
if (!$errors) {
$profile = $project->getProfile();
if ($is_default) {
$profile->setProfileImagePHID(null);
} else {
$profile->setProfileImagePHID($xformed->getPHID());
$xformed->attachToObject($viewer, $project->getPHID());
}
$profile->save();
return id(new AphrontRedirectResponse())->setURI($project_uri);
}
}
$title = pht('Edit Project Picture');
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addCrumb(
id(new PhabricatorCrumbView())
->setName($project->getName())
->setHref($project_uri));
$crumbs->addCrumb(
id(new PhabricatorCrumbView())
->setName($title));
$form = id(new PHUIFormLayoutView())
->setUser($viewer);
$default_image = PhabricatorFile::loadBuiltin($viewer, 'project.png');
$images = array();
$current = $project->getProfile()->getProfileImagePHID();
$has_current = false;
if ($current) {
$files = id(new PhabricatorFileQuery())
->setViewer($viewer)
->withPHIDs(array($current))
->execute();
if ($files) {
$file = head($files);
if ($file->isTransformableImage()) {
$has_current = true;
$images[$current] = array(
'uri' => $file->getBestURI(),
'tip' => pht('Current Picture'),
);
}
}
}
$images[PhabricatorPHIDConstants::PHID_VOID] = array(
'uri' => $default_image->getBestURI(),
'tip' => pht('Default Picture'),
);
require_celerity_resource('people-profile-css');
Javelin::initBehavior('phabricator-tooltips', array());
$buttons = array();
foreach ($images as $phid => $spec) {
$button = javelin_tag(
'button',
array(
'class' => 'grey profile-image-button',
'sigil' => 'has-tooltip',
'meta' => array(
'tip' => $spec['tip'],
'size' => 300,
),
),
phutil_tag(
'img',
array(
'height' => 50,
'width' => 50,
'src' => $spec['uri'],
)));
$button = array(
phutil_tag(
'input',
array(
'type' => 'hidden',
'name' => 'phid',
'value' => $phid,
)),
$button);
$button = phabricator_form(
$viewer,
array(
'class' => 'profile-image-form',
'method' => 'POST',
),
$button);
$buttons[] = $button;
}
if ($has_current) {
$form->appendChild(
id(new AphrontFormMarkupControl())
->setLabel(pht('Current Picture'))
->setValue(array_shift($buttons)));
}
$form->appendChild(
id(new AphrontFormMarkupControl())
->setLabel(pht('Use Picture'))
->setValue($buttons));
$launch_id = celerity_generate_unique_node_id();
$input_id = celerity_generate_unique_node_id();
Javelin::initBehavior(
'launch-icon-composer',
array(
'launchID' => $launch_id,
'inputID' => $input_id,
));
$compose_button = javelin_tag(
'button',
array(
'class' => 'grey',
'id' => $launch_id,
'sigil' => 'icon-composer',
),
pht('Choose Icon and Color...'));
$compose_input = javelin_tag(
'input',
array(
'type' => 'hidden',
'id' => $input_id,
'name' => 'phid',
));
$compose_form = phabricator_form(
$viewer,
array(
'class' => 'profile-image-form',
'method' => 'POST',
),
array(
$compose_input,
$compose_button,
));
$form->appendChild(
id(new AphrontFormMarkupControl())
->setLabel(pht('Quick Create'))
->setValue($compose_form));
$form_box = id(new PHUIObjectBoxView())
->setHeaderText($title)
->setFormError($errors)
->setForm($form);
$upload_form = id(new AphrontFormView())
->setUser($viewer)
->setEncType('multipart/form-data')
->appendChild(
id(new AphrontFormFileControl())
->setName('picture')
->setLabel(pht('Upload Picture'))
->setError($e_file)
->setCaption(
pht('Supported formats: %s', implode(', ', $supported_formats))))
->appendChild(
id(new AphrontFormSubmitControl())
->addCancelButton($project_uri)
->setValue(pht('Upload Picture')));
if ($errors) {
$errors = id(new AphrontErrorView())->setErrors($errors);
}
$form_box = id(new PHUIObjectBoxView())
->setHeaderText($title)
->setFormError($errors)
->setForm($form);
$upload_box = id(new PHUIObjectBoxView())
->setHeaderText(pht('Upload New Picture'))
->setForm($upload_form);
return $this->buildApplicationPage(
array(
$crumbs,
$form_box,
$upload_box,
),
array(
'title' => $title,
'device' => true,
));
}
}

View file

@ -142,7 +142,7 @@ final class PhabricatorProjectQuery
if (!$default) {
$default = PhabricatorFile::loadBuiltin(
$this->getViewer(),
'profile.png');
'project.png');
}
$file = $default;
}
@ -156,7 +156,7 @@ final class PhabricatorProjectQuery
if (!$default) {
$default = PhabricatorFile::loadBuiltin(
$this->getViewer(),
'profile.png');
'project.png');
}
$profile = id(new PhabricatorProjectProfile())
->setProjectPHID($project->getPHID())

View file

@ -129,8 +129,8 @@ final class CelerityResourceTransformer {
$data);
}
public function replaceCSSVariable($matches) {
static $map = array(
public static function getCSSVariableMap() {
return array(
// Base Colors
'red' => '#c0392b',
'lightred' => '#f4dddb',
@ -148,6 +148,8 @@ final class CelerityResourceTransformer {
'lightindigo' => '#f5e2ef',
'violet' => '#8e44ad',
'lightviolet' => '#ecdff1',
'charcoal' => '#4b4d51',
'backdrop' => '#c4cde0',
// Base Greys
'lightgreyborder' => '#C7CCD9',
@ -170,6 +172,13 @@ final class CelerityResourceTransformer {
'bluetext' => '#6B748C',
'darkbluetext' => '#464C5C',
);
}
public function replaceCSSVariable($matches) {
static $map;
if (!$map) {
$map = self::getCSSVariableMap();
}
$var_name = $matches[1];
if (empty($map[$var_name])) {

View file

@ -347,14 +347,14 @@ final class CeleritySpriteGenerator {
->setSourceSize(50, 50);
$sprites = array();
$prefix = 'projects_';
$prefix = 'projects-';
foreach ($icons as $icon) {
$sprite = id(clone $template)
->setName($prefix.$icon)
->setTargetCSS('.'.$prefix.$icon);
foreach ($scales as $scale_key => $scale) {
$path = $this->getPath($prefix.$scale_key.'/'.$icon.'.png');
$path = $this->getPath('projects_'.$scale_key.'/'.$icon.'.png');
$sprite->setSourceFile($path, $scale);
}
$sprites[] = $sprite;

View file

@ -10,6 +10,7 @@ final class PHUIIconView extends AphrontTagView {
const SPRITE_ICONS = 'icons';
const SPRITE_LOGIN = 'login';
const SPRITE_STATUS = 'status';
const SPRITE_PROJECTS = 'projects';
const HEAD_SMALL = 'phuihead-small';
const HEAD_MEDIUM = 'phuihead-medium';

View file

@ -11,3 +11,69 @@ button.profile-image-button {
padding: 4px;
margin: 0;
}
.compose-dialog button.profile-image-button-selected {
background-image: none;
background-color: {$lightblue};
border-color: {$blueborder};
}
.compose-header {
color: {$bluetext};
border-bottom: 1px solid {$lightblueborder};
padding: 4px 0;
margin: 0 0 8px;
}
form.compose-dialog {
width: 80%;
}
.compose-dialog .phui-icon-view {
display: block;
position: relative;
width: 50px;
height: 50px;
background-color: {$darkgreytext};
}
.compose-dialog .compose-background-red {
background-color: {$red};
}
.compose-dialog .compose-background-orange {
background-color: {$orange};
}
.compose-dialog .compose-background-yellow {
background-color: {$yellow};
}
.compose-dialog .compose-background-green {
background-color: {$green};
}
.compose-dialog .compose-background-blue {
background-color: {$blue};
}
.compose-dialog .compose-background-sky {
background-color: {$sky};
}
.compose-dialog .compose-background-indigo {
background-color: {$indigo};
}
.compose-dialog .compose-background-violet {
background-color: {$violet};
}
.compose-dialog .compose-background-charcoal {
background-color: {$charcoal};
}
.compose-dialog .compose-background-backdrop {
background-color: {$backdrop};
}

View file

@ -15,7 +15,7 @@
}
.phui-workpanel-view .phui-workpanel-body {
background: #c4cde0;
background: {$backdrop};
padding: 5px 5px 1px 5px;
border-bottom-left-radius: 5px;
border-bottom-right-radius: 5px;

View file

@ -18,226 +18,226 @@ only screen and (-webkit-min-device-pixel-ratio: 1.5) {
}
.projects_8ball {
.projects-8ball {
background-position: 0px 0px;
}
.projects_alien {
.projects-alien {
background-position: -51px 0px;
}
.projects_annouce {
.projects-announce {
background-position: -102px 0px;
}
.projects_art {
.projects-art {
background-position: -153px 0px;
}
.projects_award {
.projects-award {
background-position: -204px 0px;
}
.projects_bacon {
.projects-bacon {
background-position: -255px 0px;
}
.projects_bandaid {
.projects-bandaid {
background-position: -306px 0px;
}
.projects_beer {
.projects-beer {
background-position: 0px -51px;
}
.projects_bomb {
.projects-bomb {
background-position: -51px -51px;
}
.projects_briefcase {
.projects-briefcase {
background-position: -102px -51px;
}
.projects_bug {
.projects-bug {
background-position: -153px -51px;
}
.projects_calendar {
.projects-calendar {
background-position: -204px -51px;
}
.projects_cloud {
.projects-cloud {
background-position: -255px -51px;
}
.projects_coffee {
.projects-coffee {
background-position: -306px -51px;
}
.projects_creditcard {
.projects-creditcard {
background-position: 0px -102px;
}
.projects_death {
.projects-death {
background-position: -51px -102px;
}
.projects_desktop {
.projects-desktop {
background-position: -102px -102px;
}
.projects_dropbox {
.projects-dropbox {
background-position: -153px -102px;
}
.projects_education {
.projects-education {
background-position: -204px -102px;
}
.projects_experimental {
.projects-experimental {
background-position: -255px -102px;
}
.projects_facebook {
.projects-facebook {
background-position: -306px -102px;
}
.projects_facility {
.projects-facility {
background-position: 0px -153px;
}
.projects_film {
.projects-film {
background-position: -51px -153px;
}
.projects_forked {
.projects-forked {
background-position: -102px -153px;
}
.projects_games {
.projects-games {
background-position: -153px -153px;
}
.projects_ghost {
.projects-ghost {
background-position: -204px -153px;
}
.projects_gift {
.projects-gift {
background-position: -255px -153px;
}
.projects_globe {
.projects-globe {
background-position: -306px -153px;
}
.projects_golf {
.projects-golf {
background-position: 0px -204px;
}
.projects_heart {
.projects-heart {
background-position: -51px -204px;
}
.projects_intergalactic {
.projects-intergalactic {
background-position: -102px -204px;
}
.projects_lock {
.projects-lock {
background-position: -153px -204px;
}
.projects_mail {
.projects-mail {
background-position: -204px -204px;
}
.projects_martini {
.projects-martini {
background-position: -255px -204px;
}
.projects_medical {
.projects-medical {
background-position: -306px -204px;
}
.projects_mobile {
.projects-mobile {
background-position: 0px -255px;
}
.projects_music {
.projects-music {
background-position: -51px -255px;
}
.projects_news {
.projects-news {
background-position: -102px -255px;
}
.projects_orgchart {
.projects-orgchart {
background-position: -153px -255px;
}
.projects_peoples {
.projects-peoples {
background-position: -204px -255px;
}
.projects_piechart {
.projects-piechart {
background-position: -255px -255px;
}
.projects_poison {
.projects-poison {
background-position: -306px -255px;
}
.projects_putabirdonit {
.projects-putabirdonit {
background-position: 0px -306px;
}
.projects_radiate {
.projects-radiate {
background-position: -51px -306px;
}
.projects_savings {
.projects-savings {
background-position: -102px -306px;
}
.projects_search {
.projects-search {
background-position: -153px -306px;
}
.projects_shield {
.projects-shield {
background-position: -204px -306px;
}
.projects_speed {
.projects-speed {
background-position: -255px -306px;
}
.projects_sprint {
.projects-sprint {
background-position: -306px -306px;
}
.projects_star {
.projects-star {
background-position: 0px -357px;
}
.projects_storage {
.projects-storage {
background-position: -51px -357px;
}
.projects_tablet {
.projects-tablet {
background-position: -102px -357px;
}
.projects_travel {
.projects-travel {
background-position: -153px -357px;
}
.projects_twitter {
.projects-twitter {
background-position: -204px -357px;
}
.projects_warning {
.projects-warning {
background-position: -255px -357px;
}
.projects_whale {
.projects-whale {
background-position: -306px -357px;
}

View file

@ -0,0 +1,76 @@
/**
* @provides javelin-behavior-icon-composer
* @requires javelin-behavior
* javelin-dom
* javelin-stratcom
*/
JX.behavior('icon-composer', function(config) {
var nodes = {
root: JX.$(config.dialogID),
colorInput: JX.$(config.colorInputID),
iconInput: JX.$(config.iconInputID),
preview: JX.$(config.previewID)
};
var selected = {
color: config.defaultColor,
icon: config.defaultIcon
};
var redraw = function() {
var ii;
var colors = JX.DOM.scry(nodes.root, 'button', 'compose-select-color');
for (ii = 0; ii < colors.length; ii++) {
JX.DOM.alterClass(
colors[ii],
'profile-image-button-selected',
(JX.Stratcom.getData(colors[ii]).color == selected.color));
}
var icons = JX.DOM.scry(nodes.root, 'button', 'compose-select-icon');
for (ii = 0; ii < icons.length; ii++) {
JX.DOM.alterClass(
icons[ii],
'profile-image-button-selected',
(JX.Stratcom.getData(icons[ii]).icon == selected.icon));
}
nodes.colorInput.value = selected.color;
nodes.iconInput.value = selected.icon;
var classes = ['phui-icon-view', 'sprite-projects'];
classes.push('compose-background-' + selected.color);
classes.push('projects-' + selected.icon);
nodes.preview.className = classes.join(' ');
};
JX.DOM.listen(
nodes.root,
'click',
'compose-select-color',
function (e) {
e.kill();
selected.color = e.getNodeData('compose-select-color').color;
redraw();
});
JX.DOM.listen(
nodes.root,
'click',
'compose-select-icon',
function (e) {
e.kill();
selected.icon = e.getNodeData('compose-select-icon').icon;
redraw();
});
redraw();
});

View file

@ -0,0 +1,25 @@
/**
* @provides javelin-behavior-launch-icon-composer
* @requires javelin-behavior
* javelin-dom
* javelin-workflow
*/
JX.behavior('launch-icon-composer', function(config) {
JX.DOM.listen(
JX.$(config.launchID),
'click',
null,
function(e) {
e.kill();
new JX.Workflow('/file/compose/')
.setHandler(function(r) {
JX.$(config.inputID).value = r.phid;
JX.DOM.findAbove(e.getTarget(), 'form').submit();
})
.start();
});
});