Add modal and initial select
This commit is contained in:
parent
4a9ba8e2a3
commit
28d35026ef
38
jirs-client/js/css/issue.css
Normal file
38
jirs-client/js/css/issue.css
Normal file
@ -0,0 +1,38 @@
|
||||
.issueDetails > .content {
|
||||
display: flex;
|
||||
padding: 0 30px 60px;
|
||||
}
|
||||
|
||||
.issueDetails > .content > .left {
|
||||
width: 65%;
|
||||
padding-right: 50px;
|
||||
}
|
||||
|
||||
.issueDetails > .content > .right {
|
||||
width: 35%;
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
.issueDetails > .topActions {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 21px 18px 0;
|
||||
}
|
||||
|
||||
.issueDetails > .topActions > .topActionsRight {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.issueDetails > .topActions > .topActionsRight > * {
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.issueDetails > .sectionTitle {
|
||||
margin: 24px 0 5px;
|
||||
text-transform: uppercase;
|
||||
color: var(--textMedium);
|
||||
font-size: 12.5px;
|
||||
font-family: "CircularStdBold", serif;
|
||||
font-weight: normal
|
||||
}
|
98
jirs-client/js/css/styledSelect.css
Normal file
98
jirs-client/js/css/styledSelect.css
Normal file
@ -0,0 +1,98 @@
|
||||
.styledSelect {
|
||||
position: relative;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 14px
|
||||
}
|
||||
|
||||
.styledSelect.normal {
|
||||
width: 100%;
|
||||
border: 1px solid var(--borderLightest);
|
||||
background: var(--backgroundLightest);
|
||||
transition: background 0.1s;
|
||||
}
|
||||
|
||||
.styledSelect.empty {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.styledSelect:hover {
|
||||
background: var(--backgroundLight);
|
||||
}
|
||||
|
||||
.styledSelect:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.styledSelect.normal:focus {
|
||||
border: 1px solid var(--borderInputFocus);
|
||||
box-shadow: 0 0 0 1px var(--borderInputFocus);
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.styledSelect.invalid, .styledSelect.invalid:focus {
|
||||
border: 1px solid var(--danger);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.styledSelect > .dropDownInput {
|
||||
padding: 10px 14px 8px;
|
||||
width: 100%;
|
||||
border: none;
|
||||
color: var(--textDarkest);
|
||||
background: none;
|
||||
}
|
||||
|
||||
.styledSelect > .dropDownInput:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.styledSelect > .options {
|
||||
max-height: 200px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.styledSelect > .options::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
.styledSelect > .options::-webkit-scrollbar-track {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.styledSelect > .options::-webkit-scrollbar-thumb {
|
||||
border-radius: 99px;
|
||||
background: var(--backgroundMedium);
|
||||
}
|
||||
|
||||
.styledSelect > .options > .option {
|
||||
padding: 8px 14px;
|
||||
word-break: break-word;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.styledSelect > .options > .option:last-of-type {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.styledSelect > .options > .option.jira-select-option-is-active {
|
||||
background: var(--backgroundLightPrimary);
|
||||
}
|
||||
|
||||
.styledSelect > .noOptions {
|
||||
padding: 5px 15px 15px;
|
||||
color: var(--textLight);
|
||||
}
|
||||
|
||||
.styledSelect > .styledIcon {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
right: 7px;
|
||||
padding: 5px;
|
||||
font-size: 16px;
|
||||
color: var(--textMedium);
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
@ -4,10 +4,12 @@
|
||||
@import "css/global.css";
|
||||
@import "css/sidebar.css";
|
||||
@import "css/aside.css";
|
||||
@import "css/icon.css";
|
||||
@import "css/styledIcon.css";
|
||||
@import "css/shared.css";
|
||||
@import "css/styledTooltip.css";
|
||||
@import "css/styledAvatar.css";
|
||||
@import "css/styledSelect.css";
|
||||
@import "css/app.css";
|
||||
@import "css/modal.css";
|
||||
@import "css/issue.css";
|
||||
@import "css/project.css";
|
||||
|
@ -37,11 +37,13 @@ pub enum Msg {
|
||||
// dragging
|
||||
IssueDragStarted(IssueId),
|
||||
IssueDragStopped(IssueId),
|
||||
IssueDragOver(f64, f64),
|
||||
IssueDropZone(IssueStatus),
|
||||
|
||||
// issues
|
||||
IssueUpdateResult(FetchObject<String>),
|
||||
|
||||
// modals
|
||||
CloseModal,
|
||||
}
|
||||
|
||||
fn update(msg: Msg, model: &mut model::Model, orders: &mut impl Orders<Msg>) {
|
||||
@ -52,6 +54,9 @@ fn update(msg: Msg, model: &mut model::Model, orders: &mut impl Orders<Msg>) {
|
||||
Msg::ChangePage(page) => {
|
||||
model.page = page;
|
||||
}
|
||||
Msg::CloseModal => {
|
||||
model.modal = None;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
crate::shared::update(&msg, model, orders);
|
||||
|
@ -9,6 +9,11 @@ use crate::{IssueId, UserId, HOST_URL};
|
||||
|
||||
pub type ProjectId = i32;
|
||||
|
||||
#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialOrd, PartialEq)]
|
||||
pub enum ModalType {
|
||||
EditIssue(IssueId),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialOrd, PartialEq)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub enum Page {
|
||||
@ -47,12 +52,6 @@ pub struct UpdateProjectForm {
|
||||
pub fields: UpdateProjectPayload,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Default)]
|
||||
pub struct Point {
|
||||
pub x: f64,
|
||||
pub y: f64,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct ProjectPage {
|
||||
pub about_tooltip_visible: bool,
|
||||
@ -61,7 +60,6 @@ pub struct ProjectPage {
|
||||
pub only_my_filter: bool,
|
||||
pub recently_updated_filter: bool,
|
||||
pub dragged_issue_id: Option<IssueId>,
|
||||
pub drag_point: Point,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
@ -77,6 +75,7 @@ pub struct Model {
|
||||
pub page: Page,
|
||||
pub host_url: String,
|
||||
pub project_page: ProjectPage,
|
||||
pub modal: Option<ModalType>,
|
||||
}
|
||||
|
||||
impl Default for Model {
|
||||
@ -100,8 +99,8 @@ impl Default for Model {
|
||||
only_my_filter: false,
|
||||
recently_updated_filter: false,
|
||||
dragged_issue_id: None,
|
||||
drag_point: Point::default(),
|
||||
},
|
||||
modal: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,11 +2,13 @@ use seed::{prelude::*, *};
|
||||
|
||||
use jirs_data::*;
|
||||
|
||||
use crate::model::{Icon, Model, Page};
|
||||
use crate::model::{Icon, ModalType, Model, Page};
|
||||
use crate::shared::modal::{Modal, Variant as ModalVariant};
|
||||
use crate::shared::styled_avatar::StyledAvatar;
|
||||
use crate::shared::styled_button::{StyledButton, Variant};
|
||||
use crate::shared::styled_button::{StyledButton, Variant as ButtonVariant};
|
||||
use crate::shared::styled_input::StyledInput;
|
||||
use crate::shared::{drag_ev, inner_layout, ToNode};
|
||||
use crate::shared::styled_select::StyledSelect;
|
||||
use crate::shared::{drag_ev, find_issue, inner_layout, ToNode};
|
||||
use crate::Msg;
|
||||
|
||||
pub fn update(msg: Msg, model: &mut crate::model::Model, orders: &mut impl Orders<Msg>) {
|
||||
@ -19,6 +21,15 @@ pub fn update(msg: Msg, model: &mut crate::model::Model, orders: &mut impl Order
|
||||
.skip()
|
||||
.perform_cmd(crate::api::fetch_current_user(model.host_url.clone()));
|
||||
}
|
||||
Msg::ChangePage(Page::EditIssue(issue_id)) => {
|
||||
orders
|
||||
.skip()
|
||||
.perform_cmd(crate::api::fetch_current_project(model.host_url.clone()));
|
||||
orders
|
||||
.skip()
|
||||
.perform_cmd(crate::api::fetch_current_user(model.host_url.clone()));
|
||||
model.modal = Some(ModalType::EditIssue(issue_id));
|
||||
}
|
||||
Msg::ToggleAboutTooltip => {
|
||||
model.project_page.about_tooltip_visible = !model.project_page.about_tooltip_visible;
|
||||
}
|
||||
@ -58,10 +69,6 @@ pub fn update(msg: Msg, model: &mut crate::model::Model, orders: &mut impl Order
|
||||
Msg::IssueDragStopped(_) => {
|
||||
model.project_page.dragged_issue_id = None;
|
||||
}
|
||||
Msg::IssueDragOver(x, y) => {
|
||||
model.project_page.drag_point.x = x;
|
||||
model.project_page.drag_point.y = y;
|
||||
}
|
||||
Msg::IssueDropZone(status) => {
|
||||
match (
|
||||
model.project_page.dragged_issue_id.as_ref().cloned(),
|
||||
@ -116,6 +123,25 @@ pub fn update(msg: Msg, model: &mut crate::model::Model, orders: &mut impl Order
|
||||
}
|
||||
|
||||
pub fn view(model: &Model) -> Node<Msg> {
|
||||
let modal = match model.modal {
|
||||
Some(ModalType::EditIssue(issue_id)) => {
|
||||
if let Some(issue) = find_issue(model, issue_id) {
|
||||
let details = issue_details(model, issue);
|
||||
let modal = Modal {
|
||||
variant: ModalVariant::Center,
|
||||
width: 1040,
|
||||
with_icon: false,
|
||||
children: vec![details],
|
||||
}
|
||||
.into_node();
|
||||
Some(modal)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let project_section = vec![
|
||||
breadcrumbs(model),
|
||||
header(),
|
||||
@ -123,7 +149,7 @@ pub fn view(model: &Model) -> Node<Msg> {
|
||||
project_board_lists(model),
|
||||
];
|
||||
|
||||
inner_layout(model, "projectPage", project_section)
|
||||
inner_layout(model, "projectPage", project_section, modal)
|
||||
}
|
||||
|
||||
fn breadcrumbs(model: &Model) -> Node<Msg> {
|
||||
@ -144,7 +170,7 @@ fn breadcrumbs(model: &Model) -> Node<Msg> {
|
||||
|
||||
fn header() -> Node<Msg> {
|
||||
let button = StyledButton {
|
||||
variant: Variant::Secondary,
|
||||
variant: ButtonVariant::Secondary,
|
||||
icon_only: false,
|
||||
disabled: false,
|
||||
active: false,
|
||||
@ -175,7 +201,7 @@ fn project_board_filters(model: &Model) -> Node<Msg> {
|
||||
let project_page = &model.project_page;
|
||||
|
||||
let only_my = StyledButton {
|
||||
variant: Variant::Empty,
|
||||
variant: ButtonVariant::Empty,
|
||||
icon_only: false,
|
||||
disabled: false,
|
||||
active: model.project_page.only_my_filter,
|
||||
@ -186,7 +212,7 @@ fn project_board_filters(model: &Model) -> Node<Msg> {
|
||||
.into_node();
|
||||
|
||||
let recently_updated = StyledButton {
|
||||
variant: Variant::Empty,
|
||||
variant: ButtonVariant::Empty,
|
||||
icon_only: false,
|
||||
disabled: false,
|
||||
active: model.project_page.recently_updated_filter,
|
||||
@ -345,8 +371,10 @@ fn project_issue(model: &Model, project: &FullProject, issue: &Issue) -> Node<Ms
|
||||
class_list.push("hidden");
|
||||
}
|
||||
|
||||
let href = format!("/issues/{id}", id = issue_id);
|
||||
|
||||
a![
|
||||
attrs![At::Class => "issueLink"],
|
||||
attrs![At::Class => "issueLink"; At::Href => href],
|
||||
div![
|
||||
attrs![At::Class => class_list.join(" "), At::Draggable => true],
|
||||
drag_started,
|
||||
@ -363,3 +391,43 @@ fn project_issue(model: &Model, project: &FullProject, issue: &Issue) -> Node<Ms
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
impl ToNode for IssueType {
|
||||
fn into_node(self) -> Node<Msg> {
|
||||
div![self.to_string()]
|
||||
}
|
||||
}
|
||||
|
||||
fn issue_details(_model: &Model, _issue: &Issue) -> Node<Msg> {
|
||||
let issue_type_select = StyledSelect {
|
||||
on_change: mouse_ev(Ev::Click, |_| Msg::NoOp),
|
||||
variant: crate::shared::styled_select::Variant::Empty,
|
||||
width: 150,
|
||||
name: None,
|
||||
placeholder: None,
|
||||
valid: false,
|
||||
is_multi: false,
|
||||
allow_clear: true,
|
||||
options: vec![IssueType::Story, IssueType::Task, IssueType::Bug],
|
||||
}
|
||||
.into_node();
|
||||
|
||||
div![
|
||||
attrs![At::Class => "issueDetails"],
|
||||
div![
|
||||
attrs![At::Class => "topActions"],
|
||||
issue_type_select,
|
||||
div![attrs![At::Class => "topActionsRight"]],
|
||||
],
|
||||
div![
|
||||
attrs![At::Class => "content"],
|
||||
div![
|
||||
attrs![At::Class => "left"],
|
||||
div![attrs![At::Class => "title"]],
|
||||
div![attrs![At::Class => "description"]],
|
||||
div![attrs![At::Class => "comments"]],
|
||||
],
|
||||
div![attrs![At::Class => "right"]],
|
||||
],
|
||||
]
|
||||
}
|
||||
|
@ -8,5 +8,5 @@ pub fn update(_msg: Msg, _model: &mut model::Model, _orders: &mut impl Orders<Ms
|
||||
pub fn view(model: &model::Model) -> Node<Msg> {
|
||||
let project_section = vec![];
|
||||
|
||||
inner_layout(model, "projectSettings", project_section)
|
||||
inner_layout(model, "projectSettings", project_section, None)
|
||||
}
|
||||
|
@ -1,8 +1,10 @@
|
||||
use seed::{prelude::*, *};
|
||||
use wasm_bindgen::JsCast;
|
||||
|
||||
use jirs_data::Issue;
|
||||
|
||||
use crate::model::{Icon, Model};
|
||||
use crate::Msg;
|
||||
use crate::{IssueId, Msg};
|
||||
|
||||
pub mod aside;
|
||||
pub mod modal;
|
||||
@ -10,8 +12,16 @@ pub mod navbar_left;
|
||||
pub mod styled_avatar;
|
||||
pub mod styled_button;
|
||||
pub mod styled_input;
|
||||
pub mod styled_select;
|
||||
pub mod styled_tooltip;
|
||||
|
||||
pub fn find_issue(model: &Model, issue_id: IssueId) -> Option<&Issue> {
|
||||
match model.project.as_ref() {
|
||||
Some(p) => p.issues.iter().find(|issue| issue.id == issue_id),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ToNode {
|
||||
fn into_node(self) -> Node<Msg>;
|
||||
}
|
||||
@ -24,8 +34,18 @@ pub fn divider() -> Node<Msg> {
|
||||
div![attrs![At::Class => "divider"], ""]
|
||||
}
|
||||
|
||||
pub fn inner_layout(model: &Model, page_name: &str, children: Vec<Node<Msg>>) -> Node<Msg> {
|
||||
pub fn inner_layout(
|
||||
model: &Model,
|
||||
page_name: &str,
|
||||
children: Vec<Node<Msg>>,
|
||||
modal: Option<Node<Msg>>,
|
||||
) -> Node<Msg> {
|
||||
let modal_node = match modal {
|
||||
Some(modal) => vec![modal],
|
||||
_ => vec![],
|
||||
};
|
||||
article![
|
||||
modal_node,
|
||||
attrs![At::Class => "inner-layout"],
|
||||
id![page_name],
|
||||
navbar_left::render(model),
|
||||
|
@ -48,6 +48,7 @@ pub fn render(values: Modal) -> Node<Msg> {
|
||||
with_icon,
|
||||
children,
|
||||
} = values;
|
||||
|
||||
let icon = if with_icon {
|
||||
let mut styled_icon = styled_icon(Icon::Close);
|
||||
styled_icon.add_class(variant.to_icon_class_name().to_string());
|
||||
@ -56,6 +57,12 @@ pub fn render(values: Modal) -> Node<Msg> {
|
||||
empty![]
|
||||
};
|
||||
|
||||
let close_handler = mouse_ev(Ev::Click, |_| Msg::CloseModal);
|
||||
let body_handler = mouse_ev(Ev::Click, |ev| {
|
||||
ev.stop_propagation();
|
||||
Msg::NoOp
|
||||
});
|
||||
|
||||
let clickable_class = format!("clickableOverlay {}", variant.to_class_name());
|
||||
let styled_modal_class = format!("styledModal {}", variant.to_class_name());
|
||||
let styled_modal_style = format!("max-width: {width}px", width = width);
|
||||
@ -63,8 +70,10 @@ pub fn render(values: Modal) -> Node<Msg> {
|
||||
attrs![At::Class => "modal"],
|
||||
div![
|
||||
attrs![At::Class => clickable_class],
|
||||
close_handler,
|
||||
div![
|
||||
attrs![At::Class => styled_modal_class, At::Style => styled_modal_style],
|
||||
body_handler,
|
||||
icon,
|
||||
children
|
||||
]
|
||||
|
93
jirs-client/src/shared/styled_select.rs
Normal file
93
jirs-client/src/shared/styled_select.rs
Normal file
@ -0,0 +1,93 @@
|
||||
use seed::{prelude::*, *};
|
||||
|
||||
use crate::shared::ToNode;
|
||||
use crate::Msg;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum Variant {
|
||||
Empty,
|
||||
Normal,
|
||||
}
|
||||
|
||||
pub struct StyledSelect<Child>
|
||||
where
|
||||
Child: ToNode,
|
||||
{
|
||||
pub on_change: EventHandler<Msg>,
|
||||
pub variant: Variant,
|
||||
pub width: usize,
|
||||
pub name: Option<String>,
|
||||
pub placeholder: Option<String>,
|
||||
pub valid: bool,
|
||||
pub is_multi: bool,
|
||||
pub allow_clear: bool,
|
||||
pub options: Vec<Child>,
|
||||
}
|
||||
|
||||
impl<Child> ToNode for StyledSelect<Child>
|
||||
where
|
||||
Child: ToNode,
|
||||
{
|
||||
fn into_node(self) -> Node<Msg> {
|
||||
render(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render<Child>(values: StyledSelect<Child>) -> Node<Msg>
|
||||
where
|
||||
Child: ToNode,
|
||||
{
|
||||
let StyledSelect {
|
||||
on_change,
|
||||
variant,
|
||||
width,
|
||||
name,
|
||||
placeholder,
|
||||
valid,
|
||||
is_multi,
|
||||
allow_clear,
|
||||
options,
|
||||
} = values;
|
||||
|
||||
let select_style = format!("width: {width}px", width = width);
|
||||
let mut select_class = vec!["styledSelect"];
|
||||
if !valid {
|
||||
select_class.push("invalid");
|
||||
}
|
||||
|
||||
let children: Vec<Node<Msg>> = options
|
||||
.into_iter()
|
||||
.map(|child| render_option(child.into_node()))
|
||||
.collect();
|
||||
|
||||
let clear_icon = match allow_clear {
|
||||
true => crate::shared::styled_icon(crate::model::Icon::Close),
|
||||
false => empty![],
|
||||
};
|
||||
|
||||
seed::div![
|
||||
on_change.clone(),
|
||||
attrs![At::Class => "styledSelect", At::Style => select_style],
|
||||
seed::input![
|
||||
attrs![
|
||||
At::Class => "dropDownInput",
|
||||
At::Type => "text"
|
||||
At::Placeholder => "Search"
|
||||
At::AutoFocus => true,
|
||||
],
|
||||
on_change,
|
||||
],
|
||||
clear_icon,
|
||||
seed::div![
|
||||
attrs![
|
||||
At::Class => "options",
|
||||
],
|
||||
children
|
||||
],
|
||||
seed::div![attrs![At::Class => "noOptions"], "No results"]
|
||||
]
|
||||
}
|
||||
|
||||
pub fn render_option(content: Node<Msg>) -> Node<Msg> {
|
||||
seed::div![attrs![At::Class => "option"], content,]
|
||||
}
|
2
react-client/src/App/BaseStyles.js
vendored
2
react-client/src/App/BaseStyles.js
vendored
@ -49,7 +49,7 @@ export default createGlobalStyle`
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6, strong {
|
||||
${font.bold}
|
||||
font-family: "CircularStdBold"; font-weight: normal
|
||||
}
|
||||
|
||||
button {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { color, font } from 'shared/utils/styles';
|
||||
import { color } from 'shared/utils/styles';
|
||||
|
||||
export const Tip = styled.div`
|
||||
display: flex;
|
||||
@ -22,6 +22,6 @@ export const TipLetter = styled.span`
|
||||
border-radius: 2px;
|
||||
color: ${color.textDarkest};
|
||||
background: ${color.backgroundMedium};
|
||||
${font.bold}
|
||||
font-family: "CircularStdBold"; font-weight: normal
|
||||
font-size: 12px
|
||||
`;
|
||||
|
@ -1,6 +1,6 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { color, font } from 'shared/utils/styles';
|
||||
import { color } from 'shared/utils/styles';
|
||||
|
||||
export const Content = styled.div`
|
||||
display: flex;
|
||||
@ -36,5 +36,5 @@ export const SectionTitle = styled.div`
|
||||
text-transform: uppercase;
|
||||
color: ${color.textMedium};
|
||||
font-size: 12.5px
|
||||
${font.bold}
|
||||
font-family: "CircularStdBold"; font-weight: normal
|
||||
`;
|
||||
|
@ -1,10 +1,10 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { IssueType, IssueTypeCopy } from 'shared/constants/issues';
|
||||
import { IssueTypeIcon, Select } from 'shared/components';
|
||||
import { IssueType, IssueTypeCopy } from '../../../../shared/constants/issues';
|
||||
import { IssueTypeIcon, Select } from '../../../../shared/components';
|
||||
|
||||
import { TypeButton, Type, TypeLabel } from './Styles';
|
||||
import { Type, TypeButton, TypeLabel } from './Styles';
|
||||
|
||||
const propTypes = {
|
||||
issue: PropTypes.object.isRequired,
|
||||
|
@ -1,7 +1,7 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { color, font, mixin } from 'shared/utils/styles';
|
||||
import { InputDebounced, Spinner, Icon } from 'shared/components';
|
||||
import { color, font } from 'shared/utils/styles';
|
||||
import { Icon, InputDebounced, Spinner } from 'shared/components';
|
||||
|
||||
export const IssueSearch = styled.div`
|
||||
padding: 25px 35px 60px;
|
||||
@ -76,7 +76,7 @@ export const SectionTitle = styled.div`
|
||||
padding-bottom: 12px;
|
||||
text-transform: uppercase;
|
||||
color: ${color.textMedium};
|
||||
${font.bold}
|
||||
font-family: "CircularStdBold"; font-weight: normal
|
||||
font-size: 11.5px
|
||||
`;
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import styled from 'styled-components';
|
||||
import { NavLink } from 'react-router-dom';
|
||||
|
||||
import { font, sizes, color, mixin, zIndexValues } from 'shared/utils/styles';
|
||||
import { color, mixin, sizes, zIndexValues } from 'shared/utils/styles';
|
||||
import { Logo } from 'shared/components';
|
||||
|
||||
export const NavLeft = styled.aside`
|
||||
@ -71,7 +71,7 @@ export const ItemText = styled.div`
|
||||
text-transform: uppercase;
|
||||
transition: all 0.1s;
|
||||
transition-property: right, visibility, opacity;
|
||||
${font.bold}
|
||||
font-family: "CircularStdBold"; font-weight: normal
|
||||
font-size: 12px
|
||||
${NavLeft}:hover & {
|
||||
right: 0;
|
||||
|
2
react-client/src/Project/Sidebar/Styles.js
vendored
2
react-client/src/Project/Sidebar/Styles.js
vendored
@ -90,7 +90,7 @@ export const NotImplemented = styled.div`
|
||||
background: ${color.backgroundMedium};
|
||||
opacity: 0;
|
||||
font-size: 11.5px;
|
||||
${font.bold}
|
||||
font-family: "CircularStdBold"; font-weight: normal
|
||||
${LinkItem}:hover & {
|
||||
opacity: 1;
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ export const DateSection = styled.div`
|
||||
export const SelectedMonthYear = styled.div`
|
||||
display: inline-block;
|
||||
padding-left: 7px;
|
||||
${font.bold}
|
||||
font-family: "CircularStdBold"; font-weight: normal
|
||||
font-size: 16px
|
||||
`;
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
import React, { useState, useRef, useLayoutEffect } from 'react';
|
||||
import React, { useLayoutEffect, useRef, useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { uniq } from 'lodash';
|
||||
|
||||
import { KeyCodes } from 'shared/constants/keyCodes';
|
||||
import { KeyCodes } from '../../../shared/constants/keyCodes';
|
||||
|
||||
import { ClearIcon, Dropdown, DropdownInput, Options, Option, OptionsNoResults } from './Styles';
|
||||
import { ClearIcon, Dropdown, DropdownInput, Option, Options, OptionsNoResults } from './Styles';
|
||||
|
||||
const propTypes = {
|
||||
dropdownWidth: PropTypes.number,
|
||||
@ -179,8 +179,8 @@ const SelectDropdown = ({
|
||||
<DropdownInput
|
||||
type="text"
|
||||
placeholder="Search"
|
||||
ref={$inputRef}
|
||||
autoFocus
|
||||
ref={$inputRef}
|
||||
onKeyDown={handleInputKeyDown}
|
||||
onChange={event => setSearchValue(event.target.value)}
|
||||
/>
|
||||
|
@ -126,7 +126,7 @@ export const Options = styled.div`
|
||||
max-height: 200px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
${mixin.customScrollbar()};
|
||||
`;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useState, useRef } from 'react';
|
||||
import React, { useRef, useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import useOnOutsideClick from 'shared/hooks/onOutsideClick';
|
||||
@ -6,49 +6,7 @@ import { KeyCodes } from 'shared/constants/keyCodes';
|
||||
import Icon from 'shared/components/Icon';
|
||||
|
||||
import Dropdown from './Dropdown';
|
||||
import {
|
||||
StyledSelect,
|
||||
ValueContainer,
|
||||
ChevronIcon,
|
||||
Placeholder,
|
||||
ValueMulti,
|
||||
ValueMultiItem,
|
||||
AddMore,
|
||||
} from './Styles';
|
||||
|
||||
const propTypes = {
|
||||
className: PropTypes.string,
|
||||
variant: PropTypes.oneOf(['normal', 'empty']),
|
||||
dropdownWidth: PropTypes.number,
|
||||
name: PropTypes.string,
|
||||
value: PropTypes.oneOfType([PropTypes.array, PropTypes.string, PropTypes.number]),
|
||||
defaultValue: PropTypes.any,
|
||||
placeholder: PropTypes.string,
|
||||
invalid: PropTypes.bool,
|
||||
options: PropTypes.array.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
onCreate: PropTypes.func,
|
||||
isMulti: PropTypes.bool,
|
||||
withClearValue: PropTypes.bool,
|
||||
renderValue: PropTypes.func,
|
||||
renderOption: PropTypes.func,
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
className: undefined,
|
||||
variant: 'normal',
|
||||
dropdownWidth: undefined,
|
||||
name: undefined,
|
||||
value: undefined,
|
||||
defaultValue: undefined,
|
||||
placeholder: 'Select',
|
||||
invalid: false,
|
||||
onCreate: undefined,
|
||||
isMulti: false,
|
||||
withClearValue: true,
|
||||
renderValue: undefined,
|
||||
renderOption: undefined,
|
||||
};
|
||||
import { AddMore, ChevronIcon, Placeholder, StyledSelect, ValueContainer, ValueMulti, ValueMultiItem, } from './Styles';
|
||||
|
||||
const Select = ({
|
||||
className,
|
||||
@ -203,7 +161,37 @@ const Select = ({
|
||||
);
|
||||
};
|
||||
|
||||
Select.propTypes = propTypes;
|
||||
Select.defaultProps = defaultProps;
|
||||
Select.propTypes = {
|
||||
className: PropTypes.string,
|
||||
variant: PropTypes.oneOf(['normal', 'empty']),
|
||||
dropdownWidth: PropTypes.number,
|
||||
name: PropTypes.string,
|
||||
value: PropTypes.oneOfType([PropTypes.array, PropTypes.string, PropTypes.number]),
|
||||
defaultValue: PropTypes.any,
|
||||
placeholder: PropTypes.string,
|
||||
invalid: PropTypes.bool,
|
||||
options: PropTypes.array.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
onCreate: PropTypes.func,
|
||||
isMulti: PropTypes.bool,
|
||||
withClearValue: PropTypes.bool,
|
||||
renderValue: PropTypes.func,
|
||||
renderOption: PropTypes.func,
|
||||
};
|
||||
Select.defaultProps = {
|
||||
className: undefined,
|
||||
variant: 'normal',
|
||||
dropdownWidth: undefined,
|
||||
name: undefined,
|
||||
value: undefined,
|
||||
defaultValue: undefined,
|
||||
placeholder: 'Select',
|
||||
invalid: false,
|
||||
onCreate: undefined,
|
||||
isMulti: false,
|
||||
withClearValue: true,
|
||||
renderValue: undefined,
|
||||
renderOption: undefined,
|
||||
};
|
||||
|
||||
export default Select;
|
||||
|
4
react-client/src/shared/utils/styles.js
vendored
4
react-client/src/shared/utils/styles.js
vendored
@ -1,7 +1,7 @@
|
||||
import { css } from 'styled-components';
|
||||
import Color from 'color';
|
||||
|
||||
import { IssueType, IssueStatus, IssuePriority } from 'shared/constants/issues';
|
||||
import { IssuePriority, IssueStatus, IssueType } from 'shared/constants/issues';
|
||||
|
||||
export const color = {
|
||||
primary: '#0052cc', // Blue
|
||||
@ -174,7 +174,7 @@ export const mixin = {
|
||||
user-select: none;
|
||||
color: ${colorValue};
|
||||
background: ${background};
|
||||
${font.bold}
|
||||
font-family: "CircularStdBold"; font-weight: normal
|
||||
font-size: 12px
|
||||
i {
|
||||
margin-left: 4px;
|
||||
|
Loading…
Reference in New Issue
Block a user