diff --git a/ci/workflows.yml b/ci/workflows.yml index 999cf9d9d..1bdbe6eef 100644 --- a/ci/workflows.yml +++ b/ci/workflows.yml @@ -336,6 +336,10 @@ workflows: run: >- yarn --cwd ui/frontend/ test:lint + - name: "Style" + run: >- + yarn --cwd ui/frontend/ test:style + - name: "Build frontend" run: >- yarn --cwd ui/frontend/ run build:production diff --git a/tests/Gemfile.lock b/tests/Gemfile.lock index aed349900..357745d44 100644 --- a/tests/Gemfile.lock +++ b/tests/Gemfile.lock @@ -18,9 +18,9 @@ GEM diff-lcs (1.4.4) launchy (2.5.0) addressable (~> 2.7) - mini_mime (1.0.2) + mini_mime (1.0.3) mini_portile2 (2.5.0) - nokogiri (1.11.1) + nokogiri (1.11.2) mini_portile2 (~> 2.5.0) racc (~> 1.4) public_suffix (4.0.6) diff --git a/tests/spec/features/assistance_spec.rb b/tests/spec/features/assistance_spec.rb index 76788ed9f..d4b43ddcb 100644 --- a/tests/spec/features/assistance_spec.rb +++ b/tests/spec/features/assistance_spec.rb @@ -13,13 +13,11 @@ EOF click_on("Build") - within('.output-warning') do + within(:output, :warning) do click_on("add a main function") end - within('.editor') do - expect(editor).to have_line 'println!("Hello, world!")' - end + expect(editor).to have_line 'println!("Hello, world!")' end scenario "using an unstable feature offers adding the feature flag" do @@ -29,13 +27,11 @@ EOF click_on("Build") - within('.output-stderr') do + within(:output, :stderr) do click_on("add `#![feature(abi_avr_interrupt)]`") end - within('.editor') do - expect(editor).to have_line '#![feature(abi_avr_interrupt)]' - end + expect(editor).to have_line '#![feature(abi_avr_interrupt)]' end scenario "using a type that hasn't been imported offers importing it" do @@ -44,13 +40,11 @@ EOF click_on("Build") - within('.output-stderr') do + within(:output, :stderr) do click_on("use std::collections::HashMap;") end - within('.editor') do - expect(editor).to have_line 'use std::collections::HashMap;' - end + expect(editor).to have_line 'use std::collections::HashMap;' end scenario "triggering a panic offers enabling backtraces" do @@ -61,11 +55,11 @@ EOF click_on("Run") - within('.output-stderr') do + within(:output, :stderr) do click_on("run with `RUST_BACKTRACE=1` environment variable to display a backtrace") end - within('.output-stderr') do + within(:output, :stderr) do expect(page).to have_content("stack backtrace:") end end diff --git a/tests/spec/features/automatic_primary_action_spec.rb b/tests/spec/features/automatic_primary_action_spec.rb index f4caa1d27..25967fc9f 100644 --- a/tests/spec/features/automatic_primary_action_spec.rb +++ b/tests/spec/features/automatic_primary_action_spec.rb @@ -13,7 +13,7 @@ EOF click_on("Run") - within('.output-stdout') do + within(:output, :stdout) do expect(page).to have_content 'Hello, world' end end @@ -27,7 +27,7 @@ EOF click_on("Build") - within('.output-stderr') do + within(:output, :stderr) do expect(page).to have_content 'function is never used: `main`' end end @@ -47,7 +47,7 @@ EOF click_on("Build") - within('.output-stderr') do + within(:output, :stderr) do expect(page).to have_content 'function is never used: `main`' end end @@ -59,7 +59,7 @@ EOF click_on("Test") - within('.output-stdout') do + within(:output, :stdout) do expect(page).to have_content 'running 1 test' expect(page).to have_content 'test awesome ... ok' expect(page).to have_content 'test result: ok' @@ -79,7 +79,7 @@ EOF click_on("Test") - within('.output-stdout') do + within(:output, :stdout) do expect(page).to have_content 'running 1 test' expect(page).to_not have_content 'Running in main' end @@ -93,7 +93,7 @@ EOF click_on("Run") - within('.output-stdout') do + within(:output, :stdout) do expect(page).to have_content 'Running in main' end end @@ -106,7 +106,7 @@ EOF click_on("Build") - within('.output-stderr') do + within(:output, :stderr) do expect(page).to have_content 'function is never used: `arbitrary_code`' end end diff --git a/tests/spec/features/backtrace_spec.rb b/tests/spec/features/backtrace_spec.rb index cdbe498fd..33b94d573 100644 --- a/tests/spec/features/backtrace_spec.rb +++ b/tests/spec/features/backtrace_spec.rb @@ -13,18 +13,18 @@ context "backtraces are enabled" do before do in_advanced_options_menu { choose 'enabled' } - within('.header') { click_on("Run") } + within(:header) { click_on("Run") } end scenario "a backtrace is shown" do - within('.output-stderr') do + within(:output, :stderr) do expect(page).to have_content 'stack backtrace:' expect(page).to have_content 'rust_begin_unwind' end end scenario "filenames link to that line of code" do - within('.output-stderr') do + within(:output, :stderr) do expect(page).to have_link('main.rs:2') expect(page).to have_link('main.rs:6') end @@ -33,11 +33,11 @@ context "backtraces are disabled" do before do - within('.header') { click_on("Run") } + within(:header) { click_on("Run") } end scenario "the backtrace suggestion is a link" do - within('.output-stderr') do + within(:output, :stderr) do expect(page).to have_link(text: /Run with .* a backtrace/i) end end diff --git a/tests/spec/features/compilation_modes_spec.rb b/tests/spec/features/compilation_modes_spec.rb index 8551cf0fc..bb2058cef 100644 --- a/tests/spec/features/compilation_modes_spec.rb +++ b/tests/spec/features/compilation_modes_spec.rb @@ -14,7 +14,7 @@ in_mode_menu { click_on("Debug") } click_on("Run") - within('.output-stdout') do + within(:output, :stdout) do expect(page).to have_content 'Compiling in debug mode' expect(page).to_not have_content 'Compiling in release mode' end @@ -24,7 +24,7 @@ in_mode_menu { click_on("Release") } click_on("Run") - within('.output-stdout') do + within(:output, :stdout) do expect(page).to_not have_content 'Compiling in debug mode' expect(page).to have_content 'Compiling in release mode' end diff --git a/tests/spec/features/compilation_targets_spec.rb b/tests/spec/features/compilation_targets_spec.rb index 8c07e70f3..bfd34e1b1 100644 --- a/tests/spec/features/compilation_targets_spec.rb +++ b/tests/spec/features/compilation_targets_spec.rb @@ -22,21 +22,21 @@ scenario "choosing to run the code" do in_build_menu { click_on(build_button: "Run") } - within('.output-stdout') do + within(:output, :stdout) do expect(page).to have_content 'Hello, world!' end end scenario "choosing to build the code" do in_build_menu { click_on(build_button: "Build") } - within('.output-stderr') do + within(:output, :stderr) do expect(page).to have_content 'function is never used: `main`' end end scenario "choosing to test the code" do in_build_menu { click_on(build_button: "Test") } - within('.output-stdout') do + within(:output, :stdout) do expect(page).to have_content "panicked at 'assertion failed: false'" end end @@ -50,7 +50,7 @@ scenario "compiling to assembly" do in_build_menu { click_on("assembly") } - within('.output-code') do + within(:output, :code) do # We demangle the symbols expect(page).to have_content 'playground::main:' @@ -67,7 +67,7 @@ scenario "compiling to assembly" do in_build_menu { click_on("assembly") } - within('.output-code') do + within(:output, :code) do # We demangle the symbols expect(page).to have_content 'playground::main:' @@ -79,7 +79,7 @@ scenario "compiling to LLVM IR" do in_build_menu { click_on("LLVM IR") } - within('.output-code') do + within(:output, :code) do expect(page).to have_content 'ModuleID' expect(page).to have_content 'target datalayout' expect(page).to have_content 'target triple' @@ -89,7 +89,7 @@ scenario "compiling to MIR" do in_build_menu { click_on("MIR") } - within('.output-result') do + within(:output, :result) do expect(page).to have_content 'StorageLive' expect(page).to have_content 'StorageDead' end @@ -102,7 +102,7 @@ in_build_menu { click_on("HIR") } - within('.output-result') do + within(:output, :result) do expect(page).to have_content 'fn demo() -> /*impl Trait*/ { 42 }' end end @@ -110,7 +110,7 @@ scenario "compiling to WebAssembly" do in_build_menu { click_on("WASM") } - within('.output-code') do + within(:output, :code) do expect(page).to have_content '(module' expect(page).to have_content '(block' end @@ -122,7 +122,7 @@ scenario "it shows the compilation error" do in_build_menu { click_on("MIR") } - within('.output-stderr') do + within(:output, :stderr) do expect(page).to have_content 'an unclosed delimiter' end end diff --git a/tests/spec/features/editions_spec.rb b/tests/spec/features/editions_spec.rb index b13a2b778..af991b9ed 100644 --- a/tests/spec/features/editions_spec.rb +++ b/tests/spec/features/editions_spec.rb @@ -14,7 +14,7 @@ in_advanced_options_menu { choose '2015' } click_on("Run") - within('.output-stderr') do + within(:output, :stderr) do expect(page).to have_content 'unused variable: `async`' expect(page).to_not have_content 'expected identifier, found keyword `async`' end @@ -24,7 +24,7 @@ in_advanced_options_menu { choose '2018' } click_on("Run") - within('.output-stderr') do + within(:output, :stderr) do expect(page).to have_content 'expected identifier, found keyword `async`' expect(page).to_not have_content 'unused variable: `async`' end diff --git a/tests/spec/features/editor_types_spec.rb b/tests/spec/features/editor_types_spec.rb index 53d8a8ac8..9503dca90 100644 --- a/tests/spec/features/editor_types_spec.rb +++ b/tests/spec/features/editor_types_spec.rb @@ -13,7 +13,7 @@ click_on("Run") - within('.output-stdout') do + within(:output, :stdout) do expect(page).to have_content 'simple editor' end end diff --git a/tests/spec/features/highlighting_error_output_spec.rb b/tests/spec/features/highlighting_error_output_spec.rb index f72729d28..21625d6b1 100644 --- a/tests/spec/features/highlighting_error_output_spec.rb +++ b/tests/spec/features/highlighting_error_output_spec.rb @@ -5,11 +5,11 @@ before do visit '/' editor.set(code) - within('.header') { click_on("Run") } + within(:header) { click_on("Run") } end scenario "errors are highlighted" do - within('.output-stderr') do + within(:output, :stderr) do expect(page).to have_css '.error', text: '1 type argument but 2 type arguments were supplied' expect(page).to have_css '.error', text: 'aborting due to 2 previous errors' expect(page).to have_css '.error', text: /Could not compile `playground`/i @@ -17,19 +17,19 @@ end scenario "error locations are links" do - within('.output-stderr') do + within(:output, :stderr) do expect(page).to have_link('src/main.rs') end end scenario "github see-issues are links" do - within('.output-stderr') do + within(:output, :stderr) do expect(page).to have_link('see issue #23416 ', href: 'https://github.com/rust-lang/rust/issues/23416') end end scenario "error codes link to the error page" do - within('.output-stderr') do + within(:output, :stderr) do expect(page).to have_link('E0107', href: /error-index.html#E0107/) end end diff --git a/tests/spec/features/highlighting_mir_output_spec.rb b/tests/spec/features/highlighting_mir_output_spec.rb index efa473d45..f123f6fe7 100644 --- a/tests/spec/features/highlighting_mir_output_spec.rb +++ b/tests/spec/features/highlighting_mir_output_spec.rb @@ -12,7 +12,7 @@ end scenario "error locations are links" do - within('.output-mir') do + within(:output, :mir) do click_link('src/main.rs:4:14: 4:19', match: :first) end expect(editor).to have_highlighted_text('a + b') diff --git a/tests/spec/features/multiple_channels_spec.rb b/tests/spec/features/multiple_channels_spec.rb index 141f81f80..a77a0c182 100644 --- a/tests/spec/features/multiple_channels_spec.rb +++ b/tests/spec/features/multiple_channels_spec.rb @@ -14,7 +14,7 @@ in_channel_menu { click_on("Stable") } click_on("Run") - within('.output-stdout') do + within(:output, :stdout) do expect(page).to have_content 'rustc' expect(page).to_not have_content 'beta' expect(page).to_not have_content 'nightly' @@ -25,7 +25,7 @@ in_channel_menu { click_on("Beta") } click_on("Run") - within('.output-stdout') do + within(:output, :stdout) do expect(page).to have_content 'rustc' expect(page).to have_content 'beta' expect(page).to_not have_content 'nightly' @@ -36,7 +36,7 @@ in_channel_menu { click_on("Nightly") } click_on("Run") - within('.output-stdout') do + within(:output, :stdout) do expect(page).to have_content 'rustc' expect(page).to_not have_content 'beta' expect(page).to have_content 'nightly' diff --git a/tests/spec/features/sharing_with_others_spec.rb b/tests/spec/features/sharing_with_others_spec.rb index 637b3aa25..13e3b1b26 100644 --- a/tests/spec/features/sharing_with_others_spec.rb +++ b/tests/spec/features/sharing_with_others_spec.rb @@ -16,7 +16,7 @@ in_mode_menu { click_on("Release") } in_advanced_options_menu { choose("2018") } - within('.header') { click_on 'Share' } + within(:header) { click_on 'Share' } # Save the links before we navigate away perma_link = find_link("Permalink to the playground")[:href] diff --git a/tests/spec/features/tools_spec.rb b/tests/spec/features/tools_spec.rb index e95237dfe..2ec081006 100644 --- a/tests/spec/features/tools_spec.rb +++ b/tests/spec/features/tools_spec.rb @@ -13,16 +13,14 @@ editor.set 'fn main() { [1,2,3,4]; }' in_tools_menu { click_on("Rustfmt") } - within('.editor') do - expect(editor).to have_line '[1, 2, 3, 4];' - end + expect(editor).to have_line '[1, 2, 3, 4];' end scenario "linting code with Clippy" do editor.set code_with_lint_warnings in_tools_menu { click_on("Clippy") } - within(".output-stderr") do + within(:output, :stderr) do expect(page).to have_content 'deny(clippy::eq_op)' expect(page).to have_content 'warn(clippy::zero_divided_by_zero)' end @@ -43,7 +41,7 @@ def code_with_lint_warnings editor.set code_with_undefined_behavior in_tools_menu { click_on("Miri") } - within(".output-stderr") do + within(:output, :stderr) do expect(page).to have_content %r{pointer must be in-bounds at offset 1, but is outside bounds of alloc\d+ which has size 0}, wait: 10 end @@ -62,7 +60,7 @@ def code_with_undefined_behavior editor.set code_that_uses_macros in_tools_menu { click_on("Expand macros") } - within(".output-stdout") do + within(:output, :stdout) do # First-party expect(page).to have_content('core::fmt::Arguments::new_v1') diff --git a/tests/spec/features/url_parameters_spec.rb b/tests/spec/features/url_parameters_spec.rb index e19a755fd..31034b16c 100644 --- a/tests/spec/features/url_parameters_spec.rb +++ b/tests/spec/features/url_parameters_spec.rb @@ -40,7 +40,7 @@ scenario "loading from a Gist preserves the links" do visit '/?gist=20fb1e0475f890d0fdb7864e3ad0820c' - within('.output') { click_on 'Share' } + within(:output) { click_on 'Share' } expect(page).to have_link("Permalink to the playground", href: /gist=20fb1e0475f890d0fdb7864e3ad0820c/) end diff --git a/tests/spec/requests/cors_spec.rb b/tests/spec/requests/cors_spec.rb index d798a54b0..a4c051af3 100644 --- a/tests/spec/requests/cors_spec.rb +++ b/tests/spec/requests/cors_spec.rb @@ -1,7 +1,9 @@ + + require 'net/http' require 'spec_helper' -RSpec.feature "Cross-origin requests", type: :request do +RSpec.feature "Cross-origin requests", :cors, type: :request do let(:evaluate_json_uri) { URI.join(Capybara.app_host, '/evaluate.json') } it "allows preflight requests for POSTing to evaluate.json" do diff --git a/tests/spec/spec_helper.rb b/tests/spec/spec_helper.rb index 52c9f5670..4fb782488 100644 --- a/tests/spec/spec_helper.rb +++ b/tests/spec/spec_helper.rb @@ -63,5 +63,17 @@ Capybara.save_path = "./test-failures" Capybara.modify_selector(:link_or_button) do - expression_filter(:build_button) {|xpath, name| xpath[XPath.css('.button-menu-item__name').contains(name)] } + expression_filter(:build_button) {|xpath, name| xpath[XPath.css('[data-test-id="button-menu-item__name"]').contains(name)] } +end + +Capybara.add_selector(:header) do + css { |_id| "[data-test-id = 'header']" } +end + +Capybara.add_selector(:output) do + css do |id| + id_s = 'output' + id_s += "-#{id}" if id + "[data-test-id = '#{id_s}']" + end end diff --git a/tests/spec/support/editor.rb b/tests/spec/support/editor.rb index 5cfb34277..c3e7ab364 100644 --- a/tests/spec/support/editor.rb +++ b/tests/spec/support/editor.rb @@ -5,7 +5,7 @@ def initialize(page) end def set(text) - page.within('.editor .ace_text-input', visible: :any) do + page.within('.ace_text-input', visible: :any) do page.execute_script <<~JS window.rustPlayground.setCode(#{text.to_json}); JS @@ -17,7 +17,7 @@ def has_line?(text) end def has_highlighted_text?(text) - page.within('.editor .ace_text-input', visible: :any) do + page.within('.ace_text-input', visible: :any) do selected = page.evaluate_script <<~JS (() => { const editor = document.querySelector('.ace_editor').env.editor; diff --git a/ui/frontend/.babelrc b/ui/frontend/.babelrc index 6a7958afa..2e39f1724 100644 --- a/ui/frontend/.babelrc +++ b/ui/frontend/.babelrc @@ -5,7 +5,9 @@ "modules": false, "useBuiltIns": "entry", }], - "@babel/react" + [ "@babel/react", { + "runtime": "automatic", + }], ], "plugins": [ "lodash", diff --git a/ui/frontend/.prettierignore b/ui/frontend/.prettierignore new file mode 100644 index 000000000..99dda5005 --- /dev/null +++ b/ui/frontend/.prettierignore @@ -0,0 +1,10 @@ +build +node_modules + +# Not for these ready yet +.babelrc +*.js +*.json +*.ts +*.tsx +*.scss diff --git a/ui/frontend/.prettierrc.json b/ui/frontend/.prettierrc.json new file mode 100644 index 000000000..544138be4 --- /dev/null +++ b/ui/frontend/.prettierrc.json @@ -0,0 +1,3 @@ +{ + "singleQuote": true +} diff --git a/ui/frontend/.stylelintignore b/ui/frontend/.stylelintignore new file mode 100644 index 000000000..378eac25d --- /dev/null +++ b/ui/frontend/.stylelintignore @@ -0,0 +1 @@ +build diff --git a/ui/frontend/.stylelintrc.json b/ui/frontend/.stylelintrc.json new file mode 100644 index 000000000..f053dccd4 --- /dev/null +++ b/ui/frontend/.stylelintrc.json @@ -0,0 +1,14 @@ +{ + "extends": [ + "stylelint-config-standard", + "stylelint-config-css-modules", + "stylelint-config-idiomatic-order" + ], + "rules": { + "value-keyword-case": ["lower", { + "ignoreProperties": [ + "composes" + ] + }] + } +} diff --git a/ui/frontend/AdvancedEditor.tsx b/ui/frontend/AdvancedEditor.tsx index 35f27b4a9..0ba0a9cef 100644 --- a/ui/frontend/AdvancedEditor.tsx +++ b/ui/frontend/AdvancedEditor.tsx @@ -1,8 +1,11 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { connect } from 'react-redux'; +import { aceResizeKey } from './selectors'; import State from './state'; -import { CommonEditorProps, Crate, Edition, Focus, PairCharacters, Position, Selection } from './types'; +import { AceResizeKey, CommonEditorProps, Crate, Edition, PairCharacters, Position, Selection } from './types'; + +import styles from './Editor.module.css'; type Ace = typeof import('ace-builds'); type AceEditor = import('ace-builds').Ace.Editor; @@ -67,7 +70,7 @@ interface AdvancedEditorProps { selection: Selection; theme: string; crates: Crate[]; - focus?: Focus; + resizeKey?: AceResizeKey; pairCharacters: PairCharacters; } @@ -281,14 +284,14 @@ const AdvancedEditor: React.SFC = props => { // 4. Try to scroll // // Ace doesn't know that we changed the visible area and so - // doesn't recalculate. Knowing if the focus changed is enough - // to force such a recalculation. - useEditorProp(editor, props.focus, useCallback((editor, _focus) => { + // doesn't recalculate. We track factors that lead to this case to + // force such a recalculation. + useEditorProp(editor, props.resizeKey, useCallback((editor, _resizeKey) => { editor.resize(); }, [])); return ( -
+
); }; @@ -321,7 +324,7 @@ interface AdvancedEditorAsyncProps { selection: Selection; theme: string; crates: Crate[]; - focus?: Focus; + resizeKey?: AceResizeKey; pairCharacters: PairCharacters; } @@ -462,7 +465,7 @@ interface AdvancedEditorAsyncState { interface PropsFromState { theme: string; keybinding?: string; - focus?: Focus; + resizeKey?: AceResizeKey; autocompleteOnUse: boolean; pairCharacters: PairCharacters; } @@ -474,7 +477,7 @@ const mapStateToProps = (state: State) => { theme, pairCharacters, keybinding: keybinding === 'ace' ? null : keybinding, - focus: state.output.meta.focus, + resizeKey: aceResizeKey(state), autocompleteOnUse: state.configuration.edition === Edition.Rust2018, }; }; diff --git a/ui/frontend/BuildMenu.module.css b/ui/frontend/BuildMenu.module.css new file mode 100644 index 000000000..ba906e4e3 --- /dev/null +++ b/ui/frontend/BuildMenu.module.css @@ -0,0 +1,4 @@ +.code { + padding: 0 0.25em; + background: #eee; +} diff --git a/ui/frontend/BuildMenu.tsx b/ui/frontend/BuildMenu.tsx index 9a4ea349a..e755c0051 100644 --- a/ui/frontend/BuildMenu.tsx +++ b/ui/frontend/BuildMenu.tsx @@ -6,6 +6,9 @@ import * as selectors from './selectors'; import ButtonMenuItem from './ButtonMenuItem'; import MenuGroup from './MenuGroup'; +import MenuAside from './MenuAside'; + +import styles from './BuildMenu.module.css'; interface BuildMenuProps { close: () => void; @@ -40,15 +43,15 @@ const BuildMenu: React.SFC = props => { Build and run the code, showing the output. - Equivalent to cargo run. + Equivalent to cargo run. Build the code without running it. - Equivalent to cargo build. + Equivalent to cargo build. Build the code and run all the tests. - Equivalent to cargo test. + Equivalent to cargo test. Build and show the resulting assembly code. @@ -72,17 +75,17 @@ const BuildMenu: React.SFC = props => { }; const HirAside: React.SFC = () => ( -

+ Note: HIR currently requires using the Nightly channel, selecting this option will switch to Nightly. -

+ ); const WasmAside: React.SFC = () => ( -

+ Note: WASM currently requires using the Nightly channel, selecting this option will switch to Nightly. -

+ ); export default BuildMenu; diff --git a/ui/frontend/ButtonMenuItem.module.css b/ui/frontend/ButtonMenuItem.module.css new file mode 100644 index 000000000..b691a3c08 --- /dev/null +++ b/ui/frontend/ButtonMenuItem.module.css @@ -0,0 +1,16 @@ +.container { + composes: -menuItemFullButton from './shared.module.css'; + + &:hover { + color: var(--header-tint); + } +} + +.name { + composes: -menuItemTitle from './shared.module.css'; + margin: 0; +} + +.description { + margin: 0; +} diff --git a/ui/frontend/ButtonMenuItem.tsx b/ui/frontend/ButtonMenuItem.tsx index e802e47fa..1da72a580 100644 --- a/ui/frontend/ButtonMenuItem.tsx +++ b/ui/frontend/ButtonMenuItem.tsx @@ -2,6 +2,8 @@ import React from 'react'; import MenuItem from './MenuItem'; +import styles from './ButtonMenuItem.module.css'; + type Button = JSX.IntrinsicElements['button']; interface ButtonMenuItemProps extends Button { @@ -10,9 +12,9 @@ interface ButtonMenuItemProps extends Button { const ButtonMenuItem: React.SFC = ({ name, children, ...props }) => ( - ); diff --git a/ui/frontend/ChannelMenu.module.css b/ui/frontend/ChannelMenu.module.css new file mode 100644 index 000000000..cd2bed250 --- /dev/null +++ b/ui/frontend/ChannelMenu.module.css @@ -0,0 +1,3 @@ +.description { + margin: 0; +} diff --git a/ui/frontend/ChannelMenu.tsx b/ui/frontend/ChannelMenu.tsx index 202a52470..39c454366 100644 --- a/ui/frontend/ChannelMenu.tsx +++ b/ui/frontend/ChannelMenu.tsx @@ -9,6 +9,8 @@ import * as selectors from './selectors'; import State from './state'; import { Channel } from './types'; +import styles from './ChannelMenu.module.css'; + interface ChannelMenuProps { close: () => void; } @@ -62,7 +64,7 @@ const ChannelMenu: React.SFC = props => { }; const Desc: React.SFC<{}> = ({ children }) => ( -

{children}

+

{children}

); export default ChannelMenu; diff --git a/ui/frontend/ConfigElement.module.css b/ui/frontend/ConfigElement.module.css new file mode 100644 index 000000000..3082e239f --- /dev/null +++ b/ui/frontend/ConfigElement.module.css @@ -0,0 +1,68 @@ +.container { + display: flex; + align-items: center; +} + +.name { + flex: 1; + font-size: 13px; +} + +.notDefault { + composes: name; + color: var(--header-tint); + font-weight: 600; +} + +.value { + flex: 1; +} + +.select { + width: 100%; +} + +.toggle { + display: flex; + + & label { + $border: 1px solid #bbb; + + flex: 1; + padding: 0 1em; + border: $border; + border-right-width: 0; + border-bottom-left-radius: var(--header-border-radius); + border-top-left-radius: var(--header-border-radius); + color: #777; + cursor: pointer; + font-size: 11px; + font-weight: 600; + text-align: center; + text-transform: uppercase; + + & ~ label { + border-right-width: 1px; + border-left: $border; + border-radius: 0 var(--header-border-radius) var(--header-border-radius) 0; + } + + &:hover { + background: hsla(208, 100%, 43%, 0.1); + } + } + + & input { + display: none; + + &:checked + label { + border-color: var(--header-tint); + background: var(--header-tint); + color: #fff; + + & ~ label { + border-left-width: 0; + } + } + } +} diff --git a/ui/frontend/ConfigElement.tsx b/ui/frontend/ConfigElement.tsx index 77c86e389..e347f414b 100644 --- a/ui/frontend/ConfigElement.tsx +++ b/ui/frontend/ConfigElement.tsx @@ -2,6 +2,8 @@ import React from 'react'; import MenuItem from './MenuItem'; +import styles from './ConfigElement.module.css'; + interface EitherProps extends ConfigElementProps { id: string; a: string; @@ -15,7 +17,7 @@ interface EitherProps extends ConfigElementProps { export const Either: React.SFC = ({ id, a, b, aLabel = a, bLabel = b, value, onChange, ...rest }) => ( -
+
= ({ value, onChange, children, ...rest }) => ( - onChange(e.target.value)}> {children} @@ -54,9 +56,9 @@ interface ConfigElementProps { const ConfigElement: React.SFC = ({ name, isNotDefault, children }) => ( -
- {name} -
+
+ {name} +
{children}
diff --git a/ui/frontend/Editor.module.css b/ui/frontend/Editor.module.css new file mode 100644 index 000000000..365a1bdfa --- /dev/null +++ b/ui/frontend/Editor.module.css @@ -0,0 +1,14 @@ +.container { + composes: -autoSize from './shared.module.css'; + position: relative; +} + +.advanced { + composes: -bodyMonospace -autoSize from './shared.module.css'; + position: absolute; +} + +.simple { + composes: advanced; + border: none; +} diff --git a/ui/frontend/Editor.tsx b/ui/frontend/Editor.tsx index 400410dac..12f4003db 100644 --- a/ui/frontend/Editor.tsx +++ b/ui/frontend/Editor.tsx @@ -6,6 +6,8 @@ import AdvancedEditor from './AdvancedEditor'; import { CommonEditorProps, Editor as EditorType, Position, Selection } from './types'; import { State } from './reducers'; +import styles from './Editor.module.css'; + class CodeByteOffsets { readonly code: string; readonly lines: string[]; @@ -61,7 +63,7 @@ class SimpleEditor extends React.PureComponent { return (