Merge pull request #271 from github/super-command-panel

Super command panel
This commit is contained in:
Kevin Sawicki 2013-02-14 10:13:40 -08:00
commit eb179af0d4
13 changed files with 458 additions and 124 deletions

View File

@ -18,6 +18,7 @@ require.paths.unshift(fixturePackagesPath)
[bindingSetsToRestore, bindingSetsByFirstKeystrokeToRestore] = []
beforeEach ->
jQuery.fx.off = true
window.fixturesProject = new Project(require.resolve('fixtures'))
window.resetTimeouts()
atom.atomPackageStates = {}

View File

@ -12,3 +12,13 @@
'meta-e': 'command-panel:set-selection-as-regex-address'
'meta-f': 'command-panel:find-in-file'
'meta-F': 'command-panel:find-in-project'
'.command-panel':
'ctrl-{': 'command-panel:collapse-all'
'ctrl-}': 'command-panel:expand-all'
'.command-panel .preview-list':
'left': 'command-panel:collapse-result'
'ctrl-[': 'command-panel:collapse-result'
'right': 'command-panel:expand-result'
'ctrl-]': 'command-panel:expand-result'

View File

@ -11,7 +11,13 @@ module.exports =
class CommandPanelView extends View
@content: ->
@div class: 'command-panel tool-panel', =>
@div outlet: 'previewCount', class: 'preview-count'
@div class: 'loading', outlet: 'loadingMessage'
@div class: 'header', outlet: 'previewHeader', =>
@ul outlet: 'expandCollapse', class: 'expand-collapse', =>
@li class: 'expand', 'Expand All'
@li class: 'collapse', 'Collapse All'
@span outlet: 'previewCount', class: 'preview-count'
@subview 'previewList', new PreviewList(rootView)
@ul class: 'error-messages', outlet: 'errorMessages'
@div class: 'prompt-and-editor', =>
@ -40,8 +46,11 @@ class CommandPanelView extends View
rootView.command 'command-panel:repeat-relative-address-in-reverse', => @repeatRelativeAddressInReverse()
rootView.command 'command-panel:set-selection-as-regex-address', => @setSelectionAsLastRelativeAddress()
@on 'click', '.expand', @onExpandAll
@on 'click', '.collapse', @onCollapseAll
@previewList.hide()
@previewCount.hide()
@previewHeader.hide()
@errorMessages.hide()
@prompt.iconSize(@miniEditor.getFontSize())
@ -66,17 +75,35 @@ class CommandPanelView extends View
togglePreview: ->
if @previewList.is(':focus')
@previewList.hide()
@previewCount.hide()
@previewHeader.hide()
@detach()
rootView.focus()
else
@attach() unless @hasParent()
if @previewList.hasOperations()
@previewList.show().focus()
@previewCount.show()
@previewHeader.show()
else
@miniEditor.focus()
toggleLoading: ->
if @loadingMessage.hasClass 'is-loading'
@loadingMessage.removeClass 'is-loading'
@loadingMessage.html ''
@loadingMessage.hide()
else
@loadingMessage.addClass 'is-loading'
@loadingMessage.html 'Searching...'
@loadingMessage.show()
onExpandAll: (event) =>
@previewList.expandAllPaths()
@previewList.focus()
onCollapseAll: (event) =>
@previewList.collapseAllPaths()
@previewList.focus()
attach: (text='', options={}) ->
@errorMessages.hide()
@ -89,17 +116,19 @@ class CommandPanelView extends View
detach: ->
rootView.focus()
@previewList.hide()
@previewCount.hide()
@previewHeader.hide()
super
escapedCommand: ->
@miniEditor.getText()
execute: (command=@escapedCommand())->
@toggleLoading()
@errorMessages.empty()
try
@commandInterpreter.eval(command, rootView.getActiveEditSession()).done ({operationsToPreview, errorMessages}) =>
@toggleLoading()
@history.push(command)
@historyIndex = @history.length
@ -109,6 +138,7 @@ class CommandPanelView extends View
@errorMessages.append $$ ->
@li errorMessage for errorMessage in errorMessages
else if operationsToPreview?.length
@previewHeader.show()
@previewList.populate(operationsToPreview)
@previewList.focus()
@previewCount.text("#{_.pluralize(operationsToPreview.length, 'match', 'matches')} in #{_.pluralize(@previewList.getPathCount(), 'file')}").show()

View File

@ -0,0 +1,28 @@
{View} = require 'space-pen'
module.exports =
class OperationView extends View
@content: ({operation} = {}) ->
{prefix, suffix, match, range} = operation.preview()
@li 'data-index': operation.index, class: 'operation', =>
@span range.start.row + 1, class: 'line-number'
@span class: 'preview', =>
@span prefix
@span match, class: 'match'
@span suffix
initialize: ({@previewList, @operation}) ->
@subscribe @previewList, 'core:confirm', =>
if @hasClass('selected')
@executeOperation()
false
@on 'mousedown', (e) =>
@executeOperation()
@previewList.find('.selected').removeClass('selected')
@addClass('selected')
executeOperation: ->
editSession = rootView.open(@operation.getPath())
bufferRange = @operation.execute(editSession)
editSession.setSelectedBufferRange(bufferRange, autoscroll: true) if bufferRange
@previewList.focus()

View File

@ -0,0 +1,58 @@
{View} = require 'space-pen'
fs = require 'fs'
OperationView = require './operation-view'
$ = require 'jquery'
module.exports =
class PathView extends View
@content: ({path, operations, previewList} = {}) ->
classes = ['path']
classes.push('readme') if fs.isReadmePath(path)
@li class: classes.join(' '), =>
@div outlet: 'pathDetails', class: 'path-details', =>
@span class: 'path-name', path
@span "(#{operations.length})", class: 'path-match-number'
@ul outlet: 'matches', class: 'matches', =>
for operation in operations
@subview "operation#{operation.index}", new OperationView({operation, previewList})
initialize: ({@previewList}) ->
@pathDetails.on 'mousedown', => @toggle(true)
@subscribe @previewList, 'command-panel:collapse-result', =>
@collapse(true) if @isSelected()
@subscribe @previewList, 'command-panel:expand-result', =>
@expand(true) if @isSelected()
@subscribe @previewList, 'core:confirm', =>
if @hasClass('selected')
@toggle(true)
false
isSelected: ->
@hasClass('selected') or @find('.selected').length
setSelected: ->
@previewList.find('.selected').removeClass('selected')
@addClass('selected')
toggle: (animate) ->
if @hasClass('is-collapsed')
@expand(animate)
else
@collapse(animate)
expand: (animate=false) ->
if animate
@matches.show 100, => @removeClass 'is-collapsed'
else
@matches.show()
@removeClass 'is-collapsed'
collapse: (animate=false) ->
if animate
@matches.hide 100, =>
@addClass 'is-collapsed'
@setSelected() if @isSelected()
else
@matches.hide()
@addClass 'is-collapsed'
@setSelected() if @isSelected()

View File

@ -3,24 +3,30 @@ $ = require 'jquery'
ScrollView = require 'scroll-view'
_ = require 'underscore'
fs = require 'fs'
PathView = require './path-view'
OperationView = require './operation-view'
module.exports =
class PreviewList extends ScrollView
@content: ->
@ol class: 'preview-list', tabindex: -1, ->
@ol class: 'preview-list', tabindex: -1
selectedOperationIndex: 0
operations: null
initialize: (@rootView) ->
initialize: ->
super
@on 'core:move-down', => @selectNextOperation(); false
@on 'core:move-up', => @selectPreviousOperation(); false
@on 'core:confirm', => @executeSelectedOperation()
@on 'mousedown', 'li.operation', (e) =>
@setSelectedOperationIndex(parseInt($(e.target).closest('li').data('index')))
@executeSelectedOperation()
@command 'command-panel:collapse-all', => @collapseAllPaths()
@command 'command-panel:expand-all', => @expandAllPaths()
expandAllPaths: ->
@children().each (index, element) -> $(element).view().expand()
collapseAllPaths: ->
@children().each (index, element) -> $(element).view().collapse()
destroy: ->
@destroyOperations() if @operations
@ -31,26 +37,14 @@ class PreviewList extends ScrollView
@destroyOperations() if @operations
@operations = operations
@empty()
@html $$$ ->
operation.index = index for operation, index in operations
operationsByPath = _.groupBy(operations, (operation) -> operation.getPath())
for path, ops of operationsByPath
classes = ['path']
classes.push('readme') if fs.isReadmePath(path)
@li class: classes.join(' '), =>
@span path
@span "(#{ops.length})", class: 'path-match-number'
for operation in ops
{prefix, suffix, match, range} = operation.preview()
@li 'data-index': operation.index, class: 'operation', =>
@span range.start.row + 1, class: 'line-number'
@span class: 'preview', =>
@span prefix
@span match, class: 'match'
@span suffix
@setSelectedOperationIndex(0)
operation.index = index for operation, index in operations
operationsByPath = _.groupBy(operations, (operation) -> operation.getPath())
for path, operations of operationsByPath
@append new PathView({path, operations, previewList: this})
@show()
@find('.operation:first').addClass('selected')
@setLineNumberWidth()
setLineNumberWidth: ->
@ -61,33 +55,33 @@ class PreviewList extends ScrollView
lineNumbers.width(maxWidth)
selectNextOperation: ->
@setSelectedOperationIndex(@selectedOperationIndex + 1)
selectedView = @find('.selected').view()
if selectedView instanceof PathView
if selectedView.hasClass('is-collapsed')
nextView = selectedView.next().view()
else
nextView = selectedView.find('.operation:first')
else
nextView = selectedView.next().view() ? selectedView.closest('.path').next().view()
if nextView?
selectedView.removeClass('selected')
nextView.addClass('selected')
@scrollToElement(nextView)
selectPreviousOperation: ->
@setSelectedOperationIndex(@selectedOperationIndex - 1)
selectedView = @find('.selected').view()
setSelectedOperationIndex: (index, scrollToOperation=true) ->
index = Math.max(0, index)
index = Math.min(@operations.length - 1, index)
@children(".selected").removeClass('selected')
element = @children("li.operation:eq(#{index})")
element.addClass('selected')
if selectedView instanceof PathView
previousView = selectedView.prev()
previousView = previousView.find('.operation:last').view() unless previousView.hasClass('is-collapsed')
else
previousView = selectedView.prev().view() ? selectedView.closest('.path').view()
if scrollToOperation
if index is 0
@scrollToTop()
else
@scrollToElement(element)
@selectedOperationIndex = index
executeSelectedOperation: ->
operation = @getSelectedOperation()
editSession = @rootView.open(operation.getPath())
bufferRange = operation.execute(editSession)
editSession.setSelectedBufferRange(bufferRange, autoscroll: true) if bufferRange
@focus()
false
if previousView?
selectedView.removeClass('selected')
previousView.addClass('selected')
@scrollToElement(previousView)
getPathCount: ->
_.keys(_.groupBy(@operations, (operation) -> operation.getPath())).length
@ -100,23 +94,27 @@ class PreviewList extends ScrollView
@operations = null
getSelectedOperation: ->
@operations[@selectedOperationIndex]
@find('.operation.selected').view()?.operation
scrollToElement: (element) ->
top = @scrollTop() + element.position().top
top = @scrollTop() + element.offset().top - @offset().top
bottom = top + element.outerHeight()
if bottom > @scrollBottom()
@scrollBottom(bottom)
if top < @scrollTop()
@scrollTop(top)
@scrollBottom(bottom) if bottom > @scrollBottom()
@scrollTop(top) if top < @scrollTop()
scrollToBottom: ->
super()
@setSelectedOperationIndex(Infinity, false)
@find('.selected').removeClass('selected')
lastPath = @find('.path:last')
if lastPath.hasClass('is-collapsed')
lastPath.addClass('selected')
else
lastPath.find('.operation:last').addClass('selected')
scrollToTop: ->
super()
@setSelectedOperationIndex(0, false)
@find('.selected').removeClass('selected')
@find('.path:first').addClass('selected')

View File

@ -128,6 +128,9 @@ describe "CommandPanel", ->
beforeEach ->
expect(commandPanel.previewList).toBeVisible()
it "shows the expand and collapse all buttons", ->
expect(commandPanel.find('.expand-collapse')).toBeVisible()
describe "when the preview list is focused", ->
it "hides the command panel", ->
expect(commandPanel.previewList).toMatchSelector(':focus')
@ -171,19 +174,19 @@ describe "CommandPanel", ->
expect(commandPanel.hasParent()).toBeTruthy()
describe "when the mini editor is focused", ->
it "retains focus on the mini editor and does not show the preview list or preview count", ->
it "retains focus on the mini editor and does not show the preview list or preview header", ->
expect(commandPanel.miniEditor.isFocused).toBeTruthy()
rootView.trigger 'command-panel:toggle-preview'
expect(commandPanel.previewList).toBeHidden()
expect(commandPanel.previewCount).toBeHidden()
expect(commandPanel.previewHeader).toBeHidden()
expect(commandPanel.miniEditor.isFocused).toBeTruthy()
describe "when the mini editor is not focused", ->
it "focuses the mini editor and does not show the preview list or preview count", ->
it "focuses the mini editor and does not show the preview list or preview header", ->
rootView.focus()
rootView.trigger 'command-panel:toggle-preview'
expect(commandPanel.previewList).toBeHidden()
expect(commandPanel.previewCount).toBeHidden()
expect(commandPanel.previewHeader).toBeHidden()
expect(commandPanel.miniEditor.isFocused).toBeTruthy()
describe "when the command panel is not visible", ->
@ -290,7 +293,7 @@ describe "CommandPanel", ->
expect(commandPanel.previewList).toBeVisible()
expect(commandPanel.previewList).toMatchSelector ':focus'
previewItem = commandPanel.previewList.find("li:contains(sample.js):first")
expect(previewItem.text()).toBe "sample.js(1)"
expect(previewItem.find('.path-details').text()).toBe "sample.js(1)"
expect(previewItem.next().find('.preview').text()).toBe "var quicksort = function () {"
expect(previewItem.next().find('.preview > .match').text()).toBe "quicksort"
@ -392,29 +395,38 @@ describe "CommandPanel", ->
expect(previewList.find('li.operation:eq(1)')).toHaveClass 'selected'
expect(previewList.getSelectedOperation()).toBe previewList.getOperations()[1]
_.times previewList.getOperations().length - 2, -> previewList.trigger 'core:move-down'
_.times previewList.getOperations().length + previewList.getPathCount(), -> previewList.trigger 'core:move-down'
expect(previewList.find("li.operation:last")).toHaveClass 'selected'
expect(previewList.getSelectedOperation()).toBe _.last(previewList.getOperations())
expect(previewList.scrollBottom()).toBeCloseTo previewList.prop('scrollHeight'), -1
_.times previewList.getOperations().length, -> previewList.trigger 'core:move-up'
_.times previewList.getOperations().length + previewList.getPathCount(), -> previewList.trigger 'core:move-up'
expect(previewList.scrollTop()).toBe 0
it "doesn't bubble up the event and the command panel text doesn't change", ->
rootView.attachToDom()
commandPanel.miniEditor.setText "command"
previewList.focus()
previewList.trigger 'core:move-up'
expect(previewList.find('li.operation:eq(0)')).toHaveClass 'selected'
expect(commandPanel.miniEditor.getText()).toBe 'command'
previewList.trigger 'core:move-down'
expect(previewList.find('li.operation:eq(1)')).toHaveClass 'selected'
expect(commandPanel.miniEditor.getText()).toBe 'command'
previewList.trigger 'core:move-up'
expect(previewList.find('li.operation:eq(0)')).toHaveClass 'selected'
expect(commandPanel.miniEditor.getText()).toBe 'command'
it "doesn't select collapsed operations", ->
rootView.attachToDom()
previewList.trigger 'command-panel:collapse-result'
expect(previewList.find('li.path:eq(0)')).toHaveClass 'selected'
previewList.trigger 'core:move-down'
expect(previewList.find('li.path:eq(1)')).toHaveClass 'selected'
previewList.trigger 'core:move-up'
expect(previewList.find('li.path:eq(0)')).toHaveClass 'selected'
describe "when move-to-top and move-to-bottom are triggered on the preview list", ->
it "selects the first/last operation", ->
it "selects the first path or last operation", ->
rootView.attachToDom()
expect(previewList.getOperations().length).toBeGreaterThan 0
expect(previewList.find('li.operation:eq(0)')).toHaveClass 'selected'
@ -425,8 +437,8 @@ describe "CommandPanel", ->
expect(previewList.getSelectedOperation()).toBe _.last(previewList.getOperations())
previewList.trigger 'core:move-to-top'
expect(previewList.find('li.operation:eq(0)')).toHaveClass 'selected'
expect(previewList.getSelectedOperation()).toBe previewList.getOperations()[0]
expect(previewList.find('li.path:eq(0)')).toHaveClass 'selected'
expect(previewList.getSelectedOperation()).toBeUndefined()
describe "when core:confirm is triggered on the preview list", ->
it "opens the operation's buffer, selects and scrolls to the search result, and refocuses the preview list", ->
@ -453,6 +465,15 @@ describe "CommandPanel", ->
expect(executeHandler).not.toHaveBeenCalled()
it "toggles the expansion state when a path is selected", ->
rootView.attachToDom()
previewList.trigger 'core:move-to-top'
expect(previewList.find('li.path:first')).toHaveClass 'selected'
expect(previewList.find('li.path:first')).not.toHaveClass 'is-collapsed'
previewList.trigger 'core:confirm'
expect(previewList.find('li.path:first')).toHaveClass 'selected'
expect(previewList.find('li.path:first')).toHaveClass 'is-collapsed'
describe "when an operation in the preview list is clicked", ->
it "opens the operation's buffer, selects the search result, and refocuses the preview list", ->
spyOn(previewList, 'focus')
@ -465,3 +486,24 @@ describe "CommandPanel", ->
expect(editSession.buffer.getPath()).toBe project.resolve(operation.getPath())
expect(editSession.getSelectedBufferRange()).toEqual operation.getBufferRange()
expect(previewList.focus).toHaveBeenCalled()
describe "when a path in the preview list is clicked", ->
it "shows and hides the matches for that path", ->
rootView.attachToDom()
expect(previewList.find('li.path:first-child ul.matches')).toBeVisible()
previewList.find('li.path:first-child .path-details').mousedown()
expect(previewList.find('li.path:first-child ul.matches')).toBeHidden()
previewList.find('li.path:first-child .path-details').mousedown()
expect(previewList.find('li.path:first-child ul.matches')).toBeVisible()
describe "when command-panel:collapse-result and command-panel:expand-result are triggered", ->
it "collapses and selects the path, and then expands the selected path", ->
rootView.attachToDom()
expect(previewList.find('li.path:first-child ul.matches')).toBeVisible()
previewList.trigger 'command-panel:collapse-result'
expect(previewList.find('li.path:first-child ul.matches')).toBeHidden()
expect(previewList.find('li.path:first-child')).toHaveClass 'selected'
previewList.trigger 'command-panel:expand-result'
expect(previewList.find('li.path:first-child ul.matches')).toBeVisible()
expect(previewList.find('li.path:first-child')).toHaveClass 'selected'

View File

@ -19,15 +19,10 @@ describe "Gists package", ->
[request, originalFxOffValue] = []
beforeEach ->
originalFxOffValue = $.fx.off
$.fx.off = true
editor.trigger 'gist:create'
expect($.ajax).toHaveBeenCalled()
request = $.ajax.argsForCall[0][0]
afterEach ->
$.fx.off = originalFxOffValue
it "creates an Ajax request to api.github.com with the entire buffer contents as the Gist's content", ->
expect(request.url).toBe 'https://api.github.com/gists'
expect(request.type).toBe 'POST'
@ -46,7 +41,7 @@ describe "Gists package", ->
expect(rootView.find('.notification')).toExist()
expect(rootView.find('.notification .title').text()).toBe 'Gist 1 created'
advanceClock(2000)
expect(rootView.find('.gist-notification')).not.toExist()
expect(rootView.find('.notification')).not.toExist()
describe "when the editor has a selection", ->
beforeEach ->

View File

@ -60,4 +60,16 @@ html, body {
src: url("octicons-regular-webfont.woff") format("woff");
font-weight: normal;
font-style: normal;
}
.is-loading {
background-image: url(images/spinner.svg);
background-repeat: no-repeat;
width: 14px;
height: 14px;
opacity: 0.5;
background-size: contain;
position: relative;
display: inline-block;
padding-left: 19px;
}

View File

@ -1,30 +1,77 @@
.command-panel {
padding: 5px;
position: relative;
padding: 0;
}
.command-panel .is-loading {
display: block;
margin: 0 auto 10px auto;
width: 100px;
background-color: #111;
background-size: auto;
background-position: 5px 5px;
padding: 5px 5px 10px 30px;
border-radius: 3px;
border: 1px solid rgba(255, 255, 255, 0.1);
border-top: 1px solid rgba(0, 0, 0, 1);
border-left: 1px solid rgba(0, 0, 0, 1);
}
.command-panel .preview-list {
max-height: 300px;
overflow: auto;
margin: 10px 0 10px 10px;
margin: 0 0 10px 0;
position: relative;
cursor: default;
}
.command-panel .preview-count {
.command-panel .header:after {
content: ".";
display: block;
visibility: hidden;
clear: both;
height: 0;
}
.command-panel .expand-collapse {
float: right;
}
.command-panel .expand-collapse li {
display: inline-block;
padding: 5px;
cursor: pointer;
font-size: 11px;
text-align: right;
position: absolute;
right: 15px;
top: 24px;
z-index: 9999;
}
.command-panel .preview-count,
.command-panel .expand-collapse {
-webkit-user-select: none;
}
.command-panel .preview-list .path {
padding-left: 5px;
position: relative;
-webkit-user-select: none;
}
.command-panel .preview-list .path:before {
.command-panel .preview-list .path-details:before {
font-family: 'Octicons Regular';
font-size: 12px;
width: 12px;
height: 12px;
margin-right: 5px;
-webkit-font-smoothing: antialiased;
content: "\f05b";
position: relative;
top: 0;
}
.command-panel .preview-list .is-collapsed .path-details:before {
content: "\f05a";
}
.command-panel .preview-list .path-name:before {
font-family: 'Octicons Regular';
font-size: 16px;
width: 16px;
@ -36,13 +83,14 @@
top: 1px;
}
.command-panel .preview-list .path.readme:before {
.command-panel .preview-list .path.readme .path-name:before {
content: "\f007";
}
.command-panel .preview-list .operation {
padding-top: 2px;
padding-bottom: 2px;
padding-left: 10px;
}
.command-panel .preview-list .line-number {
@ -65,20 +113,8 @@
padding: 1px;
}
.command-panel .prompt-and-editor .prompt:before {
color: #969696;
content: '\f078';
font-family: 'Octicons Regular';
position: relative;
top: 0;
left: -5px;
-webkit-font-smoothing: antialiased;
}
.command-panel .prompt-and-editor .editor {
position: relative;
left: -4px;
margin-right: -4px;
}
.command-panel .prompt-and-editor {

30
static/images/spinner.svg Normal file
View File

@ -0,0 +1,30 @@
<?xml version='1.0' standalone='no'?>
<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'>
<svg xmlns='http://www.w3.org/2000/svg' version='1.1' width='20px' height='20px'>
<g>
<circle cx='10' cy='2' r='2' style='opacity:0;fill:#fff'>
<animate attributeType='CSS' attributeName='opacity' from='1' to='0' dur='0.8s' repeatCount='indefinite' begin='0s' />
</circle>
<circle cx='15.6569' cy='4.3431' r='2' style='opacity:0;fill:#fff'>
<animate attributeType='CSS' attributeName='opacity' from='1' to='0' dur='0.8s' repeatCount='indefinite' begin='0.1s' />
</circle>
<circle cx='18' cy='10' r='2' style='opacity:0;fill:#fff'>
<animate attributeType='CSS' attributeName='opacity' from='1' to='0' dur='0.8s' repeatCount='indefinite' begin='0.2s' />
</circle>
<circle cx='15.6569' cy='15.6569' r='2' style='opacity:0;fill:#fff'>
<animate attributeType='CSS' attributeName='opacity' from='1' to='0' dur='0.8s' repeatCount='indefinite' begin='0.3s' />
</circle>
<circle cx='10' cy='18' r='2' style='opacity:0;fill:#fff'>
<animate attributeType='CSS' attributeName='opacity' from='1' to='0' dur='0.8s' repeatCount='indefinite' begin='0.4s' />
</circle>
<circle cx='4.3431' cy='15.6569' r='2' style='opacity:0;fill:#fff'>
<animate attributeType='CSS' attributeName='opacity' from='1' to='0' dur='0.8s' repeatCount='indefinite' begin='0.5s' />
</circle>
<circle cx='2' cy='10' r='2' style='opacity:0;fill:#fff'>
<animate attributeType='CSS' attributeName='opacity' from='1' to='0' dur='0.8s' repeatCount='indefinite' begin='0.6s' />
</circle>
<circle cx='4.3431' cy='4.3431' r='2' style='opacity:0;fill:#fff'>
<animate attributeType='CSS' attributeName='opacity' from='1' to='0' dur='0.8s' repeatCount='indefinite' begin='0.7s' />
</circle>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -6,39 +6,89 @@
padding: 10px;
}
.command-panel .header {
background-image: -webkit-linear-gradient(rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.05));
border: 1px solid rgba(0, 0, 0, 0.5);
padding: 5px;
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, 0.05),
inset 0 -1px 0 rgba(255, 255, 255, 0.02);
margin-bottom: 0;
border-top-right-radius: 3px;
border-top-left-radius: 3px;
}
.command-panel .preview-list {
background-color: #19191b;
color: #C5C8C6;
border: 1px solid rgba(0, 0, 0, 0.5);
color: #6d736f;
border: 1px solid rgba(0, 0, 0, 0.2);
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
border-right: 1px solid rgba(255, 255, 255, 0.05);
}
.command-panel .preview-count {
display: inline-block;
margin-top: 5px;
color: #969696;
background: #161719;
padding: 5px;
text-shadow: -1px -1px 0 rgba(0, 0, 0, 0.05);
}
.command-panel .expand-collapse {
color: #969696;
}
.command-panel .expand-collapse li {
background: -webkit-linear-gradient(#19191a, #1a1b1c);
margin-left: 5px;
padding: 5px 10px;
border-radius: 3px;
box-shadow:
inset -1px -1px 0 rgba(255, 255, 255, 0.1),
inset 1px 1px rgba(0, 0, 0, 0.1);
}
.command-panel .preview-list li.selected, .command-panel .preview-list li.operation:hover {
background-color: rgba(255, 255, 255, .13);
}
.command-panel .preview-list:focus li.selected {
background-color: rgba(255, 255, 255, .2);
}
.command-panel .preview-list .path {
.command-panel .expand-collapse li:hover {
color: #fff;
}
.command-panel .preview-list .path.selected .path-details,
.command-panel .preview-list li.operation.selected {
background-color: rgba(255, 255, 255, 0.05);
}
.command-panel .preview-list:focus .path.selected .path-details,
.command-panel .preview-list:focus li.operation.selected {
background-color: rgba(255, 255, 255, 0.05);
}
.command-panel .preview-list .path {
color: #bbb;
border-top: 1px solid rgba(255, 255, 255, 0.02);
}
.command-panel .preview-list .path:hover .path-name {
color: #fff;
}
.command-panel .preview-list .path:before {
color: #555;
}
.command-panel .preview-list .path:hover:before {
color: #fff;
}
.command-panel .preview-list .path:first-child {
border-top: none;
}
.command-panel .preview-list .line-number {
color: rgba(255, 255, 255, .3);
color: rgba(255, 255, 255, 0.3);
font-family: monospace;
}
.command-panel .preview-list .path-match-number {
color: rgba(255, 255, 255, .3);
color: rgba(255, 255, 255, 0.3);
}
.command-panel .preview-list .preview {
@ -46,6 +96,18 @@
}
.command-panel .preview-list .preview .match {
background-color: rgba(255, 255, 255, .2);
color: yellow;
background-color: rgba(255, 255, 255, 0.1);
color: #cca300;
}
.command-panel .preview-list li.operation {
color: #777;
}
.command-panel .preview-list li.operation:hover,
.command-panel li.operation.selected .preview {
color: #fff;
}
{
color: #fff;
}

View File

@ -2,12 +2,26 @@
background-color: #f4f4f4;
border-top: 1px solid #979797;
color: #ededed;
padding: 10px;
}
.command-panel .header {
padding: 5px;
background-image: -webkit-linear-gradient(#e7e7e7, #cfcfcf);
border: 1px solid rgba(0, 0, 0, 0.2);
padding: 5px;
border-top-right-radius: 3px;
border-top-left-radius: 3px;
}
.command-panel .expand-collapse {
color: #333;
}
.command-panel .preview-list {
background-color: #e7e7e7;
color: #222;
border: 1px solid #989898;
border: 1px solid #ccc;
}
.command-panel .preview-count {
@ -19,11 +33,24 @@
}
.command-panel .preview-list .path {
color: #3D5075;
color: #999;
border-top: 1px solid #ddd;
}
.command-panel .preview-list .path-name {
color: #555;
}
.command-panel .preview-list .path:before {
color: #555;
}
.command-panel .preview-list .path:hover:before {
color: #000;
}
.command-panel .preview-list .line-number {
color: #3D5075;
color: #999;
}
.command-panel .preview-list .path-match-number {
@ -31,5 +58,10 @@
}
.command-panel .preview-list .preview .match {
background-color: #c8d4d7;
}
background-color: #bbb;
color: #333;
}
.command-panel .preview-list li.operation {
color: #777;
}