diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php index 2e444e3c2b..4b5f1ec05c 100644 --- a/src/__celerity_resource_map__.php +++ b/src/__celerity_resource_map__.php @@ -604,6 +604,15 @@ celerity_register_resource_map(array( ), 'disk' => '/rsrc/css/aphront/attached-file-view.css', ), + 'aphront-bars' => + array( + 'uri' => '/res/d7bd9032/rsrc/css/core/aphront-bars.css', + 'type' => 'css', + 'requires' => + array( + ), + 'disk' => '/rsrc/css/core/aphront-bars.css', + ), 'aphront-calendar-view-css' => array( 'uri' => '/res/73061a31/rsrc/css/aphront/calendar-view.css', diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index fb189ffb9a..59f3fd6e57 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -17,6 +17,7 @@ phutil_register_library_map(array( 'AphrontAjaxResponse' => 'aphront/response/AphrontAjaxResponse.php', 'AphrontApplicationConfiguration' => 'aphront/configuration/AphrontApplicationConfiguration.php', 'AphrontAttachedFileView' => 'view/control/AphrontAttachedFileView.php', + 'AphrontBarView' => 'view/widget/bars/AphrontBarView.php', 'AphrontCSRFException' => 'aphront/exception/AphrontCSRFException.php', 'AphrontCalendarEventView' => 'applications/calendar/view/AphrontCalendarEventView.php', 'AphrontCalendarMonthView' => 'applications/calendar/view/AphrontCalendarMonthView.php', @@ -53,6 +54,7 @@ phutil_register_library_map(array( 'AphrontFormToggleButtonsControl' => 'view/form/control/AphrontFormToggleButtonsControl.php', 'AphrontFormTokenizerControl' => 'view/form/control/AphrontFormTokenizerControl.php', 'AphrontFormView' => 'view/form/AphrontFormView.php', + 'AphrontGlyphBarView' => 'view/widget/bars/AphrontGlyphBarView.php', 'AphrontHTMLResponse' => 'aphront/response/AphrontHTMLResponse.php', 'AphrontHTTPSink' => 'aphront/sink/AphrontHTTPSink.php', 'AphrontHTTPSinkTestCase' => 'aphront/sink/__tests__/AphrontHTTPSinkTestCase.php', @@ -71,6 +73,7 @@ phutil_register_library_map(array( 'AphrontPagerView' => 'view/control/AphrontPagerView.php', 'AphrontPanelView' => 'view/layout/AphrontPanelView.php', 'AphrontPlainTextResponse' => 'aphront/response/AphrontPlainTextResponse.php', + 'AphrontProgressBarView' => 'view/widget/bars/AphrontProgressBarView.php', 'AphrontProxyResponse' => 'aphront/response/AphrontProxyResponse.php', 'AphrontRedirectException' => 'aphront/exception/AphrontRedirectException.php', 'AphrontRedirectResponse' => 'aphront/response/AphrontRedirectResponse.php', @@ -638,6 +641,7 @@ phutil_register_library_map(array( 'PhabricatorActionView' => 'view/layout/PhabricatorActionView.php', 'PhabricatorAllCapsTranslation' => 'infrastructure/internationalization/PhabricatorAllCapsTranslation.php', 'PhabricatorAnchorView' => 'view/layout/PhabricatorAnchorView.php', + 'PhabricatorAphrontBarExample' => 'applications/uiexample/examples/PhabricatorAphrontBarExample.php', 'PhabricatorApplication' => 'applications/base/PhabricatorApplication.php', 'PhabricatorApplicationApplications' => 'applications/meta/application/PhabricatorApplicationApplications.php', 'PhabricatorApplicationAudit' => 'applications/audit/application/PhabricatorApplicationAudit.php', @@ -1570,6 +1574,7 @@ phutil_register_library_map(array( 'Aphront404Response' => 'AphrontHTMLResponse', 'AphrontAjaxResponse' => 'AphrontResponse', 'AphrontAttachedFileView' => 'AphrontView', + 'AphrontBarView' => 'AphrontView', 'AphrontCSRFException' => 'AphrontException', 'AphrontCalendarEventView' => 'AphrontView', 'AphrontCalendarMonthView' => 'AphrontView', @@ -1606,6 +1611,7 @@ phutil_register_library_map(array( 'AphrontFormToggleButtonsControl' => 'AphrontFormControl', 'AphrontFormTokenizerControl' => 'AphrontFormControl', 'AphrontFormView' => 'AphrontView', + 'AphrontGlyphBarView' => 'AphrontBarView', 'AphrontHTMLResponse' => 'AphrontResponse', 'AphrontHTTPSinkTestCase' => 'PhabricatorTestCase', 'AphrontIsolatedDatabaseConnectionTestCase' => 'PhabricatorTestCase', @@ -1623,6 +1629,7 @@ phutil_register_library_map(array( 'AphrontPagerView' => 'AphrontView', 'AphrontPanelView' => 'AphrontView', 'AphrontPlainTextResponse' => 'AphrontResponse', + 'AphrontProgressBarView' => 'AphrontBarView', 'AphrontProxyResponse' => 'AphrontResponse', 'AphrontRedirectException' => 'AphrontException', 'AphrontRedirectResponse' => 'AphrontResponse', @@ -2134,6 +2141,7 @@ phutil_register_library_map(array( 'PhabricatorActionView' => 'AphrontView', 'PhabricatorAllCapsTranslation' => 'PhabricatorTranslation', 'PhabricatorAnchorView' => 'AphrontView', + 'PhabricatorAphrontBarExample' => 'PhabricatorUIExample', 'PhabricatorApplicationApplications' => 'PhabricatorApplication', 'PhabricatorApplicationAudit' => 'PhabricatorApplication', 'PhabricatorApplicationAuth' => 'PhabricatorApplication', diff --git a/src/applications/uiexample/examples/PhabricatorAphrontBarExample.php b/src/applications/uiexample/examples/PhabricatorAphrontBarExample.php new file mode 100644 index 0000000000..f22f5757f9 --- /dev/null +++ b/src/applications/uiexample/examples/PhabricatorAphrontBarExample.php @@ -0,0 +1,75 @@ +renderTestThings('AphrontProgressBarView', 13, 10); + $out .= $this->renderTestThings('AphrontGlyphBarView', 13, 10); + $out .= $this->renderWeirdOrderGlyphBars(); + $out .= $this->renderAsciiStarBar(); + return phutil_safe_html($out); + } + + private function wrap($title, $thing) { + return id(new AphrontPanelView()) + ->setHeader($title) + ->appendChild($thing) + ->render(); + } + + private function renderTestThings($class, $max, $incr) { + $bars = array(); + for ($ii = 0; $ii <= $max; $ii++) { + $bars[] = newv($class, array()) + ->setValue($ii * $incr) + ->setMax($max * $incr) + ->setCaption("{$ii} outta {$max} ain't bad!"); + } + return $this->wrap( + "Test {$class}", + phutil_implode_html('', mpull($bars, 'render'))); + } + + private function renderWeirdOrderGlyphBars() { + $views = array(); + $indices = array(1, 3, 7, 4, 2, 8, 9, 5, 10, 6); + $max = count($indices); + foreach ($indices as $index) { + $views[] = id(new AphrontGlyphBarView()) + ->setValue($index) + ->setMax($max) + ->setNumGlyphs(5) + ->setCaption("Lol score is {$index}/{$max}") + ->setGlyph(hsprintf('%s', 'LOL!')) + ->setBackgroundGlyph(hsprintf('%s', '____')) + ->render(); + $views[] = hsprintf('
'); + } + + return $this->wrap( + "Glyph bars in weird order", + phutil_implode_html('', $views)); + } + + private function renderAsciiStarBar() { + return $this->wrap( + "Ascii star glyph bar", + id(new AphrontGlyphBarView()) + ->setValue(50) + ->setMax(100) + ->setCaption('Glyphs!') + ->setNumGlyphs(10) + ->setGlyph(hsprintf('%s', '*')) + ->render()); + } + +} diff --git a/src/view/widget/bars/AphrontBarView.php b/src/view/widget/bars/AphrontBarView.php new file mode 100644 index 0000000000..23a3e4b365 --- /dev/null +++ b/src/view/widget/bars/AphrontBarView.php @@ -0,0 +1,63 @@ +color = $color; + return $this; + } + + final public function setCaption($text) { + $this->caption = $text; + return $this; + } + + final protected function getColor() { + $color = $this->color; + if (!$color) { + $color = $this->getDefaultColor(); + } + + switch ($color) { + case self::COLOR_DEFAULT: + case self::COLOR_WARNING: + case self::COLOR_DANGER: + return $color; + } + + $ratio = $this->getRatio(); + if ($color === self::COLOR_AUTO_GOODNESS) { + $ratio = 1.0 - $ratio; + } + + if ($ratio >= self::THRESHOLD_DANGER) { + return self::COLOR_DANGER; + } else if ($ratio >= self::THRESHOLD_WARNING) { + return self::COLOR_WARNING; + } else { + return self::COLOR_DEFAULT; + } + } + + final protected function getCaption() { + return $this->caption; + } + +} diff --git a/src/view/widget/bars/AphrontGlyphBarView.php b/src/view/widget/bars/AphrontGlyphBarView.php new file mode 100644 index 0000000000..c013d18b72 --- /dev/null +++ b/src/view/widget/bars/AphrontGlyphBarView.php @@ -0,0 +1,102 @@ +value = $value; + return $this; + } + + public function setMax($max) { + $this->max = $max; + return $this; + } + + public function setNumGlyphs($nn) { + $this->numGlyphs = $nn; + return $this; + } + + public function setGlyph(PhutilSafeHTML $fg_glyph) { + $this->fgGlyph = $fg_glyph; + return $this; + } + + public function setBackgroundGlyph(PhutilSafeHTML $bg_glyph) { + $this->bgGlyph = $bg_glyph; + return $this; + } + + protected function getRatio() { + return min($this->value, $this->max) / $this->max; + } + + public function render() { + require_celerity_resource('aphront-bars'); + $ratio = $this->getRatio(); + $percentage = 100 * $ratio; + + $is_star = false; + if ($this->fgGlyph) { + $fg_glyph = $this->fgGlyph; + if ($this->bgGlyph) { + $bg_glyph = $this->bgGlyph; + } else { + $bg_glyph = $fg_glyph; + } + } else { + $is_star = true; + $fg_glyph = self::BLACK_STAR; + $bg_glyph = self::WHITE_STAR; + } + + $fg_glyphs = array_fill(0, $this->numGlyphs, $fg_glyph); + $bg_glyphs = array_fill(0, $this->numGlyphs, $bg_glyph); + + $color = $this->getColor(); + + return phutil_tag( + 'div', + array( + 'class' => "aphront-bar glyph color-{$color}", + ), + array( + phutil_tag( + 'div', + array( + 'class' => 'glyphs'.($is_star ? ' starstar' : ''), + ), + array( + phutil_tag( + 'div', + array( + 'class' => 'fg', + 'style' => "width: {$percentage}%;", + ), + $fg_glyphs), + phutil_tag( + 'div', + array(), + $bg_glyphs) + )), + phutil_tag( + 'div', + array('class' => 'caption'), + $this->getCaption()) + )); + } + +} diff --git a/src/view/widget/bars/AphrontProgressBarView.php b/src/view/widget/bars/AphrontProgressBarView.php new file mode 100644 index 0000000000..4584c08c8f --- /dev/null +++ b/src/view/widget/bars/AphrontProgressBarView.php @@ -0,0 +1,60 @@ +value = $value; + return $this; + } + + public function setMax($max) { + $this->max = $max; + return $this; + } + + public function setAlt($text) { + $this->alt = $text; + return $this; + } + + protected function getRatio() { + return min($this->value, $this->max) / $this->max; + } + + public function render() { + require_celerity_resource('aphront-bars'); + $ratio = $this->getRatio(); + $width = self::WIDTH * $ratio; + + $color = $this->getColor(); + + return phutil_tag( + 'div', + array( + 'class' => "aphront-bar progress color-{$color}", + ), + array( + phutil_tag( + 'div', + array('title' => $this->alt), + phutil_tag( + 'div', + array('style' => hsprintf("width: %dpx;", $width)), + '')), + phutil_tag( + 'span', + array(), + $this->getCaption()))); + } + +} diff --git a/webroot/rsrc/css/core/aphront-bars.css b/webroot/rsrc/css/core/aphront-bars.css new file mode 100644 index 0000000000..1a3e3dfcc4 --- /dev/null +++ b/webroot/rsrc/css/core/aphront-bars.css @@ -0,0 +1,100 @@ +/** + * @provides aphront-bars + */ + +/** + * Progress bars + */ + +div.aphront-bar.progress { + border: 0px; +} + +div.aphront-bar.progress div { + width: 100px; + border: 1px solid; + border-top-color: #A4A4A4; + border-right-color: #BBB; + border-bottom-color: #D5D5D5; + border-left-color: #BBB; + background: white; + float: left; + margin-right: 1em; +} + +div.aphront-bar.progress div div { + height: 10px; +} + +div.aphront-bar.progress span { + color: #555; +} + + +/** + * Glyph bars + */ + +div.aphront-bar.glyph { + clear: both; +} + +div.aphront-bar.glyph div.glyphs { + padding: 0; + margin: 0; + + float: left; + position: relative; + color: #aaa; + font-family: monospace; + height: 1.3em; +} + +div.aphront-bar.glyph div.glyphs.starstar { + /* http://daringfireball.net/2005/08/star_star */ + font-family: "Hiragino Kaku Gothic Pro", "Osaka", "Zapf Dingbats"; +} + +div.aphront-bar.glyph div.glyphs div.fg { + padding: 0; + margin: 0; + float: left; + position: absolute; + overflow: hidden; +} + +div.aphront-bar.glyph div.caption { + padding: 0; + margin: 0; + float: left; + margin-left: 1.5em; + color: #666; +} + + +/** + * Common color classes + */ +div.aphront-bar.progress.color-default div div { + background: #6D84B4; +} + +div.aphront-bar.glyph.color-default div.glyphs div.fg { + color: #6D84B4; +} + +div.aphront-bar.progress.color-warning div div { + background: #FFCC5F; +} + +div.aphront-bar.glyph.color-warning div.glyphs div.fg { + color: #FFCC5F; +} + +div.aphront-bar.progress.color-danger div div { + background: #FF6E6E; +} + +div.aphront-bar.glyph.color-danger div.glyphs div.fg { + color: #FF6E6E; +}