mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-26 08:42:41 +01:00
Calendar upgrades
Summary: Does a handful of things to make Calendar significantly more useful - Enabled overlapping events - Profile has a 'week view' of the user - Profile has a 'month view' of the users - Multiple users on a calendar are color coded - Browse view slightly more useful This stops short of implementing the new 'home' view on Calendar, mostly this is a big step though to make that happen next. Test Plan: Make lots of events on diffent users. Reviewers: epriestley, btrahan Reviewed By: epriestley CC: Korvin, epriestley, aran Maniphest Tasks: T2897, T4375 Differential Revision: https://secure.phabricator.com/D8317
This commit is contained in:
parent
e7254944ec
commit
396e8ba82c
23 changed files with 696 additions and 157 deletions
|
@ -94,7 +94,7 @@ return array(
|
|||
'rsrc/css/application/ponder/feed.css' => 'e62615b6',
|
||||
'rsrc/css/application/ponder/post.css' => 'ebab8a70',
|
||||
'rsrc/css/application/ponder/vote.css' => '8ed6ed8b',
|
||||
'rsrc/css/application/profile/profile-view.css' => '3a7e04ca',
|
||||
'rsrc/css/application/profile/profile-view.css' => '9bdb9804',
|
||||
'rsrc/css/application/projects/phabricator-object-list-view.css' => '1a1ea560',
|
||||
'rsrc/css/application/projects/project-tag.css' => '095c9404',
|
||||
'rsrc/css/application/releeph/releeph-branch.css' => 'b8821d2d',
|
||||
|
@ -123,9 +123,12 @@ return array(
|
|||
'rsrc/css/layout/phabricator-hovercard-view.css' => '67c12b16',
|
||||
'rsrc/css/layout/phabricator-side-menu-view.css' => '503699d0',
|
||||
'rsrc/css/layout/phabricator-source-code-view.css' => '62a99814',
|
||||
'rsrc/css/phui/phui-box.css' => '1a82a4ae',
|
||||
'rsrc/css/phui/calendar/phui-calendar-day.css' => 'de035c8a',
|
||||
'rsrc/css/phui/calendar/phui-calendar-list.css' => 'c1d0ca59',
|
||||
'rsrc/css/phui/calendar/phui-calendar-month.css' => '5e762971',
|
||||
'rsrc/css/phui/calendar/phui-calendar.css' => '5e1ad989',
|
||||
'rsrc/css/phui/phui-box.css' => 'a36cf3a5',
|
||||
'rsrc/css/phui/phui-button.css' => '8784a966',
|
||||
'rsrc/css/phui/phui-calendar-month.css' => '3474d15a',
|
||||
'rsrc/css/phui/phui-document.css' => '143b2ac8',
|
||||
'rsrc/css/phui/phui-feed-story.css' => '3a59c2cf',
|
||||
'rsrc/css/phui/phui-form-view.css' => '0efd3326',
|
||||
|
@ -134,7 +137,7 @@ return array(
|
|||
'rsrc/css/phui/phui-icon.css' => 'fcb145a7',
|
||||
'rsrc/css/phui/phui-info-panel.css' => '27ea50a1',
|
||||
'rsrc/css/phui/phui-list.css' => '2edb76cf',
|
||||
'rsrc/css/phui/phui-object-box.css' => '95767d08',
|
||||
'rsrc/css/phui/phui-object-box.css' => 'ce92d8ec',
|
||||
'rsrc/css/phui/phui-object-item-list-view.css' => 'eb579d6c',
|
||||
'rsrc/css/phui/phui-pinboard-view.css' => '4b346c2a',
|
||||
'rsrc/css/phui/phui-property-list-view.css' => 'dbf53b12',
|
||||
|
@ -702,7 +705,7 @@ return array(
|
|||
'phabricator-object-selector-css' => '029a133d',
|
||||
'phabricator-phtize' => 'd254d646',
|
||||
'phabricator-prefab' => '0326e5d0',
|
||||
'phabricator-profile-css' => '3a7e04ca',
|
||||
'phabricator-profile-css' => '9bdb9804',
|
||||
'phabricator-project-tag-css' => '095c9404',
|
||||
'phabricator-remarkup-css' => 'ca7f2265',
|
||||
'phabricator-search-results-css' => 'f240504c',
|
||||
|
@ -735,9 +738,12 @@ return array(
|
|||
'phortune-credit-card-form-css' => 'b25b4beb',
|
||||
'phrequent-css' => 'ffc185ad',
|
||||
'phriction-document-css' => 'b0309d8e',
|
||||
'phui-box-css' => '1a82a4ae',
|
||||
'phui-box-css' => 'a36cf3a5',
|
||||
'phui-button-css' => '8784a966',
|
||||
'phui-calendar-month-css' => '3474d15a',
|
||||
'phui-calendar-css' => '5e1ad989',
|
||||
'phui-calendar-day-css' => 'de035c8a',
|
||||
'phui-calendar-list-css' => 'c1d0ca59',
|
||||
'phui-calendar-month-css' => '5e762971',
|
||||
'phui-document-view-css' => '143b2ac8',
|
||||
'phui-feed-story-css' => '3a59c2cf',
|
||||
'phui-form-css' => 'b78ec020',
|
||||
|
@ -746,7 +752,7 @@ return array(
|
|||
'phui-icon-view-css' => 'fcb145a7',
|
||||
'phui-info-panel-css' => '27ea50a1',
|
||||
'phui-list-view-css' => '2edb76cf',
|
||||
'phui-object-box-css' => '95767d08',
|
||||
'phui-object-box-css' => 'ce92d8ec',
|
||||
'phui-object-item-list-view-css' => 'eb579d6c',
|
||||
'phui-pinboard-view-css' => '4b346c2a',
|
||||
'phui-property-list-view-css' => 'dbf53b12',
|
||||
|
|
|
@ -93,6 +93,8 @@ phutil_register_library_map(array(
|
|||
'AphrontWebpageResponse' => 'aphront/response/AphrontWebpageResponse.php',
|
||||
'AuditActionMenuEventListener' => 'applications/audit/events/AuditActionMenuEventListener.php',
|
||||
'BuildStepImplementation' => 'applications/harbormaster/step/BuildStepImplementation.php',
|
||||
'CalendarColors' => 'applications/calendar/constants/CalendarColors.php',
|
||||
'CalendarConstants' => 'applications/calendar/constants/CalendarConstants.php',
|
||||
'CelerityAPI' => 'infrastructure/celerity/CelerityAPI.php',
|
||||
'CelerityManagementMapWorkflow' => 'infrastructure/celerity/management/CelerityManagementMapWorkflow.php',
|
||||
'CelerityManagementWorkflow' => 'infrastructure/celerity/management/CelerityManagementWorkflow.php',
|
||||
|
@ -1000,7 +1002,9 @@ phutil_register_library_map(array(
|
|||
'PHUIButtonBarView' => 'view/phui/PHUIButtonBarView.php',
|
||||
'PHUIButtonExample' => 'applications/uiexample/examples/PHUIButtonExample.php',
|
||||
'PHUIButtonView' => 'view/phui/PHUIButtonView.php',
|
||||
'PHUICalendarMonthView' => 'applications/calendar/view/PHUICalendarMonthView.php',
|
||||
'PHUICalendarListView' => 'view/phui/calendar/PHUICalendarListView.php',
|
||||
'PHUICalendarMonthView' => 'view/phui/calendar/PHUICalendarMonthView.php',
|
||||
'PHUICalendarWidgetView' => 'view/phui/calendar/PHUICalendarWidgetView.php',
|
||||
'PHUIColorPalletteExample' => 'applications/uiexample/examples/PHUIColorPalletteExample.php',
|
||||
'PHUIDocumentExample' => 'applications/uiexample/examples/PHUIDocumentExample.php',
|
||||
'PHUIDocumentView' => 'view/phui/PHUIDocumentView.php',
|
||||
|
@ -1291,7 +1295,6 @@ phutil_register_library_map(array(
|
|||
'PhabricatorCalendarEventEditController' => 'applications/calendar/controller/PhabricatorCalendarEventEditController.php',
|
||||
'PhabricatorCalendarEventInvalidEpochException' => 'applications/calendar/exception/PhabricatorCalendarEventInvalidEpochException.php',
|
||||
'PhabricatorCalendarEventListController' => 'applications/calendar/controller/PhabricatorCalendarEventListController.php',
|
||||
'PhabricatorCalendarEventOverlapException' => 'applications/calendar/exception/PhabricatorCalendarEventOverlapException.php',
|
||||
'PhabricatorCalendarEventQuery' => 'applications/calendar/query/PhabricatorCalendarEventQuery.php',
|
||||
'PhabricatorCalendarEventSearchEngine' => 'applications/calendar/query/PhabricatorCalendarEventSearchEngine.php',
|
||||
'PhabricatorCalendarEventViewController' => 'applications/calendar/controller/PhabricatorCalendarEventViewController.php',
|
||||
|
@ -1800,6 +1803,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorPasteTransactionQuery' => 'applications/paste/query/PhabricatorPasteTransactionQuery.php',
|
||||
'PhabricatorPasteViewController' => 'applications/paste/controller/PhabricatorPasteViewController.php',
|
||||
'PhabricatorPeopleApproveController' => 'applications/people/controller/PhabricatorPeopleApproveController.php',
|
||||
'PhabricatorPeopleCalendarController' => 'applications/people/controller/PhabricatorPeopleCalendarController.php',
|
||||
'PhabricatorPeopleController' => 'applications/people/controller/PhabricatorPeopleController.php',
|
||||
'PhabricatorPeopleDisableController' => 'applications/people/controller/PhabricatorPeopleDisableController.php',
|
||||
'PhabricatorPeopleEditController' => 'applications/people/controller/PhabricatorPeopleEditController.php',
|
||||
|
@ -2652,6 +2656,7 @@ phutil_register_library_map(array(
|
|||
),
|
||||
'AphrontWebpageResponse' => 'AphrontHTMLResponse',
|
||||
'AuditActionMenuEventListener' => 'PhabricatorEventListener',
|
||||
'CalendarColors' => 'CalendarConstants',
|
||||
'CelerityManagementMapWorkflow' => 'CelerityManagementWorkflow',
|
||||
'CelerityManagementWorkflow' => 'PhabricatorManagementWorkflow',
|
||||
'CelerityPhabricatorResourceController' => 'CelerityResourceController',
|
||||
|
@ -3666,7 +3671,9 @@ phutil_register_library_map(array(
|
|||
'PHUIButtonBarView' => 'AphrontTagView',
|
||||
'PHUIButtonExample' => 'PhabricatorUIExample',
|
||||
'PHUIButtonView' => 'AphrontTagView',
|
||||
'PHUICalendarListView' => 'AphrontTagView',
|
||||
'PHUICalendarMonthView' => 'AphrontView',
|
||||
'PHUICalendarWidgetView' => 'AphrontTagView',
|
||||
'PHUIColorPalletteExample' => 'PhabricatorUIExample',
|
||||
'PHUIDocumentExample' => 'PhabricatorUIExample',
|
||||
'PHUIDocumentView' => 'AphrontTagView',
|
||||
|
@ -3987,7 +3994,6 @@ phutil_register_library_map(array(
|
|||
0 => 'PhabricatorCalendarController',
|
||||
1 => 'PhabricatorApplicationSearchResultsControllerInterface',
|
||||
),
|
||||
'PhabricatorCalendarEventOverlapException' => 'Exception',
|
||||
'PhabricatorCalendarEventQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||
'PhabricatorCalendarEventSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||
'PhabricatorCalendarEventViewController' => 'PhabricatorCalendarController',
|
||||
|
@ -4563,6 +4569,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorPasteTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||
'PhabricatorPasteViewController' => 'PhabricatorPasteController',
|
||||
'PhabricatorPeopleApproveController' => 'PhabricatorPeopleController',
|
||||
'PhabricatorPeopleCalendarController' => 'PhabricatorPeopleController',
|
||||
'PhabricatorPeopleController' => 'PhabricatorController',
|
||||
'PhabricatorPeopleDisableController' => 'PhabricatorPeopleController',
|
||||
'PhabricatorPeopleEditController' => 'PhabricatorPeopleController',
|
||||
|
|
30
src/applications/calendar/constants/CalendarColors.php
Normal file
30
src/applications/calendar/constants/CalendarColors.php
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @group calendar
|
||||
*/
|
||||
final class CalendarColors extends CalendarConstants {
|
||||
|
||||
const COLOR_RED = 'red';
|
||||
const COLOR_ORANGE = 'orange';
|
||||
const COLOR_YELLOW = 'yellow';
|
||||
const COLOR_GREEN = 'green';
|
||||
const COLOR_BLUE = 'blue';
|
||||
const COLOR_SKY = 'sky';
|
||||
const COLOR_INDIGO = 'indigo';
|
||||
const COLOR_VIOLET = 'violet';
|
||||
|
||||
public static function getColors() {
|
||||
return array(
|
||||
self::COLOR_SKY,
|
||||
self::COLOR_GREEN,
|
||||
self::COLOR_VIOLET,
|
||||
self::COLOR_ORANGE,
|
||||
self::COLOR_BLUE,
|
||||
self::COLOR_INDIGO,
|
||||
self::COLOR_RED,
|
||||
self::COLOR_YELLOW,
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @group calendar
|
||||
*/
|
||||
abstract class CalendarConstants {
|
||||
|
||||
}
|
|
@ -39,6 +39,24 @@ final class PhabricatorCalendarBrowseController
|
|||
$phids = mpull($statuses, 'getUserPHID');
|
||||
$handles = $this->loadViewerHandles($phids);
|
||||
|
||||
/* Assign Colors */
|
||||
$unique = array_unique($phids);
|
||||
$allblue = false;
|
||||
$calcolors = CalendarColors::getColors();
|
||||
if (count($unique) > count($calcolors)) {
|
||||
$allblue = true;
|
||||
}
|
||||
$i = 0;
|
||||
$eventcolor = array();
|
||||
foreach ($unique as $phid) {
|
||||
if ($allblue) {
|
||||
$eventcolor[$phid] = CalendarColors::COLOR_SKY;
|
||||
} else {
|
||||
$eventcolor[$phid] = $calcolors[$i];
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
|
||||
foreach ($statuses as $status) {
|
||||
$event = new AphrontCalendarEventView();
|
||||
$event->setEpochRange($status->getDateFrom(), $status->getDateTo());
|
||||
|
@ -46,14 +64,10 @@ final class PhabricatorCalendarBrowseController
|
|||
$name_text = $handles[$status->getUserPHID()]->getName();
|
||||
$status_text = $status->getHumanStatus();
|
||||
$event->setUserPHID($status->getUserPHID());
|
||||
$event->setName("{$name_text} ({$status_text})");
|
||||
$details = '';
|
||||
if ($status->getDescription()) {
|
||||
$details = "\n\n".rtrim($status->getDescription());
|
||||
}
|
||||
$event->setDescription(
|
||||
$status->getTerseSummary($user).$details);
|
||||
$event->setDescription(pht('%s (%s)', $name_text, $status_text));
|
||||
$event->setName($status_text);
|
||||
$event->setEventID($status->getID());
|
||||
$event->setColor($eventcolor[$status->getUserPHID()]);
|
||||
$month_view->addEvent($event);
|
||||
}
|
||||
|
||||
|
|
|
@ -73,9 +73,6 @@ final class PhabricatorCalendarEventEditController
|
|||
->save();
|
||||
} catch (PhabricatorCalendarEventInvalidEpochException $e) {
|
||||
$errors[] = pht('Start must be before end.');
|
||||
} catch (PhabricatorCalendarEventOverlapException $e) {
|
||||
$errors[] = pht('There is already a status within the specified '.
|
||||
'timeframe. Edit or delete this existing status.');
|
||||
}
|
||||
|
||||
if (!$errors) {
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorCalendarEventOverlapException extends Exception {
|
||||
}
|
|
@ -73,7 +73,7 @@ final class PhabricatorCalendarEvent
|
|||
|
||||
/**
|
||||
* Validates data and throws exceptions for non-sensical status
|
||||
* windows and attempts to create an overlapping status.
|
||||
* windows
|
||||
*/
|
||||
public function save() {
|
||||
|
||||
|
@ -81,28 +81,7 @@ final class PhabricatorCalendarEvent
|
|||
throw new PhabricatorCalendarEventInvalidEpochException();
|
||||
}
|
||||
|
||||
$this->openTransaction();
|
||||
$this->beginWriteLocking();
|
||||
|
||||
if ($this->shouldInsertWhenSaved()) {
|
||||
|
||||
$overlap = $this->loadAllWhere(
|
||||
'userPHID = %s AND dateFrom < %d AND dateTo > %d',
|
||||
$this->getUserPHID(),
|
||||
$this->getDateTo(),
|
||||
$this->getDateFrom());
|
||||
|
||||
if ($overlap) {
|
||||
$this->endWriteLocking();
|
||||
$this->killTransaction();
|
||||
throw new PhabricatorCalendarEventOverlapException();
|
||||
}
|
||||
}
|
||||
|
||||
parent::save();
|
||||
|
||||
$this->endWriteLocking();
|
||||
return $this->saveTransaction();
|
||||
return parent::save();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ final class AphrontCalendarEventView extends AphrontView {
|
|||
private $epochEnd;
|
||||
private $description;
|
||||
private $eventID;
|
||||
private $color;
|
||||
|
||||
public function setEventID($event_id) {
|
||||
$this->eventID = $event_id;
|
||||
|
@ -58,6 +59,18 @@ final class AphrontCalendarEventView extends AphrontView {
|
|||
return $this->description;
|
||||
}
|
||||
|
||||
public function setColor($color) {
|
||||
$this->color = $color;
|
||||
return $this;
|
||||
}
|
||||
public function getColor() {
|
||||
if ($this->color) {
|
||||
return $this->color;
|
||||
} else {
|
||||
return CalendarColors::COLOR_SKY;
|
||||
}
|
||||
}
|
||||
|
||||
public function render() {
|
||||
throw new Exception("Events are only rendered indirectly.");
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
final class PhabricatorApplicationPeople extends PhabricatorApplication {
|
||||
|
||||
public function getShortDescription() {
|
||||
return 'User Accounts';
|
||||
return pht('User Accounts');
|
||||
}
|
||||
|
||||
public function getBaseURI() {
|
||||
|
@ -53,6 +53,8 @@ final class PhabricatorApplicationPeople extends PhabricatorApplication {
|
|||
),
|
||||
'/p/(?P<username>[\w._-]+)/'
|
||||
=> 'PhabricatorPeopleProfileController',
|
||||
'/p/(?P<username>[\w._-]+)/calendar/'
|
||||
=> 'PhabricatorPeopleCalendarController',
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -51,8 +51,6 @@ final class ConduitAPI_user_addstatus_Method extends ConduitAPI_user_Method {
|
|||
->save();
|
||||
} catch (PhabricatorCalendarEventInvalidEpochException $e) {
|
||||
throw new ConduitException('ERR-BAD-EPOCH');
|
||||
} catch (PhabricatorCalendarEventOverlapException $e) {
|
||||
throw new ConduitException('ERR-OVERLAP');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorPeopleCalendarController
|
||||
extends PhabricatorPeopleController {
|
||||
|
||||
private $username;
|
||||
|
||||
public function shouldRequireAdmin() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->username = idx($data, 'username');
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
$viewer = $this->getRequest()->getUser();
|
||||
$user = id(new PhabricatorPeopleQuery())
|
||||
->setViewer($viewer)
|
||||
->withUsernames(array($this->username))
|
||||
->needProfileImage(true)
|
||||
->executeOne();
|
||||
|
||||
if (!$user) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$picture = $user->loadProfileImageURI();
|
||||
|
||||
$now = time();
|
||||
$request = $this->getRequest();
|
||||
$year_d = phabricator_format_local_time($now, $user, 'Y');
|
||||
$year = $request->getInt('year', $year_d);
|
||||
$month_d = phabricator_format_local_time($now, $user, 'm');
|
||||
$month = $request->getInt('month', $month_d);
|
||||
$day = phabricator_format_local_time($now, $user, 'j');
|
||||
|
||||
|
||||
$holidays = id(new PhabricatorCalendarHoliday())->loadAllWhere(
|
||||
'day BETWEEN %s AND %s',
|
||||
"{$year}-{$month}-01",
|
||||
"{$year}-{$month}-31");
|
||||
|
||||
$statuses = id(new PhabricatorCalendarEventQuery())
|
||||
->setViewer($user)
|
||||
->withInvitedPHIDs(array($user->getPHID()))
|
||||
->withDateRange(
|
||||
strtotime("{$year}-{$month}-01"),
|
||||
strtotime("{$year}-{$month}-01 next month"))
|
||||
->execute();
|
||||
|
||||
if ($month == $month_d && $year == $year_d) {
|
||||
$month_view = new PHUICalendarMonthView($month, $year, $day);
|
||||
} else {
|
||||
$month_view = new PHUICalendarMonthView($month, $year);
|
||||
}
|
||||
|
||||
$month_view->setBrowseURI($request->getRequestURI());
|
||||
$month_view->setUser($user);
|
||||
$month_view->setHolidays($holidays);
|
||||
$month_view->setImage($picture);
|
||||
|
||||
$phids = mpull($statuses, 'getUserPHID');
|
||||
$handles = $this->loadViewerHandles($phids);
|
||||
|
||||
foreach ($statuses as $status) {
|
||||
$event = new AphrontCalendarEventView();
|
||||
$event->setEpochRange($status->getDateFrom(), $status->getDateTo());
|
||||
$event->setUserPHID($status->getUserPHID());
|
||||
$event->setName($status->getHumanStatus());
|
||||
$event->setDescription($status->getDescription());
|
||||
$event->setEventID($status->getID());
|
||||
$month_view->addEvent($event);
|
||||
}
|
||||
|
||||
$date = new DateTime("{$year}-{$month}-01");
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addTextCrumb(
|
||||
$user->getUsername(),
|
||||
'/p/'.$user->getUsername().'/');
|
||||
$crumbs->addTextCrumb($date->format('F Y'));
|
||||
|
||||
return $this->buildApplicationPage(
|
||||
array(
|
||||
$crumbs,
|
||||
$month_view),
|
||||
array(
|
||||
'title' => pht('Calendar'),
|
||||
'device' => true,
|
||||
));
|
||||
}
|
||||
}
|
|
@ -73,6 +73,16 @@ final class PhabricatorPeopleProfileController
|
|||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addTextCrumb($user->getUsername());
|
||||
$feed = $this->renderUserFeed($user);
|
||||
$calendar = $this->renderUserCalendar($user);
|
||||
$activity = phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'profile-activity-view grouped'
|
||||
),
|
||||
array(
|
||||
$calendar,
|
||||
$feed
|
||||
));
|
||||
|
||||
$object_box = id(new PHUIObjectBoxView())
|
||||
->setHeader($header)
|
||||
|
@ -82,7 +92,7 @@ final class PhabricatorPeopleProfileController
|
|||
array(
|
||||
$crumbs,
|
||||
$object_box,
|
||||
$feed,
|
||||
$activity,
|
||||
),
|
||||
array(
|
||||
'title' => $user->getUsername(),
|
||||
|
@ -129,4 +139,72 @@ final class PhabricatorPeopleProfileController
|
|||
'profile-feed',
|
||||
$view->render());
|
||||
}
|
||||
|
||||
private function renderUserCalendar(PhabricatorUser $user) {
|
||||
$now = time();
|
||||
$year = phabricator_format_local_time($now, $user, 'Y');
|
||||
$month = phabricator_format_local_time($now, $user, 'm');
|
||||
$day = phabricator_format_local_time($now, $user, 'j');
|
||||
$statuses = id(new PhabricatorCalendarEventQuery())
|
||||
->setViewer($user)
|
||||
->withInvitedPHIDs(array($user->getPHID()))
|
||||
->withDateRange(
|
||||
strtotime("{$year}-{$month}-{$day}"),
|
||||
strtotime("{$year}-{$month}-{$day} +7 days"))
|
||||
->execute();
|
||||
|
||||
$events = array();
|
||||
foreach ($statuses as $status) {
|
||||
$event = new AphrontCalendarEventView();
|
||||
$event->setEpochRange($status->getDateFrom(), $status->getDateTo());
|
||||
|
||||
$status_text = $status->getHumanStatus();
|
||||
$event->setUserPHID($status->getUserPHID());
|
||||
$event->setName($status_text);
|
||||
$event->setDescription($status->getDescription());
|
||||
$event->setEventID($status->getID());
|
||||
$key = date('Y-m-d', $event->getEpochStart());
|
||||
$events[$key][] = $event;
|
||||
// Populate multiday events
|
||||
// Better means?
|
||||
$next_day = strtotime("{$key} +1 day");
|
||||
if ($event->getEpochEnd() >= $next_day) {
|
||||
$nextkey = date('Y-m-d', $next_day);
|
||||
$events[$nextkey][] = $event;
|
||||
}
|
||||
}
|
||||
|
||||
$i = 0;
|
||||
$week = array();
|
||||
for ($i = 0;$i <= 6;$i++) {
|
||||
$datetime = strtotime("{$year}-{$month}-{$day} +{$i} days");
|
||||
$headertext = phabricator_format_local_time($datetime, $user, 'l, M d');
|
||||
$this_day = date('Y-m-d', $datetime);
|
||||
|
||||
$list = new PHUICalendarListView();
|
||||
$list->setUser($user);
|
||||
$list->showBlankState(true);
|
||||
if (isset($events[$this_day])) {
|
||||
foreach ($events[$this_day] as $event) {
|
||||
$list->addEvent($event);
|
||||
}
|
||||
}
|
||||
|
||||
$header = phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => $this->getRequest()->getRequestURI().'calendar/'
|
||||
),
|
||||
$headertext);
|
||||
|
||||
$calendar = new PHUICalendarWidgetView();
|
||||
$calendar->setHeader($header);
|
||||
$calendar->setCalendarList($list);
|
||||
$week[] = $calendar;
|
||||
}
|
||||
|
||||
return phutil_tag_div(
|
||||
'profile-calendar',
|
||||
$week);
|
||||
}
|
||||
}
|
||||
|
|
138
src/view/phui/calendar/PHUICalendarListView.php
Normal file
138
src/view/phui/calendar/PHUICalendarListView.php
Normal file
|
@ -0,0 +1,138 @@
|
|||
<?php
|
||||
|
||||
final class PHUICalendarListView extends AphrontTagView {
|
||||
|
||||
private $events = array();
|
||||
private $blankState;
|
||||
|
||||
protected $user;
|
||||
|
||||
public function addEvent(AphrontCalendarEventView $event) {
|
||||
$this->events[] = $event;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setUser($user) {
|
||||
$this->user = $user;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function showBlankState($state) {
|
||||
$this->blankState = $state;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTagName() {
|
||||
return 'div';
|
||||
}
|
||||
|
||||
public function getTagAttributes() {
|
||||
require_celerity_resource('phui-calendar-css');
|
||||
require_celerity_resource('phui-calendar-list-css');
|
||||
return array('class' => 'phui-calendar-day-list');
|
||||
}
|
||||
|
||||
protected function getTagContent() {
|
||||
if (!$this->blankState && empty($this->events)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$events = msort($this->events, 'getEpochStart');
|
||||
|
||||
// All Day Event (well, 23 hours, 59 minutes worth)
|
||||
$timespan = ((3600 * 24) - 60);
|
||||
|
||||
$singletons = array();
|
||||
$allday = false;
|
||||
foreach ($events as $event) {
|
||||
$color = $event->getColor();
|
||||
|
||||
$length = ($event->getEpochEnd() - $event->getEpochStart());
|
||||
if ($length >= $timespan) {
|
||||
$timelabel = pht('All Day');
|
||||
} else {
|
||||
$timelabel = phabricator_time($event->getEpochStart(), $this->user);
|
||||
}
|
||||
|
||||
$dot = phutil_tag(
|
||||
'span',
|
||||
array(
|
||||
'class' => 'phui-calendar-list-dot'),
|
||||
'');
|
||||
$title = phutil_tag(
|
||||
'span',
|
||||
array(
|
||||
'class' => 'phui-calendar-list-title'),
|
||||
$this->renderEventLink($event, $allday));
|
||||
$time = phutil_tag(
|
||||
'span',
|
||||
array(
|
||||
'class' => 'phui-calendar-list-time'),
|
||||
$timelabel);
|
||||
|
||||
$singletons[] = phutil_tag(
|
||||
'li',
|
||||
array(
|
||||
'class' => 'phui-calendar-list-item phui-calendar-'.$color
|
||||
),
|
||||
array(
|
||||
$dot,
|
||||
$title,
|
||||
$time));
|
||||
}
|
||||
|
||||
if (empty($singletons)) {
|
||||
$singletons[] = phutil_tag(
|
||||
'li',
|
||||
array(
|
||||
'class' => 'phui-calendar-list-item-empty'
|
||||
),
|
||||
pht('Clear sailing ahead.'));
|
||||
}
|
||||
|
||||
$list = phutil_tag(
|
||||
'ul',
|
||||
array(
|
||||
'class' => 'phui-calendar-list'
|
||||
),
|
||||
$singletons);
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
private function renderEventLink($event) {
|
||||
|
||||
Javelin::initBehavior('phabricator-tooltips');
|
||||
|
||||
// Multiple Days
|
||||
$timespan = ((3600 * 24) + 60);
|
||||
$length = ($event->getEpochEnd() - $event->getEpochStart());
|
||||
if ($length >= $timespan) {
|
||||
$tip = pht('%s, Until: %s', $event->getName(),
|
||||
phabricator_date($event->getEpochEnd(), $this->user));
|
||||
} else {
|
||||
$tip = pht('%s, Until: %s', $event->getName(),
|
||||
phabricator_time($event->getEpochEnd(), $this->user));
|
||||
}
|
||||
|
||||
$description = $event->getDescription();
|
||||
if (strlen($description) == 0) {
|
||||
$description = pht('(%s)', $event->getName());
|
||||
}
|
||||
|
||||
$anchor = javelin_tag(
|
||||
'a',
|
||||
array(
|
||||
'sigil' => 'has-tooltip',
|
||||
'class' => 'phui-calendar-item-link',
|
||||
'href' => '/calendar/event/view/'.$event->getEventID().'/',
|
||||
'meta' => array(
|
||||
'tip' => $tip,
|
||||
'size' => 200,
|
||||
),
|
||||
),
|
||||
$description);
|
||||
|
||||
return $anchor;
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ final class PHUICalendarMonthView extends AphrontView {
|
|||
private $holidays = array();
|
||||
private $events = array();
|
||||
private $browseURI;
|
||||
private $image;
|
||||
|
||||
public function setBrowseURI($browse_uri) {
|
||||
$this->browseURI = $browse_uri;
|
||||
|
@ -22,6 +23,11 @@ final class PHUICalendarMonthView extends AphrontView {
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function setImage($uri) {
|
||||
$this->image = $uri;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setHolidays(array $holidays) {
|
||||
assert_instances_of($holidays, 'PhabricatorCalendarHoliday');
|
||||
$this->holidays = mpull($holidays, null, 'getDay');
|
||||
|
@ -92,6 +98,7 @@ final class PHUICalendarMonthView extends AphrontView {
|
|||
"\xC2\xA0")); //
|
||||
}
|
||||
|
||||
$list_events = array();
|
||||
foreach ($events as $event) {
|
||||
if ($event->getEpochStart() >= $epoch_end) {
|
||||
// This list is sorted, so we can stop looking.
|
||||
|
@ -99,13 +106,16 @@ final class PHUICalendarMonthView extends AphrontView {
|
|||
}
|
||||
if ($event->getEpochStart() < $epoch_end &&
|
||||
$event->getEpochEnd() > $epoch_start) {
|
||||
$show_events[$event->getUserPHID()] = $this->renderEvent(
|
||||
$event,
|
||||
$epoch_start,
|
||||
$epoch_end);
|
||||
$list_events[] = $event;
|
||||
}
|
||||
}
|
||||
|
||||
$list = new PHUICalendarListView();
|
||||
$list->setUser($this->user);
|
||||
foreach ($list_events as $item) {
|
||||
$list->addEvent($item);
|
||||
}
|
||||
|
||||
$holiday_markup = null;
|
||||
if ($holiday) {
|
||||
$name = $holiday->getName();
|
||||
|
@ -123,7 +133,7 @@ final class PHUICalendarMonthView extends AphrontView {
|
|||
array(
|
||||
phutil_tag_div('phui-calendar-date-number', $day_number),
|
||||
$holiday_markup,
|
||||
phutil_implode_html("\n", $show_events),
|
||||
$list,
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -227,6 +237,10 @@ final class PHUICalendarMonthView extends AphrontView {
|
|||
$header->setButtonBar($button_bar);
|
||||
}
|
||||
|
||||
if ($this->image) {
|
||||
$header->setImage($this->image);
|
||||
}
|
||||
|
||||
return $header;
|
||||
}
|
||||
|
||||
|
@ -293,60 +307,4 @@ final class PHUICalendarMonthView extends AphrontView {
|
|||
return $days;
|
||||
}
|
||||
|
||||
private function renderEvent(
|
||||
AphrontCalendarEventView $event,
|
||||
$epoch_start,
|
||||
$epoch_end) {
|
||||
|
||||
$user = $this->user;
|
||||
|
||||
$event_start = $event->getEpochStart();
|
||||
$event_end = $event->getEpochEnd();
|
||||
|
||||
$classes = array();
|
||||
$when = array();
|
||||
|
||||
$classes[] = 'phui-calendar-event';
|
||||
if ($event_start < $epoch_start) {
|
||||
$classes[] = 'phui-calendar-event-continues-before';
|
||||
$when[] = 'Started '.phabricator_datetime($event_start, $user);
|
||||
} else {
|
||||
$when[] = 'Starts at '.phabricator_time($event_start, $user);
|
||||
}
|
||||
|
||||
if ($event_end > $epoch_end) {
|
||||
$classes[] = 'phui-calendar-event-continues-after';
|
||||
$when[] = 'Ends '.phabricator_datetime($event_end, $user);
|
||||
} else {
|
||||
$when[] = 'Ends at '.phabricator_time($event_end, $user);
|
||||
}
|
||||
|
||||
Javelin::initBehavior('phabricator-tooltips');
|
||||
|
||||
$info = $event->getName();
|
||||
if ($event->getDescription()) {
|
||||
$info .= "\n\n".$event->getDescription();
|
||||
}
|
||||
|
||||
$text_div = javelin_tag(
|
||||
'a',
|
||||
array(
|
||||
'sigil' => 'has-tooltip',
|
||||
'meta' => array(
|
||||
'tip' => $info."\n\n".implode("\n", $when),
|
||||
'size' => 240,
|
||||
),
|
||||
'class' => 'phui-calendar-event-text',
|
||||
'href' => '/calendar/event/view/'.$event->getEventID().'/',
|
||||
),
|
||||
phutil_utf8_shorten($event->getName(), 32));
|
||||
|
||||
return javelin_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => implode(' ', $classes),
|
||||
),
|
||||
$text_div);
|
||||
}
|
||||
|
||||
}
|
39
src/view/phui/calendar/PHUICalendarWidgetView.php
Normal file
39
src/view/phui/calendar/PHUICalendarWidgetView.php
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
final class PHUICalendarWidgetView extends AphrontTagView {
|
||||
|
||||
private $header;
|
||||
private $list;
|
||||
|
||||
public function setHeader($date) {
|
||||
$this->header = $date;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setCalendarList(PHUICalendarListView $list) {
|
||||
$this->list = $list;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTagName() {
|
||||
return 'div';
|
||||
}
|
||||
|
||||
public function getTagAttributes() {
|
||||
require_celerity_resource('phui-calendar-list-css');
|
||||
return array('class' => 'phui-calendar-list-container');
|
||||
}
|
||||
|
||||
protected function getTagContent() {
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader($this->header);
|
||||
|
||||
$box = id(new PHUIObjectBoxView())
|
||||
->setHeader($header)
|
||||
->setFlush(true)
|
||||
->appendChild($this->list);
|
||||
|
||||
return $box;
|
||||
}
|
||||
}
|
|
@ -4,8 +4,7 @@
|
|||
|
||||
.device-desktop .profile-feed,
|
||||
.device-tablet .profile-feed {
|
||||
max-width: 640px;
|
||||
padding: 12px 16px;
|
||||
padding: 0 16px 16px 0;
|
||||
}
|
||||
|
||||
.device-phone .profile-feed {
|
||||
|
@ -16,3 +15,26 @@
|
|||
font-size: 16px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.profile-activity-view {
|
||||
padding-top: 16px;
|
||||
}
|
||||
|
||||
.profile-activity-view .profile-calendar {
|
||||
float: left;
|
||||
margin: 0 16px;
|
||||
}
|
||||
|
||||
.profile-activity-view .profile-feed {
|
||||
margin-left: 332px;
|
||||
}
|
||||
|
||||
.device-phone .profile-activity-view .profile-calendar {
|
||||
float: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.device-phone .profile-activity-view .profile-feed {
|
||||
float: none;
|
||||
margin: 0 8px;
|
||||
}
|
||||
|
|
3
webroot/rsrc/css/phui/calendar/phui-calendar-day.css
Normal file
3
webroot/rsrc/css/phui/calendar/phui-calendar-day.css
Normal file
|
@ -0,0 +1,3 @@
|
|||
/**
|
||||
* @provides phui-calendar-day-css
|
||||
*/
|
64
webroot/rsrc/css/phui/calendar/phui-calendar-list.css
Normal file
64
webroot/rsrc/css/phui/calendar/phui-calendar-list.css
Normal file
|
@ -0,0 +1,64 @@
|
|||
/**
|
||||
* @provides phui-calendar-list-css
|
||||
*/
|
||||
|
||||
.phui-calendar-list-container {
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.device-phone .phui-calendar-list-container {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.phui-calendar-list-container .phui-object-box {
|
||||
border-bottom: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.phui-calendar-list-container:last-child .phui-object-box {
|
||||
border-bottom: 1px solid {$blueborder};
|
||||
}
|
||||
|
||||
.phui-calendar-list-container .phui-object-box .phui-header-shell h1 {
|
||||
padding: 6px 0;
|
||||
}
|
||||
|
||||
.phui-calendar-list {
|
||||
padding: 16px 12px;
|
||||
}
|
||||
|
||||
.phui-calendar-list-item {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.phui-calendar-list-dot {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
margin-right: 6px;
|
||||
top: -5px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.phui-calendar-list-title {
|
||||
width: 200px;
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.phui-calendar-list-item .phui-calendar-list-time {
|
||||
position: absolute;
|
||||
width: 60px;
|
||||
right: 0;
|
||||
top: 0;
|
||||
color: {$lightgreytext};
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.phui-calendar-list-item-empty {
|
||||
color: {$lightgreytext};
|
||||
}
|
|
@ -23,6 +23,7 @@ table.phui-calendar-view td {
|
|||
|
||||
table.phui-calendar-view td div.phui-calendar-day {
|
||||
min-height: 125px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.phui-calendar-holiday {
|
||||
|
@ -43,12 +44,14 @@ table.phui-calendar-view td.phui-calendar-month-weekstart {
|
|||
border-color: {$thinblueborder};
|
||||
border-style: solid;
|
||||
border-width: 0 0 1px 1px;
|
||||
float: right;
|
||||
position: absolute;
|
||||
background: #ffffff;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
text-align: center;
|
||||
margin-bottom: 3px;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.phui-calendar-not-work-day {
|
||||
|
@ -63,40 +66,36 @@ table.phui-calendar-view td.phui-calendar-month-weekstart {
|
|||
background-color: {$greybackground};
|
||||
}
|
||||
|
||||
.phui-calendar-event {
|
||||
clear: both;
|
||||
background: {$sky};
|
||||
font-size: 11px;
|
||||
margin: 2px 0;
|
||||
border-radius: 3px;
|
||||
padding: 3px 5%;
|
||||
width: 90%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.phui-calendar-event a:link {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.phui-calendar-event-empty {
|
||||
border-color: transparent;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.phui-calendar-event-text {
|
||||
color: #fff;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
.phui-calendar-view .phui-calendar-list {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.phui-calendar-event-continues-before {
|
||||
border-top-left-radius: 0px;
|
||||
border-bottom-left-radius: 0px;
|
||||
border-left-width: 0px;
|
||||
.phui-calendar-view .phui-calendar-list li:first-child {
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
.phui-calendar-event-continues-after {
|
||||
border-top-right-radius: 0px;
|
||||
border-bottom-right-radius: 0px;
|
||||
border-right-width: 0px;
|
||||
.phui-calendar-view .phui-calendar-list-dot {
|
||||
width: 3px;
|
||||
height: 3px;
|
||||
margin-right: 4px;
|
||||
border-radius: 10px;
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.phui-calendar-view .phui-calendar-list-title {
|
||||
width: auto;
|
||||
margin-left: 10px;
|
||||
white-space: normal;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.phui-calendar-view .phui-calendar-list-time {
|
||||
display: none;
|
||||
}
|
107
webroot/rsrc/css/phui/calendar/phui-calendar.css
Normal file
107
webroot/rsrc/css/phui/calendar/phui-calendar.css
Normal file
|
@ -0,0 +1,107 @@
|
|||
/**
|
||||
* @provides phui-calendar-css
|
||||
*/
|
||||
|
||||
.phui-calendar-red a {
|
||||
color: {$red};
|
||||
}
|
||||
|
||||
.phui-calendar-orange a {
|
||||
color: {$orange};
|
||||
}
|
||||
|
||||
.phui-calendar-yellow a {
|
||||
color: {$yellow};
|
||||
}
|
||||
|
||||
.phui-calendar-green a {
|
||||
color: {$green}
|
||||
}
|
||||
|
||||
.phui-calendar-blue a {
|
||||
color: {$blue};
|
||||
}
|
||||
|
||||
.phui-calendar-sky a {
|
||||
color: {$sky};
|
||||
}
|
||||
|
||||
.phui-calendar-indigo a {
|
||||
color: {$indigo};
|
||||
}
|
||||
|
||||
.phui-calendar-violet a {
|
||||
color: {$violet};
|
||||
}
|
||||
|
||||
.phui-calendar-bg-red {
|
||||
background-color: {$lightred};
|
||||
}
|
||||
|
||||
.phui-calendar-bg-orange {
|
||||
background-color: {$lightorange};
|
||||
}
|
||||
|
||||
.phui-calendar-bg-yellow {
|
||||
background-color: {$lightyellow};
|
||||
}
|
||||
|
||||
.phui-calendar-bg-green {
|
||||
background-color: {$lightgreen}
|
||||
}
|
||||
|
||||
.phui-calendar-bg-blue {
|
||||
background-color: {$lightblue};
|
||||
}
|
||||
|
||||
.phui-calendar-bg-sky {
|
||||
background-color: {$lightsky};
|
||||
}
|
||||
|
||||
.phui-calendar-bg-indigo {
|
||||
background-color: {$lightindigo};
|
||||
}
|
||||
|
||||
.phui-calendar-bg-violet {
|
||||
background-color: {$lightviolet};
|
||||
}
|
||||
|
||||
.phui-calendar-red .phui-calendar-list-dot {
|
||||
background-color: {$red};
|
||||
border-color: {$red};
|
||||
}
|
||||
|
||||
.phui-calendar-orange .phui-calendar-list-dot {
|
||||
background-color: {$orange};
|
||||
border-color: {$orange};
|
||||
}
|
||||
|
||||
.phui-calendar-yellow .phui-calendar-list-dot {
|
||||
background-color: {$orange};
|
||||
border-color: {$orange};
|
||||
}
|
||||
|
||||
.phui-calendar-green .phui-calendar-list-dot {
|
||||
background-color: {$green};
|
||||
border-color: {$green};
|
||||
}
|
||||
|
||||
.phui-calendar-blue .phui-calendar-list-dot {
|
||||
background-color: {$blue};
|
||||
border-color: {$blue};
|
||||
}
|
||||
|
||||
.phui-calendar-sky .phui-calendar-list-dot {
|
||||
background-color: {$sky};
|
||||
border-color: {$sky};
|
||||
}
|
||||
|
||||
.phui-calendar-indigo .phui-calendar-list-dot {
|
||||
background-color: {$indigo};
|
||||
border-color: {$indigo};
|
||||
}
|
||||
|
||||
.phui-calendar-violet .phui-calendar-list-dot {
|
||||
background-color: {$violet};
|
||||
border-color: {$violet};
|
||||
}
|
|
@ -7,10 +7,3 @@
|
|||
border-bottom: 1px solid {$blueborder};
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.device-phone .phui-box {
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* @provides phui-object-box-css
|
||||
*/
|
||||
|
||||
.phui-object-box.phui-object-box-flush {
|
||||
div.phui-object-box.phui-object-box-flush {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
|
@ -29,9 +29,5 @@
|
|||
}
|
||||
|
||||
.device-phone .phui-object-box {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.device-phone .phui-object-box + .phui-object-box {
|
||||
border-top: none;
|
||||
margin: 8px 8px 0 8px;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue