Add edit epic and delete epic, refactor, fix drag sorting
This commit is contained in:
parent
7803e0fc3d
commit
1b8069103f
125
Cargo.lock
generated
125
Cargo.lock
generated
@ -1018,6 +1018,7 @@ dependencies = [
|
||||
"bitflags",
|
||||
"byteorder",
|
||||
"chrono",
|
||||
"derive_db_execute",
|
||||
"diesel",
|
||||
"dotenv",
|
||||
"env_logger",
|
||||
@ -1042,10 +1043,6 @@ dependencies = [
|
||||
"uuid 0.8.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "database-actor-derive"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "dbg"
|
||||
version = "1.0.4"
|
||||
@ -1055,6 +1052,10 @@ dependencies = [
|
||||
"version_check 0.1.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_db_execute"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "derive_enum_iter"
|
||||
version = "0.1.0"
|
||||
@ -1353,18 +1354,6 @@ dependencies = [
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
version = "0.2.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c122a393ea57648015bf06fbd3d372378992e86b9ff5a7a497b076a28c79efe"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.19"
|
||||
@ -1408,25 +1397,6 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fsevent"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ab7d1bd1bd33cc98b0889831b72da23c0aa4df9cec7e0702f46ecea04b35db6"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"fsevent-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fsevent-sys"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f41b048a94555da0f42f1d632e2e19510084fb8e303b0daa2816e733fb3644a0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-cprng"
|
||||
version = "0.1.1"
|
||||
@ -1605,12 +1575,6 @@ version = "0.23.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce"
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||
|
||||
[[package]]
|
||||
name = "gloo-events"
|
||||
version = "0.1.1"
|
||||
@ -1647,26 +1611,6 @@ dependencies = [
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gumdrop"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46571f5d540478cf70d2a42dd0d6d8e9f4b9cc7531544b93311e657b86568a0b"
|
||||
dependencies = [
|
||||
"gumdrop_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gumdrop_derive"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "915ef07c710d84733522461de2a734d4d62a3fd39a4d4f404c2f385ef8618d05"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.2.7"
|
||||
@ -1867,26 +1811,6 @@ dependencies = [
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inotify"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4816c66d2c8ae673df83366c18341538f234a26d65a9ecea5c348b453ac1d02f"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"inotify-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inotify-sys"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4563555856585ab3180a5bf0b2f9f8d301a728462afffc8195b3f5394229c55"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.9"
|
||||
@ -1963,15 +1887,6 @@ dependencies = [
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jirs-css"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"glob",
|
||||
"gumdrop",
|
||||
"notify",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jirs-data"
|
||||
version = "0.1.0"
|
||||
@ -2285,18 +2200,6 @@ dependencies = [
|
||||
"winapi 0.2.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio-extras"
|
||||
version = "2.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19"
|
||||
dependencies = [
|
||||
"lazycell",
|
||||
"log",
|
||||
"mio",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio-named-pipes"
|
||||
version = "0.1.7"
|
||||
@ -2381,24 +2284,6 @@ dependencies = [
|
||||
"version_check 0.1.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "notify"
|
||||
version = "4.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "80ae4a7688d1fab81c5bf19c64fc8db920be8d519ce6336ed4e7efe024724dbd"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"filetime",
|
||||
"fsevent",
|
||||
"fsevent-sys",
|
||||
"inotify",
|
||||
"libc",
|
||||
"mio",
|
||||
"mio-extras",
|
||||
"walkdir",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.2.6"
|
||||
|
@ -12,15 +12,14 @@
|
||||
members = [
|
||||
"./jirs-cli",
|
||||
"./jirs-server",
|
||||
"./jirs-css",
|
||||
"./shared/jirs-config",
|
||||
"./shared/jirs-data",
|
||||
"./derive/derive_enum_iter",
|
||||
"./derive/derive_enum_primitive",
|
||||
"./derive/derive_enum_sql",
|
||||
"./derive/derive_db_execute",
|
||||
"./actors/highlight-actor",
|
||||
"./actors/database-actor",
|
||||
"./actors/database-actor/database_actor-derive",
|
||||
"./actors/web-actor",
|
||||
"./actors/websocket-actor",
|
||||
"./actors/mail-actor",
|
||||
|
@ -54,6 +54,9 @@ features = ["database"]
|
||||
path = "../../shared/jirs-data"
|
||||
features = ["backend"]
|
||||
|
||||
[dependencies.derive_db_execute]
|
||||
path = "../../derive/derive_db_execute"
|
||||
|
||||
[dependencies.diesel]
|
||||
version = "1.4.5"
|
||||
features = ["unstable", "postgres", "numeric", "extras", "uuidv07"]
|
||||
|
@ -1,29 +1,54 @@
|
||||
use {
|
||||
crate::{
|
||||
db_create_with_conn, db_delete_with_conn, db_find, db_load, db_update_with_conn,
|
||||
models::Issue,
|
||||
},
|
||||
crate::models::Issue,
|
||||
derive_db_execute::Execute,
|
||||
diesel::{expression::sql_literal::sql, prelude::*},
|
||||
jirs_data::{IssueId, IssuePriority, IssueStatusId, IssueType, ProjectId, UserId},
|
||||
};
|
||||
|
||||
db_find! {
|
||||
LoadIssue,
|
||||
msg => issues => issues.filter(id.eq(msg.issue_id)).distinct(),
|
||||
Issue,
|
||||
issue_id => IssueId
|
||||
#[derive(Default, Execute)]
|
||||
#[db_exec(
|
||||
result = "Issue",
|
||||
schema = "issues",
|
||||
find = "issues.filter(id.eq(msg.issue_id)).distinct()"
|
||||
)]
|
||||
pub struct LoadIssue {
|
||||
pub issue_id: IssueId,
|
||||
}
|
||||
|
||||
db_load! {
|
||||
LoadProjectIssues,
|
||||
msg => issues => issues.filter(project_id.eq(msg.project_id)).distinct(),
|
||||
Issue,
|
||||
project_id => ProjectId
|
||||
#[derive(Execute)]
|
||||
#[db_exec(
|
||||
result = "Issue",
|
||||
schema = "issues",
|
||||
load = "issues.filter(project_id.eq(msg.project_id)).distinct()"
|
||||
)]
|
||||
pub struct LoadProjectIssues {
|
||||
pub project_id: ProjectId,
|
||||
}
|
||||
|
||||
db_update_with_conn! {
|
||||
UpdateIssue,
|
||||
msg => conn => issues => {
|
||||
#[derive(Default, Execute)]
|
||||
#[db_exec(result = "Issue", schema = "issues")]
|
||||
pub struct UpdateIssue {
|
||||
pub issue_id: i32,
|
||||
pub title: Option<String>,
|
||||
pub issue_type: Option<IssueType>,
|
||||
pub priority: Option<IssuePriority>,
|
||||
pub list_position: Option<i32>,
|
||||
pub description: Option<String>,
|
||||
pub description_text: Option<String>,
|
||||
pub estimate: Option<i32>,
|
||||
pub time_spent: Option<i32>,
|
||||
pub time_remaining: Option<i32>,
|
||||
pub project_id: Option<i32>,
|
||||
pub user_ids: Option<Vec<i32>>,
|
||||
pub reporter_id: Option<i32>,
|
||||
pub issue_status_id: Option<i32>,
|
||||
pub epic_id: Option<Option<i32>>,
|
||||
}
|
||||
|
||||
impl UpdateIssue {
|
||||
fn execute(self, conn: &crate::DbPooledConn) -> Result<Issue, crate::DatabaseError> {
|
||||
let msg = self;
|
||||
use crate::schema::issues::dsl::*;
|
||||
if let Some(user_ids) = msg.user_ids {
|
||||
crate::issue_assignees::DropIssueAssignees {
|
||||
issue_id: msg.issue_id,
|
||||
@ -44,7 +69,8 @@ db_update_with_conn! {
|
||||
}
|
||||
.execute(conn)?;
|
||||
}
|
||||
diesel::update(issues.find(msg.issue_id)).set((
|
||||
diesel::update(issues.find(msg.issue_id))
|
||||
.set((
|
||||
msg.title.map(|v| title.eq(v)),
|
||||
msg.issue_type.map(|v| issue_type.eq(v)),
|
||||
msg.issue_status_id.map(|v| issue_status_id.eq(v)),
|
||||
@ -60,46 +86,45 @@ db_update_with_conn! {
|
||||
msg.epic_id.map(|v| epic_id.eq(v)),
|
||||
updated_at.eq(chrono::Utc::now().naive_utc()),
|
||||
))
|
||||
},
|
||||
Issue,
|
||||
issue_id => i32,
|
||||
title => Option<String>,
|
||||
issue_type => Option<IssueType>,
|
||||
priority => Option<IssuePriority>,
|
||||
list_position => Option<i32>,
|
||||
description => Option<String>,
|
||||
description_text => Option<String>,
|
||||
estimate => Option<i32>,
|
||||
time_spent => Option<i32>,
|
||||
time_remaining => Option<i32>,
|
||||
project_id => Option<i32>,
|
||||
user_ids => Option<Vec<i32>>,
|
||||
reporter_id => Option<i32>,
|
||||
issue_status_id => Option<i32>,
|
||||
epic_id => Option<Option<i32>>
|
||||
.get_result(conn)
|
||||
.map_err(|e| {
|
||||
log::debug!("{:?}", e);
|
||||
crate::DatabaseError::GenericFailure(
|
||||
crate::OperationError::Create,
|
||||
crate::ResourceKind::Issue,
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
db_delete_with_conn! {
|
||||
DeleteIssue,
|
||||
msg => conn => issues => {
|
||||
#[derive(Execute)]
|
||||
#[db_exec(
|
||||
result = "Issue",
|
||||
schema = "issues",
|
||||
destroy = r#"{
|
||||
crate::issue_assignees::DeleteIssueAssignees { issue_id: msg.issue_id }
|
||||
.execute(conn)?;
|
||||
diesel::delete(issues.find(msg.issue_id))
|
||||
},
|
||||
Issue,
|
||||
issue_id => IssueId
|
||||
}"#
|
||||
)]
|
||||
pub struct DeleteIssue {
|
||||
pub issue_id: IssueId,
|
||||
}
|
||||
|
||||
mod inner {
|
||||
use {
|
||||
crate::{db_create, models::Issue},
|
||||
crate::models::Issue,
|
||||
derive_db_execute::Execute,
|
||||
diesel::prelude::*,
|
||||
jirs_data::{IssuePriority, IssueStatusId, IssueType},
|
||||
};
|
||||
|
||||
db_create! {
|
||||
CreateIssue,
|
||||
msg => issues => diesel::insert_into(issues)
|
||||
#[derive(Default, Execute)]
|
||||
#[db_exec(
|
||||
result = "Issue",
|
||||
schema = "issues",
|
||||
create = r#"
|
||||
diesel::insert_into(issues)
|
||||
.values((
|
||||
title.eq(msg.title),
|
||||
issue_type.eq(msg.issue_type),
|
||||
@ -115,27 +140,49 @@ mod inner {
|
||||
project_id.eq(msg.project_id),
|
||||
epic_id.eq(msg.epic_id)
|
||||
))
|
||||
.on_conflict_do_nothing(),
|
||||
Issue,
|
||||
title => String,
|
||||
list_position => i32,
|
||||
issue_type => IssueType,
|
||||
issue_status_id => IssueStatusId,
|
||||
priority => IssuePriority,
|
||||
description => Option<String>,
|
||||
description_text => Option<String>,
|
||||
estimate => Option<i32>,
|
||||
time_spent => Option<i32>,
|
||||
time_remaining => Option<i32>,
|
||||
project_id => jirs_data::ProjectId,
|
||||
reporter_id => jirs_data::UserId,
|
||||
epic_id => Option<jirs_data::EpicId>
|
||||
.on_conflict_do_nothing()
|
||||
"#
|
||||
)]
|
||||
pub struct CreateIssue {
|
||||
pub title: String,
|
||||
pub list_position: i32,
|
||||
pub issue_type: IssueType,
|
||||
pub issue_status_id: IssueStatusId,
|
||||
pub priority: IssuePriority,
|
||||
pub description: Option<String>,
|
||||
pub description_text: Option<String>,
|
||||
pub estimate: Option<i32>,
|
||||
pub time_spent: Option<i32>,
|
||||
pub time_remaining: Option<i32>,
|
||||
pub project_id: jirs_data::ProjectId,
|
||||
pub reporter_id: jirs_data::UserId,
|
||||
pub epic_id: Option<jirs_data::EpicId>,
|
||||
}
|
||||
}
|
||||
|
||||
db_create_with_conn! {
|
||||
CreateIssue,
|
||||
msg => conn => issues => {
|
||||
#[derive(Execute)]
|
||||
#[db_exec(result = "Issue", schema = "issues")]
|
||||
pub struct CreateIssue {
|
||||
pub title: String,
|
||||
pub issue_type: IssueType,
|
||||
pub issue_status_id: IssueStatusId,
|
||||
pub priority: IssuePriority,
|
||||
pub description: Option<String>,
|
||||
pub description_text: Option<String>,
|
||||
pub estimate: Option<i32>,
|
||||
pub time_spent: Option<i32>,
|
||||
pub time_remaining: Option<i32>,
|
||||
pub project_id: jirs_data::ProjectId,
|
||||
pub reporter_id: jirs_data::UserId,
|
||||
pub user_ids: Vec<jirs_data::UserId>,
|
||||
pub epic_id: Option<jirs_data::EpicId>,
|
||||
}
|
||||
|
||||
impl CreateIssue {
|
||||
fn execute(self, conn: &crate::DbPooledConn) -> Result<Issue, crate::DatabaseError> {
|
||||
use crate::schema::issues::dsl::*;
|
||||
let msg = self;
|
||||
|
||||
let pos = issues
|
||||
.select(sql("COALESCE(max(list_position), 0) + 1"))
|
||||
.get_result::<i32>(conn)
|
||||
@ -144,7 +191,9 @@ db_create_with_conn! {
|
||||
crate::DatabaseError::Issue(crate::IssueError::BadListPosition)
|
||||
})?;
|
||||
let i_s_id: IssueStatusId = if msg.issue_status_id == 0 {
|
||||
crate::issue_statuses::LoadIssueStatuses { project_id: msg.project_id }
|
||||
crate::issue_statuses::LoadIssueStatuses {
|
||||
project_id: msg.project_id,
|
||||
}
|
||||
.execute(conn)?
|
||||
.first()
|
||||
.ok_or_else(|| crate::DatabaseError::Issue(crate::IssueError::NoIssueStatuses))?
|
||||
@ -152,7 +201,8 @@ db_create_with_conn! {
|
||||
} else {
|
||||
msg.issue_status_id
|
||||
};
|
||||
let assign_users = msg.user_ids
|
||||
let assign_users = msg
|
||||
.user_ids
|
||||
.iter()
|
||||
.cloned()
|
||||
.filter(|u_id| *u_id != msg.reporter_id)
|
||||
@ -171,25 +221,18 @@ db_create_with_conn! {
|
||||
project_id: msg.project_id,
|
||||
reporter_id: msg.reporter_id,
|
||||
epic_id: msg.epic_id,
|
||||
}.execute(conn)?;
|
||||
}
|
||||
.execute(conn)?;
|
||||
crate::issue_assignees::AsignMultiple {
|
||||
issue_id: issue.id,
|
||||
user_ids: assign_users,
|
||||
};
|
||||
issues.find(issue.id)
|
||||
},
|
||||
Issue,
|
||||
title => String,
|
||||
issue_type => IssueType,
|
||||
issue_status_id => IssueStatusId,
|
||||
priority => IssuePriority,
|
||||
description => Option<String>,
|
||||
description_text => Option<String>,
|
||||
estimate => Option<i32>,
|
||||
time_spent => Option<i32>,
|
||||
time_remaining => Option<i32>,
|
||||
project_id => jirs_data::ProjectId,
|
||||
reporter_id => jirs_data::UserId,
|
||||
user_ids => Vec<jirs_data::UserId>,
|
||||
epic_id => Option<jirs_data::EpicId>
|
||||
issues.find(issue.id).get_result(conn).map_err(|e| {
|
||||
log::error!("{:?}", e);
|
||||
crate::DatabaseError::GenericFailure(
|
||||
crate::OperationError::Create,
|
||||
crate::ResourceKind::Issue,
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use {
|
||||
crate::{
|
||||
db_create_with_conn, db_delete, db_load,
|
||||
db_create, db_delete, db_load,
|
||||
users::{FindUser, LookupUser},
|
||||
},
|
||||
diesel::prelude::*,
|
||||
@ -30,7 +30,7 @@ pub enum CreateMessageReceiver {
|
||||
Lookup { name: String, email: String },
|
||||
}
|
||||
|
||||
db_create_with_conn! {
|
||||
db_create! {
|
||||
CreateMessage,
|
||||
msg => conn => messages => {
|
||||
let user: User = match msg.receiver {
|
||||
|
@ -147,12 +147,8 @@ macro_rules! db_load_field {
|
||||
#[macro_export]
|
||||
macro_rules! db_create {
|
||||
($action: ident, $self: ident => $schema: ident => $q: expr, $resource: ident, $($field: ident => $ty: ty),+) => {
|
||||
$crate::db_create_with_conn! { $action, $self => conn => $schema => $q, $resource, $($field => $ty),+ }
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! db_create_with_conn {
|
||||
$crate::db_create! { $action, $self => conn => $schema => $q, $resource, $($field => $ty),+ }
|
||||
};
|
||||
($action: ident, $self: ident => $conn: ident => $schema: ident => $q: expr, $resource: ident, $($field: ident => $ty: ty),+) => {
|
||||
pub struct $action {
|
||||
$(pub $field : $ty),+
|
||||
@ -191,15 +187,12 @@ macro_rules! db_create_with_conn {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! db_update {
|
||||
($action: ident, $self: ident => $schema: ident => $q: expr, $resource: ident, $($field: ident => $ty: ty),+) => {
|
||||
$crate::db_update_with_conn! { $action, $self => conn => $schema => $q, $resource, $($field => $ty),+ }
|
||||
$crate::db_update! { $action, $self => conn => $schema => $q, $resource, $($field => $ty),+ }
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! db_update_with_conn {
|
||||
($action: ident, $self: ident => $conn: ident => $schema: ident => $q: expr, $resource: ident, $($field: ident => $ty: ty),+) => {
|
||||
pub struct $action {
|
||||
$(pub $field : $ty),+
|
||||
@ -240,12 +233,8 @@ macro_rules! db_update_with_conn {
|
||||
#[macro_export]
|
||||
macro_rules! db_delete {
|
||||
($action: ident, $self: ident => $schema: ident => $q: expr, $resource: ident, $($field: ident => $ty: ty),+) => {
|
||||
$crate::db_delete_with_conn! { $action, $self => conn => $schema => $q, $resource, $($field => $ty),+ }
|
||||
$crate::db_delete! { $action, $self => conn => $schema => $q, $resource, $($field => $ty),+ }
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! db_delete_with_conn {
|
||||
($action: ident, $self: ident => $conn: ident => $schema: ident => $q: expr, $resource: ident, $($field: ident => $ty: ty),+) => {
|
||||
pub struct $action {
|
||||
$(pub $field : $ty),+
|
||||
|
@ -1,5 +1,5 @@
|
||||
use {
|
||||
crate::{db_create_with_conn, db_find, db_load, db_update},
|
||||
crate::{db_create, db_find, db_load, db_update},
|
||||
diesel::prelude::*,
|
||||
jirs_data::{NameString, Project, ProjectCategory, ProjectId, TimeTracking, UserId},
|
||||
};
|
||||
@ -38,7 +38,7 @@ mod inner {
|
||||
}
|
||||
}
|
||||
|
||||
db_create_with_conn! {
|
||||
db_create! {
|
||||
CreateProject,
|
||||
msg => conn => projects => {
|
||||
let p = inner::CreateProject {
|
||||
|
@ -1,5 +1,5 @@
|
||||
use {
|
||||
crate::{db_create, db_find, db_update_with_conn},
|
||||
crate::{db_create, db_find, db_update},
|
||||
diesel::prelude::*,
|
||||
jirs_data::{Token, UserId},
|
||||
};
|
||||
@ -18,7 +18,7 @@ db_find! {
|
||||
token => uuid::Uuid
|
||||
}
|
||||
|
||||
db_update_with_conn! {
|
||||
db_update! {
|
||||
UseBindToken,
|
||||
msg => conn => tokens => {
|
||||
let token = FindBindToken { token: msg.token }.execute(conn)?;
|
||||
|
@ -1,5 +1,5 @@
|
||||
use {
|
||||
crate::{db_create, db_delete_with_conn, db_find, db_load, db_update_with_conn},
|
||||
crate::{db_create, db_delete, db_find, db_load, db_update},
|
||||
diesel::prelude::*,
|
||||
jirs_data::{ProjectId, UserId, UserProject, UserProjectId, UserRole},
|
||||
};
|
||||
@ -48,7 +48,7 @@ mod inner {
|
||||
}
|
||||
}
|
||||
|
||||
db_update_with_conn! {
|
||||
db_update! {
|
||||
ChangeCurrentUserProject,
|
||||
msg => conn => user_projects => {
|
||||
FindUserProject {
|
||||
@ -91,7 +91,7 @@ db_find! {
|
||||
role => UserRole
|
||||
}
|
||||
|
||||
db_delete_with_conn! {
|
||||
db_delete! {
|
||||
RemoveInvitedUser,
|
||||
msg => conn => user_projects => {
|
||||
if msg.invited_id == msg.inviter_id {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use {
|
||||
crate::{
|
||||
db_create, db_create_with_conn, db_find, db_load, db_update, projects::CreateProject, q,
|
||||
db_create, db_find, db_load, db_update, projects::CreateProject, q,
|
||||
user_projects::CreateUserProject, DbPooledConn,
|
||||
},
|
||||
diesel::prelude::*,
|
||||
@ -64,7 +64,7 @@ db_create! {
|
||||
email => EmailString
|
||||
}
|
||||
|
||||
db_create_with_conn! {
|
||||
db_create! {
|
||||
Register,
|
||||
msg => conn => users => {
|
||||
if count_matching_users(msg.name.as_str(), msg.email.as_str(), conn) > 0 {
|
||||
|
@ -1,3 +1,4 @@
|
||||
use jirs_data::{EpicId, IssueStatusId, ListPosition};
|
||||
use {
|
||||
crate::{WebSocketActor, WsHandler, WsResult},
|
||||
database_actor::{
|
||||
@ -148,7 +149,7 @@ impl WsHandler<UpdateIssueHandler> for WebSocketActor {
|
||||
return Ok(None);
|
||||
}
|
||||
Err(e) => {
|
||||
error!("{}", e);
|
||||
error!("{:?}", e);
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
@ -187,7 +188,7 @@ impl WsHandler<CreateIssuePayload> for WebSocketActor {
|
||||
return Ok(None);
|
||||
}
|
||||
Err(e) => {
|
||||
error!("{}", e);
|
||||
error!("{:?}", e);
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
@ -212,7 +213,7 @@ impl WsHandler<DeleteIssue> for WebSocketActor {
|
||||
return Ok(None);
|
||||
}
|
||||
Err(e) => {
|
||||
error!("{}", e);
|
||||
error!("{:?}", e);
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
@ -255,3 +256,25 @@ impl WsHandler<LoadIssues> for WebSocketActor {
|
||||
Ok(Some(WsMsg::ProjectIssuesLoaded(issues)))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SyncIssueListPosition(pub Vec<(IssueId, ListPosition, IssueStatusId, Option<EpicId>)>);
|
||||
|
||||
impl WsHandler<SyncIssueListPosition> for WebSocketActor {
|
||||
fn handle_msg(&mut self, msg: SyncIssueListPosition, ctx: &mut Self::Context) -> WsResult {
|
||||
let _project_id = self.require_user_project()?.project_id;
|
||||
for (issue_id, list_position, status_id, epic_id) in msg.0 {
|
||||
match block_on(self.db.send(database_actor::issues::UpdateIssue {
|
||||
issue_id,
|
||||
list_position: Some(list_position),
|
||||
issue_status_id: Some(status_id),
|
||||
epic_id: Some(epic_id),
|
||||
..Default::default()
|
||||
})) {
|
||||
Ok(Ok(_)) => (),
|
||||
_ => return Ok(None),
|
||||
};
|
||||
}
|
||||
|
||||
self.handle_msg(LoadIssues, ctx)
|
||||
}
|
||||
}
|
||||
|
@ -94,6 +94,9 @@ impl WebSocketActor {
|
||||
)?,
|
||||
WsMsg::IssueCreate(payload) => self.handle_msg(payload, ctx)?,
|
||||
WsMsg::IssueDelete(id) => self.handle_msg(DeleteIssue { id }, ctx)?,
|
||||
WsMsg::IssueSyncListPosition(sync) => {
|
||||
self.handle_msg(SyncIssueListPosition(sync), ctx)?
|
||||
}
|
||||
WsMsg::ProjectIssuesLoad => self.handle_msg(LoadIssues, ctx)?,
|
||||
|
||||
// issue statuses
|
||||
|
@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "database-actor-derive"
|
||||
name = "derive_db_execute"
|
||||
version = "0.1.0"
|
||||
authors = ["Adrian Wozniak <adrian.wozniak@ita-prog.pl>"]
|
||||
edition = "2018"
|
||||
@ -9,9 +9,8 @@ license = "MPL-2.0"
|
||||
#license-file = "../LICENSE"
|
||||
|
||||
[lib]
|
||||
name = "database_actor_derive"
|
||||
name = "derive_db_execute"
|
||||
path = "./src/lib.rs"
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
|
270
derive/derive_db_execute/src/lib.rs
Normal file
270
derive/derive_db_execute/src/lib.rs
Normal file
@ -0,0 +1,270 @@
|
||||
mod parse_attr;
|
||||
mod utils;
|
||||
|
||||
extern crate proc_macro;
|
||||
|
||||
use crate::parse_attr::Attributes;
|
||||
use proc_macro::{token_stream::IntoIter, TokenStream, TokenTree};
|
||||
use std::iter::Peekable;
|
||||
|
||||
fn parse_meta(mut it: Peekable<IntoIter>) -> (Peekable<IntoIter>, Option<Attributes>) {
|
||||
let mut attrs: Option<Attributes> = None;
|
||||
while let Some(token) = it.peek() {
|
||||
match token {
|
||||
// lookup for attr
|
||||
TokenTree::Punct(p) if p.as_char() == '#' => {
|
||||
let res = parse_attr::parse(it);
|
||||
it = res.0;
|
||||
attrs = res.1;
|
||||
}
|
||||
TokenTree::Ident(_) => {
|
||||
break;
|
||||
}
|
||||
_ => {
|
||||
eprintln!("skip token {:#?}", token);
|
||||
it.next();
|
||||
}
|
||||
};
|
||||
}
|
||||
(it, attrs)
|
||||
}
|
||||
|
||||
#[proc_macro_derive(Execute, attributes(db_exec))]
|
||||
pub fn derive_enum_iter(item: TokenStream) -> TokenStream {
|
||||
let mut it = item.into_iter().peekable();
|
||||
let res = parse_meta(it);
|
||||
it = res.0;
|
||||
let attrs = res.1.expect("Result meta attribute is required");
|
||||
let result = attrs
|
||||
.result
|
||||
.expect("Meta attribute `result` is required. Try add db_exec(result = \"foo\")");
|
||||
let schema = attrs
|
||||
.schema
|
||||
.expect("Meta attribute `schema` is required. Try add db_exec(schema = \"foo\")");
|
||||
|
||||
it = utils::skip_pub(it);
|
||||
it = utils::skip_struct(it);
|
||||
|
||||
let name = it
|
||||
.next()
|
||||
.expect("Expect to struct name but nothing was found")
|
||||
.to_string();
|
||||
|
||||
let action_result = if attrs.load.is_some() {
|
||||
format!("Vec<{}>", result)
|
||||
} else if attrs.destroy.is_some() {
|
||||
"usize".to_string()
|
||||
} else {
|
||||
result.clone()
|
||||
};
|
||||
|
||||
let query = if let Some(q) = attrs.find {
|
||||
build_find_exec(&name, &result, &schema, &q, &action_result)
|
||||
} else if let Some(q) = attrs.load {
|
||||
build_load_exec(&name, &result, &schema, &q, &action_result)
|
||||
} else if let Some(q) = attrs.update {
|
||||
build_update_exec(&name, &result, &schema, &q, &action_result)
|
||||
} else if let Some(q) = attrs.destroy {
|
||||
build_destroy_exec(&name, &result, &schema, &q, &action_result)
|
||||
} else if let Some(q) = attrs.create {
|
||||
build_create_exec(&name, &result, &schema, &q, &action_result)
|
||||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
|
||||
let code = format!(
|
||||
r#"
|
||||
impl actix::Message for {name} {{
|
||||
type Result = Result<{action_result}, crate::DatabaseError>;
|
||||
}}
|
||||
|
||||
impl actix::Handler<{name}> for crate::DbExecutor {{
|
||||
type Result = Result<{action_result}, crate::DatabaseError>;
|
||||
|
||||
fn handle(&mut self, msg: {name}, _ctx: &mut Self::Context) -> Self::Result {{
|
||||
let conn = crate::db_pool!(self);
|
||||
|
||||
msg.execute(conn)
|
||||
}}
|
||||
}}
|
||||
|
||||
{query}
|
||||
"#,
|
||||
name = name,
|
||||
query = query,
|
||||
action_result = action_result
|
||||
);
|
||||
code.parse().unwrap()
|
||||
}
|
||||
|
||||
fn build_create_exec(
|
||||
name: &str,
|
||||
resource: &str,
|
||||
schema: &str,
|
||||
query: &str,
|
||||
action_result: &str,
|
||||
) -> String {
|
||||
format!(
|
||||
r#"
|
||||
impl {name} {{
|
||||
pub fn execute(
|
||||
self,
|
||||
conn: &crate::DbPooledConn,
|
||||
) -> Result<{action_result}, crate::DatabaseError> {{
|
||||
crate::Guard::new(conn)?.run(|_guard| {{
|
||||
use crate::schema::{schema}::dsl::*;
|
||||
let msg = self;
|
||||
crate::q!({query}).get_result(conn).map_err(|e| {{
|
||||
log::error!("{{:?}}", e);
|
||||
crate::DatabaseError::GenericFailure(
|
||||
crate::OperationError::Create,
|
||||
crate::ResourceKind::{resource},
|
||||
)
|
||||
}})
|
||||
}})
|
||||
}}
|
||||
}}
|
||||
"#,
|
||||
name = name,
|
||||
schema = schema,
|
||||
query = query,
|
||||
resource = resource,
|
||||
action_result = action_result
|
||||
)
|
||||
}
|
||||
|
||||
fn build_find_exec(
|
||||
name: &str,
|
||||
resource: &str,
|
||||
schema: &str,
|
||||
query: &str,
|
||||
action_result: &str,
|
||||
) -> String {
|
||||
format!(
|
||||
r#"
|
||||
impl {name} {{
|
||||
pub fn execute(
|
||||
self,
|
||||
conn: &crate::DbPooledConn,
|
||||
) -> Result<{action_result}, crate::DatabaseError> {{
|
||||
use crate::schema::{schema}::dsl::*;
|
||||
let msg = self;
|
||||
crate::q!({query}).first(conn).map_err(|e| {{
|
||||
log::error!("{{:?}}", e);
|
||||
crate::DatabaseError::GenericFailure(
|
||||
crate::OperationError::LoadSingle,
|
||||
crate::ResourceKind::{resource},
|
||||
)
|
||||
}})
|
||||
}}
|
||||
}}
|
||||
"#,
|
||||
name = name,
|
||||
schema = schema,
|
||||
query = query,
|
||||
resource = resource,
|
||||
action_result = action_result
|
||||
)
|
||||
}
|
||||
|
||||
fn build_load_exec(
|
||||
name: &str,
|
||||
resource: &str,
|
||||
schema: &str,
|
||||
query: &str,
|
||||
action_result: &str,
|
||||
) -> String {
|
||||
format!(
|
||||
r#"
|
||||
impl {name} {{
|
||||
pub fn execute(
|
||||
self,
|
||||
conn: &crate::DbPooledConn,
|
||||
) -> Result<{action_result}, crate::DatabaseError> {{
|
||||
use crate::schema::{schema}::dsl::*;
|
||||
let msg = self;
|
||||
crate::q!({query}).load(conn).map_err(|e| {{
|
||||
log::error!("{{:?}}", e);
|
||||
crate::DatabaseError::GenericFailure(
|
||||
crate::OperationError::LoadCollection,
|
||||
crate::ResourceKind::{resource},
|
||||
)
|
||||
}})
|
||||
}}
|
||||
}}
|
||||
"#,
|
||||
name = name,
|
||||
schema = schema,
|
||||
query = query,
|
||||
resource = resource,
|
||||
action_result = action_result
|
||||
)
|
||||
}
|
||||
|
||||
fn build_update_exec(
|
||||
name: &str,
|
||||
resource: &str,
|
||||
schema: &str,
|
||||
query: &str,
|
||||
action_result: &str,
|
||||
) -> String {
|
||||
format!(
|
||||
r#"
|
||||
impl {name} {{
|
||||
pub fn execute(
|
||||
self,
|
||||
conn: &crate::DbPooledConn,
|
||||
) -> Result<{action_result}, crate::DatabaseError> {{
|
||||
use crate::schema::{schema}::dsl::*;
|
||||
let msg = self;
|
||||
crate::q!({query}).get_result(conn).map_err(|e| {{
|
||||
log::error!("{{:?}}", e);
|
||||
crate::DatabaseError::GenericFailure(
|
||||
crate::OperationError::Update,
|
||||
crate::ResourceKind::{resource},
|
||||
)
|
||||
}})
|
||||
}}
|
||||
}}
|
||||
"#,
|
||||
name = name,
|
||||
schema = schema,
|
||||
query = query,
|
||||
resource = resource,
|
||||
action_result = action_result
|
||||
)
|
||||
}
|
||||
|
||||
fn build_destroy_exec(
|
||||
name: &str,
|
||||
resource: &str,
|
||||
schema: &str,
|
||||
query: &str,
|
||||
action_result: &str,
|
||||
) -> String {
|
||||
format!(
|
||||
r#"
|
||||
impl {name} {{
|
||||
pub fn execute(
|
||||
self,
|
||||
conn: &crate::DbPooledConn,
|
||||
) -> Result<{action_result}, crate::DatabaseError> {{
|
||||
use crate::schema::{schema}::dsl::*;
|
||||
let msg = self;
|
||||
crate::q!({query}).execute(conn).map_err(|e| {{
|
||||
log::error!("{{:?}}", e);
|
||||
crate::DatabaseError::GenericFailure(
|
||||
crate::OperationError::Delete,
|
||||
crate::ResourceKind::{resource},
|
||||
)
|
||||
}})
|
||||
}}
|
||||
}}
|
||||
"#,
|
||||
name = name,
|
||||
schema = schema,
|
||||
query = query,
|
||||
resource = resource,
|
||||
action_result = action_result
|
||||
)
|
||||
}
|
101
derive/derive_db_execute/src/parse_attr.rs
Normal file
101
derive/derive_db_execute/src/parse_attr.rs
Normal file
@ -0,0 +1,101 @@
|
||||
use proc_macro::{token_stream::IntoIter, TokenTree};
|
||||
use std::iter::Peekable;
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct Attributes {
|
||||
pub result: Option<String>,
|
||||
pub schema: Option<String>,
|
||||
pub find: Option<String>,
|
||||
pub load: Option<String>,
|
||||
pub create: Option<String>,
|
||||
pub destroy: Option<String>,
|
||||
pub update: Option<String>,
|
||||
}
|
||||
|
||||
pub fn parse(mut it: Peekable<IntoIter>) -> (Peekable<IntoIter>, Option<Attributes>) {
|
||||
it.next();
|
||||
let group = if let Some(TokenTree::Group(group)) = it.next() {
|
||||
group
|
||||
} else {
|
||||
panic!("Expect meta group");
|
||||
};
|
||||
let mut git = group.stream().into_iter();
|
||||
let ident = if let Some(TokenTree::Ident(ident)) = git.next() {
|
||||
ident
|
||||
} else {
|
||||
panic!("Expect attribute name")
|
||||
};
|
||||
if ident.to_string().as_str() != "db_exec" {
|
||||
return (it, None);
|
||||
}
|
||||
|
||||
let group = if let Some(TokenTree::Group(group)) = git.next() {
|
||||
group
|
||||
} else {
|
||||
panic!("Expect attribute name")
|
||||
};
|
||||
(it, Some(parse_db_exec(group.stream().into_iter())))
|
||||
}
|
||||
|
||||
fn parse_db_exec(mut it: IntoIter) -> Attributes {
|
||||
let mut attrs = Attributes::default();
|
||||
while let Some(token) = it.next() {
|
||||
let ident = if let TokenTree::Ident(ident) = token {
|
||||
ident
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
match ident.to_string().as_str() {
|
||||
"result" => {
|
||||
attrs.result = Some(fetch_name(&mut it));
|
||||
}
|
||||
"schema" => {
|
||||
attrs.schema = Some(fetch_name(&mut it));
|
||||
}
|
||||
"find" => {
|
||||
attrs.find = Some(fetch_name(&mut it));
|
||||
}
|
||||
"load" => {
|
||||
attrs.load = Some(fetch_name(&mut it));
|
||||
}
|
||||
"create" => {
|
||||
attrs.create = Some(fetch_name(&mut it));
|
||||
}
|
||||
"destroy" => {
|
||||
attrs.destroy = Some(fetch_name(&mut it));
|
||||
}
|
||||
"update" => {
|
||||
attrs.update = Some(fetch_name(&mut it));
|
||||
}
|
||||
_ => continue,
|
||||
};
|
||||
}
|
||||
attrs
|
||||
}
|
||||
|
||||
fn fetch_name(it: &mut IntoIter) -> String {
|
||||
if let Some(TokenTree::Punct(_)) = it.next() {
|
||||
} else {
|
||||
panic!("Expect equal token");
|
||||
}
|
||||
let lit = if let Some(TokenTree::Literal(lit)) = it.next() {
|
||||
lit
|
||||
} else {
|
||||
panic!("Expect type name as string");
|
||||
};
|
||||
let mut name = lit.to_string();
|
||||
|
||||
if name.starts_with('"') {
|
||||
name.remove(0);
|
||||
name.remove(name.len() - 1);
|
||||
} else if name.starts_with("r#\"") {
|
||||
name.remove(0);
|
||||
name.remove(0);
|
||||
name.remove(0);
|
||||
name.remove(name.len() - 1);
|
||||
name.remove(name.len() - 1);
|
||||
}
|
||||
let name = name.trim();
|
||||
|
||||
name.to_string()
|
||||
}
|
@ -1,10 +1,7 @@
|
||||
extern crate proc_macro;
|
||||
use proc_macro::{token_stream::IntoIter, TokenTree};
|
||||
use std::iter::Peekable;
|
||||
|
||||
use proc_macro::{TokenStream, TokenTree};
|
||||
|
||||
#[proc_macro_derive(DbMsg, attributes(query))]
|
||||
pub fn db_msg(item: TokenStream) -> TokenStream {
|
||||
let mut it = item.into_iter();
|
||||
pub fn skip_pub(mut it: Peekable<IntoIter>) -> Peekable<IntoIter> {
|
||||
if let Some(TokenTree::Ident(ident)) = it.next() {
|
||||
if ident.to_string().as_str() != "pub" {
|
||||
panic!("Expect to find keyword pub but was found {:?}", ident)
|
||||
@ -12,6 +9,10 @@ pub fn db_msg(item: TokenStream) -> TokenStream {
|
||||
} else {
|
||||
panic!("Expect to find keyword pub but nothing was found")
|
||||
}
|
||||
it
|
||||
}
|
||||
|
||||
pub fn skip_struct(mut it: Peekable<IntoIter>) -> Peekable<IntoIter> {
|
||||
if let Some(TokenTree::Ident(ident)) = it.next() {
|
||||
if ident.to_string().as_str() != "struct" {
|
||||
panic!("Expect to find keyword struct but was found {:?}", ident)
|
||||
@ -19,9 +20,5 @@ pub fn db_msg(item: TokenStream) -> TokenStream {
|
||||
} else {
|
||||
panic!("Expect to find keyword struct but nothing was found")
|
||||
}
|
||||
let _name = it
|
||||
.next()
|
||||
.expect("Expect to struct name but nothing was found");
|
||||
|
||||
"".parse().unwrap()
|
||||
it
|
||||
}
|
16
derive/derive_utils/Cargo.toml
Normal file
16
derive/derive_utils/Cargo.toml
Normal file
@ -0,0 +1,16 @@
|
||||
[package]
|
||||
name = "derive_utils"
|
||||
version = "0.1.0"
|
||||
authors = ["Adrian Wozniak <adrian.wozniak@ita-prog.pl>"]
|
||||
edition = "2018"
|
||||
description = "JIRS (Simplified JIRA in Rust) shared data types"
|
||||
repository = "https://gitlab.com/adrian.wozniak/jirs"
|
||||
license = "MPL-2.0"
|
||||
#license-file = "../LICENSE"
|
||||
|
||||
[lib]
|
||||
name = "derive_utils"
|
||||
path = "./src/lib.rs"
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
35
derive/derive_utils/src/lib.rs
Normal file
35
derive/derive_utils/src/lib.rs
Normal file
@ -0,0 +1,35 @@
|
||||
use proc_macro::{token_stream::IntoIter, TokenTree};
|
||||
use std::iter::Peekable;
|
||||
|
||||
pub fn skip_pub(mut it: Peekable<IntoIter>) -> Peekable<IntoIter> {
|
||||
if let Some(TokenTree::Ident(ident)) = it.next() {
|
||||
if ident.to_string().as_str() != "pub" {
|
||||
panic!("Expect to find keyword pub but was found {:?}", ident)
|
||||
}
|
||||
} else {
|
||||
panic!("Expect to find keyword pub but nothing was found")
|
||||
}
|
||||
it
|
||||
}
|
||||
|
||||
pub fn skip_enum(mut it: Peekable<IntoIter>) -> Peekable<IntoIter> {
|
||||
if let Some(TokenTree::Ident(ident)) = it.next() {
|
||||
if ident.to_string().as_str() != "enum" {
|
||||
panic!("Expect to find keyword enum but was found {:?}", ident)
|
||||
}
|
||||
} else {
|
||||
panic!("Expect to find keyword enum but nothing was found")
|
||||
}
|
||||
it
|
||||
}
|
||||
|
||||
pub fn skip_struct(mut it: Peekable<IntoIter>) -> Peekable<IntoIter> {
|
||||
if let Some(TokenTree::Ident(ident)) = it.next() {
|
||||
if ident.to_string().as_str() != "struct" {
|
||||
panic!("Expect to find keyword struct but was found {:?}", ident)
|
||||
}
|
||||
} else {
|
||||
panic!("Expect to find keyword struct but nothing was found")
|
||||
}
|
||||
it
|
||||
}
|
@ -24,7 +24,6 @@ services:
|
||||
- ./jirs-data:/app/jirs-data
|
||||
- ./jirs-cli:/app/jirs-cli
|
||||
- ./jirs-client:/app/jirs-client
|
||||
- ./jirs-css:/app/jirs-css
|
||||
server:
|
||||
build:
|
||||
dockerfile: ./jirs-server/Dockerfile
|
||||
|
@ -9,9 +9,6 @@ RUN rustup toolchain install nightly && \
|
||||
curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
|
||||
|
||||
ADD ./jirs-data /app/jirs-data
|
||||
ADD ./jirs-css /app/jirs-css
|
||||
|
||||
RUN cd /app/jirs-css && cargo build --bin jirs-css && cp ./target/debug/jirs-css /bin
|
||||
|
||||
ADD ./jirs-client /app/jirs-client
|
||||
|
||||
@ -19,7 +16,6 @@ RUN cd ./jirs-client && \
|
||||
rm -Rf build && \
|
||||
mkdir build && \
|
||||
wasm-pack build --mode normal --release --out-name jirs --out-dir ./build --target web && \
|
||||
jirs-css -i ./js/styles.css -O ./build/styles.css && \
|
||||
cp -r ./static/* ./build && \
|
||||
cat ./static/index.js \
|
||||
| sed -e "s/process.env.JIRS_SERVER_BIND/'$JIRS_SERVER_BIND'/g" \
|
||||
|
@ -13,10 +13,3 @@ main {
|
||||
article.inner-layout {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@media (min-width: 1240px) {
|
||||
/*article.inner-layout {*/
|
||||
/* display: flex;*/
|
||||
/* justify-content: start;*/
|
||||
/*}*/
|
||||
}
|
@ -1,126 +0,0 @@
|
||||
aside#navbar-left {
|
||||
z-index: var(--navLeft);
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
overflow-x: hidden;
|
||||
height: 100vh;
|
||||
width: var(--appNavBarLeftWidth);
|
||||
background: var(--backgroundDarkPrimary);
|
||||
transition: all 0.1s;
|
||||
transform: translateZ(0);
|
||||
}
|
||||
|
||||
aside#navbar-left:hover {
|
||||
width: 200px;
|
||||
box-shadow: 0 0 50px 0 rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
aside#navbar-left > .logoLink {
|
||||
display: block;
|
||||
position: relative;
|
||||
left: 0;
|
||||
margin: 20px 0 10px;
|
||||
transition: left 0.1s;
|
||||
}
|
||||
|
||||
aside#navbar-left > .logoLink > .styledLogo {
|
||||
display: inline-block;
|
||||
margin-left: 0;
|
||||
padding: 11px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
background: rgb(246, 246, 246);
|
||||
}
|
||||
|
||||
aside#navbar-left > .logoLink > .styledLogo > img {
|
||||
width: 42px;
|
||||
}
|
||||
|
||||
aside#navbar-left:hover > .logoLink {
|
||||
margin: 20px calc((200px - 64px) / 2) 10px;
|
||||
}
|
||||
|
||||
aside#navbar-left:hover > .logoLink > .styledLogo {
|
||||
border-radius: 34px;
|
||||
}
|
||||
|
||||
aside#navbar-left .item {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 42px;
|
||||
line-height: 42px;
|
||||
padding-left: 64px;
|
||||
color: #deebff;
|
||||
transition: color 0.1s;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
display: block;
|
||||
}
|
||||
|
||||
aside#navbar-left .item:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
aside#navbar-left .item > .styledIcon {
|
||||
position: absolute;
|
||||
left: 18px;
|
||||
height: 42px;
|
||||
line-height: 42px;
|
||||
}
|
||||
|
||||
aside#navbar-left .item > .styledIcon > .styledAvatar {
|
||||
margin-top: 7px;
|
||||
width: 27px;
|
||||
height: 27px;
|
||||
}
|
||||
|
||||
aside#navbar-left > .item > i.styledIcon.search {
|
||||
font-size: 22px;
|
||||
color: var(--asideIcon);
|
||||
}
|
||||
|
||||
aside#navbar-left > .item > i.styledIcon,
|
||||
aside#navbar-left > .bottom > .item > i.styledIcon {
|
||||
font-size: 27px;
|
||||
color: var(--asideIcon);
|
||||
}
|
||||
|
||||
aside#navbar-left .item > .itemText {
|
||||
position: relative;
|
||||
right: 12px;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
text-transform: uppercase;
|
||||
transition: all 0.1s;
|
||||
font-family: var(--font-bold);
|
||||
font-size: 12px;
|
||||
transition-property: right, visibility, opacity;
|
||||
display: block;
|
||||
}
|
||||
|
||||
aside#navbar-left > .bottom {
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
aside#navbar-left > .bottom > .aboutTooltip > .item > i.styledIcon {
|
||||
color: var(--asideIcon);
|
||||
}
|
||||
|
||||
aside#navbar-left:hover .item > .itemText {
|
||||
right: 0;
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.styledTooltip.aboutTooltipPopup {
|
||||
bottom: 48px;
|
||||
left: 120px;
|
||||
}
|
||||
|
||||
.styledTooltip.aboutTooltipPopup #about-github-button {
|
||||
margin-left: 10px;
|
||||
}
|
140
jirs-client/js/css/aside.scss
Normal file
140
jirs-client/js/css/aside.scss
Normal file
@ -0,0 +1,140 @@
|
||||
aside#navbar-left {
|
||||
z-index: var(--navLeft);
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
overflow-x: hidden;
|
||||
height: 100vh;
|
||||
width: var(--appNavBarLeftWidth);
|
||||
background: var(--backgroundDarkPrimary);
|
||||
transition: all 0.1s;
|
||||
transform: translateZ(0);
|
||||
|
||||
&:hover {
|
||||
width: 200px;
|
||||
box-shadow: 0 0 50px 0 rgba(0, 0, 0, 0.6);
|
||||
|
||||
> .logoLink {
|
||||
margin: 20px calc((200px - 64px) / 2) 10px;
|
||||
|
||||
> .styledLogo {
|
||||
border-radius: 34px;
|
||||
}
|
||||
}
|
||||
|
||||
.item {
|
||||
> .itemText {
|
||||
right: 0;
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> .logoLink {
|
||||
display: block;
|
||||
position: relative;
|
||||
left: 0;
|
||||
margin: 20px 0 10px;
|
||||
transition: left 0.1s;
|
||||
|
||||
> .styledLogo {
|
||||
display: inline-block;
|
||||
margin-left: 0;
|
||||
padding: 11px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
background: rgb(246, 246, 246);
|
||||
|
||||
> img {
|
||||
width: 42px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.item {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 42px;
|
||||
line-height: 42px;
|
||||
padding-left: 64px;
|
||||
color: #deebff;
|
||||
transition: color 0.1s;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
display: block;
|
||||
|
||||
&:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
> .styledIcon {
|
||||
position: absolute;
|
||||
left: 18px;
|
||||
height: 42px;
|
||||
line-height: 42px;
|
||||
|
||||
> .styledAvatar {
|
||||
margin-top: 7px;
|
||||
width: 27px;
|
||||
height: 27px;
|
||||
}
|
||||
}
|
||||
|
||||
> .itemText {
|
||||
position: relative;
|
||||
right: 12px;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
text-transform: uppercase;
|
||||
transition: all 0.1s;
|
||||
font-family: var(--font-bold);
|
||||
font-size: 12px;
|
||||
transition-property: right, visibility, opacity;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
> .item {
|
||||
> i.styledIcon.search {
|
||||
font-size: 22px;
|
||||
color: var(--asideIcon);
|
||||
}
|
||||
|
||||
> i.styledIcon {
|
||||
font-size: 27px;
|
||||
color: var(--asideIcon);
|
||||
}
|
||||
}
|
||||
|
||||
> .bottom {
|
||||
> .item {
|
||||
> i.styledIcon {
|
||||
font-size: 27px;
|
||||
color: var(--asideIcon);
|
||||
}
|
||||
}
|
||||
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
|
||||
> .aboutTooltip {
|
||||
> .item {
|
||||
> i.styledIcon {
|
||||
color: var(--asideIcon);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.styledTooltip.aboutTooltipPopup {
|
||||
bottom: 48px;
|
||||
left: 120px;
|
||||
|
||||
#about-github-button {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
@ -1,128 +0,0 @@
|
||||
html, body, #root {
|
||||
height: 100%;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
@media (min-width: 1240px) {
|
||||
html, body, #root {
|
||||
min-width: 768px;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
font-weight: normal;
|
||||
color: var(--textDark);
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
line-height: 1.2;
|
||||
font-size: 16px;
|
||||
font-family: var(--font-regular);
|
||||
}
|
||||
|
||||
#app {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
button,
|
||||
input,
|
||||
optgroup,
|
||||
select,
|
||||
textarea {
|
||||
font-family: var(--font-regular);
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
*, *:after, *:before, input[type="search"] {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
ul, li, ol, dd, h1, h2, h3, h4, h5, h6, p {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6, strong {
|
||||
font-family: var(--font-bold);
|
||||
}
|
||||
|
||||
button {
|
||||
background: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* Workaround for IE11 focus highlighting for select elements */
|
||||
select::-ms-value {
|
||||
background: none;
|
||||
color: #42413d;
|
||||
}
|
||||
|
||||
[role="button"], button, input, select, textarea {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
[role="button"]:disabled, button:disabled, input:disabled, select:disabled, textarea:disabled {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
[role="button"], button, input, textarea {
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
select:-moz-focusring {
|
||||
color: transparent;
|
||||
text-shadow: 0 0 0 #000;
|
||||
}
|
||||
|
||||
select::-ms-expand {
|
||||
display: none;
|
||||
}
|
||||
|
||||
select option {
|
||||
color: var(--textDark)
|
||||
}
|
||||
|
||||
p {
|
||||
line-height: 1.4285;
|
||||
}
|
||||
|
||||
p a::-webkit-input-placeholder {
|
||||
color: var(--textLight);
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
p a:-moz-placeholder {
|
||||
color: var(--textLight);
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
p a::-moz-placeholder {
|
||||
color: var(--textLight);
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
p a:-ms-input-placeholder {
|
||||
color: var(--textLight);
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
textarea {
|
||||
line-height: 1.4285;
|
||||
}
|
||||
|
||||
body, select {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
html {
|
||||
touch-action: manipulation;
|
||||
}
|
231
jirs-client/js/css/global.scss
Normal file
231
jirs-client/js/css/global.scss
Normal file
@ -0,0 +1,231 @@
|
||||
/* Workaround for IE11 focus highlighting for select elements */
|
||||
html {
|
||||
height: 100%;
|
||||
min-height: 100%;
|
||||
touch-action: manipulation;
|
||||
}
|
||||
|
||||
body {
|
||||
height: 100%;
|
||||
min-height: 100%;
|
||||
font-weight: normal;
|
||||
color: var(--textDark);
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
line-height: 1.2;
|
||||
font-size: 16px;
|
||||
font-family: var(--font-regular);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
#root {
|
||||
height: 100%;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
#app {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
button {
|
||||
font-family: var(--font-regular);
|
||||
font-weight: normal;
|
||||
background: none;
|
||||
border: none;
|
||||
outline: none;
|
||||
appearance: none;
|
||||
|
||||
&:disabled {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
input {
|
||||
font-family: var(--font-regular);
|
||||
font-weight: normal;
|
||||
outline: none;
|
||||
appearance: none;
|
||||
|
||||
&:disabled {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
optgroup {
|
||||
font-family: var(--font-regular);
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
select {
|
||||
font-family: var(--font-regular);
|
||||
font-weight: normal;
|
||||
outline: none;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
|
||||
&::-ms-value {
|
||||
background: none;
|
||||
color: #42413d;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&:-moz-focusring {
|
||||
color: transparent;
|
||||
text-shadow: 0 0 0 #000;
|
||||
}
|
||||
|
||||
&::-ms-expand {
|
||||
display: none;
|
||||
}
|
||||
|
||||
option {
|
||||
color: var(--textDark);
|
||||
}
|
||||
}
|
||||
|
||||
textarea {
|
||||
font-family: var(--font-regular);
|
||||
font-weight: normal;
|
||||
outline: none;
|
||||
appearance: none;
|
||||
line-height: 1.4285;
|
||||
|
||||
&:disabled {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
|
||||
&:after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
&:before {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
|
||||
input[type="search"] {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
li {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
ol {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
dd {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-family: var(--font-bold);
|
||||
}
|
||||
|
||||
h2 {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-family: var(--font-bold);
|
||||
}
|
||||
|
||||
h3 {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-family: var(--font-bold);
|
||||
}
|
||||
|
||||
h4 {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-family: var(--font-bold);
|
||||
}
|
||||
|
||||
h5 {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-family: var(--font-bold);
|
||||
}
|
||||
|
||||
h6 {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-family: var(--font-bold);
|
||||
}
|
||||
|
||||
p {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
line-height: 1.4285;
|
||||
|
||||
a {
|
||||
&::-webkit-input-placeholder {
|
||||
color: var(--textLight);
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
&:-moz-placeholder {
|
||||
color: var(--textLight);
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
&::-moz-placeholder {
|
||||
color: var(--textLight);
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
&:-ms-input-placeholder {
|
||||
color: var(--textLight);
|
||||
opacity: 1 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
strong {
|
||||
font-family: var(--font-bold);
|
||||
}
|
||||
|
||||
[role="button"] {
|
||||
outline: none;
|
||||
appearance: none;
|
||||
|
||||
&:disabled {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1240px) {
|
||||
html {
|
||||
min-width: 768px;
|
||||
}
|
||||
body {
|
||||
min-width: 768px;
|
||||
}
|
||||
#root {
|
||||
min-width: 768px;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
12812
jirs-client/js/css/iconfonts.scss
Normal file
12812
jirs-client/js/css/iconfonts.scss
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,25 +0,0 @@
|
||||
#invite > .styledForm {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 0 auto 24px;
|
||||
width: 400px;
|
||||
background: rgb(255, 255, 255) none repeat scroll 0 0;
|
||||
border-radius: 3px;
|
||||
box-shadow: rgba(0, 0, 0, 0.1) 0 0 10px;
|
||||
box-sizing: border-box;
|
||||
color: var(--textMedium);
|
||||
}
|
||||
|
||||
#invite > .styledForm:first-of-type {
|
||||
margin-top: 124.5px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#invite > .styledForm:last-of-type {
|
||||
box-shadow: rgba(0, 0, 0, 0.1) 0 10px 10px;
|
||||
}
|
||||
|
||||
#invite .error {
|
||||
color: var(--danger);
|
||||
margin-top: 15px;
|
||||
}
|
27
jirs-client/js/css/invite.scss
Normal file
27
jirs-client/js/css/invite.scss
Normal file
@ -0,0 +1,27 @@
|
||||
#invite {
|
||||
> .styledForm {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 0 auto 24px;
|
||||
width: 400px;
|
||||
background: rgb(255, 255, 255) none repeat scroll 0 0;
|
||||
border-radius: 3px;
|
||||
box-shadow: rgba(0, 0, 0, 0.1) 0 0 10px;
|
||||
box-sizing: border-box;
|
||||
color: var(--textMedium);
|
||||
|
||||
&:first-of-type {
|
||||
margin-top: 124.5px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
&:last-of-type {
|
||||
box-shadow: rgba(0, 0, 0, 0.1) 0 10px 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.error {
|
||||
color: var(--danger);
|
||||
margin-top: 15px;
|
||||
}
|
||||
}
|
@ -1,157 +0,0 @@
|
||||
.issueDetails > .content {
|
||||
display: flex;
|
||||
padding: 0 30px 60px;
|
||||
}
|
||||
|
||||
/*===================================================*/
|
||||
/* LEFT */
|
||||
/*===================================================*/
|
||||
.issueDetails > .content > .left {
|
||||
width: 65%;
|
||||
padding-right: 50px;
|
||||
}
|
||||
|
||||
.issueDetails > .content > .left > .styledInput,
|
||||
.issueDetails > .content > .left > .styledTextArea {
|
||||
margin: 18px 0 0 -8px;
|
||||
height: 44px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.issueDetails > .content > .left > .styledInput > input,
|
||||
.issueDetails > .content > .left > .styledTextArea > textarea {
|
||||
padding: 7px 7px 8px;
|
||||
line-height: 1.28;
|
||||
resize: none;
|
||||
transition: background 0.1s;
|
||||
font-size: 24px;
|
||||
font-family: var(--font-medium);
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.issueDetails > .content > .left > .styledTextArea > textarea:not(:focus),
|
||||
.issueDetails > .content > .left > .styledInput > input:not(:focus) {
|
||||
background: #fff;
|
||||
border: 1px solid transparent;
|
||||
box-shadow: 0 0 0 1px transparent;
|
||||
}
|
||||
|
||||
.issueDetails > .content > .left > .styledTextArea > textarea:hover:not(:focus) {
|
||||
background: var(--backgroundLight);
|
||||
}
|
||||
|
||||
.issueDetails > .content > .left > .comments {
|
||||
padding-top: 40px;
|
||||
}
|
||||
|
||||
.issueDetails > .content > .left > .comments > .title {
|
||||
font-family: var(--font-medium);
|
||||
font-weight: normal;
|
||||
font-size: 15px
|
||||
}
|
||||
|
||||
.issueDetails > .content > .left > .comments > .create {
|
||||
position: relative;
|
||||
margin-top: 25px;
|
||||
font-size: 15px
|
||||
}
|
||||
|
||||
.issueDetails > .content > .left > .comments > .create > .userAvatar {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.issueDetails > .content > .left > .comments > .create > .right {
|
||||
padding-left: 44px;
|
||||
}
|
||||
|
||||
.issueDetails > .content > .left > .comments > .create > .right > .fakeTextArea {
|
||||
padding: 12px 16px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--borderLightest);
|
||||
color: var(--textLight);
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.issueDetails > .content > .left > .comments > .create > .right > .fakeTextArea:hover {
|
||||
border: 1px solid var(--borderLight);
|
||||
}
|
||||
|
||||
.issueDetails > .content > .left > .comments > .create > .right > .proTip {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-top: 8px;
|
||||
color: var(--textMedium);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.issueDetails > .content > .left > .comments > .create > .right > .proTip > .strong {
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
.issueDetails > .content > .left > .comments > .create > .right > .proTip > .tipLetter {
|
||||
position: relative;
|
||||
top: 1px;
|
||||
display: inline-block;
|
||||
margin: 0 4px;
|
||||
padding: 0 4px;
|
||||
border-radius: 2px;
|
||||
color: var(--textDarkest);
|
||||
background: var(--backgroundMedium);
|
||||
font-family: var(--font-bold);
|
||||
font-weight: normal;
|
||||
font-size: 12px
|
||||
}
|
||||
|
||||
.issueDetails > .content > .left > .comments > .create > .right > .actions {
|
||||
display: flex;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.issueDetails > .content > .left > .comments > .create > .right > .actions > .styledButton {
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
/*===================================================*/
|
||||
/* RIGHT */
|
||||
/*===================================================*/
|
||||
.issueDetails > .content > .right {
|
||||
width: 35%;
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
/*===================================================*/
|
||||
/* TOP ACTIONS */
|
||||
/*===================================================*/
|
||||
.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 > .topActions .styledSelect > .valueContainer > .value {
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
color: var(--textMedium);
|
||||
font-size: 13px
|
||||
}
|
||||
|
||||
.issueDetails > .sectionTitle {
|
||||
margin: 24px 0 5px;
|
||||
text-transform: uppercase;
|
||||
color: var(--textMedium);
|
||||
font-size: 12.5px;
|
||||
font-family: "CircularStdBold", serif;
|
||||
font-weight: normal
|
||||
}
|
183
jirs-client/js/css/issue.scss
Normal file
183
jirs-client/js/css/issue.scss
Normal file
@ -0,0 +1,183 @@
|
||||
.issueDetails {
|
||||
> .content {
|
||||
display: flex;
|
||||
padding: 0 30px 60px;
|
||||
/*===================================================*/
|
||||
/* LEFT */
|
||||
/*===================================================*/
|
||||
> .left {
|
||||
width: 65%;
|
||||
padding-right: 50px;
|
||||
|
||||
> .styledInput {
|
||||
margin: 18px 0 0 -8px;
|
||||
height: 44px;
|
||||
width: 100%;
|
||||
|
||||
> input {
|
||||
padding: 7px 7px 8px;
|
||||
line-height: 1.28;
|
||||
resize: none;
|
||||
transition: background 0.1s;
|
||||
font-size: 24px;
|
||||
font-family: var(--font-medium);
|
||||
font-weight: normal;
|
||||
|
||||
&:not(:focus) {
|
||||
background: #fff;
|
||||
border: 1px solid transparent;
|
||||
box-shadow: 0 0 0 1px transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> .styledTextArea {
|
||||
margin: 18px 0 0 -8px;
|
||||
height: 44px;
|
||||
width: 100%;
|
||||
|
||||
> textarea {
|
||||
padding: 7px 7px 8px;
|
||||
line-height: 1.28;
|
||||
resize: none;
|
||||
transition: background 0.1s;
|
||||
font-size: 24px;
|
||||
font-family: var(--font-medium);
|
||||
font-weight: normal;
|
||||
|
||||
&:not(:focus) {
|
||||
background: #fff;
|
||||
border: 1px solid transparent;
|
||||
box-shadow: 0 0 0 1px transparent;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
&:not(:focus) {
|
||||
background: var(--backgroundLight);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> .comments {
|
||||
padding-top: 40px;
|
||||
|
||||
> .title {
|
||||
font-family: var(--font-medium);
|
||||
font-weight: normal;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
> .create {
|
||||
position: relative;
|
||||
margin-top: 25px;
|
||||
font-size: 15px;
|
||||
|
||||
> .userAvatar {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
> .right {
|
||||
padding-left: 44px;
|
||||
|
||||
> .fakeTextArea {
|
||||
padding: 12px 16px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--borderLightest);
|
||||
color: var(--textLight);
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
|
||||
&:hover {
|
||||
border: 1px solid var(--borderLight);
|
||||
}
|
||||
}
|
||||
|
||||
> .proTip {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-top: 8px;
|
||||
color: var(--textMedium);
|
||||
font-size: 13px;
|
||||
|
||||
> .strong {
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
> .tipLetter {
|
||||
position: relative;
|
||||
top: 1px;
|
||||
display: inline-block;
|
||||
margin: 0 4px;
|
||||
padding: 0 4px;
|
||||
border-radius: 2px;
|
||||
color: var(--textDarkest);
|
||||
background: var(--backgroundMedium);
|
||||
font-family: var(--font-bold);
|
||||
font-weight: normal;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
> .actions {
|
||||
display: flex;
|
||||
padding-top: 10px;
|
||||
|
||||
> .styledButton {
|
||||
margin-right: 6px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*===================================================*/
|
||||
/* RIGHT */
|
||||
/*===================================================*/
|
||||
> .right {
|
||||
width: 35%;
|
||||
padding-top: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
/*===================================================*/
|
||||
/* TOP ACTIONS */
|
||||
/*===================================================*/
|
||||
> .topActions {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 21px 18px 0;
|
||||
|
||||
> .topActionsRight {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
> * {
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.styledSelect {
|
||||
> .valueContainer {
|
||||
> .value {
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
color: var(--textMedium);
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> .sectionTitle {
|
||||
margin: 24px 0 5px;
|
||||
text-transform: uppercase;
|
||||
color: var(--textMedium);
|
||||
font-size: 12.5px;
|
||||
font-family: "CircularStdBold", serif;
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
#login > .styledForm {
|
||||
margin-top: 5rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: rgb(255, 255, 255) none repeat scroll 0 0;
|
||||
border-radius: 3px;
|
||||
box-shadow: rgba(0, 0, 0, 0.1) 0 0 10px;
|
||||
box-sizing: border-box;
|
||||
color: var(--textMedium);
|
||||
}
|
||||
|
||||
#login > .styledForm:first-of-type {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#login > .styledForm:last-of-type {
|
||||
box-shadow: rgba(0, 0, 0, 0.1) 0 10px 10px;
|
||||
}
|
||||
|
||||
#login > .styledForm:first-of-type > .formElement {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
#login > .styledForm:last-of-type > .formElement {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
#login > .styledForm > .formElement > .formHeading {
|
||||
color: var(--textMedium);
|
||||
font-size: 1em;
|
||||
line-height: 1.1428571428571428;
|
||||
letter-spacing: -.003em;
|
||||
font-family: var(--font-bold);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#login > .styledForm > .formElement > .noPasswordSection {
|
||||
line-height: 32px;
|
||||
margin-top: 15px;
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#login > .styledForm > .formElement > .noPasswordSection > .styledIcon {
|
||||
margin-right: 5px;
|
||||
line-height: 32px;
|
||||
}
|
||||
|
||||
#login > .styledForm > .formElement > .noPasswordSection > span {
|
||||
display: block;
|
||||
line-height: 32px;
|
||||
}
|
||||
|
||||
#login > .styledForm .twoRow {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
@media (min-width: 1240px) {
|
||||
#login > .styledForm {
|
||||
margin: 0 auto 24px;
|
||||
width: 400px;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
#login > .styledForm:first-of-type {
|
||||
margin-top: 124.5px;
|
||||
}
|
||||
}
|
75
jirs-client/js/css/login.scss
Normal file
75
jirs-client/js/css/login.scss
Normal file
@ -0,0 +1,75 @@
|
||||
#login {
|
||||
> .styledForm {
|
||||
margin-top: 5rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: rgb(255, 255, 255) none repeat scroll 0 0;
|
||||
border-radius: 3px;
|
||||
box-shadow: rgba(0, 0, 0, 0.1) 0 0 10px;
|
||||
box-sizing: border-box;
|
||||
color: var(--textMedium);
|
||||
|
||||
&:first-of-type {
|
||||
margin-bottom: 0;
|
||||
|
||||
> .formElement {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&:last-of-type {
|
||||
box-shadow: rgba(0, 0, 0, 0.1) 0 10px 10px;
|
||||
|
||||
> .formElement {
|
||||
padding-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
> .formElement {
|
||||
> .formHeading {
|
||||
color: var(--textMedium);
|
||||
font-size: 1em;
|
||||
line-height: 1.1428571428571428;
|
||||
letter-spacing: -.003em;
|
||||
font-family: var(--font-bold);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
> .noPasswordSection {
|
||||
line-height: 32px;
|
||||
margin-top: 15px;
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
|
||||
> .styledIcon {
|
||||
margin-right: 5px;
|
||||
line-height: 32px;
|
||||
}
|
||||
|
||||
> span {
|
||||
display: block;
|
||||
line-height: 32px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.twoRow {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1240px) {
|
||||
#login {
|
||||
> .styledForm {
|
||||
margin: 0 auto 24px;
|
||||
width: 400px;
|
||||
max-width: 400px;
|
||||
|
||||
&:first-of-type {
|
||||
margin-top: 124.5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,255 +0,0 @@
|
||||
#projectPage {
|
||||
}
|
||||
|
||||
#projectPage > .breadcrumbsContainer {
|
||||
color: var(--textMedium);
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
#projectPage > .breadcrumbsContainer > .breadcrumbsDivider {
|
||||
position: relative;
|
||||
top: 2px;
|
||||
margin: 0 10px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
#projectPage > #projectBoardHeader {
|
||||
margin-top: 6px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#projectPage > #projectBoardHeader > #boardName {
|
||||
font-size: 24px;
|
||||
font-family: var(--font-medium);
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
#projectPage > #projectBoardFilters {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
#projectPage > #projectBoardFilters > .textFilterBoard {
|
||||
margin-right: 18px;
|
||||
width: 160px;
|
||||
}
|
||||
|
||||
#projectPage > #projectBoardFilters > #avatars {
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
margin: 0 12px 0 2px;
|
||||
}
|
||||
|
||||
#projectPage > #projectBoardFilters > #avatars > .avatarIsActiveBorder {
|
||||
display: inline-flex;
|
||||
margin-left: -2px;
|
||||
border-radius: 50%;
|
||||
transition: transform 0.1s;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
background: var(--backgroundMedium);
|
||||
border-color: var(--backgroundLight)
|
||||
}
|
||||
|
||||
#projectPage > #projectBoardFilters > #avatars > .avatarIsActiveBorder.isActive {
|
||||
box-shadow: 0 0 0 4px var(--primary);
|
||||
}
|
||||
|
||||
#projectPage > #projectBoardFilters > #avatars > .avatarIsActiveBorder > .letter {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
font-size: 16px;
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
#projectPage > #projectBoardFilters > #avatars > .avatarIsActiveBorder:hover {
|
||||
transform: translateY(-5px);
|
||||
}
|
||||
|
||||
#projectPage > #projectBoardFilters > #avatars > .avatarIsActiveBorder > .styledAvatar {
|
||||
box-shadow: 0 0 0 2px #fff;
|
||||
}
|
||||
|
||||
#projectPage > #projectBoardFilters .styledButton {
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
||||
#projectPage > #projectBoardFilters > #clearAllFilters {
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
margin-left: 15px;
|
||||
padding-left: 12px;
|
||||
border-left: 1px solid var(--borderLightest);
|
||||
color: var(--textDark);
|
||||
font-size: 14.5px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
#projectPage > #projectBoardFilters > #clearAllFilters:hover {
|
||||
color: var(--textMedium);
|
||||
}
|
||||
|
||||
#projectPage > .rows > .row > .epicName {
|
||||
margin: 18px 0 10px 0;
|
||||
}
|
||||
|
||||
#projectPage > .rows > .row > .projectBoardLists {
|
||||
display: flex;
|
||||
margin: 10px -5px 0;
|
||||
position: relative;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#projectPage > .rows > .row > .rowName {
|
||||
position: relative;
|
||||
color: var(--textDark);
|
||||
font-family: var(--font-regular);
|
||||
margin: 26px -5px 0;
|
||||
}
|
||||
|
||||
#projectPage > .rows > .row > .projectBoardLists > .list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 0 5px;
|
||||
min-height: 400px;
|
||||
border-radius: 3px;
|
||||
background: var(--backgroundLightest);
|
||||
}
|
||||
|
||||
#projectPage > .rows > .row > .projectBoardLists > .list > .title {
|
||||
padding: 13px 10px 17px;
|
||||
text-transform: uppercase;
|
||||
color: var(--textMedium);
|
||||
font-size: 12.5px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
#projectPage > .rows > .row > .projectBoardLists > .list > .title > .issuesCount {
|
||||
text-transform: lowercase;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
#projectPage > .rows > .row > .projectBoardLists > .list > .issues {
|
||||
height: 100%;
|
||||
padding: 0 5px;
|
||||
}
|
||||
|
||||
#projectPage > .rows > .row > .projectBoardLists > .list > .issues > .issueLink {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#projectPage > .rows > .row > .projectBoardLists > .list > .issues > .issueLink > .dragCover {
|
||||
display: block;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#projectPage > .rows > .row > .projectBoardLists > .list > .issues > .issueLink > .dragCover:-moz-drag-over {
|
||||
border: var(--borderInputFocus);
|
||||
}
|
||||
|
||||
#projectPage > .rows > .row > .projectBoardLists > .list > .issues > .issueLink > .issue {
|
||||
padding: 10px;
|
||||
border-radius: 3px;
|
||||
background: #fff;
|
||||
box-shadow: 0 1px 2px 0 rgba(9, 30, 66, 0.25);
|
||||
transition: background 0.1s;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
#projectPage > .rows > .row > .projectBoardLists > .list > .issues > .issueLink > .issue.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#projectPage > .rows > .row > .projectBoardLists > .list > .issues > .issueLink > .issue.isBeingDragged {
|
||||
transform: rotate(3deg);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 2;
|
||||
width: 90px;
|
||||
}
|
||||
|
||||
#projectPage > .rows > .row > .projectBoardLists > .list > .issues > .issueLink > .issue:hover {
|
||||
background: var(--backgroundLight);
|
||||
}
|
||||
|
||||
#projectPage > .rows > .row > .projectBoardLists > .list > .issues > .issueLink > .issue > .title {
|
||||
padding-bottom: 11px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
#projectPage > .rows > .row > .projectBoardLists > .list > .issues > .issueLink > .issue > .bottom {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#projectPage > .rows > .row > .projectBoardLists > .list > .issues > .issueLink > .issue > .bottom > div {
|
||||
}
|
||||
|
||||
#projectPage > .rows > .row > .projectBoardLists > .list > .issues > .issueLink > .issue > .bottom > div > .issueTypeIcon {
|
||||
}
|
||||
|
||||
#projectPage > .rows > .row > .projectBoardLists > .list > .issues > .issueLink > .issue > .bottom > div > .issuePriorityIcon {
|
||||
}
|
||||
|
||||
#projectPage > .rows > .row > .projectBoardLists > .list > .issues > .issueLink > .issue > .bottom > .assignees {
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
#projectPage > .rows > .row > .projectBoardLists > .list > .issues > .issueLink > .issue > .bottom > .assignees > .assigneeAvatar,
|
||||
#projectPage > .rows > .row > .projectBoardLists > .list > .issues > .issueLink > .issue > .bottom > .assignees > .styledAvatar {
|
||||
margin-left: -2px;
|
||||
box-shadow: 0 0 0 2px #fff;
|
||||
}
|
||||
|
||||
#projectPage > .rows > .row > .projectBoardLists > .list > .issues > .issueLink > .issue {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#projectPage > #projectBoardFilters > .filterChild {
|
||||
width: 90%;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
@media (min-width: 1240px) {
|
||||
#projectPage {}
|
||||
|
||||
#projectPage > #projectBoardFilters {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
#projectPage > #projectBoardFilters > .filterChild {
|
||||
width: auto;
|
||||
margin-bottom: auto;
|
||||
}
|
||||
|
||||
#projectPage > .rows > .row > .projectBoardLists {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
#projectPage > .rows > .row > .projectBoardLists > .list {
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
#projectPage > .rows > .row > .projectBoardLists > .list > .issues > .issueLink > .issue {
|
||||
display: block;
|
||||
padding: 10px 8px;
|
||||
}
|
||||
}
|
281
jirs-client/js/css/project.scss
Normal file
281
jirs-client/js/css/project.scss
Normal file
@ -0,0 +1,281 @@
|
||||
#projectPage {
|
||||
> .breadcrumbsContainer {
|
||||
color: var(--textMedium);
|
||||
font-size: 15px;
|
||||
|
||||
> .breadcrumbsDivider {
|
||||
position: relative;
|
||||
top: 2px;
|
||||
margin: 0 10px;
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
> #projectBoardHeader {
|
||||
margin-top: 6px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
> #boardName {
|
||||
font-size: 24px;
|
||||
font-family: var(--font-medium);
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
|
||||
> #projectBoardFilters {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-top: 24px;
|
||||
|
||||
> .textFilterBoard {
|
||||
margin-right: 18px;
|
||||
width: 160px;
|
||||
}
|
||||
|
||||
> #avatars {
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
margin: 0 12px 0 2px;
|
||||
|
||||
> .avatarIsActiveBorder {
|
||||
display: inline-flex;
|
||||
margin-left: -2px;
|
||||
border-radius: 50%;
|
||||
transition: transform 0.1s;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
background: var(--backgroundMedium);
|
||||
border-color: var(--backgroundLight);
|
||||
|
||||
> .letter {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
font-size: 16px;
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-5px);
|
||||
}
|
||||
|
||||
> .styledAvatar {
|
||||
box-shadow: 0 0 0 2px #fff;
|
||||
}
|
||||
}
|
||||
|
||||
> .avatarIsActiveBorder.isActive {
|
||||
box-shadow: 0 0 0 4px var(--primary);
|
||||
}
|
||||
}
|
||||
|
||||
.styledButton {
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
||||
> #clearAllFilters {
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
margin-left: 15px;
|
||||
padding-left: 12px;
|
||||
border-left: 1px solid var(--borderLightest);
|
||||
color: var(--textDark);
|
||||
font-size: 14.5px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
|
||||
&:hover {
|
||||
color: var(--textMedium);
|
||||
}
|
||||
}
|
||||
|
||||
> .filterChild {
|
||||
width: 90%;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
> .rows {
|
||||
> .row {
|
||||
> .epicHeader {
|
||||
margin: 18px 0 10px 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
> .epicName {
|
||||
}
|
||||
|
||||
> .epicActions {
|
||||
> .styledButton {
|
||||
> .styledIcon {
|
||||
color: var(--backgroundLightest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
> .epicActions {
|
||||
> .styledButton {
|
||||
> .styledIcon {
|
||||
color: var(--textDark);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> .projectBoardLists {
|
||||
display: flex;
|
||||
margin: 10px -5px 0;
|
||||
position: relative;
|
||||
flex-direction: column;
|
||||
|
||||
> .list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 0 5px;
|
||||
min-height: 400px;
|
||||
border-radius: 3px;
|
||||
background: var(--backgroundLightest);
|
||||
|
||||
> .title {
|
||||
padding: 13px 10px 17px;
|
||||
text-transform: uppercase;
|
||||
color: var(--textMedium);
|
||||
font-size: 12.5px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
> .issuesCount {
|
||||
text-transform: lowercase;
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
> .issues {
|
||||
height: 100%;
|
||||
padding: 0 5px;
|
||||
|
||||
> .issueLink {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
position: relative;
|
||||
|
||||
> .dragCover {
|
||||
display: block;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
&:-moz-drag-over {
|
||||
border: var(--borderInputFocus);
|
||||
}
|
||||
}
|
||||
|
||||
> .issue {
|
||||
padding: 10px;
|
||||
border-radius: 3px;
|
||||
background: #fff;
|
||||
box-shadow: 0 1px 2px 0 rgba(9, 30, 66, 0.25);
|
||||
transition: background 0.1s;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background: var(--backgroundLight);
|
||||
}
|
||||
|
||||
> .title {
|
||||
padding-bottom: 11px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
> .bottom {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
> .assignees {
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
margin-left: 2px;
|
||||
|
||||
> .assigneeAvatar {
|
||||
margin-left: -2px;
|
||||
box-shadow: 0 0 0 2px #fff;
|
||||
}
|
||||
|
||||
> .styledAvatar {
|
||||
margin-left: -2px;
|
||||
box-shadow: 0 0 0 2px #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> .issue.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
> .issue.isBeingDragged {
|
||||
transform: rotate(3deg);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 2;
|
||||
width: 90px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> .rowName {
|
||||
position: relative;
|
||||
color: var(--textDark);
|
||||
font-family: var(--font-regular);
|
||||
margin: 26px -5px 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1240px) {
|
||||
#projectPage {
|
||||
> #projectBoardFilters {
|
||||
flex-direction: row;
|
||||
|
||||
> .filterChild {
|
||||
width: auto;
|
||||
margin-bottom: auto;
|
||||
}
|
||||
}
|
||||
|
||||
> .rows {
|
||||
> .row {
|
||||
> .projectBoardLists {
|
||||
flex-direction: row;
|
||||
|
||||
> .list {
|
||||
width: 25%;
|
||||
|
||||
> .issues {
|
||||
> .issueLink {
|
||||
> .issue {
|
||||
display: block;
|
||||
padding: 10px 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
#projectSettings > .formContainer {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#projectSettings > .formContainer .styledForm {
|
||||
max-width: 1024px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#projectSettings > .formContainer .styledForm > .formElement > .actionButton {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
#projectSettings > .formContainer .styledForm > .formElement > .styledField.columnsField > .styledLabel {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
#projectSettings > .formContainer .styledForm > .formElement > .styledField > .columnsSection > .columns {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
#projectSettings > .formContainer .styledForm > .formElement > .styledField > .columnsSection > .columns > .columnPreview {
|
||||
width: auto;
|
||||
min-height: 60px;
|
||||
background: var(--backgroundLightest);
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
#projectSettings > .formContainer .styledForm > .formElement > .styledField > .columnsSection > .columns > .columnPreview > .columnName {
|
||||
display: block;
|
||||
margin: 0 5px;
|
||||
padding: 13px 10px 17px;
|
||||
text-transform: uppercase;
|
||||
color: var(--textMedium);
|
||||
font-size: 12.5px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
#projectSettings > .formContainer .styledForm > .formElement > .styledField > .columnsSection > .columns > .columnPreview > .columnName > span {
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
#projectSettings > .formContainer .styledForm > .formElement > .styledField > .columnsSection > .columns > .columnPreview > .columnName > .styledInput {
|
||||
}
|
||||
|
||||
#projectSettings > .formContainer .styledForm > .formElement > .styledField > .columnsSection > .columns > .columnPreview > .columnName.addColumn,
|
||||
#projectSettings > .formContainer .styledForm > .formElement > .styledField > .columnsSection > .columns > .columnPreview > .columnName.addColumn > i {
|
||||
color: var(--textMedium);
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#projectSettings > .formContainer .styledForm > .formElement > .styledField > .columnsSection > .columns > .columnPreview > .columnName > .removeColumn {
|
||||
text-align: center;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
padding-top: 15px;
|
||||
}
|
||||
|
||||
#projectSettings > .formContainer .styledForm > .formElement > .styledField > .columnsSection > .columns > .columnPreview:hover > .columnName > .removeColumn,
|
||||
#projectSettings > .formContainer .styledForm > .formElement > .styledField > .columnsSection > .columns > .columnPreview:focus > .columnName > .removeColumn,
|
||||
#projectSettings > .formContainer .styledForm > .formElement > .styledField > .columnsSection > .columns > .columnPreview:active > .columnName > .removeColumn {
|
||||
|
||||
}
|
||||
|
||||
#projectSettings > .formContainer .styledForm > .formElement > .styledField > .columnsSection > .columns > .columnPreview > .columnName > .issueCount {
|
||||
text-transform: none;
|
||||
padding-top: 15px;
|
||||
}
|
81
jirs-client/js/css/projectSettings.scss
Normal file
81
jirs-client/js/css/projectSettings.scss
Normal file
@ -0,0 +1,81 @@
|
||||
#projectSettings {
|
||||
> .formContainer {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
.styledForm {
|
||||
max-width: 1024px;
|
||||
width: 100%;
|
||||
|
||||
> .formElement {
|
||||
> .actionButton {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
> .styledField.columnsField {
|
||||
> .styledLabel {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
> .styledField {
|
||||
> .columnsSection {
|
||||
> .columns {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-around;
|
||||
|
||||
> .columnPreview {
|
||||
width: auto;
|
||||
min-height: 60px;
|
||||
background: var(--backgroundLightest);
|
||||
margin: 0 5px;
|
||||
|
||||
> .columnName {
|
||||
display: block;
|
||||
margin: 0 5px;
|
||||
padding: 13px 10px 17px;
|
||||
text-transform: uppercase;
|
||||
color: var(--textMedium);
|
||||
font-size: 12.5px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
> span {
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
> .removeColumn {
|
||||
text-align: center;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
padding-top: 15px;
|
||||
}
|
||||
|
||||
> .issueCount {
|
||||
text-transform: none;
|
||||
padding-top: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
> .columnName.addColumn {
|
||||
color: var(--textMedium);
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
|
||||
> i {
|
||||
color: var(--textMedium);
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
#register > .styledForm {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 0 auto 24px;
|
||||
width: 400px;
|
||||
background: rgb(255, 255, 255) none repeat scroll 0 0;
|
||||
border-radius: 3px;
|
||||
box-shadow: rgba(0, 0, 0, 0.1) 0 0 10px;
|
||||
box-sizing: border-box;
|
||||
color: var(--textMedium);
|
||||
}
|
||||
|
||||
#register > .styledForm:first-of-type {
|
||||
margin-top: 124.5px;
|
||||
}
|
||||
|
||||
#register .twoRow {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#register > .styledForm > .formElement > .noPasswordSection {
|
||||
line-height: 32px;
|
||||
margin-top: 15px;
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#register > .styledForm > .formElement > .noPasswordSection > .styledIcon {
|
||||
margin-right: 5px;
|
||||
line-height: 32px;
|
||||
}
|
||||
|
||||
#register > .styledForm > .formElement > .noPasswordSection > span {
|
||||
display: block;
|
||||
line-height: 32px;
|
||||
}
|
||||
|
||||
#register .error > p {
|
||||
line-height: 1.4285;
|
||||
color: var(--danger);
|
||||
font-family: var(--font-medium);
|
||||
text-align: center;
|
||||
font-size: 14.5px;
|
||||
border-top: 1px solid var(--danger);
|
||||
margin-top: 15px;
|
||||
}
|
53
jirs-client/js/css/register.scss
Normal file
53
jirs-client/js/css/register.scss
Normal file
@ -0,0 +1,53 @@
|
||||
#register {
|
||||
> .styledForm {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 0 auto 24px;
|
||||
width: 400px;
|
||||
background: rgb(255, 255, 255) none repeat scroll 0 0;
|
||||
border-radius: 3px;
|
||||
box-shadow: rgba(0, 0, 0, 0.1) 0 0 10px;
|
||||
box-sizing: border-box;
|
||||
color: var(--textMedium);
|
||||
|
||||
&:first-of-type {
|
||||
margin-top: 124.5px;
|
||||
}
|
||||
|
||||
> .formElement {
|
||||
> .noPasswordSection {
|
||||
line-height: 32px;
|
||||
margin-top: 15px;
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
|
||||
> .styledIcon {
|
||||
margin-right: 5px;
|
||||
line-height: 32px;
|
||||
}
|
||||
|
||||
> span {
|
||||
display: block;
|
||||
line-height: 32px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.twoRow {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.error {
|
||||
> p {
|
||||
line-height: 1.4285;
|
||||
color: var(--danger);
|
||||
font-family: var(--font-medium);
|
||||
text-align: center;
|
||||
font-size: 14.5px;
|
||||
border-top: 1px solid var(--danger);
|
||||
margin-top: 15px;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
#reports {
|
||||
}
|
||||
|
||||
#reports > .top > .graph {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
#reports > .top > .graph > .graphHeader {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
#reports > .top > .issueList {
|
||||
display: block;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
#reports > .top > .issueList > .issueListHeader {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
#reports > .top > .issueList > .issue {
|
||||
display: grid;
|
||||
grid-template-columns: 32px 32px 240px auto 120px;
|
||||
}
|
||||
|
||||
#reports > .top > .issueList > .issue.selected {
|
||||
color: var(--primary);
|
||||
font-family: var(--font-bold);
|
||||
}
|
||||
|
||||
#reports > .top > .issueList > .issue.nonSelected {
|
||||
color: var(--textLight);
|
||||
font-family: var(--font-regular);
|
||||
}
|
35
jirs-client/js/css/reports.scss
Normal file
35
jirs-client/js/css/reports.scss
Normal file
@ -0,0 +1,35 @@
|
||||
#reports {
|
||||
> .top {
|
||||
> .graph {
|
||||
margin-top: 15px;
|
||||
|
||||
> .graphHeader {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
> .issueList {
|
||||
display: block;
|
||||
margin-top: 15px;
|
||||
|
||||
> .issueListHeader {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
> .issue {
|
||||
display: grid;
|
||||
grid-template-columns: 32px 32px 240px auto 120px;
|
||||
}
|
||||
|
||||
> .issue.selected {
|
||||
color: var(--primary);
|
||||
font-family: var(--font-bold);
|
||||
}
|
||||
|
||||
> .issue.nonSelected {
|
||||
color: var(--textLight);
|
||||
font-family: var(--font-regular);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,166 +0,0 @@
|
||||
nav#sidebar {
|
||||
position: fixed;
|
||||
z-index: calc(var(--navLeft) - 1);
|
||||
top: 0;
|
||||
left: var(--appNavBarLeftWidth);
|
||||
height: 100vh;
|
||||
width: var(--secondarySideBarWidth);
|
||||
padding: 0 16px 24px;
|
||||
background: var(--backgroundLightest);
|
||||
border-right: 1px solid var(--borderLightest);
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
nav#sidebar::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
nav#sidebar::-webkit-scrollbar-track {
|
||||
background: none;
|
||||
}
|
||||
|
||||
nav#sidebar::-webkit-scrollbar-thumb {
|
||||
border-radius: 99px;
|
||||
background: var(--backgroundMedium);
|
||||
}
|
||||
|
||||
@media (max-width: 1100px) {
|
||||
nav#sidebar {
|
||||
width: calc(var(--secondarySideBarWidth) - 10px);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 999px) {
|
||||
nav#sidebar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
nav#sidebar #projectInfo {
|
||||
display: flex;
|
||||
padding: 24px 4px;
|
||||
}
|
||||
|
||||
nav#sidebar #projectInfo > .projectTexts {
|
||||
padding: 3px 0 0 10px;
|
||||
}
|
||||
|
||||
nav#sidebar #projectInfo > .projectTexts > .projectName {
|
||||
color: var(--textDark);
|
||||
font-size: 15px;
|
||||
font-family: var(--font-medium);
|
||||
}
|
||||
|
||||
nav#sidebar #projectInfo > .projectTexts > .projectCategory {
|
||||
color: var(--textMedium);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
nav#sidebar .linkItem {
|
||||
position: relative;
|
||||
display: flex;
|
||||
padding: 8px 12px;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
nav#sidebar .linkItem > a {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
nav#sidebar .linkItem.notAllowed, nav#sidebar .linkItem.notAllowed > a {
|
||||
cursor: not-allowed;
|
||||
color: var(--textDark);
|
||||
}
|
||||
|
||||
nav#sidebar .linkItem.notAllowed, nav#sidebar .linkItem.notAllowed > a > .styledIcon {
|
||||
cursor: not-allowed;
|
||||
color: var(--textDark);
|
||||
}
|
||||
|
||||
nav#sidebar .linkItem:hover {
|
||||
background: var(--backgroundLight);
|
||||
}
|
||||
|
||||
nav#sidebar .linkItem.active {
|
||||
color: var(--primary);
|
||||
background: var(--backgroundLight);
|
||||
}
|
||||
|
||||
nav#sidebar .linkItem > a {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
nav#sidebar .linkItem > a > i.styledIcon {
|
||||
margin-right: 15px;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
nav#sidebar .linkItem > a > .linkText {
|
||||
padding-top: 2px;
|
||||
font-size: 14.7px;
|
||||
}
|
||||
|
||||
.styledTooltip.messages {
|
||||
min-width: 800px;
|
||||
}
|
||||
|
||||
.styledTooltip.messages > .messagesList {
|
||||
}
|
||||
|
||||
.styledTooltip.messages > .messagesList > .message {
|
||||
padding: 15px;
|
||||
/*max-height: 90px;*/
|
||||
/*overflow: hidden;*/
|
||||
}
|
||||
|
||||
/*.styledTooltip.messages > .messagesList > .message:hover {*/
|
||||
/* max-height: 100%;*/
|
||||
/*}*/
|
||||
|
||||
.styledTooltip.messages > .messagesList > .message > .top {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.styledTooltip.messages > .messagesList > .message > .top > .summary {
|
||||
font-family: var(--font-bold);
|
||||
font-size: 20px;
|
||||
line-height: 32px;
|
||||
}
|
||||
|
||||
.styledTooltip.messages > .messagesList > .message > .top > .action {
|
||||
width: 32px;
|
||||
}
|
||||
|
||||
.styledTooltip.messages > .messagesList > .message > .description {
|
||||
font-family: var(--font-regular);
|
||||
}
|
||||
|
||||
.styledTooltip.messages > .messagesList > .message > .hyperlink {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.styledTooltip.messages > .messagesList > .message > .hyperlink > a {
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
.styledTooltip.messages > .messagesList > .message > .hyperlink > a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.styledTooltip.messages > .messagesList > .message > .hyperlink > a > .styledIcon {
|
||||
padding-right: 5px;
|
||||
font-size: 14.5px;
|
||||
}
|
||||
|
||||
.styledTooltip.messages > .messagesList > .message > .actions {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.styledTooltip.messages > .messagesList > .message > .actions > .styledButton {
|
||||
margin-right: 15px;
|
||||
}
|
164
jirs-client/js/css/sidebar.scss
Normal file
164
jirs-client/js/css/sidebar.scss
Normal file
@ -0,0 +1,164 @@
|
||||
/*.styledTooltip.messages > .messagesList > .message:hover {*/
|
||||
/* max-height: 100%;*/
|
||||
/*}*/
|
||||
nav#sidebar {
|
||||
position: fixed;
|
||||
z-index: calc(var(--navLeft) - 1);
|
||||
top: 0;
|
||||
left: var(--appNavBarLeftWidth);
|
||||
height: 100vh;
|
||||
width: var(--secondarySideBarWidth);
|
||||
padding: 0 16px 24px;
|
||||
background: var(--backgroundLightest);
|
||||
border-right: 1px solid var(--borderLightest);
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background: none;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
border-radius: 99px;
|
||||
background: var(--backgroundMedium);
|
||||
}
|
||||
|
||||
#projectInfo {
|
||||
display: flex;
|
||||
padding: 24px 4px;
|
||||
|
||||
> .projectTexts {
|
||||
padding: 3px 0 0 10px;
|
||||
|
||||
> .projectName {
|
||||
color: var(--textDark);
|
||||
font-size: 15px;
|
||||
font-family: var(--font-medium);
|
||||
}
|
||||
|
||||
> .projectCategory {
|
||||
color: var(--textMedium);
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.linkItem {
|
||||
position: relative;
|
||||
display: flex;
|
||||
padding: 8px 12px;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
|
||||
> a {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
|
||||
> i.styledIcon {
|
||||
margin-right: 15px;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
> .linkText {
|
||||
padding-top: 2px;
|
||||
font-size: 14.7px;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: var(--backgroundLight);
|
||||
}
|
||||
}
|
||||
|
||||
.linkItem.notAllowed {
|
||||
cursor: not-allowed;
|
||||
color: var(--textDark);
|
||||
|
||||
> a {
|
||||
cursor: not-allowed;
|
||||
color: var(--textDark);
|
||||
|
||||
> .styledIcon {
|
||||
cursor: not-allowed;
|
||||
color: var(--textDark);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.linkItem.active {
|
||||
color: var(--primary);
|
||||
background: var(--backgroundLight);
|
||||
}
|
||||
}
|
||||
|
||||
.styledTooltip.messages {
|
||||
min-width: 800px;
|
||||
|
||||
> .messagesList {
|
||||
> .message {
|
||||
padding: 15px;
|
||||
|
||||
> .top {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
> .summary {
|
||||
font-family: var(--font-bold);
|
||||
font-size: 20px;
|
||||
line-height: 32px;
|
||||
}
|
||||
|
||||
> .action {
|
||||
width: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
> .description {
|
||||
font-family: var(--font-regular);
|
||||
}
|
||||
|
||||
> .hyperlink {
|
||||
margin-top: 15px;
|
||||
|
||||
> a {
|
||||
color: var(--primary);
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
> .styledIcon {
|
||||
padding-right: 5px;
|
||||
font-size: 14.5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> .actions {
|
||||
margin-top: 15px;
|
||||
|
||||
> .styledButton {
|
||||
margin-right: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1100px) {
|
||||
nav#sidebar {
|
||||
width: calc(var(--secondarySideBarWidth) - 10px);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 999px) {
|
||||
nav#sidebar {
|
||||
display: none;
|
||||
}
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
.styledAvatar.image {
|
||||
display: inline-block;
|
||||
border-radius: 100%;
|
||||
/*background-image: url("${imageURL}");*/
|
||||
background-position: 50% 50%;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
background-color: var(--backgroundLight);
|
||||
}
|
||||
|
||||
.styledAvatar.letter {
|
||||
display: inline-block;
|
||||
/*width: ${props => props.size} px;*/
|
||||
/*height: ${props => props.size} px;*/
|
||||
border-radius: 100%;
|
||||
text-transform: uppercase;
|
||||
color: #fff;
|
||||
/*background: ${props => props.color};*/
|
||||
font-family: var(--font-medium);
|
||||
font-weight: normal;
|
||||
/*${props => font.size(Math.round(props.size / 1.7))}*/
|
||||
}
|
||||
|
||||
.styledAvatar.letter > span {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.styledAvatar.avatarColor1, .styledAvatar span.avatarColor1 {
|
||||
color: var(--avatar-color-1);
|
||||
}
|
||||
|
||||
.styledAvatar.avatarColor2, .styledAvatar span.avatarColor2 {
|
||||
color: var(--avatar-color-2);
|
||||
}
|
||||
|
||||
.styledAvatar.avatarColor3, .styledAvatar span.avatarColor3 {
|
||||
color: var(--avatar-color-3);
|
||||
}
|
||||
|
||||
.styledAvatar.avatarColor4, .styledAvatar span.avatarColor4 {
|
||||
color: var(--avatar-color-4);
|
||||
}
|
||||
|
||||
.styledAvatar.avatarColor5, .styledAvatar span.avatarColor5 {
|
||||
color: var(--avatar-color-5);
|
||||
}
|
||||
|
||||
.styledAvatar.avatarColor6, .styledAvatar span.avatarColor6 {
|
||||
color: var(--avatar-color-6);
|
||||
}
|
||||
|
||||
.styledAvatar.avatarColor7, .styledAvatar span.avatarColor7 {
|
||||
color: var(--avatar-color-7);
|
||||
}
|
||||
|
||||
.styledAvatar.avatarColor8, .styledAvatar span.avatarColor8 {
|
||||
color: var(--avatar-color-8);
|
||||
}
|
90
jirs-client/js/css/styledAvatar.scss
Normal file
90
jirs-client/js/css/styledAvatar.scss
Normal file
@ -0,0 +1,90 @@
|
||||
.styledAvatar.image {
|
||||
display: inline-block;
|
||||
border-radius: 100%;
|
||||
background-position: 50% 50%;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
background-color: var(--backgroundLight);
|
||||
}
|
||||
|
||||
.styledAvatar.letter {
|
||||
display: inline-block;
|
||||
border-radius: 100%;
|
||||
text-transform: uppercase;
|
||||
color: #fff;
|
||||
font-family: var(--font-medium);
|
||||
font-weight: normal;
|
||||
|
||||
> span {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.styledAvatar.avatarColor1 {
|
||||
color: var(--avatar-color-1);
|
||||
}
|
||||
|
||||
.styledAvatar {
|
||||
span.avatarColor1 {
|
||||
color: var(--avatar-color-1);
|
||||
}
|
||||
|
||||
span.avatarColor2 {
|
||||
color: var(--avatar-color-2);
|
||||
}
|
||||
|
||||
span.avatarColor3 {
|
||||
color: var(--avatar-color-3);
|
||||
}
|
||||
|
||||
span.avatarColor4 {
|
||||
color: var(--avatar-color-4);
|
||||
}
|
||||
|
||||
span.avatarColor5 {
|
||||
color: var(--avatar-color-5);
|
||||
}
|
||||
|
||||
span.avatarColor6 {
|
||||
color: var(--avatar-color-6);
|
||||
}
|
||||
|
||||
span.avatarColor7 {
|
||||
color: var(--avatar-color-7);
|
||||
}
|
||||
|
||||
span.avatarColor8 {
|
||||
color: var(--avatar-color-8);
|
||||
}
|
||||
}
|
||||
|
||||
.styledAvatar.avatarColor2 {
|
||||
color: var(--avatar-color-2);
|
||||
}
|
||||
|
||||
.styledAvatar.avatarColor3 {
|
||||
color: var(--avatar-color-3);
|
||||
}
|
||||
|
||||
.styledAvatar.avatarColor4 {
|
||||
color: var(--avatar-color-4);
|
||||
}
|
||||
|
||||
.styledAvatar.avatarColor5 {
|
||||
color: var(--avatar-color-5);
|
||||
}
|
||||
|
||||
.styledAvatar.avatarColor6 {
|
||||
color: var(--avatar-color-6);
|
||||
}
|
||||
|
||||
.styledAvatar.avatarColor7 {
|
||||
color: var(--avatar-color-7);
|
||||
}
|
||||
|
||||
.styledAvatar.avatarColor8 {
|
||||
color: var(--avatar-color-8);
|
||||
}
|
@ -1,100 +0,0 @@
|
||||
.styledButton {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 32px;
|
||||
vertical-align: middle;
|
||||
line-height: 2;
|
||||
white-space: nowrap;
|
||||
border-radius: 3px;
|
||||
transition: all 0.1s;
|
||||
appearance: none;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
font-size: 14.5px;
|
||||
}
|
||||
|
||||
.styledButton.withIcon > span.text {
|
||||
margin-left: 7px;
|
||||
}
|
||||
|
||||
.styledButton:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.styledButton:not(.iconOnly) {
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
.styledButton.iconOnly {
|
||||
padding: 0 9px;
|
||||
}
|
||||
|
||||
.styledButton.primary, .styledButton.primary > i {
|
||||
color: #fff;
|
||||
background: var(--primary);
|
||||
font-family: var(--font-medium);
|
||||
}
|
||||
|
||||
.styledButton.primary:not(:disabled):hover {
|
||||
filter: brightness(115%);
|
||||
}
|
||||
|
||||
.styledButton.primary:not(:disabled):active {
|
||||
filter: brightness(110%);
|
||||
}
|
||||
|
||||
.styledButton.primary:not(:disabled).isActive {
|
||||
filter: brightness(110%);
|
||||
}
|
||||
|
||||
.styledButton.success, .styledButton.success > i {
|
||||
color: #fff;
|
||||
background: var(--success);
|
||||
}
|
||||
|
||||
.styledButton.danger, .styledButton.danger > i {
|
||||
color: #fff;
|
||||
background: var(--danger);
|
||||
}
|
||||
|
||||
.styledButton.secondary, .styledButton.secondary > i {
|
||||
color: var(--textDark);
|
||||
background: var(--secondary);
|
||||
font-family: var(--font-regular);
|
||||
}
|
||||
|
||||
.styledButton.secondary:not(:disabled):hover {
|
||||
background: var(--backgroundLight);
|
||||
}
|
||||
|
||||
.styledButton.secondary:not(:disabled):active {
|
||||
color: var(--primary);
|
||||
background: var(--backgroundLightPrimary);
|
||||
}
|
||||
|
||||
.styledButton.secondary:not(:disabled).isActive {
|
||||
color: var(--primary);
|
||||
background: var(--backgroundLightPrimary);
|
||||
}
|
||||
|
||||
.styledButton.empty, .styledButton.empty > i {
|
||||
background: #fff;
|
||||
color: var(--textDark);
|
||||
font-family: var(--font-regular);
|
||||
}
|
||||
|
||||
.styledButton.empty:not(:disabled):hover, .styledButton.empty:not(:disabled):hover > i {
|
||||
background: var(--backgroundLight);
|
||||
}
|
||||
|
||||
.styledButton.empty:not(:disabled):active {
|
||||
color: var(--primary);
|
||||
background: var(--backgroundLightPrimary);
|
||||
}
|
||||
|
||||
.styledButton.empty:not(:disabled).isActive {
|
||||
color: var(--primary);
|
||||
background: var(--backgroundLightPrimary);
|
||||
}
|
140
jirs-client/js/css/styledButton.scss
Normal file
140
jirs-client/js/css/styledButton.scss
Normal file
@ -0,0 +1,140 @@
|
||||
.styledButton {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 32px;
|
||||
vertical-align: middle;
|
||||
line-height: 2;
|
||||
white-space: nowrap;
|
||||
border-radius: 3px;
|
||||
transition: all 0.1s;
|
||||
appearance: none;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
font-size: 14.5px;
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
&:not(.iconOnly) {
|
||||
padding: 0 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.styledButton.withIcon {
|
||||
> span.text {
|
||||
margin-left: 7px;
|
||||
}
|
||||
}
|
||||
|
||||
.styledButton.iconOnly {
|
||||
padding: 0 9px;
|
||||
}
|
||||
|
||||
.styledButton.primary {
|
||||
color: #fff;
|
||||
background: var(--primary);
|
||||
font-family: var(--font-medium);
|
||||
|
||||
> i {
|
||||
color: #fff;
|
||||
background: var(--primary);
|
||||
font-family: var(--font-medium);
|
||||
}
|
||||
|
||||
&:not(:disabled) {
|
||||
&:hover {
|
||||
filter: brightness(115%);
|
||||
}
|
||||
|
||||
&:active {
|
||||
filter: brightness(110%);
|
||||
}
|
||||
}
|
||||
|
||||
&:not(:disabled).isActive {
|
||||
filter: brightness(110%);
|
||||
}
|
||||
}
|
||||
|
||||
.styledButton.success {
|
||||
color: #fff;
|
||||
background: var(--success);
|
||||
|
||||
> i {
|
||||
color: #fff;
|
||||
background: var(--success);
|
||||
}
|
||||
}
|
||||
|
||||
.styledButton.danger {
|
||||
color: #fff;
|
||||
background: var(--danger);
|
||||
|
||||
> i {
|
||||
color: #fff;
|
||||
background: var(--danger);
|
||||
}
|
||||
}
|
||||
|
||||
.styledButton.secondary {
|
||||
color: var(--textDark);
|
||||
background: var(--secondary);
|
||||
font-family: var(--font-regular);
|
||||
|
||||
> i {
|
||||
color: var(--textDark);
|
||||
background: var(--secondary);
|
||||
font-family: var(--font-regular);
|
||||
}
|
||||
|
||||
&:not(:disabled) {
|
||||
&:hover {
|
||||
background: var(--backgroundLight);
|
||||
}
|
||||
|
||||
&:active {
|
||||
color: var(--primary);
|
||||
background: var(--backgroundLightPrimary);
|
||||
}
|
||||
}
|
||||
|
||||
&:not(:disabled).isActive {
|
||||
color: var(--primary);
|
||||
background: var(--backgroundLightPrimary);
|
||||
}
|
||||
}
|
||||
|
||||
.styledButton.empty {
|
||||
background: #fff;
|
||||
color: var(--textDark);
|
||||
font-family: var(--font-regular);
|
||||
|
||||
> i {
|
||||
background: #fff;
|
||||
color: var(--textDark);
|
||||
font-family: var(--font-regular);
|
||||
}
|
||||
|
||||
&:not(:disabled) {
|
||||
&:hover {
|
||||
background: var(--backgroundLight);
|
||||
|
||||
> i {
|
||||
background: var(--backgroundLight);
|
||||
}
|
||||
}
|
||||
|
||||
&:active {
|
||||
color: var(--primary);
|
||||
background: var(--backgroundLightPrimary);
|
||||
}
|
||||
}
|
||||
|
||||
&:not(:disabled).isActive {
|
||||
color: var(--primary);
|
||||
background: var(--backgroundLightPrimary);
|
||||
}
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
.styledCheckbox {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.styledCheckbox > .styledCheckboxChild {
|
||||
display: block;
|
||||
border: 1px solid var(--borderLight);
|
||||
font-family: var(--font-medium);
|
||||
line-height: 2;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
font-size: 14.5px;
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
.styledCheckbox > .styledCheckboxChild.selected,
|
||||
.styledCheckbox > .styledCheckboxChild:focus {
|
||||
border-color: var(--borderInputFocus);
|
||||
}
|
||||
|
||||
.styledCheckbox > .styledCheckboxChild.selected {
|
||||
color: var(--borderInputFocus);
|
||||
}
|
||||
|
||||
.styledCheckbox > .styledCheckboxChild > input[type=radio] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.styledCheckbox > .styledCheckboxChild.untracking.selected {
|
||||
color: var(--success);
|
||||
border-color: var(--success);
|
||||
}
|
||||
|
||||
.styledCheckbox > .styledCheckboxChild.fibonacci.selected {
|
||||
color: var(--warning);
|
||||
border-color: var(--warning);
|
||||
}
|
||||
|
||||
.styledCheckbox > .styledCheckboxChild.hourly.selected {
|
||||
color: var(--danger);
|
||||
border-color: var(--danger);
|
||||
}
|
43
jirs-client/js/css/styledCheckbox.scss
Normal file
43
jirs-client/js/css/styledCheckbox.scss
Normal file
@ -0,0 +1,43 @@
|
||||
.styledCheckbox {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
> .styledCheckboxChild {
|
||||
display: block;
|
||||
border: 1px solid var(--borderLight);
|
||||
font-family: var(--font-medium);
|
||||
line-height: 2;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
font-size: 14.5px;
|
||||
padding: 0 12px;
|
||||
|
||||
&:focus {
|
||||
border-color: var(--borderInputFocus);
|
||||
}
|
||||
|
||||
> input[type=radio] {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
> .styledCheckboxChild.selected {
|
||||
border-color: var(--borderInputFocus);
|
||||
color: var(--borderInputFocus);
|
||||
}
|
||||
|
||||
> .styledCheckboxChild.untracking.selected {
|
||||
color: var(--success);
|
||||
border-color: var(--success);
|
||||
}
|
||||
|
||||
> .styledCheckboxChild.fibonacci.selected {
|
||||
color: var(--warning);
|
||||
border-color: var(--warning);
|
||||
}
|
||||
|
||||
> .styledCheckboxChild.hourly.selected {
|
||||
color: var(--danger);
|
||||
border-color: var(--danger);
|
||||
}
|
||||
}
|
@ -1,74 +0,0 @@
|
||||
.styledComment {
|
||||
position: relative;
|
||||
margin-top: 25px;
|
||||
font-size: 15px
|
||||
}
|
||||
|
||||
.styledComment > .userAvatar {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.styledComment > .content {
|
||||
padding-left: 44px;
|
||||
}
|
||||
|
||||
.styledComment > .content > .userName {
|
||||
display: inline-block;
|
||||
padding-right: 12px;
|
||||
padding-bottom: 10px;
|
||||
color: var(--textDark);
|
||||
font-family: var(--font-medium);
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.styledComment > .content > .createdAt {
|
||||
display: inline-block;
|
||||
padding-bottom: 10px;
|
||||
color: var(--textDark);
|
||||
font-size: 14.5px
|
||||
}
|
||||
|
||||
/* as view */
|
||||
|
||||
.styledComment > .content > .body {
|
||||
padding-bottom: 10px;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.styledComment > .content > .editButton {
|
||||
margin-right: 12px;
|
||||
display: inline-block;
|
||||
padding: 2px 0;
|
||||
color: var(--textMedium);
|
||||
font-size: 14.5px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.styledComment > .content > .editButton:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.styledComment > .content > .deleteButton {
|
||||
display: inline-block;
|
||||
padding: 2px 0;
|
||||
color: var(--textMedium);
|
||||
font-size: 14.5px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.styledComment > .content > .deleteButton:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.styledComment > .content > .deleteButton:before {
|
||||
position: relative;
|
||||
right: 6px;
|
||||
content: '·';
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/* as form */
|
71
jirs-client/js/css/styledComment.scss
Normal file
71
jirs-client/js/css/styledComment.scss
Normal file
@ -0,0 +1,71 @@
|
||||
.styledComment {
|
||||
position: relative;
|
||||
margin-top: 25px;
|
||||
font-size: 15px;
|
||||
|
||||
> .userAvatar {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
> .content {
|
||||
padding-left: 44px;
|
||||
|
||||
> .userName {
|
||||
display: inline-block;
|
||||
padding-right: 12px;
|
||||
padding-bottom: 10px;
|
||||
color: var(--textDark);
|
||||
font-family: var(--font-medium);
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
> .createdAt {
|
||||
display: inline-block;
|
||||
padding-bottom: 10px;
|
||||
color: var(--textDark);
|
||||
font-size: 14.5px;
|
||||
}
|
||||
|
||||
/* as view */
|
||||
> .body {
|
||||
padding-bottom: 10px;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
> .editButton {
|
||||
margin-right: 12px;
|
||||
display: inline-block;
|
||||
padding: 2px 0;
|
||||
color: var(--textMedium);
|
||||
font-size: 14.5px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
> .deleteButton {
|
||||
display: inline-block;
|
||||
padding: 2px 0;
|
||||
color: var(--textMedium);
|
||||
font-size: 14.5px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
&:before {
|
||||
position: relative;
|
||||
right: 6px;
|
||||
content: '·';
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,94 +0,0 @@
|
||||
.styledDateTimeInput {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* TOOLTIP */
|
||||
|
||||
.dateTimeTooltip {
|
||||
padding: 15px;
|
||||
position: absolute;
|
||||
top: -50px;
|
||||
left: 110px;
|
||||
width: 610px;
|
||||
min-width: 610px;
|
||||
max-width: 610px;
|
||||
}
|
||||
|
||||
.dateTimeTooltip:before {
|
||||
content: '';
|
||||
display: block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
position: absolute;
|
||||
left: -10px;
|
||||
top: 56px;
|
||||
transform: rotate(45deg);
|
||||
background: white;
|
||||
z-index: -1;
|
||||
border-left: 1px solid rgba(9, 30, 66, 0.25);
|
||||
border-bottom: 1px solid rgba(9, 30, 66, 0.25);
|
||||
}
|
||||
|
||||
.dateTimeTooltip > h2 {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 15px;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.dateTimeTooltip > .actions {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
height: 2rem;
|
||||
line-height: 2rem;
|
||||
}
|
||||
|
||||
.dateTimeTooltip > .calendar {
|
||||
}
|
||||
|
||||
.dateTimeTooltip > .calendar > .week {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.dateTimeTooltip > .calendar > .week.weekHeader {
|
||||
border-bottom: 1px solid var(--textDarkest);
|
||||
cursor: auto;
|
||||
}
|
||||
|
||||
.dateTimeTooltip > .calendar > .week.weekHeader > .day {
|
||||
cursor: auto;
|
||||
}
|
||||
|
||||
.dateTimeTooltip > .calendar > .week > .day {
|
||||
width: calc(100% / 7);
|
||||
text-align: center;
|
||||
height: 2rem;
|
||||
line-height: 2rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dateTimeTooltip > .calendar > .week > .day.inCurrentMonth:hover,
|
||||
.dateTimeTooltip > .calendar > .week > .day.outCurrentMonth:hover {
|
||||
background: var(--primary);
|
||||
color: var(--asideIcon);
|
||||
}
|
||||
|
||||
.dateTimeTooltip > .calendar > .week > .day.inCurrentMonth {
|
||||
color: var(--textDarkest);
|
||||
}
|
||||
|
||||
.dateTimeTooltip > .calendar > .week > .day.outCurrentMonth {
|
||||
color: var(--textLight);
|
||||
}
|
||||
|
||||
.dateTimeTooltip > .calendar > .week > .day.inCurrentMonth.selected,
|
||||
.dateTimeTooltip > .calendar > .week > .day.outCurrentMonth.selected {
|
||||
color: var(--primary);
|
||||
background: var(--asideIcon);
|
||||
}
|
||||
|
||||
.dateTimeTooltip > .calendar > .week > .day {
|
||||
font-family: var(--font-medium);
|
||||
font-size: 1rem;
|
||||
cursor: pointer;
|
||||
}
|
96
jirs-client/js/css/styledDateTimeInput.scss
Normal file
96
jirs-client/js/css/styledDateTimeInput.scss
Normal file
@ -0,0 +1,96 @@
|
||||
/* TOOLTIP */
|
||||
.styledDateTimeInput {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.dateTimeTooltip {
|
||||
padding: 15px;
|
||||
position: absolute;
|
||||
top: -50px;
|
||||
left: 110px;
|
||||
width: 610px;
|
||||
min-width: 610px;
|
||||
max-width: 610px;
|
||||
|
||||
&:before {
|
||||
content: '';
|
||||
display: block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
position: absolute;
|
||||
left: -10px;
|
||||
top: 56px;
|
||||
transform: rotate(45deg);
|
||||
background: white;
|
||||
z-index: -1;
|
||||
border-left: 1px solid rgba(9, 30, 66, 0.25);
|
||||
border-bottom: 1px solid rgba(9, 30, 66, 0.25);
|
||||
}
|
||||
|
||||
> h2 {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 15px;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
> .actions {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
height: 2rem;
|
||||
line-height: 2rem;
|
||||
}
|
||||
|
||||
> .calendar {
|
||||
> .week {
|
||||
display: flex;
|
||||
|
||||
> .day {
|
||||
width: calc(100% / 7);
|
||||
text-align: center;
|
||||
height: 2rem;
|
||||
line-height: 2rem;
|
||||
cursor: pointer;
|
||||
font-family: var(--font-medium);
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
> .day.inCurrentMonth {
|
||||
&:hover {
|
||||
background: var(--primary);
|
||||
color: var(--asideIcon);
|
||||
}
|
||||
|
||||
color: var(--textDarkest);
|
||||
}
|
||||
|
||||
> .day.outCurrentMonth {
|
||||
&:hover {
|
||||
background: var(--primary);
|
||||
color: var(--asideIcon);
|
||||
}
|
||||
|
||||
color: var(--textLight);
|
||||
}
|
||||
|
||||
> .day.inCurrentMonth.selected {
|
||||
color: var(--primary);
|
||||
background: var(--asideIcon);
|
||||
}
|
||||
|
||||
> .day.outCurrentMonth.selected {
|
||||
color: var(--primary);
|
||||
background: var(--asideIcon);
|
||||
}
|
||||
}
|
||||
|
||||
> .week.weekHeader {
|
||||
border-bottom: 1px solid var(--textDarkest);
|
||||
cursor: auto;
|
||||
|
||||
> .day {
|
||||
cursor: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,76 +0,0 @@
|
||||
.styledEditor {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
flex-wrap: wrap;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.styledEditor > input[type="radio"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.styledEditor > .navbar {
|
||||
border: 1px solid var(--borderLight);
|
||||
border-top-left-radius: 5px;
|
||||
border-top-right-radius: 5px;
|
||||
font-family: var(--font-medium);
|
||||
font-weight: normal;
|
||||
text-align: center;
|
||||
height: 32px;
|
||||
vertical-align: middle;
|
||||
line-height: 2;
|
||||
white-space: nowrap;
|
||||
transition: all 0.1s;
|
||||
appearance: none;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
font-size: 14.5px;
|
||||
}
|
||||
|
||||
.styledEditor > .navbar:not(:hover) {
|
||||
border-color: var(--backgroundLightest);
|
||||
background-color: var(--borderLight);
|
||||
}
|
||||
|
||||
.styledEditor > .navbar.activeTab {
|
||||
background-color: var(--backgroundLightest);
|
||||
border-color: var(--borderLight);
|
||||
}
|
||||
|
||||
.styledEditor > .navbar:hover {
|
||||
background: #fff;
|
||||
border: 1px solid var(--borderInputFocus);
|
||||
box-shadow: 0 0 0 1px var(--borderInputFocus);
|
||||
}
|
||||
|
||||
.styledEditor > .navbar {
|
||||
border-color: var(--borderInputFocus);
|
||||
}
|
||||
|
||||
.styledEditor > .navbar.editorTab {
|
||||
min-width: 50%;
|
||||
}
|
||||
|
||||
.styledEditor > .navbar.viewTab {
|
||||
min-width: 50%;
|
||||
}
|
||||
|
||||
.styledEditor > .styledTextArea {
|
||||
grid-area: view;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.styledEditor > .view {
|
||||
min-width: 100%;
|
||||
display: none;
|
||||
min-height: 40px;
|
||||
padding-top: 15px;
|
||||
}
|
||||
|
||||
.styledEditor > input.editorRadio:checked ~ .styledTextArea {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.styledEditor > input.viewRadio:checked ~ .view {
|
||||
display: block;
|
||||
}
|
85
jirs-client/js/css/styledEditor.scss
Normal file
85
jirs-client/js/css/styledEditor.scss
Normal file
@ -0,0 +1,85 @@
|
||||
.styledEditor {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
flex-wrap: wrap;
|
||||
max-width: 100%;
|
||||
|
||||
> input[type="radio"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
> .navbar {
|
||||
border: 1px solid var(--borderLight);
|
||||
border-top-left-radius: 5px;
|
||||
border-top-right-radius: 5px;
|
||||
font-family: var(--font-medium);
|
||||
font-weight: normal;
|
||||
text-align: center;
|
||||
height: 32px;
|
||||
vertical-align: middle;
|
||||
line-height: 2;
|
||||
white-space: nowrap;
|
||||
transition: all 0.1s;
|
||||
appearance: none;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
font-size: 14.5px;
|
||||
border-color: var(--borderInputFocus);
|
||||
|
||||
&:not(:hover) {
|
||||
border-color: var(--backgroundLightest);
|
||||
background-color: var(--borderLight);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: #fff;
|
||||
border: 1px solid var(--borderInputFocus);
|
||||
box-shadow: 0 0 0 1px var(--borderInputFocus);
|
||||
}
|
||||
}
|
||||
|
||||
> .navbar.activeTab {
|
||||
background-color: var(--backgroundLightest);
|
||||
border-color: var(--borderLight);
|
||||
}
|
||||
|
||||
> .navbar.editorTab {
|
||||
min-width: 50%;
|
||||
}
|
||||
|
||||
> .navbar.viewTab {
|
||||
min-width: 50%;
|
||||
}
|
||||
|
||||
> .styledTextArea {
|
||||
grid-area: view;
|
||||
display: none;
|
||||
}
|
||||
|
||||
> .view {
|
||||
min-width: 100%;
|
||||
display: none;
|
||||
min-height: 40px;
|
||||
padding-top: 15px;
|
||||
}
|
||||
|
||||
> input.editorRadio {
|
||||
&:checked {
|
||||
~ {
|
||||
.styledTextArea {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> input.viewRadio {
|
||||
&:checked {
|
||||
~ {
|
||||
.view {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
.styledForm {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.styledForm > .formElement {
|
||||
padding: 25px 40px 35px;
|
||||
}
|
||||
|
||||
.styledForm > .formElement > .formHeading {
|
||||
padding-bottom: 15px;
|
||||
font-size: 21px;
|
||||
}
|
||||
|
||||
/*.styledForm > .formElement*/
|
||||
.selectItem {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.styledForm > .formElement .selectItem.withBottomMargin {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.styledForm > .formElement .selectItem > .selectItemLabel {
|
||||
padding: 0 3px 0 6px;
|
||||
}
|
||||
|
||||
.styledForm > .formElement .divider {
|
||||
margin-top: 22px;
|
||||
border-top: 1px solid var(--borderLightest);
|
||||
}
|
||||
|
||||
.styledForm > .formElement > .actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding-top: 30px;
|
||||
}
|
||||
|
||||
.styledForm > .formElement > .actions > .actionButton {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.styledField {
|
||||
display: block;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.styledField > .styledLabel {
|
||||
display: block;
|
||||
padding-bottom: 5px;
|
||||
color: var(--textMedium);
|
||||
font-family: var(--font-medium);
|
||||
font-weight: normal;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.styledField > .styledTip {
|
||||
padding-top: 6px;
|
||||
color: var(--textMedium);
|
||||
font-size: 12.5px;
|
||||
}
|
||||
|
||||
.styledField > * {
|
||||
display: block;
|
||||
}
|
67
jirs-client/js/css/styledForm.scss
Normal file
67
jirs-client/js/css/styledForm.scss
Normal file
@ -0,0 +1,67 @@
|
||||
.styledForm {
|
||||
display: block;
|
||||
|
||||
> .formElement {
|
||||
padding: 25px 40px 35px;
|
||||
|
||||
> .formHeading {
|
||||
padding-bottom: 15px;
|
||||
font-size: 21px;
|
||||
}
|
||||
|
||||
.selectItem.withBottomMargin {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.selectItem {
|
||||
> .selectItemLabel {
|
||||
padding: 0 3px 0 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.divider {
|
||||
margin-top: 22px;
|
||||
border-top: 1px solid var(--borderLightest);
|
||||
}
|
||||
|
||||
> .actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding-top: 30px;
|
||||
|
||||
> .actionButton {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.selectItem {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.styledField {
|
||||
display: block;
|
||||
margin-top: 20px;
|
||||
|
||||
> .styledLabel {
|
||||
display: block;
|
||||
padding-bottom: 5px;
|
||||
color: var(--textMedium);
|
||||
font-family: var(--font-medium);
|
||||
font-weight: normal;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
> .styledTip {
|
||||
padding-top: 6px;
|
||||
color: var(--textMedium);
|
||||
font-size: 12.5px;
|
||||
}
|
||||
|
||||
> * {
|
||||
display: block;
|
||||
}
|
||||
}
|
@ -1,423 +0,0 @@
|
||||
i.styledIcon {
|
||||
color: var(--primary);
|
||||
display: inline-block;
|
||||
font-size: 16px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
i.styledIcon.left {
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
|
||||
i.styledIcon.top {
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
|
||||
i.styledIcon:before {
|
||||
font-family: 'IcoFont';
|
||||
speak: none;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-variant: normal;
|
||||
text-transform: none;
|
||||
line-height: 1;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
i.styledIcon.stopwatch:before {
|
||||
content: "\ec89";
|
||||
}
|
||||
|
||||
i.styledIcon.bug:before {
|
||||
content: "\eec7";
|
||||
}
|
||||
|
||||
i.styledIcon.task:before {
|
||||
content: "\ef27";
|
||||
}
|
||||
|
||||
i.styledIcon.story:before {
|
||||
content: "\ef2d";
|
||||
}
|
||||
|
||||
i.styledIcon.epic:before {
|
||||
content: '\ef30';
|
||||
}
|
||||
|
||||
i.styledIcon.arrowDown:before {
|
||||
content: "\ea92";
|
||||
}
|
||||
|
||||
i.styledIcon.arrowUp:before {
|
||||
content: "\ea95";
|
||||
}
|
||||
|
||||
i.styledIcon.arrowLeftCircle:before {
|
||||
font-family: "jira";
|
||||
content: "\e917";
|
||||
}
|
||||
|
||||
i.styledIcon.chevronDown:before {
|
||||
font-family: "jira";
|
||||
content: "\e900";
|
||||
}
|
||||
|
||||
i.styledIcon.chevronLeft:before {
|
||||
font-family: "jira";
|
||||
content: "\e901";
|
||||
}
|
||||
|
||||
i.styledIcon.chevronRight:before {
|
||||
font-family: "jira";
|
||||
content: "\e902";
|
||||
}
|
||||
|
||||
i.styledIcon.chevronUp:before {
|
||||
font-family: "jira";
|
||||
content: "\e903";
|
||||
}
|
||||
|
||||
i.styledIcon.board:before {
|
||||
content: "\ead0";
|
||||
}
|
||||
|
||||
i.styledIcon.help:before {
|
||||
content: "\efca";
|
||||
}
|
||||
|
||||
i.styledIcon.link:before {
|
||||
content: "\ef71";
|
||||
|
||||
}
|
||||
|
||||
i.styledIcon.menu:before {
|
||||
font-family: "jira";
|
||||
content: "\e916";
|
||||
}
|
||||
|
||||
i.styledIcon.more:before {
|
||||
font-family: "jira";
|
||||
content: "\e90e";
|
||||
}
|
||||
|
||||
i.styledIcon.attach:before {
|
||||
font-family: "jira";
|
||||
content: "\e90d";
|
||||
}
|
||||
|
||||
i.styledIcon.plus:before {
|
||||
content: "\efc2";
|
||||
}
|
||||
|
||||
i.styledIcon.search:before {
|
||||
content: "\ec82";
|
||||
}
|
||||
|
||||
i.styledIcon.issues:before {
|
||||
content: "\ed19";
|
||||
}
|
||||
|
||||
i.styledIcon.settings:before {
|
||||
content: "\efe2";
|
||||
}
|
||||
|
||||
i.styledIcon.close:before {
|
||||
content: "\eee4";
|
||||
}
|
||||
|
||||
i.styledIcon.feedback:before {
|
||||
font-family: "jira";
|
||||
content: "\e918";
|
||||
}
|
||||
|
||||
i.styledIcon.trash:before {
|
||||
content: "\eebb";
|
||||
}
|
||||
|
||||
i.styledIcon.github:before {
|
||||
content: "\ed3e";
|
||||
}
|
||||
|
||||
i.styledIcon.shipping:before {
|
||||
content: "\efbe";
|
||||
}
|
||||
|
||||
i.styledIcon.component:before {
|
||||
content: "\eef8";
|
||||
}
|
||||
|
||||
i.styledIcon.reports:before {
|
||||
content: "\eeaf";
|
||||
}
|
||||
|
||||
i.styledIcon.page:before {
|
||||
content: "\efb2";
|
||||
}
|
||||
|
||||
i.styledIcon.calendar:before {
|
||||
content: "\ec45";
|
||||
}
|
||||
|
||||
i.styledIcon.cop:before {
|
||||
content: "\ebb4";
|
||||
}
|
||||
|
||||
i.styledIcon.arrowLeft:before {
|
||||
font-family: "jira";
|
||||
content: "\e91e";
|
||||
}
|
||||
|
||||
i.styledIcon.arrowRight:before {
|
||||
font-family: "jira";
|
||||
content: "\e91f";
|
||||
}
|
||||
|
||||
i.styledIcon.user:before {
|
||||
content: "\ec8e";
|
||||
}
|
||||
|
||||
i.styledIcon.message:before {
|
||||
content: "\efac";
|
||||
}
|
||||
|
||||
i.styledIcon.check:before {
|
||||
content: "\ec4b";
|
||||
}
|
||||
|
||||
/********/
|
||||
/* RTE */
|
||||
/********/
|
||||
|
||||
i.styledIcon.align-center:before {
|
||||
content: "\eddf";
|
||||
}
|
||||
|
||||
i.styledIcon.align-left:before {
|
||||
content: "\ede0";
|
||||
}
|
||||
|
||||
i.styledIcon.align-right:before {
|
||||
content: "\ede1";
|
||||
}
|
||||
|
||||
i.styledIcon.all-caps:before {
|
||||
content: "\ede2";
|
||||
}
|
||||
|
||||
i.styledIcon.bold:before {
|
||||
content: "\ede3";
|
||||
}
|
||||
|
||||
i.styledIcon.brush:before {
|
||||
content: "\ede4";
|
||||
}
|
||||
|
||||
i.styledIcon.clip-board:before {
|
||||
content: "\ede5";
|
||||
}
|
||||
|
||||
i.styledIcon.code-alt:before {
|
||||
content: "\ede6";
|
||||
}
|
||||
|
||||
i.styledIcon.color-bucket:before {
|
||||
content: "\ede7";
|
||||
}
|
||||
|
||||
i.styledIcon.color-picker:before {
|
||||
content: "\ede8";
|
||||
}
|
||||
|
||||
i.styledIcon.copy-invert:before {
|
||||
content: "\ede9";
|
||||
}
|
||||
|
||||
i.styledIcon.copy:before {
|
||||
content: "\edea";
|
||||
}
|
||||
|
||||
i.styledIcon.cut:before {
|
||||
content: "\edeb";
|
||||
}
|
||||
|
||||
i.styledIcon.delete-alt:before {
|
||||
content: "\edec";
|
||||
}
|
||||
|
||||
i.styledIcon.edit-alt:before {
|
||||
content: "\eded";
|
||||
}
|
||||
|
||||
i.styledIcon.eraser-alt:before {
|
||||
content: "\edee";
|
||||
}
|
||||
|
||||
i.styledIcon.font:before {
|
||||
content: "\edef";
|
||||
}
|
||||
|
||||
i.styledIcon.heading:before {
|
||||
content: "\edf0";
|
||||
}
|
||||
|
||||
i.styledIcon.indent:before {
|
||||
content: "\edf1";
|
||||
}
|
||||
|
||||
i.styledIcon.italic-alt:before {
|
||||
content: "\edf2";
|
||||
}
|
||||
|
||||
i.styledIcon.italic:before {
|
||||
content: "\edf3";
|
||||
}
|
||||
|
||||
i.styledIcon.justify-all:before {
|
||||
content: "\edf4";
|
||||
}
|
||||
|
||||
i.styledIcon.justify-center:before {
|
||||
content: "\edf5";
|
||||
}
|
||||
|
||||
i.styledIcon.justify-left:before {
|
||||
content: "\edf6";
|
||||
}
|
||||
|
||||
i.styledIcon.justify-right:before {
|
||||
content: "\edf7";
|
||||
}
|
||||
|
||||
i.styledIcon.link-broken:before {
|
||||
content: "\edf8";
|
||||
}
|
||||
|
||||
i.styledIcon.outdent:before {
|
||||
content: "\edf9";
|
||||
}
|
||||
|
||||
i.styledIcon.paper-clip:before {
|
||||
content: "\edfa";
|
||||
}
|
||||
|
||||
i.styledIcon.paragraph:before {
|
||||
content: "\edfb";
|
||||
}
|
||||
|
||||
i.styledIcon.pin:before {
|
||||
content: "\edfc";
|
||||
}
|
||||
|
||||
i.styledIcon.printer:before {
|
||||
content: "\edfd";
|
||||
}
|
||||
|
||||
i.styledIcon.redo:before {
|
||||
content: "\edfe";
|
||||
}
|
||||
|
||||
i.styledIcon.rotation:before {
|
||||
content: "\edff";
|
||||
}
|
||||
|
||||
i.styledIcon.save:before {
|
||||
content: "\ee00";
|
||||
}
|
||||
|
||||
i.styledIcon.small-cap:before {
|
||||
content: "\ee01";
|
||||
}
|
||||
|
||||
i.styledIcon.strike-through:before {
|
||||
content: "\ee02";
|
||||
}
|
||||
|
||||
i.styledIcon.sub-listing:before {
|
||||
content: "\ee03";
|
||||
}
|
||||
|
||||
i.styledIcon.subscript:before {
|
||||
content: "\ee04";
|
||||
}
|
||||
|
||||
i.styledIcon.superscript:before {
|
||||
content: "\ee05";
|
||||
}
|
||||
|
||||
i.styledIcon.table:before {
|
||||
content: "\ee06";
|
||||
}
|
||||
|
||||
i.styledIcon.text-height:before {
|
||||
content: "\ee07";
|
||||
}
|
||||
|
||||
i.styledIcon.text-width:before {
|
||||
content: "\ee08";
|
||||
}
|
||||
|
||||
i.styledIcon.trash:before {
|
||||
content: "\ee09";
|
||||
}
|
||||
|
||||
i.styledIcon.underline:before {
|
||||
content: "\ee0a";
|
||||
}
|
||||
|
||||
i.styledIcon.undo:before {
|
||||
content: "\ee0b";
|
||||
}
|
||||
|
||||
i.styledIcon.listing-dots:before {
|
||||
content: "\ef74";
|
||||
}
|
||||
|
||||
i.styledIcon.listing-number:before {
|
||||
content: "\ef76";
|
||||
}
|
||||
|
||||
i.styledIcon.double-left:before {
|
||||
content: "\ea7b";
|
||||
}
|
||||
|
||||
i.styledIcon.double-right:before {
|
||||
content: "\ea7c";
|
||||
}
|
||||
|
||||
|
||||
i.styledIcon.task {
|
||||
color: var(--task);
|
||||
}
|
||||
|
||||
i.styledIcon.bug {
|
||||
color: var(--bug);
|
||||
}
|
||||
|
||||
i.styledIcon.story {
|
||||
color: var(--story);
|
||||
}
|
||||
|
||||
i.styledIcon.epic {
|
||||
color: var(--epic);
|
||||
}
|
||||
|
||||
i.styledIcon.highest {
|
||||
color: var(--highest);
|
||||
}
|
||||
|
||||
i.styledIcon.high {
|
||||
color: var(--high);
|
||||
}
|
||||
|
||||
i.styledIcon.medium {
|
||||
color: var(--medium);
|
||||
}
|
||||
|
||||
i.styledIcon.low {
|
||||
color: var(--low);
|
||||
}
|
||||
|
||||
i.styledIcon.lowest {
|
||||
color: var(--lowest);
|
||||
}
|
576
jirs-client/js/css/styledIcon.scss
Normal file
576
jirs-client/js/css/styledIcon.scss
Normal file
@ -0,0 +1,576 @@
|
||||
i.styledIcon {
|
||||
color: var(--primary);
|
||||
display: inline-block;
|
||||
font-size: 16px;
|
||||
line-height: 1;
|
||||
|
||||
&:before {
|
||||
font-family: 'IcoFont';
|
||||
speak: none;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-variant: normal;
|
||||
text-transform: none;
|
||||
line-height: 1;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.left {
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
|
||||
i.styledIcon.top {
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
|
||||
i.styledIcon.stopwatch {
|
||||
&:before {
|
||||
content: "\ec89";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.bug {
|
||||
&:before {
|
||||
content: "\eec7";
|
||||
}
|
||||
|
||||
color: var(--bug);
|
||||
}
|
||||
|
||||
i.styledIcon.task {
|
||||
&:before {
|
||||
content: "\ef27";
|
||||
}
|
||||
|
||||
color: var(--task);
|
||||
}
|
||||
|
||||
i.styledIcon.story {
|
||||
&:before {
|
||||
content: "\ef2d";
|
||||
}
|
||||
|
||||
color: var(--story);
|
||||
}
|
||||
|
||||
i.styledIcon.epic {
|
||||
&:before {
|
||||
content: '\ef30';
|
||||
}
|
||||
|
||||
color: var(--epic);
|
||||
}
|
||||
|
||||
i.styledIcon.arrowDown {
|
||||
&:before {
|
||||
content: "\ea92";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.arrowUp {
|
||||
&:before {
|
||||
content: "\ea95";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.arrowLeftCircle {
|
||||
&:before {
|
||||
font-family: "jira";
|
||||
content: "\e917";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.chevronDown {
|
||||
&:before {
|
||||
font-family: "jira";
|
||||
content: "\e900";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.chevronLeft {
|
||||
&:before {
|
||||
font-family: "jira";
|
||||
content: "\e901";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.chevronRight {
|
||||
&:before {
|
||||
font-family: "jira";
|
||||
content: "\e902";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.chevronUp {
|
||||
&:before {
|
||||
font-family: "jira";
|
||||
content: "\e903";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.board {
|
||||
&:before {
|
||||
content: "\ead0";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.help {
|
||||
&:before {
|
||||
content: "\efca";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.link {
|
||||
&:before {
|
||||
content: "\ef71";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.menu {
|
||||
&:before {
|
||||
font-family: "jira";
|
||||
content: "\e916";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.more {
|
||||
&:before {
|
||||
font-family: "jira";
|
||||
content: "\e90e";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.attach {
|
||||
&:before {
|
||||
font-family: "jira";
|
||||
content: "\e90d";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.plus {
|
||||
&:before {
|
||||
content: "\efc2";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.search {
|
||||
&:before {
|
||||
content: "\ec82";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.issues {
|
||||
&:before {
|
||||
content: "\ed19";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.settings {
|
||||
&:before {
|
||||
content: "\efe2";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.close {
|
||||
&:before {
|
||||
content: "\eee4";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.feedback {
|
||||
&:before {
|
||||
font-family: "jira";
|
||||
content: "\e918";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.trash {
|
||||
&:before {
|
||||
content: "\eebb";
|
||||
content: "\ee09";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.github {
|
||||
&:before {
|
||||
content: "\ed3e";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.shipping {
|
||||
&:before {
|
||||
content: "\efbe";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.component {
|
||||
&:before {
|
||||
content: "\eef8";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.reports {
|
||||
&:before {
|
||||
content: "\eeaf";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.page {
|
||||
&:before {
|
||||
content: "\efb2";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.calendar {
|
||||
&:before {
|
||||
content: "\ec45";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.cop {
|
||||
&:before {
|
||||
content: "\ebb4";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.arrowLeft {
|
||||
&:before {
|
||||
font-family: "jira";
|
||||
content: "\e91e";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.arrowRight {
|
||||
&:before {
|
||||
font-family: "jira";
|
||||
content: "\e91f";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.user {
|
||||
&:before {
|
||||
content: "\ec8e";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.message {
|
||||
&:before {
|
||||
content: "\efac";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.check {
|
||||
&:before {
|
||||
content: "\ec4b";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.align-center {
|
||||
&:before {
|
||||
content: "\eddf";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.align-left {
|
||||
&:before {
|
||||
content: "\ede0";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.align-right {
|
||||
&:before {
|
||||
content: "\ede1";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.all-caps {
|
||||
&:before {
|
||||
content: "\ede2";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.bold {
|
||||
&:before {
|
||||
content: "\ede3";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.brush {
|
||||
&:before {
|
||||
content: "\ede4";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.clip-board {
|
||||
&:before {
|
||||
content: "\ede5";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.code-alt {
|
||||
&:before {
|
||||
content: "\ede6";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.color-bucket {
|
||||
&:before {
|
||||
content: "\ede7";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.color-picker {
|
||||
&:before {
|
||||
content: "\ede8";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.copy-invert {
|
||||
&:before {
|
||||
content: "\ede9";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.copy {
|
||||
&:before {
|
||||
content: "\edea";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.cut {
|
||||
&:before {
|
||||
content: "\edeb";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.delete-alt {
|
||||
&:before {
|
||||
content: "\edec";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.edit-alt {
|
||||
&:before {
|
||||
content: "\eded";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.eraser-alt {
|
||||
&:before {
|
||||
content: "\edee";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.font {
|
||||
&:before {
|
||||
content: "\edef";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.heading {
|
||||
&:before {
|
||||
content: "\edf0";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.indent {
|
||||
&:before {
|
||||
content: "\edf1";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.italic-alt {
|
||||
&:before {
|
||||
content: "\edf2";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.italic {
|
||||
&:before {
|
||||
content: "\edf3";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.justify-all {
|
||||
&:before {
|
||||
content: "\edf4";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.justify-center {
|
||||
&:before {
|
||||
content: "\edf5";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.justify-left {
|
||||
&:before {
|
||||
content: "\edf6";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.justify-right {
|
||||
&:before {
|
||||
content: "\edf7";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.link-broken {
|
||||
&:before {
|
||||
content: "\edf8";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.outdent {
|
||||
&:before {
|
||||
content: "\edf9";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.paper-clip {
|
||||
&:before {
|
||||
content: "\edfa";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.paragraph {
|
||||
&:before {
|
||||
content: "\edfb";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.pin {
|
||||
&:before {
|
||||
content: "\edfc";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.printer {
|
||||
&:before {
|
||||
content: "\edfd";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.redo {
|
||||
&:before {
|
||||
content: "\edfe";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.rotation {
|
||||
&:before {
|
||||
content: "\edff";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.save {
|
||||
&:before {
|
||||
content: "\ee00";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.small-cap {
|
||||
&:before {
|
||||
content: "\ee01";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.strike-through {
|
||||
&:before {
|
||||
content: "\ee02";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.sub-listing {
|
||||
&:before {
|
||||
content: "\ee03";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.subscript {
|
||||
&:before {
|
||||
content: "\ee04";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.superscript {
|
||||
&:before {
|
||||
content: "\ee05";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.table {
|
||||
&:before {
|
||||
content: "\ee06";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.text-height {
|
||||
&:before {
|
||||
content: "\ee07";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.text-width {
|
||||
&:before {
|
||||
content: "\ee08";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.underline {
|
||||
&:before {
|
||||
content: "\ee0a";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.undo {
|
||||
&:before {
|
||||
content: "\ee0b";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.listing-dots {
|
||||
&:before {
|
||||
content: "\ef74";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.listing-number {
|
||||
&:before {
|
||||
content: "\ef76";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.double-left {
|
||||
&:before {
|
||||
content: "\ea7b";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.double-right {
|
||||
&:before {
|
||||
content: "\ea7c";
|
||||
}
|
||||
}
|
||||
|
||||
i.styledIcon.highest {
|
||||
color: var(--highest);
|
||||
}
|
||||
|
||||
i.styledIcon.high {
|
||||
color: var(--high);
|
||||
}
|
||||
|
||||
i.styledIcon.medium {
|
||||
color: var(--medium);
|
||||
}
|
||||
|
||||
i.styledIcon.low {
|
||||
color: var(--low);
|
||||
}
|
||||
|
||||
i.styledIcon.lowest {
|
||||
color: var(--lowest);
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
.styledImageInput {
|
||||
}
|
||||
|
||||
.styledImageInput > .label {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
margin: 0 auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.styledImageInput > .label > .mask {
|
||||
display: block;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
border-radius: 60px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.styledImageInput > .input {
|
||||
display: none;
|
||||
}
|
18
jirs-client/js/css/styledImageInput.scss
Normal file
18
jirs-client/js/css/styledImageInput.scss
Normal file
@ -0,0 +1,18 @@
|
||||
.styledImageInput {
|
||||
>.label {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
margin: 0 auto;
|
||||
display: block;
|
||||
>.mask {
|
||||
display: block;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
border-radius: 60px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
>.input {
|
||||
display: none;
|
||||
}
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
.styledInput {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
min-height: 32px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.styledInput > .inputElement {
|
||||
min-height: 32px;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
padding: 0 7px;
|
||||
border-radius: 3px;
|
||||
border: 1px solid var(--borderLightest);
|
||||
color: var(--textDarkest);
|
||||
background: var(--backgroundLightest);
|
||||
transition: background 0.1s;
|
||||
font-family: var(--font-regular);
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.styledInput > .inputElement.withIcon {
|
||||
padding-left: 32px;
|
||||
}
|
||||
|
||||
.styledInput > .inputElement.primary {
|
||||
padding: 8px 12px 9px;
|
||||
height: 39px;
|
||||
}
|
||||
|
||||
.styledInput > i.styledIcon {
|
||||
font-size: 15px;
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
left: 8px;
|
||||
pointer-events: none;
|
||||
color: #5E6C84;
|
||||
}
|
||||
|
||||
.styledInput > .inputElement:hover {
|
||||
background: var(--backgroundLight);
|
||||
}
|
||||
|
||||
.styledInput > .inputElement:focus {
|
||||
background: #fff;
|
||||
border: 1px solid var(--borderInputFocus);
|
||||
box-shadow: 0 0 0 1px var(--borderInputFocus);
|
||||
}
|
||||
|
||||
.styledInput.invalid,
|
||||
.styledInput.invalid:focus {
|
||||
border: 1px solid var(--danger);
|
||||
box-shadow: none;
|
||||
}
|
58
jirs-client/js/css/styledInput.scss
Normal file
58
jirs-client/js/css/styledInput.scss
Normal file
@ -0,0 +1,58 @@
|
||||
.styledInput {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
min-height: 32px;
|
||||
width: 100%;
|
||||
|
||||
> .inputElement {
|
||||
min-height: 32px;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
padding: 0 7px;
|
||||
border-radius: 3px;
|
||||
border: 1px solid var(--borderLightest);
|
||||
color: var(--textDarkest);
|
||||
background: var(--backgroundLightest);
|
||||
transition: background 0.1s;
|
||||
font-family: var(--font-regular);
|
||||
font-size: 15px;
|
||||
|
||||
&:hover {
|
||||
background: var(--backgroundLight);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
background: #fff;
|
||||
border: 1px solid var(--borderInputFocus);
|
||||
box-shadow: 0 0 0 1px var(--borderInputFocus);
|
||||
}
|
||||
}
|
||||
|
||||
> .inputElement.withIcon {
|
||||
padding-left: 32px;
|
||||
}
|
||||
|
||||
> .inputElement.primary {
|
||||
padding: 8px 12px 9px;
|
||||
height: 39px;
|
||||
}
|
||||
|
||||
> i.styledIcon {
|
||||
font-size: 15px;
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
left: 8px;
|
||||
pointer-events: none;
|
||||
color: #5E6C84;
|
||||
}
|
||||
}
|
||||
|
||||
.styledInput.invalid {
|
||||
border: 1px solid var(--danger);
|
||||
box-shadow: none;
|
||||
|
||||
&:focus {
|
||||
border: 1px solid var(--danger);
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
@ -1,149 +0,0 @@
|
||||
.modal {
|
||||
z-index: var(--modal);
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.modal > .clickableOverlay {
|
||||
min-height: 100%;
|
||||
background: rgba(9, 30, 66, 0.54);
|
||||
}
|
||||
|
||||
.modal > .clickableOverlay.center {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 50px;
|
||||
}
|
||||
|
||||
@media (max-width: 1100px) {
|
||||
.modal {
|
||||
z-index: var(--modal);
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.modal > .clickableOverlay {
|
||||
min-height: 100%;
|
||||
background: rgba(9, 30, 66, 0.54);
|
||||
}
|
||||
|
||||
.modal > .clickableOverlay.center {
|
||||
display: block;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.modal > .clickableOverlay {
|
||||
min-height: 100%;
|
||||
background: rgba(9, 30, 66, 0.54);
|
||||
}
|
||||
|
||||
.modal > .clickableOverlay > .styledModal {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.modal > .clickableOverlay > .styledModal.center {
|
||||
vertical-align: middle;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 5px 10px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.modal > .clickableOverlay > .styledModal.aside {
|
||||
min-height: 100vh;
|
||||
box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.modal > .clickableOverlay > .styledModal.aside > .styledIcon {
|
||||
position: absolute;
|
||||
font-size: 25px;
|
||||
color: var(--textMedium);
|
||||
transition: all 0.1s;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.modal > .clickableOverlay > .styledModal.aside > .styledIcon.modalVariantCenter {
|
||||
top: 10px;
|
||||
right: 12px;
|
||||
padding: 3px 5px 0 5px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.modal > .clickableOverlay > .styledModal.aside > .styledIcon.modalVariantCenter:hover {
|
||||
background: var(--backgroundLight);
|
||||
}
|
||||
|
||||
.modal > .clickableOverlay > .styledModal.aside > .styledIcon.modalVariantAside {
|
||||
top: 10px;
|
||||
right: -30px;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
padding-top: 10px;
|
||||
border-radius: 3px;
|
||||
text-align: center;
|
||||
background: #fff;
|
||||
border: 1px solid var(--borderLightest);
|
||||
box-shadow: 0 5px 10px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.modal > .clickableOverlay > .styledModal.aside > .styledIcon.modalVariantAside:hover {
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
.modal > .clickableOverlay > .styledModal.addIssue {
|
||||
max-width: 800px;
|
||||
}
|
||||
|
||||
@media (max-width: 1100px) {
|
||||
.modal > .clickableOverlay > .styledModal.addIssue {
|
||||
max-width: none;
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.modal > .clickableOverlay > .styledModal.confirmModal {
|
||||
padding: 35px 40px 40px;
|
||||
}
|
||||
|
||||
.modal > .clickableOverlay > .styledModal.confirmModal > .title {
|
||||
padding-bottom: 25px;
|
||||
font-family: var(--font-medium);
|
||||
font-weight: normal;
|
||||
font-size: 22px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.modal > .clickableOverlay > .styledModal.confirmModal > .message {
|
||||
padding-bottom: 25px;
|
||||
white-space: pre-wrap;
|
||||
font-size: 15px
|
||||
}
|
||||
|
||||
.modal > .clickableOverlay > .styledModal.confirmModal > .actions {
|
||||
display: flex;
|
||||
padding-top: 6px;
|
||||
}
|
||||
|
||||
.modal > .clickableOverlay > .styledModal.confirmModal > .actions > .styledButton {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.modal > .clickableOverlay > .styledModal.debugModal {
|
||||
padding-left: 15px;
|
||||
}
|
142
jirs-client/js/css/styledModal.scss
Normal file
142
jirs-client/js/css/styledModal.scss
Normal file
@ -0,0 +1,142 @@
|
||||
.modal {
|
||||
z-index: var(--modal);
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
|
||||
> .clickableOverlay {
|
||||
min-height: 100%;
|
||||
background: rgba(9, 30, 66, 0.54);
|
||||
|
||||
&.center {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 50px;
|
||||
}
|
||||
|
||||
> .styledModal {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
background: #fff;
|
||||
|
||||
&.center {
|
||||
vertical-align: middle;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 5px 10px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
&.aside {
|
||||
min-height: 100vh;
|
||||
box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.15);
|
||||
|
||||
> .styledIcon {
|
||||
position: absolute;
|
||||
font-size: 25px;
|
||||
color: var(--textMedium);
|
||||
transition: all 0.1s;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
|
||||
&.modalVariantCenter {
|
||||
top: 10px;
|
||||
right: 12px;
|
||||
padding: 3px 5px 0 5px;
|
||||
border-radius: 4px;
|
||||
|
||||
&:hover {
|
||||
background: var(--backgroundLight);
|
||||
}
|
||||
}
|
||||
|
||||
&.modalVariantAside {
|
||||
top: 10px;
|
||||
right: -30px;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
padding-top: 10px;
|
||||
border-radius: 3px;
|
||||
text-align: center;
|
||||
background: #fff;
|
||||
border: 1px solid var(--borderLightest);
|
||||
box-shadow: 0 5px 10px 0 rgba(0, 0, 0, 0.1);
|
||||
|
||||
&:hover {
|
||||
color: var(--primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.addIssue {
|
||||
max-width: 800px;
|
||||
}
|
||||
|
||||
&.confirmModal {
|
||||
padding: 35px 40px 40px;
|
||||
|
||||
> .title {
|
||||
padding-bottom: 25px;
|
||||
font-family: var(--font-medium);
|
||||
font-weight: normal;
|
||||
font-size: 22px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
> .message {
|
||||
padding-bottom: 25px;
|
||||
white-space: pre-wrap;
|
||||
font-size: 15px
|
||||
}
|
||||
|
||||
> .actions {
|
||||
display: flex;
|
||||
padding-top: 6px;
|
||||
|
||||
> .styledButton {
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.debugModal {
|
||||
padding-left: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1100px) {
|
||||
.modal {
|
||||
z-index: var(--modal);
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
|
||||
> .clickableOverlay {
|
||||
min-height: 100%;
|
||||
background: rgba(9, 30, 66, 0.54);
|
||||
|
||||
&.center {
|
||||
display: block;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
> .styledModal.addIssue {
|
||||
max-width: none;
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,214 +0,0 @@
|
||||
.styledRte {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.styledRte > .bar {
|
||||
display: block;
|
||||
border-radius: 3px;
|
||||
border: 1px solid var(--borderLightest);
|
||||
background: var(--backgroundLightest);
|
||||
font-family: var(--font-regular);
|
||||
}
|
||||
|
||||
.styledRte > .bar > .row {
|
||||
padding: 0 0 var(--rte-indent) 0;
|
||||
display: flex;
|
||||
margin: 0 var(--rte-indent);
|
||||
}
|
||||
|
||||
.styledRte > .bar > .row:first-child {
|
||||
padding: var(--rte-indent) 0;
|
||||
}
|
||||
|
||||
.styledRte > .bar > .row > .group {
|
||||
padding: 0 var(--rte-indent) 0 0;
|
||||
}
|
||||
|
||||
.styledRte > .bar > .row > .group:first-child {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.styledRte > .bar > .row > .group:last-child {
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.styledRte > .bar > .row > .group > .styledRteButton > .styledButton,
|
||||
.styledRte > .bar > .row > .group > .styledButton,
|
||||
.styledRte > .bar > .row > .group > span.headingList {
|
||||
margin-right: var(--rte-indent);
|
||||
font-size: var(--small-font-size);
|
||||
}
|
||||
|
||||
.styledRte > .bar > .row > .group.font > span.headingList > .headingOption {
|
||||
margin-right: var(--rte-indent);
|
||||
}
|
||||
|
||||
.styledRte > .bar > .row > .group > .styledRteButton > .styledButton,
|
||||
.styledRte > .bar > .row > .group > .styledRteButton > .styledButton > .styledIcon,
|
||||
.styledRte > .bar > .row > .group > span.headingList > .headingOption > .styledButton,
|
||||
.styledRte > .bar > .row > .group > span.headingList > .headingOption > .styledButton > span {
|
||||
font-size: var(--small-font-size);
|
||||
line-height: calc(2 * var(--small-font-size));
|
||||
height: calc(2 * var(--small-font-size));
|
||||
}
|
||||
|
||||
.styledRte > .bar > .row > .group > .headingList {
|
||||
height: 32px;
|
||||
min-width: 40px;
|
||||
overflow-y: visible;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.styledRte > .editorWrapper {
|
||||
display: block;
|
||||
width: 100%;
|
||||
border-radius: 3px;
|
||||
border: 1px solid var(--borderLightest);
|
||||
background: var(--backgroundLightest);
|
||||
font-family: var(--font-regular);
|
||||
color: var(--textDarkest);
|
||||
font-weight: normal;
|
||||
font-size: 15px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.styledRte > .editorWrapper > .editor {
|
||||
display: block;
|
||||
margin: 8px 12px 9px;
|
||||
min-height: 60px;
|
||||
}
|
||||
|
||||
.styledRte > .editorWrapper > .editor ul,
|
||||
.styledRte > .editorWrapper > .editor ol {
|
||||
margin-left: 25px;
|
||||
}
|
||||
|
||||
.styledRte > .editorWrapper > .editor ul > li {
|
||||
list-style: square;
|
||||
}
|
||||
|
||||
.styledRte > .editorWrapper > .editor ol > li {
|
||||
list-style: decimal;
|
||||
}
|
||||
|
||||
.styledRte > .editorWrapper > .editor table {
|
||||
table-layout: fixed;
|
||||
border-spacing: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.styledRte > .editorWrapper > .editor table > tbody > tr > td {
|
||||
min-width: 24px;
|
||||
min-height: 24px;
|
||||
text-align: center;
|
||||
padding: var(--rte-indent);
|
||||
border-bottom: 1px solid var(--borderLight);
|
||||
border-right: 1px solid var(--borderLight);
|
||||
border-left: 1px solid var(--borderLight);
|
||||
border-top: 1px solid var(--borderLight);
|
||||
}
|
||||
|
||||
.styledRte > .editorWrapper > .editor *:focus {
|
||||
background: var(--secondary);
|
||||
}
|
||||
|
||||
/**********************************************************/
|
||||
/* Table tooltip */
|
||||
/**********************************************************/
|
||||
|
||||
.tableTooltip {
|
||||
min-width: 136px;
|
||||
padding: 15px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.tableTooltip > h2 {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.tableTooltip > .tablePreview {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.tableTooltip > .tablePreview > table {
|
||||
table-layout: fixed;
|
||||
border-spacing: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.tableTooltip > .tablePreview > table > tbody > tr > td {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
text-align: center;
|
||||
padding: var(--rte-indent);
|
||||
border-bottom: 1px solid var(--borderLight);
|
||||
border-right: 1px solid var(--borderLight);
|
||||
border-left: 1px solid var(--borderLight);
|
||||
border-top: 1px solid var(--borderLight);
|
||||
}
|
||||
|
||||
.tableTooltip > .tablePreview > input {
|
||||
height: 32px;
|
||||
align-self: flex-end;
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
.tableTooltip > .inputs {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
/**********************************************************/
|
||||
/* Code tooltip */
|
||||
/**********************************************************/
|
||||
|
||||
.codeTooltip {
|
||||
min-width: 336px;
|
||||
padding: 15px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
@media (min-width: 800px) {
|
||||
.codeTooltip {
|
||||
min-width: 636px;
|
||||
left: calc(100% / 2 - 318px);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.codeTooltip {
|
||||
min-width: 836px;
|
||||
left: calc(100% / 2 - 418px);
|
||||
}
|
||||
}
|
||||
|
||||
.codeTooltip > h2 {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.codeTooltip > select {
|
||||
width: 100%;
|
||||
border: 1px solid var(--borderLightest);
|
||||
margin: var(--rte-indent) 0;
|
||||
min-height: 1rem;
|
||||
background: var(--backgroundLightest);
|
||||
}
|
||||
|
||||
.codeTooltip > select > option {
|
||||
}
|
||||
|
||||
.codeTooltip > textarea {
|
||||
border: 1px solid var(--borderLightest);
|
||||
width: 100%;
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
.codeTooltip > textarea:focus {
|
||||
border: 1px solid var(--borderInputFocus);
|
||||
}
|
244
jirs-client/js/css/styledRte.scss
Normal file
244
jirs-client/js/css/styledRte.scss
Normal file
@ -0,0 +1,244 @@
|
||||
.styledRte {
|
||||
display: block;
|
||||
|
||||
> .bar {
|
||||
display: block;
|
||||
border-radius: 3px;
|
||||
border: 1px solid var(--borderLightest);
|
||||
background: var(--backgroundLightest);
|
||||
font-family: var(--font-regular);
|
||||
|
||||
> .row {
|
||||
padding: 0 0 var(--rte-indent) 0;
|
||||
display: flex;
|
||||
margin: 0 var(--rte-indent);
|
||||
|
||||
&:first-child {
|
||||
padding: var(--rte-indent) 0;
|
||||
}
|
||||
|
||||
> .group {
|
||||
padding: 0 var(--rte-indent) 0 0;
|
||||
|
||||
&:first-child {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
> .styledRteButton {
|
||||
> .styledButton {
|
||||
margin-right: var(--rte-indent);
|
||||
font-size: var(--small-font-size);
|
||||
font-size: var(--small-font-size);
|
||||
line-height: calc(2 * var(--small-font-size));
|
||||
height: calc(2 * var(--small-font-size));
|
||||
|
||||
> .styledIcon {
|
||||
font-size: var(--small-font-size);
|
||||
line-height: calc(2 * var(--small-font-size));
|
||||
height: calc(2 * var(--small-font-size));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> .styledButton {
|
||||
margin-right: var(--rte-indent);
|
||||
font-size: var(--small-font-size);
|
||||
}
|
||||
|
||||
> span.headingList {
|
||||
margin-right: var(--rte-indent);
|
||||
font-size: var(--small-font-size);
|
||||
|
||||
> .headingOption {
|
||||
> .styledButton {
|
||||
font-size: var(--small-font-size);
|
||||
line-height: calc(2 * var(--small-font-size));
|
||||
height: calc(2 * var(--small-font-size));
|
||||
|
||||
> span {
|
||||
font-size: var(--small-font-size);
|
||||
line-height: calc(2 * var(--small-font-size));
|
||||
height: calc(2 * var(--small-font-size));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> .headingList {
|
||||
height: 32px;
|
||||
min-width: 40px;
|
||||
overflow-y: visible;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
> .group.font {
|
||||
> span.headingList {
|
||||
> .headingOption {
|
||||
margin-right: var(--rte-indent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> .editorWrapper {
|
||||
display: block;
|
||||
width: 100%;
|
||||
border-radius: 3px;
|
||||
border: 1px solid var(--borderLightest);
|
||||
background: var(--backgroundLightest);
|
||||
font-family: var(--font-regular);
|
||||
color: var(--textDarkest);
|
||||
font-weight: normal;
|
||||
font-size: 15px;
|
||||
resize: vertical;
|
||||
|
||||
> .editor {
|
||||
display: block;
|
||||
margin: 8px 12px 9px;
|
||||
min-height: 60px;
|
||||
|
||||
ul {
|
||||
margin-left: 25px;
|
||||
|
||||
> li {
|
||||
list-style: square;
|
||||
}
|
||||
}
|
||||
|
||||
ol {
|
||||
margin-left: 25px;
|
||||
|
||||
> li {
|
||||
list-style: decimal;
|
||||
}
|
||||
}
|
||||
|
||||
table {
|
||||
table-layout: fixed;
|
||||
border-spacing: 0;
|
||||
text-align: center;
|
||||
|
||||
> tbody {
|
||||
> tr {
|
||||
> td {
|
||||
min-width: 24px;
|
||||
min-height: 24px;
|
||||
text-align: center;
|
||||
padding: var(--rte-indent);
|
||||
border-bottom: 1px solid var(--borderLight);
|
||||
border-right: 1px solid var(--borderLight);
|
||||
border-left: 1px solid var(--borderLight);
|
||||
border-top: 1px solid var(--borderLight);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
* {
|
||||
&:focus {
|
||||
background: var(--secondary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tableTooltip {
|
||||
min-width: 136px;
|
||||
padding: 15px;
|
||||
position: absolute;
|
||||
|
||||
> h2 {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
> .tablePreview {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: space-between;
|
||||
|
||||
> table {
|
||||
table-layout: fixed;
|
||||
border-spacing: 0;
|
||||
text-align: center;
|
||||
|
||||
> tbody {
|
||||
> tr {
|
||||
> td {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
text-align: center;
|
||||
padding: var(--rte-indent);
|
||||
border-bottom: 1px solid var(--borderLight);
|
||||
border-right: 1px solid var(--borderLight);
|
||||
border-left: 1px solid var(--borderLight);
|
||||
border-top: 1px solid var(--borderLight);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> input {
|
||||
height: 32px;
|
||||
align-self: flex-end;
|
||||
margin-left: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
> .inputs {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
|
||||
.codeTooltip {
|
||||
min-width: 336px;
|
||||
padding: 15px;
|
||||
position: absolute;
|
||||
|
||||
> h2 {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
> select {
|
||||
width: 100%;
|
||||
border: 1px solid var(--borderLightest);
|
||||
margin: var(--rte-indent) 0;
|
||||
min-height: 1rem;
|
||||
background: var(--backgroundLightest);
|
||||
}
|
||||
|
||||
> textarea {
|
||||
border: 1px solid var(--borderLightest);
|
||||
width: 100%;
|
||||
min-height: 200px;
|
||||
|
||||
&:focus {
|
||||
border: 1px solid var(--borderInputFocus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 800px) {
|
||||
.codeTooltip {
|
||||
min-width: 636px;
|
||||
left: calc(100% / 2 - 318px);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.codeTooltip {
|
||||
min-width: 836px;
|
||||
left: calc(100% / 2 - 418px);
|
||||
}
|
||||
}
|
@ -1,199 +0,0 @@
|
||||
.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 > .valueContainer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.styledSelect > .valueContainer.normal {
|
||||
min-height: 32px;
|
||||
padding: 5px 5px 5px 10px;
|
||||
}
|
||||
|
||||
.styledSelect > .valueContainer > .chevronIcon {
|
||||
margin-left: auto;
|
||||
font-size: 18px;
|
||||
color: var(--textMedium);
|
||||
}
|
||||
|
||||
.styledSelect > .valueContainer > .placeholder,
|
||||
.styledSelect > .valueContainer > .valueMulti > .placeholder {
|
||||
color: var(--textLight);
|
||||
}
|
||||
|
||||
.styledSelectTip {
|
||||
padding-top: 6px;
|
||||
color: var(--textMedium);
|
||||
font-size: 12.5px;
|
||||
}
|
||||
|
||||
.styledSelect > .dropDown {
|
||||
z-index: var(--dropdown);
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
border-radius: 0 0 4px 4px;
|
||||
background: #fff;
|
||||
box-shadow: rgba(9, 30, 66, 0.25) 0 4px 8px -2px, rgba(9, 30, 66, 0.31) 0 0 1px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.styledSelect > .dropDown > .dropDownInput {
|
||||
padding: 10px 14px 8px;
|
||||
width: 100%;
|
||||
border: none;
|
||||
color: var(--textDarkest);
|
||||
background: none;
|
||||
}
|
||||
|
||||
.styledSelect > .dropDown > .dropDownInput:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.styledSelect > .options {
|
||||
max-height: 200px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.styledSelect > .dropDown > .options::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
.styledSelect > .dropDown > .options::-webkit-scrollbar-track {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.styledSelect > .dropDown > .options::-webkit-scrollbar-thumb {
|
||||
border-radius: 99px;
|
||||
background: var(--backgroundMedium);
|
||||
}
|
||||
|
||||
.styledSelect > .dropDown > .options > .option {
|
||||
padding: 8px 14px;
|
||||
word-break: break-word;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.styledSelect > .dropDown > .options > .option:last-of-type {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.styledSelect > .dropDown > .options > .option.jira-select-option-is-active {
|
||||
background: var(--backgroundLightPrimary);
|
||||
}
|
||||
|
||||
.styledSelect > .dropDown > .options > .option:hover {
|
||||
background: var(--backgroundLightPrimary);
|
||||
}
|
||||
|
||||
.styledSelect > .dropDown > .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;
|
||||
}
|
||||
|
||||
/* multi value */
|
||||
.styledSelect > .valueContainer > .valueMulti {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.styledSelect > .valueContainer > .valueMulti.normal {
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
.styledSelect > .valueContainer > .valueMulti > .valueMultiItem {
|
||||
margin-right: 15px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
color: var(--textDarkest);
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.styledSelect > .valueContainer > .valueMulti > .valueMultiItem > .selectItem {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.styledSelect > .valueContainer > .valueMulti > .valueMultiItem > .selectItem > .styledIcon {
|
||||
margin-left: 4px;
|
||||
color: var(--textDarkest);
|
||||
}
|
||||
|
||||
.styledSelect > .valueContainer > .valueMulti > .addMore {
|
||||
display: inline-block;
|
||||
margin-bottom: 3px;
|
||||
padding: 3px 0;
|
||||
font-size: 12.5px;
|
||||
cursor: pointer;
|
||||
color: var(--textLink);
|
||||
font-family: var(--font-medium);
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.styledSelect > .valueContainer > .valueMulti > .addMore:hover,
|
||||
.styledSelect > .valueContainer > .valueMulti > .addMore:visited,
|
||||
.styledSelect > .valueContainer > .valueMulti > .addMore:active {
|
||||
color: var(--textLink);
|
||||
}
|
||||
|
||||
.styledSelect > .valueContainer > .valueMulti > .addMore:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.styledSelect > .valueContainer > .valueMulti > .addMore > .styledIcon {
|
||||
margin-right: 3px;
|
||||
vertical-align: middle;
|
||||
font-size: 14px;
|
||||
}
|
176
jirs-client/js/css/styledSelect.scss
Normal file
176
jirs-client/js/css/styledSelect.scss
Normal file
@ -0,0 +1,176 @@
|
||||
/* multi value */
|
||||
.styledSelect {
|
||||
position: relative;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
&:hover {
|
||||
background: var(--backgroundLight);
|
||||
}
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
>.valueContainer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
>.chevronIcon {
|
||||
margin-left: auto;
|
||||
font-size: 18px;
|
||||
color: var(--textMedium);
|
||||
}
|
||||
>.placeholder {
|
||||
color: var(--textLight);
|
||||
}
|
||||
>.valueMulti {
|
||||
>.placeholder {
|
||||
color: var(--textLight);
|
||||
}
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
>.valueMultiItem {
|
||||
margin-right: 15px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
color: var(--textDarkest);
|
||||
height: 24px;
|
||||
>.selectItem {
|
||||
margin-right: 5px;
|
||||
>.styledIcon {
|
||||
margin-left: 4px;
|
||||
color: var(--textDarkest);
|
||||
}
|
||||
}
|
||||
}
|
||||
>.addMore {
|
||||
display: inline-block;
|
||||
margin-bottom: 3px;
|
||||
padding: 3px 0;
|
||||
font-size: 12.5px;
|
||||
cursor: pointer;
|
||||
color: var(--textLink);
|
||||
font-family: var(--font-medium);
|
||||
font-weight: normal;
|
||||
&:hover {
|
||||
color: var(--textLink);
|
||||
text-decoration: underline;
|
||||
}
|
||||
&:visited {
|
||||
color: var(--textLink);
|
||||
}
|
||||
&:active {
|
||||
color: var(--textLink);
|
||||
}
|
||||
>.styledIcon {
|
||||
margin-right: 3px;
|
||||
vertical-align: middle;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
>.valueMulti.normal {
|
||||
padding-top: 5px;
|
||||
}
|
||||
}
|
||||
>.valueContainer.normal {
|
||||
min-height: 32px;
|
||||
padding: 5px 5px 5px 10px;
|
||||
}
|
||||
>.dropDown {
|
||||
z-index: var(--dropdown);
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
border-radius: 0 0 4px 4px;
|
||||
background: #fff;
|
||||
box-shadow: rgba(9, 30, 66, 0.25) 0 4px 8px -2px, rgba(9, 30, 66, 0.31) 0 0 1px;
|
||||
width: 100%;
|
||||
>.dropDownInput {
|
||||
padding: 10px 14px 8px;
|
||||
width: 100%;
|
||||
border: none;
|
||||
color: var(--textDarkest);
|
||||
background: none;
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
>.options {
|
||||
&::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
&::-webkit-scrollbar-track {
|
||||
background: none;
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
border-radius: 99px;
|
||||
background: var(--backgroundMedium);
|
||||
}
|
||||
>.option {
|
||||
padding: 8px 14px;
|
||||
word-break: break-word;
|
||||
cursor: pointer;
|
||||
&:last-of-type {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
&:hover {
|
||||
background: var(--backgroundLightPrimary);
|
||||
}
|
||||
}
|
||||
>.option.jira-select-option-is-active {
|
||||
background: var(--backgroundLightPrimary);
|
||||
}
|
||||
}
|
||||
>.noOptions {
|
||||
padding: 5px 15px 15px;
|
||||
color: var(--textLight);
|
||||
}
|
||||
}
|
||||
>.options {
|
||||
max-height: 200px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
>.styledIcon {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
right: 7px;
|
||||
padding: 5px;
|
||||
font-size: 16px;
|
||||
color: var(--textMedium);
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
.styledSelect.normal {
|
||||
width: 100%;
|
||||
border: 1px solid var(--borderLightest);
|
||||
background: var(--backgroundLightest);
|
||||
transition: background 0.1s;
|
||||
&:focus {
|
||||
border: 1px solid var(--borderInputFocus);
|
||||
box-shadow: 0 0 0 1px var(--borderInputFocus);
|
||||
background: #fff;
|
||||
}
|
||||
}
|
||||
.styledSelect.empty {
|
||||
display: inline-block;
|
||||
}
|
||||
.styledSelect.invalid {
|
||||
border: 1px solid var(--danger);
|
||||
box-shadow: none;
|
||||
&:focus {
|
||||
border: 1px solid var(--danger);
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
.styledSelectTip {
|
||||
padding-top: 6px;
|
||||
color: var(--textMedium);
|
||||
font-size: 12.5px;
|
||||
}
|
@ -1,72 +0,0 @@
|
||||
.selectItem {
|
||||
padding: 4px 8px;
|
||||
}
|
||||
|
||||
.selectItem.capitalize,
|
||||
.optionItem.capitalize {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.selectItem.priority.highest > .styledIcon,
|
||||
.optionItem.priority.highest > .styledIcon {
|
||||
color: var(--highest);
|
||||
}
|
||||
|
||||
.selectItem.priority.high > .styledIcon,
|
||||
.optionItem.priority.high > .styledIcon {
|
||||
color: var(--high);
|
||||
}
|
||||
|
||||
.selectItem.priority.medium > .styledIcon,
|
||||
.optionItem.priority.medium > .styledIcon {
|
||||
color: var(--medium);
|
||||
}
|
||||
|
||||
.selectItem.priority.low > .styledIcon,
|
||||
.optionItem.priority.low > .styledIcon {
|
||||
color: var(--low);
|
||||
}
|
||||
|
||||
.selectItem.priority.lowest > .styledIcon,
|
||||
.optionItem.priority.lowest > .styledIcon {
|
||||
color: var(--lowest);
|
||||
}
|
||||
|
||||
.selectItem.priority > .selectItemLabel {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.optionItem {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.optionItem > .styledIcon {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.selectItem > .selectItemLabel,
|
||||
.optionItem > .optionLabel {
|
||||
padding: 0 5px 0 7px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.optionItem.priority > .optionLabel {
|
||||
padding: 0 5px 0 7px;
|
||||
font-size: 15px;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.optionItem.priority > .styledIcon {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
/* edit issue */
|
||||
.topActions > .styledSelect > .valueContainer,
|
||||
.topActions > .styledSelect > .valueContainer > .selectItem {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.topActions .selectItem, .topActions .optionItem {
|
||||
padding: 0 12px;
|
||||
}
|
106
jirs-client/js/css/styledSelectChild.scss
Normal file
106
jirs-client/js/css/styledSelectChild.scss
Normal file
@ -0,0 +1,106 @@
|
||||
/* edit issue */
|
||||
.selectItem {
|
||||
padding: 4px 8px;
|
||||
>.selectItemLabel {
|
||||
padding: 0 5px 0 7px;
|
||||
font-size: 15px;
|
||||
}
|
||||
}
|
||||
.selectItem.capitalize {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
.optionItem.capitalize {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
.selectItem.priority.highest {
|
||||
>.styledIcon {
|
||||
color: var(--highest);
|
||||
}
|
||||
}
|
||||
.optionItem.priority.highest {
|
||||
>.styledIcon {
|
||||
color: var(--highest);
|
||||
}
|
||||
}
|
||||
.selectItem.priority.high {
|
||||
>.styledIcon {
|
||||
color: var(--high);
|
||||
}
|
||||
}
|
||||
.optionItem.priority.high {
|
||||
>.styledIcon {
|
||||
color: var(--high);
|
||||
}
|
||||
}
|
||||
.selectItem.priority.medium {
|
||||
>.styledIcon {
|
||||
color: var(--medium);
|
||||
}
|
||||
}
|
||||
.optionItem.priority.medium {
|
||||
>.styledIcon {
|
||||
color: var(--medium);
|
||||
}
|
||||
}
|
||||
.selectItem.priority.low {
|
||||
>.styledIcon {
|
||||
color: var(--low);
|
||||
}
|
||||
}
|
||||
.optionItem.priority.low {
|
||||
>.styledIcon {
|
||||
color: var(--low);
|
||||
}
|
||||
}
|
||||
.selectItem.priority.lowest {
|
||||
>.styledIcon {
|
||||
color: var(--lowest);
|
||||
}
|
||||
}
|
||||
.optionItem.priority.lowest {
|
||||
>.styledIcon {
|
||||
color: var(--lowest);
|
||||
}
|
||||
}
|
||||
.selectItem.priority {
|
||||
>.selectItemLabel {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
}
|
||||
.optionItem {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
>.styledIcon {
|
||||
font-size: 18px;
|
||||
}
|
||||
>.optionLabel {
|
||||
padding: 0 5px 0 7px;
|
||||
font-size: 15px;
|
||||
}
|
||||
}
|
||||
.optionItem.priority {
|
||||
>.optionLabel {
|
||||
padding: 0 5px 0 7px;
|
||||
font-size: 15px;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
>.styledIcon {
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
.topActions {
|
||||
>.styledSelect {
|
||||
>.valueContainer {
|
||||
height: 100%;
|
||||
>.selectItem {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
.selectItem {
|
||||
padding: 0 12px;
|
||||
}
|
||||
.optionItem {
|
||||
padding: 0 12px;
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
.styledTextArea {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.styledTextArea > textarea {
|
||||
overflow-y: hidden;
|
||||
width: 100%;
|
||||
padding: 8px 12px 9px;
|
||||
border-radius: 3px;
|
||||
border: 1px solid var(--borderLightest);
|
||||
color: var(--textDarkest);
|
||||
background: var(--backgroundLightest);
|
||||
font-family: var(--font-regular);
|
||||
font-weight: normal;
|
||||
font-size: 15px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.styledTextArea > textarea:focus {
|
||||
background: #fff;
|
||||
border: 1px solid var(--borderInputFocus);
|
||||
box-shadow: 0 0 0 1px var(--borderInputFocus);
|
||||
}
|
||||
|
||||
.styledTextArea > textarea.invalid:focus {
|
||||
border: 1px solid var(--danger);
|
||||
}
|
27
jirs-client/js/css/styledTextArea.scss
Normal file
27
jirs-client/js/css/styledTextArea.scss
Normal file
@ -0,0 +1,27 @@
|
||||
.styledTextArea {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
>textarea {
|
||||
overflow-y: hidden;
|
||||
width: 100%;
|
||||
padding: 8px 12px 9px;
|
||||
border-radius: 3px;
|
||||
border: 1px solid var(--borderLightest);
|
||||
color: var(--textDarkest);
|
||||
background: var(--backgroundLightest);
|
||||
font-family: var(--font-regular);
|
||||
font-weight: normal;
|
||||
font-size: 15px;
|
||||
resize: vertical;
|
||||
&:focus {
|
||||
background: #fff;
|
||||
border: 1px solid var(--borderInputFocus);
|
||||
box-shadow: 0 0 0 1px var(--borderInputFocus);
|
||||
}
|
||||
}
|
||||
>textarea.invalid {
|
||||
&:focus {
|
||||
border: 1px solid var(--danger);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
.styledTooltip {
|
||||
z-index: calc(var(--modal) + 1);
|
||||
position: fixed;
|
||||
width: 300px;
|
||||
border-radius: 3px;
|
||||
background: #fff;
|
||||
transform: translateZ(0);
|
||||
box-shadow: rgba(9, 30, 66, 0.25) 0 4px 8px -2px, rgba(9, 30, 66, 0.31) 0 0 1px;
|
||||
}
|
||||
|
||||
.styledTooltip .feedbackDropdown {
|
||||
padding: 16px 24px 24px;
|
||||
}
|
||||
|
||||
.styledTooltip .feedbackImageCont {
|
||||
padding: 24px 56px 20px;
|
||||
}
|
||||
|
||||
.styledTooltip .feedbackImage {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.styledTooltip .feedbackParagraph {
|
||||
margin-bottom: 12px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.styledTooltip .feedbackParagraph:last-of-type {
|
||||
margin-bottom: 22px;
|
||||
}
|
30
jirs-client/js/css/styledTooltip.scss
Normal file
30
jirs-client/js/css/styledTooltip.scss
Normal file
@ -0,0 +1,30 @@
|
||||
.styledTooltip {
|
||||
z-index: calc(var(--modal) + 1);
|
||||
position: fixed;
|
||||
width: 300px;
|
||||
border-radius: 3px;
|
||||
background: #fff;
|
||||
transform: translateZ(0);
|
||||
box-shadow: rgba(9, 30, 66, 0.25) 0 4px 8px -2px, rgba(9, 30, 66, 0.31) 0 0 1px;
|
||||
|
||||
.feedbackDropdown {
|
||||
padding: 16px 24px 24px;
|
||||
}
|
||||
|
||||
.feedbackImageCont {
|
||||
padding: 24px 56px 20px;
|
||||
}
|
||||
|
||||
.feedbackImage {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.feedbackParagraph {
|
||||
margin-bottom: 12px;
|
||||
font-size: 15px;
|
||||
|
||||
&:last-of-type {
|
||||
margin-bottom: 22px;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,76 +0,0 @@
|
||||
.trackingLink {
|
||||
padding: 4px 4px 2px 0;
|
||||
border-radius: 4px;
|
||||
transition: background 0.1s;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.trackingLink:hover {
|
||||
background: var(--backgroundLight);
|
||||
}
|
||||
|
||||
.trackingWidget {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.trackingWidget > .watchIcon {
|
||||
color: var(--textMedium);
|
||||
}
|
||||
|
||||
.trackingWidget > .right {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
.trackingWidget > .right > .barCounter {
|
||||
height: 5px;
|
||||
border-radius: 4px;
|
||||
background: var(--backgroundMedium);
|
||||
}
|
||||
|
||||
.trackingWidget > .right > .barCounter > .bar {
|
||||
height: 5px;
|
||||
border-radius: 4px;
|
||||
background: var(--primary);
|
||||
transition: all 0.1s;
|
||||
}
|
||||
|
||||
.trackingWidget > .right > .values {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding-top: 3px;
|
||||
font-size: 14.5px;
|
||||
}
|
||||
|
||||
/*MODAL*/
|
||||
.timeTrackingModal {
|
||||
padding: 20px 25px 25px;
|
||||
}
|
||||
|
||||
.timeTrackingModal > .modalTitle {
|
||||
padding-bottom: 14px;
|
||||
font-family: var(--font-medium);
|
||||
font-weight: normal;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.timeTrackingModal > .trackingWidget {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.timeTrackingModal > .inputs {
|
||||
display: flex;
|
||||
margin: 20px -5px 30px;
|
||||
}
|
||||
|
||||
.timeTrackingModal > .inputs > .inputContainer {
|
||||
margin: 0 5px;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.timeTrackingModal > .actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
75
jirs-client/js/css/timeTracking.scss
Normal file
75
jirs-client/js/css/timeTracking.scss
Normal file
@ -0,0 +1,75 @@
|
||||
.trackingLink {
|
||||
padding: 4px 4px 2px 0;
|
||||
border-radius: 4px;
|
||||
transition: background 0.1s;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
|
||||
&:hover {
|
||||
background: var(--backgroundLight);
|
||||
}
|
||||
}
|
||||
|
||||
.trackingWidget {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
> .watchIcon {
|
||||
color: var(--textMedium);
|
||||
}
|
||||
|
||||
> .right {
|
||||
width: 90%;
|
||||
|
||||
> .barCounter {
|
||||
height: 5px;
|
||||
border-radius: 4px;
|
||||
background: var(--backgroundMedium);
|
||||
|
||||
> .bar {
|
||||
height: 5px;
|
||||
border-radius: 4px;
|
||||
background: var(--primary);
|
||||
transition: all 0.1s;
|
||||
}
|
||||
}
|
||||
|
||||
> .values {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding-top: 3px;
|
||||
font-size: 14.5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.timeTrackingModal {
|
||||
padding: 20px 25px 25px;
|
||||
|
||||
> .modalTitle {
|
||||
padding-bottom: 14px;
|
||||
font-family: var(--font-medium);
|
||||
font-weight: normal;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
> .trackingWidget {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
> .inputs {
|
||||
display: flex;
|
||||
margin: 20px -5px 30px;
|
||||
|
||||
> .inputContainer {
|
||||
margin: 0 5px;
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
> .actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
#users > .usersSection,
|
||||
#users > .invitationsSection {
|
||||
padding: 25px 40px 35px;
|
||||
}
|
||||
|
||||
#users > .usersSection > .usersList,
|
||||
#users > .invitationsSection > .invitationsList {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
#users > .usersSection > .usersList > .user,
|
||||
#users > .invitationsSection > .invitationsList > .invitation {
|
||||
list-style: none;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
#users > .usersSection > .usersList > .user > span {
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
#users > .invitationsSection > .invitationsList > .invitation.revoked {
|
||||
color: var(--textLight);
|
||||
}
|
||||
|
||||
#users > .invitationsSection > .invitationsList > .invitation > * {
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
#users .invitationActions {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#users .invitationActions > .error {
|
||||
color: var(--danger);
|
||||
}
|
52
jirs-client/js/css/users.scss
Normal file
52
jirs-client/js/css/users.scss
Normal file
@ -0,0 +1,52 @@
|
||||
#users {
|
||||
> .usersSection {
|
||||
padding: 25px 40px 35px;
|
||||
|
||||
> .usersList {
|
||||
list-style: none;
|
||||
|
||||
> .user {
|
||||
list-style: none;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: 20px;
|
||||
|
||||
> span {
|
||||
width: 25%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> .invitationsSection {
|
||||
padding: 25px 40px 35px;
|
||||
|
||||
> .invitationsList {
|
||||
list-style: none;
|
||||
|
||||
> .invitation {
|
||||
list-style: none;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: 20px;
|
||||
|
||||
> * {
|
||||
width: 25%;
|
||||
}
|
||||
}
|
||||
|
||||
> .invitation.revoked {
|
||||
color: var(--textLight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.invitationActions {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
> .error {
|
||||
color: var(--danger);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,36 +1,36 @@
|
||||
@import "./css/normalize.css";
|
||||
@import "./css/fonts.css";
|
||||
@import "./css/iconfonts.css";
|
||||
@import "./css/variables.css";
|
||||
@import "./css/global.css";
|
||||
@import "./css/sidebar.css";
|
||||
@import "./css/aside.css";
|
||||
@import "./css/styledIcon.css";
|
||||
@import "./css/shared.css";
|
||||
@import "./css/styledTooltip.css";
|
||||
@import "./css/styledAvatar.css";
|
||||
@import "./css/styledSelect.css";
|
||||
@import "./css/styledSelectChild.css";
|
||||
@import "./css/styledButton.css";
|
||||
@import "./css/styledInput.css";
|
||||
@import "./css/styledImageInput.css";
|
||||
@import "./css/styledModal.css";
|
||||
@import "./css/styledTextArea.css";
|
||||
@import "./css/styledForm.css";
|
||||
@import "./css/styledEditor.css";
|
||||
@import "./css/styledComment.css";
|
||||
@import "./css/styledPage.css";
|
||||
@import "./css/styledLink.css";
|
||||
@import "./css/styledRte.css";
|
||||
@import "./css/styledDateTimeInput.css";
|
||||
@import "./css/app.css";
|
||||
@import "./css/issue.css";
|
||||
@import "./css/project.css";
|
||||
@import "./css/projectSettings.css";
|
||||
@import "./css/timeTracking.css";
|
||||
@import "./css/styledCheckbox.css";
|
||||
@import "./css/login.css";
|
||||
@import "./css/register.css";
|
||||
@import "./css/users.css";
|
||||
@import "./css/invite.css";
|
||||
@import "./css/reports.css";
|
||||
@import "css/normalize.scss";
|
||||
@import "css/fonts.scss";
|
||||
@import "css/iconfonts.scss";
|
||||
@import "css/variables.scss";
|
||||
@import "css/global.scss";
|
||||
@import "css/sidebar.scss";
|
||||
@import "css/aside.scss";
|
||||
@import "css/styledIcon.scss";
|
||||
@import "css/shared.scss";
|
||||
@import "css/styledTooltip.scss";
|
||||
@import "css/styledAvatar.scss";
|
||||
@import "./css/styledSelect.scss";
|
||||
@import "./css/styledSelectChild.scss";
|
||||
@import "css/styledButton.scss";
|
||||
@import "css/styledInput.scss";
|
||||
@import "css/styledImageInput.scss";
|
||||
@import "./css/styledModal.scss";
|
||||
@import "css/styledTextArea.scss";
|
||||
@import "css/styledForm.scss";
|
||||
@import "css/styledEditor.scss";
|
||||
@import "css/styledComment.scss";
|
||||
@import "css/styledPage.scss";
|
||||
@import "./css/styledLink.scss";
|
||||
@import "css/styledRte.scss";
|
||||
@import "css/styledDateTimeInput.scss";
|
||||
@import "css/app.scss";
|
||||
@import "css/issue.scss";
|
||||
@import "css/project.scss";
|
||||
@import "css/projectSettings.scss";
|
||||
@import "css/timeTracking.scss";
|
||||
@import "css/styledCheckbox.scss";
|
||||
@import "css/login.scss";
|
||||
@import "css/register.scss";
|
||||
@import "css/users.scss";
|
||||
@import "css/invite.scss";
|
||||
@import "css/reports.scss";
|
||||
|
@ -1,5 +1,11 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
which rsass
|
||||
if [[ "$status" != "0" ]];
|
||||
then
|
||||
cargo install rsass --features=commandline
|
||||
fi
|
||||
|
||||
export PROJECT_ROOT=$(git rev-parse --show-toplevel)
|
||||
export CLIENT_ROOT=${PROJECT_ROOT}/jirs-client
|
||||
export HI_ROOT=${PROJECT_ROOT}/highlight/jirs-highlight
|
||||
|
@ -1,14 +1,16 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
which rsass
|
||||
if [[ "$status" != "0" ]]; then
|
||||
cargo install rsass --features=commandline
|
||||
fi
|
||||
|
||||
export PROJECT_ROOT=$(git rev-parse --show-toplevel)
|
||||
export CLIENT_ROOT=${PROJECT_ROOT}/jirs-client
|
||||
export HI_ROOT=${PROJECT_ROOT}/highlight/jirs-highlight
|
||||
export MODE=force
|
||||
export BUILD_TYPE=--release
|
||||
|
||||
cd ${PROJECT_ROOT}
|
||||
cargo build --bin jirs-css
|
||||
|
||||
. .env
|
||||
|
||||
rm -Rf build
|
||||
@ -20,11 +22,13 @@ wasm-pack build --mode normal --release --out-name jirs --out-dir $CLIENT_ROOT/b
|
||||
cd $HI_ROOT
|
||||
wasm-pack build --mode normal --release --out-name hi --out-dir $CLIENT_ROOT/build --target web
|
||||
|
||||
${PROJECT_ROOT}/target/debug/jirs-css -i ./js/styles.css -o ./build/styles.css
|
||||
cd $CLIENT_ROOT
|
||||
rm -Rf ${CLIENT_ROOT}/build/styles.css
|
||||
rsass -t Compressed ${PROJECT_ROOT}/jirs-client/js/styles.css > ${CLIENT_ROOT}/build/styles.css
|
||||
|
||||
cp -r ./static/* ./build
|
||||
cat ./static/index.js \
|
||||
| sed -e "s/process.env.JIRS_SERVER_BIND/'$JIRS_SERVER_BIND'/g" \
|
||||
| sed -e "s/process.env.JIRS_SERVER_PORT/'$JIRS_SERVER_PORT'/g" &> ./build/index.js
|
||||
cat ./static/index.js |
|
||||
sed -e "s/process.env.JIRS_SERVER_BIND/'$JIRS_SERVER_BIND'/g" |
|
||||
sed -e "s/process.env.JIRS_SERVER_PORT/'$JIRS_SERVER_PORT'/g" &>./build/index.js
|
||||
|
||||
cp ./js/template.html ./build/index.html
|
||||
|
@ -12,7 +12,8 @@ cd ${CLIENT_ROOT}
|
||||
wasm-pack --verbose build --mode ${MODE} ${BUILD_TYPE} --out-name jirs --out-dir ${CLIENT_ROOT}/build --target web
|
||||
|
||||
cd ${CLIENT_ROOT}
|
||||
${PROJECT_ROOT}/target/debug/jirs-css -i ${CLIENT_ROOT}/js/styles.css -o ${CLIENT_ROOT}/tmp/styles.css
|
||||
rm -Rf ${CLIENT_ROOT}/build/styles.css
|
||||
rsass -t Expanded ${PROJECT_ROOT}/jirs-client/js/styles.css > ${CLIENT_ROOT}/tmp/styles.css
|
||||
|
||||
cp -r ${CLIENT_ROOT}/static/* ${CLIENT_ROOT}/tmp
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
#![feature(or_patterns, type_ascription, trait_alias)]
|
||||
#![feature(or_patterns, type_ascription, trait_alias, drain_filter)]
|
||||
|
||||
use {
|
||||
crate::{
|
||||
|
@ -9,7 +9,7 @@ pub struct StatusIssueIds {
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct EpicIssuePerStatus {
|
||||
pub epic_name: EpicName,
|
||||
pub epic_name: Option<EpicName>,
|
||||
pub per_status_issues: Vec<StatusIssueIds>,
|
||||
}
|
||||
|
||||
@ -57,7 +57,7 @@ impl ProjectPage {
|
||||
|
||||
for epic in epics {
|
||||
let mut per_epic_map = EpicIssuePerStatus {
|
||||
epic_name: epic.map(|(_, name)| name).unwrap_or_default().to_string(),
|
||||
epic_name: epic.map(|(_, name)| name.to_string()),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::shared::styled_button::StyledButton;
|
||||
use {
|
||||
crate::{
|
||||
model::PageContent,
|
||||
@ -31,11 +32,28 @@ pub fn project_board_lists(model: &Model) -> Node<Msg> {
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
let epic_name = match per_epic.epic_name.as_deref() {
|
||||
Some(name) => {
|
||||
let edit_button = StyledButton::build()
|
||||
.empty()
|
||||
.icon(Icon::EditAlt)
|
||||
.build()
|
||||
.into_node();
|
||||
let delete_button = StyledButton::build()
|
||||
.empty()
|
||||
.icon(Icon::DeleteAlt)
|
||||
.build()
|
||||
.into_node();
|
||||
|
||||
div![
|
||||
C!["row"],
|
||||
div![C!["epicName"], per_epic.epic_name.as_str()],
|
||||
div![C!["projectBoardLists"], columns]
|
||||
C!["epicHeader"],
|
||||
div![C!["epicName"], name],
|
||||
div![C!["epicActions"], edit_button, delete_button],
|
||||
]
|
||||
}
|
||||
_ => Node::Empty,
|
||||
};
|
||||
div![C!["row"], epic_name, div![C!["projectBoardLists"], columns]]
|
||||
});
|
||||
div![C!["rows"], rows]
|
||||
}
|
||||
@ -108,25 +126,21 @@ fn project_issue(model: &Model, issue: &Issue) -> Node<Msg> {
|
||||
.build()
|
||||
.into_node();
|
||||
|
||||
let priority_icon = {
|
||||
let icon = match issue.priority {
|
||||
IssuePriority::Low | IssuePriority::Lowest => Icon::ArrowDown,
|
||||
_ => Icon::ArrowUp,
|
||||
};
|
||||
StyledIcon::build(icon)
|
||||
let priority_icon = StyledIcon::build(issue.priority.into())
|
||||
.add_class(issue.priority.to_str())
|
||||
.with_color(issue.priority.to_str())
|
||||
.build()
|
||||
.into_node()
|
||||
};
|
||||
.into_node();
|
||||
|
||||
let issue_id = issue.id;
|
||||
let drag_started = drag_ev(Ev::DragStart, move |_| {
|
||||
let drag_started = drag_ev(Ev::DragStart, move |ev| {
|
||||
ev.stop_propagation();
|
||||
Some(Msg::PageChanged(PageChanged::Board(
|
||||
BoardPageChange::IssueDragStarted(issue_id),
|
||||
)))
|
||||
});
|
||||
let drag_stopped = drag_ev(Ev::DragEnd, move |_| {
|
||||
let drag_stopped = drag_ev(Ev::DragEnd, move |ev| {
|
||||
ev.stop_propagation();
|
||||
Some(Msg::PageChanged(PageChanged::Board(
|
||||
BoardPageChange::IssueDragStopped(issue_id),
|
||||
)))
|
||||
|
@ -1,11 +1,12 @@
|
||||
use seed::prelude::Orders;
|
||||
use seed::*;
|
||||
|
||||
use jirs_data::*;
|
||||
|
||||
use crate::model::{Model, PageContent};
|
||||
use crate::ws::send_ws_msg;
|
||||
use crate::Msg;
|
||||
use {
|
||||
crate::{
|
||||
model::{Model, PageContent},
|
||||
ws::send_ws_msg,
|
||||
Msg,
|
||||
},
|
||||
jirs_data::*,
|
||||
seed::{prelude::Orders, *},
|
||||
};
|
||||
|
||||
pub fn drag_started(issue_id: IssueId, model: &mut Model) {
|
||||
let project_page = match &mut model.page_content {
|
||||
@ -27,66 +28,47 @@ pub fn exchange_position(below_id: IssueId, model: &mut Model) {
|
||||
if below_id == dragged_id {
|
||||
return;
|
||||
}
|
||||
let below_idx = model
|
||||
|
||||
let (issue_status_id, epic_id) = model
|
||||
.issues
|
||||
.iter()
|
||||
.find_map(|issue| {
|
||||
if issue.id == dragged_id {
|
||||
Some((issue.issue_status_id, issue.epic_id))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
let mut issues: Vec<Issue> = model
|
||||
.issues
|
||||
.drain_filter(|issue| issue.issue_status_id == issue_status_id && issue.epic_id == epic_id)
|
||||
.collect();
|
||||
issues.sort_by(|a, b| a.list_position.cmp(&b.list_position));
|
||||
|
||||
let below_idx = issues
|
||||
.iter()
|
||||
.position(|issue| issue.id == below_id)
|
||||
.unwrap_or(model.issues.len());
|
||||
let dragged = model
|
||||
.issues
|
||||
.unwrap_or_default();
|
||||
let dragged_idx = issues
|
||||
.iter()
|
||||
.position(|issue| issue.id == dragged_id)
|
||||
.map(|idx| model.issues.remove(idx))
|
||||
.unwrap();
|
||||
let epic_id = dragged.epic_id;
|
||||
model.issues.insert(below_idx, dragged);
|
||||
let changed: Vec<(IssueId, i32)> = model
|
||||
.issues
|
||||
.iter_mut()
|
||||
.filter(|issue| issue.epic_id == epic_id)
|
||||
.enumerate()
|
||||
.map(|(idx, issue)| {
|
||||
.unwrap_or_default();
|
||||
|
||||
let dragged = issues.remove(dragged_idx);
|
||||
issues.insert(below_idx, dragged);
|
||||
|
||||
let mut changed = Vec::with_capacity(issues.len());
|
||||
for (idx, mut issue) in issues.into_iter().enumerate() {
|
||||
issue.list_position = idx as i32;
|
||||
(issue.id, issue.list_position)
|
||||
})
|
||||
.collect();
|
||||
for (id, pos) in changed {
|
||||
if let Some(iss) = model.issues_by_id.get_mut(&id) {
|
||||
iss.list_position = pos;
|
||||
if let Some(iss) = model.issues_by_id.get_mut(&issue.id) {
|
||||
iss.list_position = issue.list_position;
|
||||
}
|
||||
changed.push((issue.id, issue.list_position));
|
||||
model.issues.push(issue);
|
||||
}
|
||||
|
||||
// let dragged_pos = match model.issues_by_id.get(&dragged_id) {
|
||||
// Some(i) => i.list_position,
|
||||
// _ => return,
|
||||
// };
|
||||
// let below_pos = match model.issues_by_id.get(&below_id) {
|
||||
// Some(i) => i.list_position,
|
||||
// _ => return,
|
||||
// };
|
||||
// use seed::*;
|
||||
// log!(format!(
|
||||
// "exchange dragged {} {} below {} {}",
|
||||
// dragged_id, dragged_pos, below_id, below_pos
|
||||
// ));
|
||||
// for issue in model.issues_by_id.values_mut() {
|
||||
// if issue.id == below_id {
|
||||
// issue.list_position = dragged_pos;
|
||||
// } else if issue.id == dragged_id {
|
||||
// issue.list_position = below_pos;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// for issue in model.issues.iter_mut() {
|
||||
// if issue.id == below_id {
|
||||
// issue.list_position = dragged_pos;
|
||||
// } else if issue.id == dragged_id {
|
||||
// issue.list_position = below_pos;
|
||||
// }
|
||||
// }
|
||||
// model
|
||||
// .issues
|
||||
// .sort_by(|a, b| a.list_position.cmp(&b.list_position));
|
||||
if let PageContent::Project(project_page) = &mut model.page_content {
|
||||
project_page.rebuild_visible(
|
||||
&model.epics,
|
||||
@ -94,45 +76,40 @@ pub fn exchange_position(below_id: IssueId, model: &mut Model) {
|
||||
&model.issues,
|
||||
&model.user,
|
||||
);
|
||||
project_page.issue_drag.mark_dirty(dragged_id);
|
||||
project_page.issue_drag.mark_dirty(below_id);
|
||||
for (id, _) in changed.iter() {
|
||||
project_page.issue_drag.mark_dirty(*id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sync(model: &mut Model, orders: &mut impl Orders<Msg>) {
|
||||
// log!("------------------------------------------------------------------");
|
||||
// log!("| SYNC |");
|
||||
// log!("------------------------------------------------------------------");
|
||||
let project_page = match &mut model.page_content {
|
||||
PageContent::Project(project_page) => project_page,
|
||||
let dirty = match &mut model.page_content {
|
||||
PageContent::Project(project_page) => std::mem::take(&mut project_page.issue_drag.dirty),
|
||||
_ => return,
|
||||
};
|
||||
|
||||
for issue in model.issues.iter() {
|
||||
if !project_page.issue_drag.dirty.contains(&issue.id) {
|
||||
continue;
|
||||
}
|
||||
let changes: Vec<(IssueId, ListPosition, IssueStatusId, Option<EpicId>)> = dirty
|
||||
.into_iter()
|
||||
.filter_map(|id| {
|
||||
model.issues_by_id.get(&id).map(|issue| {
|
||||
(
|
||||
issue.id,
|
||||
issue.list_position,
|
||||
issue.issue_status_id,
|
||||
issue.epic_id,
|
||||
)
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
||||
send_ws_msg(
|
||||
WsMsg::IssueUpdate(
|
||||
issue.id,
|
||||
IssueFieldId::IssueStatusId,
|
||||
PayloadVariant::I32(issue.issue_status_id),
|
||||
),
|
||||
WsMsg::IssueSyncListPosition(changes),
|
||||
model.ws.as_ref(),
|
||||
orders,
|
||||
);
|
||||
send_ws_msg(
|
||||
WsMsg::IssueUpdate(
|
||||
issue.id,
|
||||
IssueFieldId::ListPosition,
|
||||
PayloadVariant::I32(issue.list_position),
|
||||
),
|
||||
model.ws.as_ref(),
|
||||
orders,
|
||||
);
|
||||
}
|
||||
project_page.issue_drag.clear();
|
||||
if let PageContent::Project(project_page) = &mut model.page_content {
|
||||
project_page.issue_drag.clear()
|
||||
};
|
||||
}
|
||||
|
||||
pub fn change_status(status_id: IssueStatusId, model: &mut Model) {
|
||||
@ -141,45 +118,46 @@ pub fn change_status(status_id: IssueStatusId, model: &mut Model) {
|
||||
_ => return,
|
||||
};
|
||||
|
||||
let issue_id = match project_page.issue_drag.dragged_id.as_ref().cloned() {
|
||||
let dragged_id = match project_page.issue_drag.dragged_id.as_ref().cloned() {
|
||||
Some(issue_id) => issue_id,
|
||||
_ => return error!("Nothing is dragged"),
|
||||
};
|
||||
|
||||
let mut old: Vec<Issue> = vec![];
|
||||
let mut pos = 0;
|
||||
let mut found: Option<Issue> = None;
|
||||
std::mem::swap(&mut old, &mut model.issues);
|
||||
old.sort_by(|a, b| a.list_position.cmp(&b.list_position));
|
||||
|
||||
for mut issue in old.into_iter() {
|
||||
if issue.issue_status_id == status_id {
|
||||
if issue.list_position != pos {
|
||||
issue.list_position = pos;
|
||||
project_page.issue_drag.mark_dirty(issue.id);
|
||||
}
|
||||
pos += 1;
|
||||
}
|
||||
if issue.id != issue_id {
|
||||
model.issues.push(issue);
|
||||
} else {
|
||||
found = Some(issue);
|
||||
}
|
||||
}
|
||||
|
||||
let mut issue = match found {
|
||||
Some(i) => i,
|
||||
_ => {
|
||||
let (issue_status_id, epic_id) = model
|
||||
.issues_by_id
|
||||
.get(&dragged_id)
|
||||
.map(|issue| (issue.issue_status_id, issue.epic_id))
|
||||
.unwrap_or_default();
|
||||
if status_id == issue_status_id {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
if issue.issue_status_id == status_id {
|
||||
model.issues.push(issue);
|
||||
} else {
|
||||
let mut issues: Vec<Issue> = model
|
||||
.issues
|
||||
.drain_filter(|issue| {
|
||||
if issue.id == dragged_id {
|
||||
issue.issue_status_id = status_id;
|
||||
issue.list_position = pos + 1;
|
||||
}
|
||||
issue.issue_status_id == status_id && issue.epic_id == epic_id
|
||||
})
|
||||
.collect();
|
||||
|
||||
issues.sort_by(|a, b| a.list_position.cmp(&b.list_position));
|
||||
|
||||
for mut issue in issues {
|
||||
if issue.id == dragged_id {
|
||||
issue.issue_status_id = status_id;
|
||||
if let Some(iss) = model.issues_by_id.get_mut(&issue.id) {
|
||||
iss.issue_status_id = status_id;
|
||||
}
|
||||
}
|
||||
project_page.issue_drag.mark_dirty(issue.id);
|
||||
model.issues.push(issue);
|
||||
project_page.issue_drag.mark_dirty(issue_id);
|
||||
}
|
||||
|
||||
project_page.rebuild_visible(
|
||||
&model.epics,
|
||||
&model.issue_statuses,
|
||||
&model.issues,
|
||||
&model.user,
|
||||
);
|
||||
}
|
||||
|
@ -1,12 +0,0 @@
|
||||
[package]
|
||||
name = "jirs-css"
|
||||
version = "0.1.0"
|
||||
authors = ["Adrian Woźniak <adrian.wozniak.1986@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
glob = { version = "*" }
|
||||
notify = { version = "*" }
|
||||
gumdrop = { version = "*", default-features = false }
|
@ -1,342 +0,0 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fs::*;
|
||||
use std::path::Path;
|
||||
use std::sync::mpsc::{channel, Sender};
|
||||
use std::sync::{Arc, RwLock, RwLockWriteGuard};
|
||||
use std::time::Duration;
|
||||
use std::time::SystemTime;
|
||||
|
||||
use notify::{watcher, DebouncedEvent, RecursiveMode, Watcher};
|
||||
|
||||
const INPUT: &str = "./jirs-client/js/styles.css";
|
||||
|
||||
type Css = Arc<RwLock<CssFile>>;
|
||||
|
||||
// mod prop;
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Partial {
|
||||
String(String),
|
||||
File(Css),
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialOrd, PartialEq)]
|
||||
enum FileState {
|
||||
Clean,
|
||||
Dirty,
|
||||
Dead,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct CssFile {
|
||||
pub path: String,
|
||||
pub lines: Vec<Partial>,
|
||||
pub last_changed: SystemTime,
|
||||
pub state: FileState,
|
||||
}
|
||||
|
||||
impl CssFile {
|
||||
pub fn new(path: String) -> Self {
|
||||
Self {
|
||||
path,
|
||||
lines: vec![],
|
||||
last_changed: SystemTime::UNIX_EPOCH,
|
||||
state: FileState::Clean,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn drop_dead(&mut self) {
|
||||
let mut old = vec![];
|
||||
std::mem::swap(&mut self.lines, &mut old);
|
||||
|
||||
for child in old {
|
||||
match child {
|
||||
Partial::String(_) => {
|
||||
self.lines.push(child);
|
||||
}
|
||||
Partial::File(file) => {
|
||||
let state = file.read().map(|f| f.state).unwrap();
|
||||
|
||||
if state != FileState::Dead {
|
||||
if let Ok(mut css) = file.write() {
|
||||
css.drop_dead();
|
||||
}
|
||||
self.lines.push(Partial::File(file));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for CssFile {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
if self.state == FileState::Dead {
|
||||
return Ok(());
|
||||
}
|
||||
f.write_str(format!("\n/* -- {} --- */\n\n", self.path).as_str())?;
|
||||
for line in self.lines.iter() {
|
||||
match line {
|
||||
Partial::String(line) => {
|
||||
f.write_str(line.as_str())?;
|
||||
f.write_str("\n")?;
|
||||
}
|
||||
Partial::File(file) => {
|
||||
if let Ok(css) = file.read() {
|
||||
f.write_str(format!("{}", css).as_str())?;
|
||||
f.write_str("\n")?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct Application<'l> {
|
||||
input: &'l str,
|
||||
output: Option<&'l str>,
|
||||
watch: bool,
|
||||
prelude_selector: bool,
|
||||
files_map: HashMap<String, HashSet<String>>,
|
||||
fm: HashMap<String, Css>,
|
||||
root_file: Option<Css>,
|
||||
sender: Option<Sender<DebouncedEvent>>,
|
||||
}
|
||||
|
||||
impl<'l> Application<'l> {
|
||||
fn read_timestamp(input: &Path) -> Result<SystemTime, String> {
|
||||
std::fs::File::open(input)
|
||||
.and_then(|file| file.metadata())
|
||||
.and_then(|meta| meta.modified())
|
||||
.map_err(|e| format!("{}", e))
|
||||
}
|
||||
|
||||
fn check_timestamps(
|
||||
&mut self,
|
||||
input: &Path,
|
||||
output_timestamp: SystemTime,
|
||||
) -> Result<bool, String> {
|
||||
let input_dir = input
|
||||
.parent()
|
||||
.ok_or_else(|| format!("Not a valid path {:?}", input))?;
|
||||
|
||||
let path = input_dir.to_str().unwrap();
|
||||
let paths =
|
||||
glob::glob(format!("{}/**/*.css", path).as_str()).map_err(|e| format!("{}", e))?;
|
||||
for path in paths.filter_map(Result::ok) {
|
||||
if Self::read_timestamp(path.as_path())? > output_timestamp {
|
||||
return Ok(false);
|
||||
}
|
||||
}
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn parse(&mut self) -> Result<(), String> {
|
||||
let root_path = self.input.to_string();
|
||||
let root = std::path::Path::new(&root_path);
|
||||
let root_file = self.parse_file(root)?;
|
||||
self.root_file = Some(root_file);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_file(&mut self, input: &Path) -> Result<Css, String> {
|
||||
let file_path = input.display().to_string();
|
||||
let input_dir = input
|
||||
.parent()
|
||||
.ok_or_else(|| format!("Not a valid path {:?}", input))?;
|
||||
|
||||
let file = if self.fm.contains_key(&file_path) {
|
||||
self.fm.get(&file_path).unwrap().clone()
|
||||
} else {
|
||||
let css = Arc::new(RwLock::new(CssFile::new(file_path.clone())));
|
||||
self.fm.insert(file_path.clone(), css.clone());
|
||||
if let Some(ref tx) = self.sender {
|
||||
let path = Path::new(&file_path);
|
||||
tx.send(DebouncedEvent::Create(path.to_path_buf()))
|
||||
.map_err(|e| format!("{}", e))?;
|
||||
}
|
||||
css
|
||||
};
|
||||
|
||||
if let Ok(mut css) = file.write() {
|
||||
css.last_changed = Self::read_timestamp(input)?;
|
||||
}
|
||||
|
||||
for line in read_to_string(file_path.as_str())
|
||||
.map_err(|e| format!("{}", e))?
|
||||
.lines()
|
||||
{
|
||||
let l = line.trim();
|
||||
match l {
|
||||
"" => continue,
|
||||
_ if l.starts_with("@import ") => {
|
||||
let imported = line
|
||||
.replace("@import ", "")
|
||||
.trim()
|
||||
.replace("\"", "")
|
||||
.replace(";", "")
|
||||
.to_string();
|
||||
let child = input_dir
|
||||
.join(imported.as_str())
|
||||
.canonicalize()
|
||||
.map_err(|e| format!("{}", e))?;
|
||||
let child_file = self.parse_file(&child)?;
|
||||
|
||||
if let Ok(mut css) = file.write() {
|
||||
css.lines.push(Partial::File(child_file));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
if let Ok(mut css) = file.write() {
|
||||
css.lines.push(Partial::String(l.to_string()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(file)
|
||||
}
|
||||
|
||||
pub fn mark_dirty(&mut self, path: &Path) {
|
||||
if let Ok(mut css) = self.css_at_path(path) {
|
||||
css.state = FileState::Dirty;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mark_dead(&mut self, path: &Path) {
|
||||
if let Ok(mut css) = self.css_at_path(path) {
|
||||
css.state = FileState::Dead;
|
||||
}
|
||||
}
|
||||
|
||||
fn css_at_path(&mut self, path: &Path) -> Result<RwLockWriteGuard<CssFile>, bool> {
|
||||
self.fm
|
||||
.get(path.display().to_string().as_str())
|
||||
.ok_or(false)
|
||||
.and_then(|css| css.write().or(Err(false)))
|
||||
}
|
||||
|
||||
fn refresh(&mut self) {
|
||||
if let Ok(mut root) = self
|
||||
.root_file
|
||||
.as_mut()
|
||||
.ok_or_else(|| false)
|
||||
.and_then(|f| f.write().map_err(|_| false))
|
||||
{
|
||||
root.drop_dead();
|
||||
}
|
||||
let mut old = HashMap::new();
|
||||
std::mem::swap(&mut old, &mut self.fm);
|
||||
for (key, file) in old.into_iter() {
|
||||
if file
|
||||
.read()
|
||||
.map(|f| f.state != FileState::Dead)
|
||||
.unwrap_or_default()
|
||||
{
|
||||
self.fm.insert(key, file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn print(&self) {
|
||||
let css = match self.root_file.as_ref().unwrap().read() {
|
||||
Ok(css) => css,
|
||||
_ => return,
|
||||
};
|
||||
match self.output.as_ref() {
|
||||
Some(f) => {
|
||||
std::fs::create_dir_all(Path::new(f).parent().unwrap()).unwrap();
|
||||
std::fs::write(f, format!("{}", css)).unwrap();
|
||||
println!("CSS merge done");
|
||||
}
|
||||
_ => println!("{}", css),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pipe(&mut self, tx: Sender<DebouncedEvent>) {
|
||||
self.sender = Some(tx);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(gumdrop::Options, Debug)]
|
||||
struct Opts {
|
||||
#[options(help = "Root input file")]
|
||||
input: Option<String>,
|
||||
#[options(help = "Optional output file. If not given result will be printed to stdout")]
|
||||
output: Option<String>,
|
||||
#[options(help = "Watch file changes")]
|
||||
watch: bool,
|
||||
#[options(help = "Add reset css prelude")]
|
||||
prelude: bool,
|
||||
#[options(help = "Print help message")]
|
||||
help: bool,
|
||||
}
|
||||
|
||||
fn main() -> Result<(), String> {
|
||||
use gumdrop::Options;
|
||||
|
||||
let opts: Opts = Opts::parse_args_default_or_exit();
|
||||
|
||||
let mut app = Application {
|
||||
input: opts.input.as_deref().unwrap_or_else(|| INPUT),
|
||||
output: opts.output.as_deref(),
|
||||
watch: opts.watch,
|
||||
prelude_selector: opts.prelude,
|
||||
files_map: Default::default(),
|
||||
fm: Default::default(),
|
||||
root_file: None,
|
||||
sender: None,
|
||||
};
|
||||
let root_path = app.input.to_string();
|
||||
let root = std::path::Path::new(&root_path);
|
||||
|
||||
let output_timestamp = opts
|
||||
.output
|
||||
.as_deref()
|
||||
.ok_or_else(|| std::io::Error::from_raw_os_error(0))
|
||||
.and_then(File::open)
|
||||
.and_then(|file| file.metadata())
|
||||
.and_then(|meta| meta.modified())
|
||||
.unwrap_or_else(|_| SystemTime::UNIX_EPOCH);
|
||||
|
||||
if app.check_timestamps(root, output_timestamp)? && !opts.watch {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let (tx, rx) = channel();
|
||||
app.pipe(tx.clone());
|
||||
let mut watcher = watcher(tx, Duration::from_secs(1)).unwrap();
|
||||
|
||||
app.parse()?;
|
||||
app.print();
|
||||
|
||||
if !opts.watch {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
loop {
|
||||
match rx.recv() {
|
||||
Ok(DebouncedEvent::NoticeWrite(path)) => {
|
||||
app.mark_dirty(path.as_path());
|
||||
if let Err(s) = app.parse_file(&path) {
|
||||
eprintln!("{}", s);
|
||||
}
|
||||
app.print();
|
||||
}
|
||||
Ok(DebouncedEvent::NoticeRemove(path)) => {
|
||||
app.mark_dead(path.as_path());
|
||||
watcher.unwatch(path).unwrap();
|
||||
app.refresh();
|
||||
app.print();
|
||||
}
|
||||
Ok(DebouncedEvent::Create(path)) => {
|
||||
if let Err(e) = watcher.watch(path, RecursiveMode::NonRecursive) {
|
||||
eprintln!("{}", e);
|
||||
}
|
||||
}
|
||||
Ok(_event) => (),
|
||||
Err(e) => eprintln!("watch error: {:?}", e),
|
||||
}
|
||||
}
|
||||
}
|
@ -1,496 +0,0 @@
|
||||
use crate::prop::{CssParser, ParseToken, Parser, PropertyValue, TimeProperty, Token, ValueResult};
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum AnimationDirectionProperty {
|
||||
Normal,
|
||||
Reverse,
|
||||
Alternate,
|
||||
AlternateReverse,
|
||||
Initial,
|
||||
Inherit,
|
||||
}
|
||||
|
||||
impl Token for AnimationDirectionProperty {}
|
||||
|
||||
impl ParseToken<AnimationDirectionProperty> for CssParser {
|
||||
fn parse_token(&mut self) -> Result<PropertyValue<AnimationDirectionProperty>, String> {
|
||||
let p = match self.expect_consume()?.as_str() {
|
||||
"normal" => AnimationDirectionProperty::Normal,
|
||||
"reverse" => AnimationDirectionProperty::Reverse,
|
||||
"alternate" => AnimationDirectionProperty::Alternate,
|
||||
"alternate-reverse" => AnimationDirectionProperty::AlternateReverse,
|
||||
"initial" => AnimationDirectionProperty::Initial,
|
||||
"inherit" => AnimationDirectionProperty::Inherit,
|
||||
_ => return Err(format!("invalid animation direction {:?}", self.current)),
|
||||
};
|
||||
Ok(PropertyValue::Other(p))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum AnimationFillModeProperty {
|
||||
None,
|
||||
Forwards,
|
||||
Backwards,
|
||||
Both,
|
||||
Initial,
|
||||
Inherit,
|
||||
}
|
||||
|
||||
impl Token for AnimationFillModeProperty {}
|
||||
|
||||
impl ParseToken<AnimationFillModeProperty> for CssParser {
|
||||
fn parse_token(&mut self) -> ValueResult<AnimationFillModeProperty> {
|
||||
let p = match self.expect_consume()?.as_str() {
|
||||
"none" => AnimationFillModeProperty::None,
|
||||
"forwards" => AnimationFillModeProperty::Forwards,
|
||||
"backwards" => AnimationFillModeProperty::Backwards,
|
||||
"both" => AnimationFillModeProperty::Both,
|
||||
"initial" => AnimationFillModeProperty::Initial,
|
||||
"inherit" => AnimationFillModeProperty::Inherit,
|
||||
_ => return Err(format!("invalid animation fill mode {:?}", self.current)),
|
||||
};
|
||||
Ok(PropertyValue::Other(p))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum AnimationPlayStateProperty {
|
||||
Paused,
|
||||
Running,
|
||||
Initial,
|
||||
Inherit,
|
||||
}
|
||||
|
||||
impl Token for AnimationPlayStateProperty {}
|
||||
|
||||
impl ParseToken<AnimationPlayStateProperty> for CssParser {
|
||||
fn parse_token(&mut self) -> ValueResult<AnimationPlayStateProperty> {
|
||||
self.skip_white();
|
||||
let name = self.expect_consume()?;
|
||||
let p = match name.as_str() {
|
||||
"paused" => AnimationPlayStateProperty::Paused,
|
||||
"running" => AnimationPlayStateProperty::Running,
|
||||
"initial" => AnimationPlayStateProperty::Initial,
|
||||
"inherit" => AnimationPlayStateProperty::Inherit,
|
||||
_ => return Err(format!("invalid animation play state {:?}", name)),
|
||||
};
|
||||
Ok(PropertyValue::Other(p))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum AnimationTimingFunctionStepsProperty {
|
||||
Start,
|
||||
End,
|
||||
}
|
||||
|
||||
impl Token for AnimationTimingFunctionStepsProperty {}
|
||||
|
||||
impl ParseToken<AnimationTimingFunctionStepsProperty> for CssParser {
|
||||
fn parse_token(&mut self) -> ValueResult<AnimationTimingFunctionStepsProperty> {
|
||||
let s = self.expect_consume()?;
|
||||
let p = match s.to_lowercase().as_str() {
|
||||
"start" => AnimationTimingFunctionStepsProperty::Start,
|
||||
"end" => AnimationTimingFunctionStepsProperty::End,
|
||||
_ => return Err(format!("invalid animation timing function step {:?}", s)),
|
||||
};
|
||||
Ok(PropertyValue::Other(p))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum AnimationTimingFunctionProperty {
|
||||
Linear,
|
||||
Ease,
|
||||
EaseIn,
|
||||
EaseOut,
|
||||
EaseInOut,
|
||||
StepStart,
|
||||
StepEnd,
|
||||
Steps(
|
||||
PropertyValue<u32>,
|
||||
PropertyValue<AnimationTimingFunctionStepsProperty>,
|
||||
),
|
||||
CubicBezier(
|
||||
PropertyValue<f64>,
|
||||
PropertyValue<f64>,
|
||||
PropertyValue<f64>,
|
||||
PropertyValue<f64>,
|
||||
),
|
||||
Initial,
|
||||
Inherit,
|
||||
}
|
||||
|
||||
impl Token for AnimationTimingFunctionProperty {}
|
||||
|
||||
impl ParseToken<AnimationTimingFunctionProperty> for CssParser {
|
||||
fn parse_token(&mut self) -> ValueResult<AnimationTimingFunctionProperty> {
|
||||
let current = self.expect_consume()?;
|
||||
let p = match current.as_str() {
|
||||
"linear" => AnimationTimingFunctionProperty::Linear,
|
||||
"ease" => AnimationTimingFunctionProperty::Ease,
|
||||
"ease-in" => AnimationTimingFunctionProperty::EaseIn,
|
||||
"ease-out" => AnimationTimingFunctionProperty::EaseOut,
|
||||
"ease-in-out" => AnimationTimingFunctionProperty::EaseInOut,
|
||||
"step-start" => AnimationTimingFunctionProperty::StepStart,
|
||||
"step-end" => AnimationTimingFunctionProperty::StepEnd,
|
||||
"initial" => AnimationTimingFunctionProperty::Initial,
|
||||
"inherit" => AnimationTimingFunctionProperty::Inherit,
|
||||
"steps" => {
|
||||
self.consume_expected("(")?;
|
||||
self.skip_white();
|
||||
let b = self.parse_token()?;
|
||||
match b {
|
||||
PropertyValue::Other(n) if n <= 0 => {
|
||||
return Err(format!("invalid animation timing function, number of iterations must be greater than 0"));
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
self.skip_white();
|
||||
self.consume_expected(",")?;
|
||||
self.skip_white();
|
||||
let c = self.parse_token()?;
|
||||
self.skip_white();
|
||||
self.consume_expected(")")?;
|
||||
self.skip_white();
|
||||
self.consume_semicolon()?;
|
||||
AnimationTimingFunctionProperty::Steps(b, c)
|
||||
}
|
||||
"cubic-bezier" => {
|
||||
self.consume_expected("(")?;
|
||||
self.skip_white();
|
||||
let a = self.parse_token()?;
|
||||
self.skip_white();
|
||||
self.consume_expected(",")?;
|
||||
self.skip_white();
|
||||
let b = self.parse_token()?;
|
||||
self.skip_white();
|
||||
self.consume_expected(",")?;
|
||||
self.skip_white();
|
||||
let c = self.parse_token()?;
|
||||
self.skip_white();
|
||||
self.consume_expected(",")?;
|
||||
self.skip_white();
|
||||
let d = self.parse_token()?;
|
||||
self.skip_white();
|
||||
self.consume_expected(")")?;
|
||||
self.skip_white();
|
||||
self.consume_semicolon()?;
|
||||
AnimationTimingFunctionProperty::CubicBezier(a, b, c, d)
|
||||
}
|
||||
_ => return Err(format!("invalid animation timing function {:?}", current)),
|
||||
};
|
||||
Ok(PropertyValue::Other(p))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum AnimationDelayProperty {
|
||||
Time(PropertyValue<TimeProperty>),
|
||||
Initial,
|
||||
Inherit,
|
||||
}
|
||||
|
||||
impl Token for AnimationDelayProperty {}
|
||||
|
||||
impl ParseToken<AnimationDelayProperty> for CssParser {
|
||||
fn parse_token(&mut self) -> Result<PropertyValue<AnimationDelayProperty>, String> {
|
||||
let p = match self.peek().cloned().unwrap_or_default().as_str() {
|
||||
"initial" => {
|
||||
self.expect_consume()?;
|
||||
AnimationDelayProperty::Initial
|
||||
}
|
||||
"inherit" => {
|
||||
self.expect_consume()?;
|
||||
AnimationDelayProperty::Inherit
|
||||
}
|
||||
_ => AnimationDelayProperty::Time(self.parse_token()?),
|
||||
};
|
||||
Ok(PropertyValue::Other(p))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum AnimationProperty {
|
||||
Initial,
|
||||
Inherit,
|
||||
Custom(
|
||||
String,
|
||||
PropertyValue<TimeProperty>,
|
||||
PropertyValue<AnimationTimingFunctionProperty>,
|
||||
PropertyValue<AnimationDelayProperty>,
|
||||
PropertyValue<usize>,
|
||||
PropertyValue<AnimationDirectionProperty>,
|
||||
PropertyValue<AnimationFillModeProperty>,
|
||||
PropertyValue<AnimationPlayStateProperty>,
|
||||
),
|
||||
}
|
||||
|
||||
impl Token for AnimationProperty {}
|
||||
|
||||
impl ParseToken<AnimationProperty> for CssParser {
|
||||
fn parse_token(&mut self) -> Result<PropertyValue<AnimationProperty>, String> {
|
||||
eprintln!("only full animation is supported!");
|
||||
if let Some(v) = self.try_parse_variable() {
|
||||
return Ok(PropertyValue::Variable(v));
|
||||
}
|
||||
let def = self
|
||||
.peek()
|
||||
.cloned()
|
||||
.ok_or_else(|| "expect to find token but EOF".to_string())?;
|
||||
let p = match def.as_str() {
|
||||
"initial" => {
|
||||
self.expect_consume()?;
|
||||
PropertyValue::Other(AnimationProperty::Initial)
|
||||
}
|
||||
"inherit" => {
|
||||
self.expect_consume()?;
|
||||
PropertyValue::Other(AnimationProperty::Inherit)
|
||||
}
|
||||
_ => {
|
||||
let duration = if self.next_is_semicolon() {
|
||||
PropertyValue::Other(TimeProperty::Seconds(0))
|
||||
} else {
|
||||
let v = self.parse_token()?;
|
||||
self.skip_white();
|
||||
v
|
||||
};
|
||||
let timing = if self.next_is_semicolon() {
|
||||
PropertyValue::Other(AnimationTimingFunctionProperty::Ease)
|
||||
} else {
|
||||
let v = self.parse_token()?;
|
||||
self.skip_white();
|
||||
v
|
||||
};
|
||||
let delay = if self.next_is_semicolon() {
|
||||
PropertyValue::Other(AnimationDelayProperty::Time(PropertyValue::Other(
|
||||
TimeProperty::Seconds(0),
|
||||
)))
|
||||
} else {
|
||||
let v = self.parse_token()?;
|
||||
self.skip_white();
|
||||
v
|
||||
};
|
||||
let iteration_count = if self.next_is_semicolon() {
|
||||
PropertyValue::Other(1)
|
||||
} else {
|
||||
let v = self.expect_consume()?.parse::<usize>().map_err(|_| {
|
||||
format!(
|
||||
"invalid animation iteration count, expect number got {:?}",
|
||||
self.current
|
||||
)
|
||||
})?;
|
||||
self.skip_white();
|
||||
PropertyValue::Other(v)
|
||||
};
|
||||
let direction = if self.next_is_semicolon() {
|
||||
PropertyValue::Other(AnimationDirectionProperty::Normal)
|
||||
} else {
|
||||
let v = self.parse_token()?;
|
||||
self.skip_white();
|
||||
v
|
||||
};
|
||||
let fill_mode = if self.next_is_semicolon() {
|
||||
PropertyValue::Other(AnimationFillModeProperty::None)
|
||||
} else {
|
||||
let v = self.parse_token()?;
|
||||
self.skip_white();
|
||||
v
|
||||
};
|
||||
let play_state = if self.next_is_semicolon() {
|
||||
PropertyValue::Other(AnimationPlayStateProperty::Running)
|
||||
} else {
|
||||
let v = self.parse_token()?;
|
||||
self.skip_white();
|
||||
v
|
||||
};
|
||||
let name = self.expect_consume()?;
|
||||
|
||||
PropertyValue::Other(AnimationProperty::Custom(
|
||||
name,
|
||||
duration,
|
||||
timing,
|
||||
delay,
|
||||
iteration_count,
|
||||
direction,
|
||||
fill_mode,
|
||||
play_state,
|
||||
))
|
||||
}
|
||||
};
|
||||
Ok(p)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::prop::CssTokenizer;
|
||||
|
||||
use super::*;
|
||||
|
||||
/// we assume currently we hit property name
|
||||
/// display : block;
|
||||
/// ^
|
||||
/// so we need to add `:`
|
||||
///
|
||||
/// But we also we adding spaces around because they are allowed in css and needs to be skipped
|
||||
fn parse_prop_value(s: &str) -> CssParser {
|
||||
let full = format!(" : {} {}", s, if s.contains(";") { "" } else { ";" });
|
||||
let tokens = CssTokenizer::new(full.as_str()).tokenize();
|
||||
CssParser::new("", tokens)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_animation_timing_function() {
|
||||
let res: ValueResult<AnimationTimingFunctionProperty> =
|
||||
parse_prop_value("linear").parse_token();
|
||||
let expected = Ok(PropertyValue::Other(
|
||||
AnimationTimingFunctionProperty::Linear,
|
||||
));
|
||||
assert_eq!(res, expected);
|
||||
let res: ValueResult<AnimationTimingFunctionProperty> =
|
||||
parse_prop_value("ease").parse_token();
|
||||
let expected = Ok(PropertyValue::Other(AnimationTimingFunctionProperty::Ease));
|
||||
assert_eq!(res, expected);
|
||||
let res: ValueResult<AnimationTimingFunctionProperty> =
|
||||
parse_prop_value("ease-in").parse_token();
|
||||
let expected = Ok(PropertyValue::Other(
|
||||
AnimationTimingFunctionProperty::EaseIn,
|
||||
));
|
||||
assert_eq!(res, expected);
|
||||
let res: ValueResult<AnimationTimingFunctionProperty> =
|
||||
parse_prop_value("ease-out").parse_token();
|
||||
let expected = Ok(PropertyValue::Other(
|
||||
AnimationTimingFunctionProperty::EaseOut,
|
||||
));
|
||||
assert_eq!(res, expected);
|
||||
let res: ValueResult<AnimationTimingFunctionProperty> =
|
||||
parse_prop_value("ease-in-out").parse_token();
|
||||
let expected = Ok(PropertyValue::Other(
|
||||
AnimationTimingFunctionProperty::EaseInOut,
|
||||
));
|
||||
assert_eq!(res, expected);
|
||||
let res: ValueResult<AnimationTimingFunctionProperty> =
|
||||
parse_prop_value("step-start").parse_token();
|
||||
let expected = Ok(PropertyValue::Other(
|
||||
AnimationTimingFunctionProperty::StepStart,
|
||||
));
|
||||
assert_eq!(res, expected);
|
||||
let res: ValueResult<AnimationTimingFunctionProperty> =
|
||||
parse_prop_value("step-end").parse_token();
|
||||
let expected = Ok(PropertyValue::Other(
|
||||
AnimationTimingFunctionProperty::StepEnd,
|
||||
));
|
||||
assert_eq!(res, expected);
|
||||
let res: ValueResult<AnimationTimingFunctionProperty> =
|
||||
parse_prop_value("steps(1,start)").parse_token();
|
||||
let expected = Ok(PropertyValue::Other(
|
||||
AnimationTimingFunctionProperty::Steps(
|
||||
PropertyValue::Other(1),
|
||||
PropertyValue::Other(AnimationTimingFunctionStepsProperty::Start),
|
||||
),
|
||||
));
|
||||
assert_eq!(res, expected);
|
||||
let res: ValueResult<AnimationTimingFunctionProperty> =
|
||||
parse_prop_value("steps(3,end)").parse_token();
|
||||
let expected = Ok(PropertyValue::Other(
|
||||
AnimationTimingFunctionProperty::Steps(
|
||||
PropertyValue::Other(3),
|
||||
PropertyValue::Other(AnimationTimingFunctionStepsProperty::End),
|
||||
),
|
||||
));
|
||||
assert_eq!(res, expected);
|
||||
let res: ValueResult<AnimationTimingFunctionProperty> =
|
||||
parse_prop_value("steps(0,start)").parse_token();
|
||||
let expected = Err(
|
||||
"invalid animation timing function, number of iterations must be greater than 0"
|
||||
.to_string(),
|
||||
);
|
||||
assert_eq!(res, expected);
|
||||
let res: ValueResult<AnimationTimingFunctionProperty> =
|
||||
parse_prop_value("steps(-2,start)").parse_token();
|
||||
let expected =
|
||||
Err("invalid token, expect number greater or equal 0 got \"-2\"".to_string());
|
||||
assert_eq!(res, expected);
|
||||
let res: ValueResult<AnimationTimingFunctionProperty> =
|
||||
parse_prop_value("steps(0,end)").parse_token();
|
||||
let expected = Err(
|
||||
"invalid animation timing function, number of iterations must be greater than 0"
|
||||
.to_string(),
|
||||
);
|
||||
assert_eq!(res, expected);
|
||||
let res: ValueResult<AnimationTimingFunctionProperty> =
|
||||
parse_prop_value("steps(-1,end)").parse_token();
|
||||
let expected =
|
||||
Err("invalid token, expect number greater or equal 0 got \"-1\"".to_string());
|
||||
assert_eq!(res, expected);
|
||||
let res: ValueResult<AnimationTimingFunctionProperty> =
|
||||
parse_prop_value("steps(end)").parse_token();
|
||||
let expected =
|
||||
Err("invalid token, expect number greater or equal 0 got \"end\"".to_string());
|
||||
assert_eq!(res, expected);
|
||||
let res: ValueResult<AnimationTimingFunctionProperty> =
|
||||
parse_prop_value("steps(start)").parse_token();
|
||||
let expected =
|
||||
Err("invalid token, expect number greater or equal 0 got \"start\"".to_string());
|
||||
assert_eq!(res, expected);
|
||||
let res: ValueResult<AnimationTimingFunctionProperty> =
|
||||
parse_prop_value("steps(0)").parse_token();
|
||||
let expected = Err(
|
||||
"invalid animation timing function, number of iterations must be greater than 0"
|
||||
.to_string(),
|
||||
);
|
||||
assert_eq!(res, expected);
|
||||
let res: ValueResult<AnimationTimingFunctionProperty> =
|
||||
parse_prop_value("steps(1)").parse_token();
|
||||
let expected = Err("expect to find token \",\" but found \")\"".to_string());
|
||||
assert_eq!(res, expected);
|
||||
let res: ValueResult<AnimationTimingFunctionProperty> =
|
||||
parse_prop_value("cubic-bezier(0.1,0.2,0.3,0.4)").parse_token();
|
||||
let expected = Ok(PropertyValue::Other(
|
||||
AnimationTimingFunctionProperty::CubicBezier(
|
||||
PropertyValue::Other(0.1),
|
||||
PropertyValue::Other(0.2),
|
||||
PropertyValue::Other(0.3),
|
||||
PropertyValue::Other(0.4),
|
||||
),
|
||||
));
|
||||
assert_eq!(res, expected);
|
||||
let res: ValueResult<AnimationTimingFunctionProperty> =
|
||||
parse_prop_value("cubic-bezier(0.1, 0.2, 0.3, 0.4)").parse_token();
|
||||
let expected = Ok(PropertyValue::Other(
|
||||
AnimationTimingFunctionProperty::CubicBezier(
|
||||
PropertyValue::Other(0.1),
|
||||
PropertyValue::Other(0.2),
|
||||
PropertyValue::Other(0.3),
|
||||
PropertyValue::Other(0.4),
|
||||
),
|
||||
));
|
||||
assert_eq!(res, expected);
|
||||
let res: ValueResult<AnimationTimingFunctionProperty> =
|
||||
parse_prop_value("cubic-bezier(0.1,0.2,0.3)").parse_token();
|
||||
let expected = Err("expect to find token \",\" but found \")\"".to_string());
|
||||
assert_eq!(res, expected);
|
||||
let res: ValueResult<AnimationTimingFunctionProperty> =
|
||||
parse_prop_value("cubic-bezier(0.1,0.2)").parse_token();
|
||||
let expected = Err("expect to find token \",\" but found \")\"".to_string());
|
||||
assert_eq!(res, expected);
|
||||
let res: ValueResult<AnimationTimingFunctionProperty> =
|
||||
parse_prop_value("cubic-bezier(0.1)").parse_token();
|
||||
let expected = Err("expect to find token \",\" but found \")\"".to_string());
|
||||
assert_eq!(res, expected);
|
||||
let res: ValueResult<AnimationTimingFunctionProperty> =
|
||||
parse_prop_value("initial").parse_token();
|
||||
let expected = Ok(PropertyValue::Other(
|
||||
AnimationTimingFunctionProperty::Initial,
|
||||
));
|
||||
assert_eq!(res, expected);
|
||||
let res: ValueResult<AnimationTimingFunctionProperty> =
|
||||
parse_prop_value("inherit").parse_token();
|
||||
let expected = Ok(PropertyValue::Other(
|
||||
AnimationTimingFunctionProperty::Inherit,
|
||||
));
|
||||
assert_eq!(res, expected);
|
||||
}
|
||||
}
|
@ -1,776 +0,0 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::prop::{CssParser, ParseToken, Parser, PropertyValue, Token, ValueResult};
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum ColorProperty {
|
||||
Rgba(
|
||||
PropertyValue<u8>,
|
||||
PropertyValue<u8>,
|
||||
PropertyValue<u8>,
|
||||
PropertyValue<u8>,
|
||||
),
|
||||
Hsla(
|
||||
PropertyValue<u16>,
|
||||
PropertyValue<u8>,
|
||||
PropertyValue<u8>,
|
||||
PropertyValue<f64>,
|
||||
),
|
||||
Current,
|
||||
}
|
||||
|
||||
impl Token for ColorProperty {}
|
||||
|
||||
impl ParseToken<ColorProperty> for CssParser {
|
||||
fn parse_token(&mut self) -> ValueResult<ColorProperty> {
|
||||
self.skip_white();
|
||||
let current = self.expect_consume()?;
|
||||
let s = current.trim();
|
||||
|
||||
let p = match s {
|
||||
"currentColor" => ColorProperty::Current,
|
||||
_ if s.len() == 7 && s.starts_with('#') => {
|
||||
let r = u8::from_str_radix(&s[1..=2], 16)
|
||||
.map_err(|_| format!("invalid color {:?}", s))?;
|
||||
let g = u8::from_str_radix(&s[3..=4], 16)
|
||||
.map_err(|_| format!("invalid color {:?}", s))?;
|
||||
let b = u8::from_str_radix(&s[5..=6], 16)
|
||||
.map_err(|_| format!("invalid color {:?}", s))?;
|
||||
ColorProperty::Rgba(
|
||||
PropertyValue::Other(r),
|
||||
PropertyValue::Other(g),
|
||||
PropertyValue::Other(b),
|
||||
PropertyValue::Other(255),
|
||||
)
|
||||
}
|
||||
_ if s.len() == 4 && s.starts_with('#') => {
|
||||
let _x = &s[1..=1];
|
||||
let r = u8::from_str_radix(&s[1..=1].repeat(2), 16)
|
||||
.map_err(|_| format!("invalid color {:?}", s))?;
|
||||
let g = u8::from_str_radix(&s[2..=2].repeat(2), 16)
|
||||
.map_err(|_| format!("invalid color {:?}", s))?;
|
||||
let b = u8::from_str_radix(&s[3..=3].repeat(2), 16)
|
||||
.map_err(|_| format!("invalid color {:?}", s))?;
|
||||
ColorProperty::Rgba(
|
||||
PropertyValue::Other(r),
|
||||
PropertyValue::Other(g),
|
||||
PropertyValue::Other(b),
|
||||
PropertyValue::Other(255),
|
||||
)
|
||||
}
|
||||
_ if s.len() == 9 && s.starts_with('#') => {
|
||||
let (r, g, b, a) = (
|
||||
u8::from_str_radix(&s[1..=2], 16)
|
||||
.map_err(|_| format!("invalid color {:?}", s))?,
|
||||
u8::from_str_radix(&s[3..=4], 16)
|
||||
.map_err(|_| format!("invalid color {:?}", s))?,
|
||||
u8::from_str_radix(&s[5..=6], 16)
|
||||
.map_err(|_| format!("invalid color {:?}", s))?,
|
||||
u8::from_str_radix(&s[7..=8], 16)
|
||||
.map_err(|_| format!("invalid color {:?}", s))?,
|
||||
);
|
||||
ColorProperty::Rgba(
|
||||
PropertyValue::Other(r),
|
||||
PropertyValue::Other(g),
|
||||
PropertyValue::Other(b),
|
||||
PropertyValue::Other(a),
|
||||
)
|
||||
}
|
||||
"rgba" => {
|
||||
self.skip_white();
|
||||
self.consume_expected("(")?;
|
||||
self.skip_white();
|
||||
let r = self.parse_token()?;
|
||||
self.skip_white();
|
||||
self.consume_expected(",")?;
|
||||
self.skip_white();
|
||||
let g = self.parse_token()?;
|
||||
self.skip_white();
|
||||
self.consume_expected(",")?;
|
||||
self.skip_white();
|
||||
let b = self.parse_token()?;
|
||||
self.skip_white();
|
||||
self.consume_expected(",")?;
|
||||
self.skip_white();
|
||||
let a = self.parse_token()?.into_color_alpha();
|
||||
self.skip_white();
|
||||
self.consume_expected(")")?;
|
||||
self.skip_white();
|
||||
ColorProperty::Rgba(r, g, b, a)
|
||||
}
|
||||
"rgb" => {
|
||||
self.skip_white();
|
||||
self.consume_expected("(")?;
|
||||
self.skip_white();
|
||||
let r = self.parse_token()?;
|
||||
self.skip_white();
|
||||
self.consume_expected(",")?;
|
||||
self.skip_white();
|
||||
let g = self.parse_token()?;
|
||||
self.skip_white();
|
||||
self.consume_expected(",")?;
|
||||
self.skip_white();
|
||||
let b = self.parse_token()?;
|
||||
self.skip_white();
|
||||
let a = PropertyValue::Other(255);
|
||||
self.skip_white();
|
||||
self.consume_expected(")")?;
|
||||
self.skip_white();
|
||||
ColorProperty::Rgba(r, g, b, a)
|
||||
}
|
||||
"hsla" => {
|
||||
self.skip_white();
|
||||
self.consume_expected("(")?;
|
||||
self.skip_white();
|
||||
let h = self.parse_token()?;
|
||||
self.skip_white();
|
||||
self.consume_expected(",")?;
|
||||
self.skip_white();
|
||||
let s = self.parse_token()?;
|
||||
self.consume_expected("%")?;
|
||||
self.skip_white();
|
||||
self.consume_expected(",")?;
|
||||
self.skip_white();
|
||||
let l = self.parse_token()?;
|
||||
self.consume_expected("%")?;
|
||||
self.skip_white();
|
||||
self.consume_expected(",")?;
|
||||
self.skip_white();
|
||||
let a = self.parse_token()?;
|
||||
match a {
|
||||
PropertyValue::Other(f) if -0.001f64 > f || f > 1.001f64 => {
|
||||
return Err(format!("out of range hsl alpha value {:?}", a));
|
||||
}
|
||||
_ => (),
|
||||
};
|
||||
self.skip_white();
|
||||
self.consume_expected(")")?;
|
||||
self.skip_white();
|
||||
ColorProperty::Hsla(h, s, l, a)
|
||||
}
|
||||
"hsl" => {
|
||||
self.skip_white();
|
||||
self.consume_expected("(")?;
|
||||
self.skip_white();
|
||||
let h = self.parse_token()?;
|
||||
self.skip_white();
|
||||
self.consume_expected(",")?;
|
||||
self.skip_white();
|
||||
let s = self.parse_token()?;
|
||||
self.consume_expected("%")?;
|
||||
self.skip_white();
|
||||
self.consume_expected(",")?;
|
||||
self.skip_white();
|
||||
let l = self.parse_token()?;
|
||||
self.consume_expected("%")?;
|
||||
let a = PropertyValue::Other(1f64);
|
||||
self.skip_white();
|
||||
self.consume_expected(")")?;
|
||||
self.skip_white();
|
||||
ColorProperty::Hsla(h, s, l, a)
|
||||
}
|
||||
|
||||
_ => s
|
||||
.parse::<Color>()
|
||||
.map(|c| c.to_values())
|
||||
.and_then(|(r, g, b)| {
|
||||
Ok(ColorProperty::Rgba(
|
||||
PropertyValue::Other(r),
|
||||
PropertyValue::Other(g),
|
||||
PropertyValue::Other(b),
|
||||
PropertyValue::Other(255),
|
||||
))
|
||||
})?,
|
||||
};
|
||||
Ok(PropertyValue::Other(p))
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Color {
|
||||
Pink,
|
||||
LightPink,
|
||||
HotPink,
|
||||
DeepPink,
|
||||
PaleVioletRed,
|
||||
MediumVioletRed,
|
||||
LightSalmon,
|
||||
Salmon,
|
||||
DarkSalmon,
|
||||
LightCoral,
|
||||
IndianRed,
|
||||
Crimson,
|
||||
Firebrick,
|
||||
DarkRed,
|
||||
Red,
|
||||
OrangeRed,
|
||||
Tomato,
|
||||
Coral,
|
||||
DarkOrange,
|
||||
Orange,
|
||||
Yellow,
|
||||
LightYellow,
|
||||
LemonChiffon,
|
||||
LightGoldenrodYellow,
|
||||
PapayaWhip,
|
||||
Moccasin,
|
||||
PeachPuff,
|
||||
PaleGoldenrod,
|
||||
Khaki,
|
||||
DarkKhaki,
|
||||
Gold,
|
||||
Cornsilk,
|
||||
BlanchedAlmond,
|
||||
Bisque,
|
||||
NavajoWhite,
|
||||
Wheat,
|
||||
Burlywood,
|
||||
Tan,
|
||||
RosyBrown,
|
||||
SandyBrown,
|
||||
Goldenrod,
|
||||
DarkGoldenrod,
|
||||
Peru,
|
||||
Chocolate,
|
||||
SaddleBrown,
|
||||
Sienna,
|
||||
Brown,
|
||||
Maroon,
|
||||
DarkOliveGreen,
|
||||
Olive,
|
||||
OliveDrab,
|
||||
YellowGreen,
|
||||
LimeGreen,
|
||||
Lime,
|
||||
LawnGreen,
|
||||
Chartreuse,
|
||||
GreenYellow,
|
||||
SpringGreen,
|
||||
MediumSpringGreen,
|
||||
LightGreen,
|
||||
PaleGreen,
|
||||
DarkSeaGreen,
|
||||
MediumAquamarine,
|
||||
MediumSeaGreen,
|
||||
SeaGreen,
|
||||
ForestGreen,
|
||||
Green,
|
||||
DarkGreen,
|
||||
Aqua,
|
||||
Cyan,
|
||||
LightCyan,
|
||||
PaleTurquoise,
|
||||
Aquamarine,
|
||||
Turquoise,
|
||||
MediumTurquoise,
|
||||
DarkTurquoise,
|
||||
LightSeaGreen,
|
||||
CadetBlue,
|
||||
DarkCyan,
|
||||
Teal,
|
||||
LightSteelBlue,
|
||||
PowderBlue,
|
||||
LightBlue,
|
||||
SkyBlue,
|
||||
LightSkyBlue,
|
||||
DeepSkyBlue,
|
||||
DodgerBlue,
|
||||
CornflowerBlue,
|
||||
SteelBlue,
|
||||
RoyalBlue,
|
||||
Blue,
|
||||
MediumBlue,
|
||||
DarkBlue,
|
||||
Navy,
|
||||
MidnightBlue,
|
||||
Lavender,
|
||||
Thistle,
|
||||
Plum,
|
||||
Violet,
|
||||
Orchid,
|
||||
Fuchsia,
|
||||
Magenta,
|
||||
MediumOrchid,
|
||||
MediumPurple,
|
||||
BlueViolet,
|
||||
DarkViolet,
|
||||
DarkOrchid,
|
||||
DarkMagenta,
|
||||
Purple,
|
||||
Indigo,
|
||||
DarkSlateBlue,
|
||||
SlateBlue,
|
||||
MediumSlateBlue,
|
||||
White,
|
||||
Snow,
|
||||
Honeydew,
|
||||
MintCream,
|
||||
Azure,
|
||||
AliceBlue,
|
||||
GhostWhite,
|
||||
WhiteSmoke,
|
||||
Seashell,
|
||||
Beige,
|
||||
OldLace,
|
||||
FloralWhite,
|
||||
Ivory,
|
||||
AntiqueWhite,
|
||||
Linen,
|
||||
LavenderBlush,
|
||||
MistyRose,
|
||||
Gainsboro,
|
||||
LightGray,
|
||||
Silver,
|
||||
DarkGray,
|
||||
Gray,
|
||||
DimGray,
|
||||
LightSlateGray,
|
||||
SlateGray,
|
||||
DarkSlateGray,
|
||||
Black,
|
||||
}
|
||||
|
||||
impl ToString for Color {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
Color::Pink => "Pink",
|
||||
Color::LightPink => "LightPink",
|
||||
Color::HotPink => "HotPink",
|
||||
Color::DeepPink => "DeepPink",
|
||||
Color::PaleVioletRed => "PaleVioletRed",
|
||||
Color::MediumVioletRed => "MediumVioletRed",
|
||||
Color::LightSalmon => "LightSalmon",
|
||||
Color::Salmon => "Salmon",
|
||||
Color::DarkSalmon => "DarkSalmon",
|
||||
Color::LightCoral => "LightCoral",
|
||||
Color::IndianRed => "IndianRed",
|
||||
Color::Crimson => "Crimson",
|
||||
Color::Firebrick => "Firebrick",
|
||||
Color::DarkRed => "DarkRed",
|
||||
Color::Red => "Red",
|
||||
Color::OrangeRed => "OrangeRed",
|
||||
Color::Tomato => "Tomato",
|
||||
Color::Coral => "Coral",
|
||||
Color::DarkOrange => "DarkOrange",
|
||||
Color::Orange => "Orange",
|
||||
Color::Yellow => "Yellow",
|
||||
Color::LightYellow => "LightYellow",
|
||||
Color::LemonChiffon => "LemonChiffon",
|
||||
Color::LightGoldenrodYellow => "LightGoldenrodYellow",
|
||||
Color::PapayaWhip => "PapayaWhip",
|
||||
Color::Moccasin => "Moccasin",
|
||||
Color::PeachPuff => "PeachPuff",
|
||||
Color::PaleGoldenrod => "PaleGoldenrod",
|
||||
Color::Khaki => "Khaki",
|
||||
Color::DarkKhaki => "DarkKhaki",
|
||||
Color::Gold => "Gold",
|
||||
Color::Cornsilk => "Cornsilk",
|
||||
Color::BlanchedAlmond => "BlanchedAlmond",
|
||||
Color::Bisque => "Bisque",
|
||||
Color::NavajoWhite => "NavajoWhite",
|
||||
Color::Wheat => "Wheat",
|
||||
Color::Burlywood => "Burlywood",
|
||||
Color::Tan => "Tan",
|
||||
Color::RosyBrown => "RosyBrown",
|
||||
Color::SandyBrown => "SandyBrown",
|
||||
Color::Goldenrod => "Goldenrod",
|
||||
Color::DarkGoldenrod => "DarkGoldenrod",
|
||||
Color::Peru => "Peru",
|
||||
Color::Chocolate => "Chocolate",
|
||||
Color::SaddleBrown => "SaddleBrown",
|
||||
Color::Sienna => "Sienna",
|
||||
Color::Brown => "Brown",
|
||||
Color::Maroon => "Maroon",
|
||||
Color::DarkOliveGreen => "DarkOliveGreen",
|
||||
Color::Olive => "Olive",
|
||||
Color::OliveDrab => "OliveDrab",
|
||||
Color::YellowGreen => "YellowGreen",
|
||||
Color::LimeGreen => "LimeGreen",
|
||||
Color::Lime => "Lime",
|
||||
Color::LawnGreen => "LawnGreen",
|
||||
Color::Chartreuse => "Chartreuse",
|
||||
Color::GreenYellow => "GreenYellow",
|
||||
Color::SpringGreen => "SpringGreen",
|
||||
Color::MediumSpringGreen => "MediumSpringGreen",
|
||||
Color::LightGreen => "LightGreen",
|
||||
Color::PaleGreen => "PaleGreen",
|
||||
Color::DarkSeaGreen => "DarkSeaGreen",
|
||||
Color::MediumAquamarine => "MediumAquamarine",
|
||||
Color::MediumSeaGreen => "MediumSeaGreen",
|
||||
Color::SeaGreen => "SeaGreen",
|
||||
Color::ForestGreen => "ForestGreen",
|
||||
Color::Green => "Green",
|
||||
Color::DarkGreen => "DarkGreen",
|
||||
Color::Aqua => "Aqua",
|
||||
Color::Cyan => "Cyan",
|
||||
Color::LightCyan => "LightCyan",
|
||||
Color::PaleTurquoise => "PaleTurquoise",
|
||||
Color::Aquamarine => "Aquamarine",
|
||||
Color::Turquoise => "Turquoise",
|
||||
Color::MediumTurquoise => "MediumTurquoise",
|
||||
Color::DarkTurquoise => "DarkTurquoise",
|
||||
Color::LightSeaGreen => "LightSeaGreen",
|
||||
Color::CadetBlue => "CadetBlue",
|
||||
Color::DarkCyan => "DarkCyan",
|
||||
Color::Teal => "Teal",
|
||||
Color::LightSteelBlue => "LightSteelBlue",
|
||||
Color::PowderBlue => "PowderBlue",
|
||||
Color::LightBlue => "LightBlue",
|
||||
Color::SkyBlue => "SkyBlue",
|
||||
Color::LightSkyBlue => "LightSkyBlue",
|
||||
Color::DeepSkyBlue => "DeepSkyBlue",
|
||||
Color::DodgerBlue => "DodgerBlue",
|
||||
Color::CornflowerBlue => "CornflowerBlue",
|
||||
Color::SteelBlue => "SteelBlue",
|
||||
Color::RoyalBlue => "RoyalBlue",
|
||||
Color::Blue => "Blue",
|
||||
Color::MediumBlue => "MediumBlue",
|
||||
Color::DarkBlue => "DarkBlue",
|
||||
Color::Navy => "Navy",
|
||||
Color::MidnightBlue => "MidnightBlue",
|
||||
Color::Lavender => "Lavender",
|
||||
Color::Thistle => "Thistle",
|
||||
Color::Plum => "Plum",
|
||||
Color::Violet => "Violet",
|
||||
Color::Orchid => "Orchid",
|
||||
Color::Fuchsia => "Fuchsia",
|
||||
Color::Magenta => "Magenta",
|
||||
Color::MediumOrchid => "MediumOrchid",
|
||||
Color::MediumPurple => "MediumPurple",
|
||||
Color::BlueViolet => "BlueViolet",
|
||||
Color::DarkViolet => "DarkViolet",
|
||||
Color::DarkOrchid => "DarkOrchid",
|
||||
Color::DarkMagenta => "DarkMagenta",
|
||||
Color::Purple => "Purple",
|
||||
Color::Indigo => "Indigo",
|
||||
Color::DarkSlateBlue => "DarkSlateBlue",
|
||||
Color::SlateBlue => "SlateBlue",
|
||||
Color::MediumSlateBlue => "MediumSlateBlue",
|
||||
Color::White => "White",
|
||||
Color::Snow => "Snow",
|
||||
Color::Honeydew => "Honeydew",
|
||||
Color::MintCream => "MintCream",
|
||||
Color::Azure => "Azure",
|
||||
Color::AliceBlue => "AliceBlue",
|
||||
Color::GhostWhite => "GhostWhite",
|
||||
Color::WhiteSmoke => "WhiteSmoke",
|
||||
Color::Seashell => "Seashell",
|
||||
Color::Beige => "Beige",
|
||||
Color::OldLace => "OldLace",
|
||||
Color::FloralWhite => "FloralWhite",
|
||||
Color::Ivory => "Ivory",
|
||||
Color::AntiqueWhite => "AntiqueWhite",
|
||||
Color::Linen => "Linen",
|
||||
Color::LavenderBlush => "LavenderBlush",
|
||||
Color::MistyRose => "MistyRose",
|
||||
Color::Gainsboro => "Gainsboro",
|
||||
Color::LightGray => "LightGray",
|
||||
Color::Silver => "Silver",
|
||||
Color::DarkGray => "DarkGray",
|
||||
Color::Gray => "Gray",
|
||||
Color::DimGray => "DimGray",
|
||||
Color::LightSlateGray => "LightSlateGray",
|
||||
Color::SlateGray => "SlateGray",
|
||||
Color::DarkSlateGray => "DarkSlateGray",
|
||||
Color::Black => "Black",
|
||||
}
|
||||
.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl Color {
|
||||
pub fn to_values(&self) -> (u8, u8, u8) {
|
||||
match self {
|
||||
Color::Pink => (255, 192, 203),
|
||||
Color::LightPink => (255, 182, 193),
|
||||
Color::HotPink => (255, 105, 180),
|
||||
Color::DeepPink => (255, 20, 147),
|
||||
Color::PaleVioletRed => (219, 112, 147),
|
||||
Color::MediumVioletRed => (199, 21, 133),
|
||||
Color::LightSalmon => (255, 160, 122),
|
||||
Color::Salmon => (250, 128, 114),
|
||||
Color::DarkSalmon => (233, 150, 122),
|
||||
Color::LightCoral => (240, 128, 128),
|
||||
Color::IndianRed => (205, 92, 92),
|
||||
Color::Crimson => (220, 20, 60),
|
||||
Color::Firebrick => (178, 34, 34),
|
||||
Color::DarkRed => (139, 0, 0),
|
||||
Color::Red => (255, 0, 0),
|
||||
Color::OrangeRed => (255, 69, 0),
|
||||
Color::Tomato => (255, 99, 71),
|
||||
Color::Coral => (255, 127, 80),
|
||||
Color::DarkOrange => (255, 140, 0),
|
||||
Color::Orange => (255, 165, 0),
|
||||
Color::Yellow => (255, 255, 0),
|
||||
Color::LightYellow => (255, 255, 224),
|
||||
Color::LemonChiffon => (255, 250, 205),
|
||||
Color::LightGoldenrodYellow => (250, 250, 210),
|
||||
Color::PapayaWhip => (255, 239, 213),
|
||||
Color::Moccasin => (255, 228, 181),
|
||||
Color::PeachPuff => (255, 218, 185),
|
||||
Color::PaleGoldenrod => (238, 232, 170),
|
||||
Color::Khaki => (240, 230, 140),
|
||||
Color::DarkKhaki => (189, 183, 107),
|
||||
Color::Gold => (255, 215, 0),
|
||||
Color::Cornsilk => (255, 248, 220),
|
||||
Color::BlanchedAlmond => (255, 235, 205),
|
||||
Color::Bisque => (255, 228, 196),
|
||||
Color::NavajoWhite => (255, 222, 173),
|
||||
Color::Wheat => (245, 222, 179),
|
||||
Color::Burlywood => (222, 184, 135),
|
||||
Color::Tan => (210, 180, 140),
|
||||
Color::RosyBrown => (188, 143, 143),
|
||||
Color::SandyBrown => (244, 164, 96),
|
||||
Color::Goldenrod => (218, 165, 32),
|
||||
Color::DarkGoldenrod => (184, 134, 11),
|
||||
Color::Peru => (205, 133, 63),
|
||||
Color::Chocolate => (210, 105, 30),
|
||||
Color::SaddleBrown => (139, 69, 19),
|
||||
Color::Sienna => (160, 82, 45),
|
||||
Color::Brown => (165, 42, 42),
|
||||
Color::Maroon => (128, 0, 0),
|
||||
Color::DarkOliveGreen => (85, 107, 47),
|
||||
Color::Olive => (128, 128, 0),
|
||||
Color::OliveDrab => (107, 142, 35),
|
||||
Color::YellowGreen => (154, 205, 50),
|
||||
Color::LimeGreen => (50, 205, 50),
|
||||
Color::Lime => (0, 255, 0),
|
||||
Color::LawnGreen => (124, 252, 0),
|
||||
Color::Chartreuse => (127, 255, 0),
|
||||
Color::GreenYellow => (173, 255, 47),
|
||||
Color::SpringGreen => (0, 255, 127),
|
||||
Color::MediumSpringGreen => (0, 250, 154),
|
||||
Color::LightGreen => (144, 238, 144),
|
||||
Color::PaleGreen => (152, 251, 152),
|
||||
Color::DarkSeaGreen => (143, 188, 143),
|
||||
Color::MediumAquamarine => (102, 205, 170),
|
||||
Color::MediumSeaGreen => (60, 179, 113),
|
||||
Color::SeaGreen => (46, 139, 87),
|
||||
Color::ForestGreen => (34, 139, 34),
|
||||
Color::Green => (0, 128, 0),
|
||||
Color::DarkGreen => (0, 100, 0),
|
||||
Color::Aqua => (0, 255, 255),
|
||||
Color::Cyan => (0, 255, 255),
|
||||
Color::LightCyan => (224, 255, 255),
|
||||
Color::PaleTurquoise => (175, 238, 238),
|
||||
Color::Aquamarine => (127, 255, 212),
|
||||
Color::Turquoise => (64, 224, 208),
|
||||
Color::MediumTurquoise => (72, 209, 204),
|
||||
Color::DarkTurquoise => (0, 206, 209),
|
||||
Color::LightSeaGreen => (32, 178, 170),
|
||||
Color::CadetBlue => (95, 158, 160),
|
||||
Color::DarkCyan => (0, 139, 139),
|
||||
Color::Teal => (0, 128, 128),
|
||||
Color::LightSteelBlue => (176, 196, 222),
|
||||
Color::PowderBlue => (176, 224, 230),
|
||||
Color::LightBlue => (173, 216, 230),
|
||||
Color::SkyBlue => (135, 206, 235),
|
||||
Color::LightSkyBlue => (135, 206, 250),
|
||||
Color::DeepSkyBlue => (0, 191, 255),
|
||||
Color::DodgerBlue => (30, 144, 255),
|
||||
Color::CornflowerBlue => (100, 149, 237),
|
||||
Color::SteelBlue => (70, 130, 180),
|
||||
Color::RoyalBlue => (65, 105, 225),
|
||||
Color::Blue => (0, 0, 255),
|
||||
Color::MediumBlue => (0, 0, 205),
|
||||
Color::DarkBlue => (0, 0, 139),
|
||||
Color::Navy => (0, 0, 128),
|
||||
Color::MidnightBlue => (25, 25, 112),
|
||||
Color::Lavender => (230, 230, 250),
|
||||
Color::Thistle => (216, 191, 216),
|
||||
Color::Plum => (221, 160, 221),
|
||||
Color::Violet => (238, 130, 238),
|
||||
Color::Orchid => (218, 112, 214),
|
||||
Color::Fuchsia => (255, 0, 255),
|
||||
Color::Magenta => (255, 0, 255),
|
||||
Color::MediumOrchid => (186, 85, 211),
|
||||
Color::MediumPurple => (147, 112, 219),
|
||||
Color::BlueViolet => (138, 43, 226),
|
||||
Color::DarkViolet => (148, 0, 211),
|
||||
Color::DarkOrchid => (153, 50, 204),
|
||||
Color::DarkMagenta => (139, 0, 139),
|
||||
Color::Purple => (128, 0, 128),
|
||||
Color::Indigo => (75, 0, 130),
|
||||
Color::DarkSlateBlue => (72, 61, 139),
|
||||
Color::SlateBlue => (106, 90, 205),
|
||||
Color::MediumSlateBlue => (123, 104, 238),
|
||||
Color::White => (255, 255, 255),
|
||||
Color::Snow => (255, 250, 250),
|
||||
Color::Honeydew => (240, 255, 240),
|
||||
Color::MintCream => (245, 255, 250),
|
||||
Color::Azure => (240, 255, 255),
|
||||
Color::AliceBlue => (240, 248, 255),
|
||||
Color::GhostWhite => (248, 248, 255),
|
||||
Color::WhiteSmoke => (245, 245, 245),
|
||||
Color::Seashell => (255, 245, 238),
|
||||
Color::Beige => (245, 245, 220),
|
||||
Color::OldLace => (253, 245, 230),
|
||||
Color::FloralWhite => (255, 250, 240),
|
||||
Color::Ivory => (255, 255, 240),
|
||||
Color::AntiqueWhite => (250, 235, 215),
|
||||
Color::Linen => (250, 240, 230),
|
||||
Color::LavenderBlush => (255, 240, 245),
|
||||
Color::MistyRose => (255, 228, 225),
|
||||
Color::Gainsboro => (220, 220, 220),
|
||||
Color::LightGray => (211, 211, 211),
|
||||
Color::Silver => (192, 192, 192),
|
||||
Color::DarkGray => (169, 169, 169),
|
||||
Color::Gray => (128, 128, 128),
|
||||
Color::DimGray => (105, 105, 105),
|
||||
Color::LightSlateGray => (119, 136, 153),
|
||||
Color::SlateGray => (112, 128, 144),
|
||||
Color::DarkSlateGray => (47, 79, 79),
|
||||
Color::Black => (0, 0, 0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Color {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> Result<Color, Self::Err> {
|
||||
let p = match s.to_lowercase().trim() {
|
||||
"pink" | "Pink" => Color::Pink,
|
||||
"lightpink" | "LightPink" => Color::LightPink,
|
||||
"hotpink" | "HotPink" => Color::HotPink,
|
||||
"deeppink" | "DeepPink" => Color::DeepPink,
|
||||
"palevioletred" | "PaleVioletRed" => Color::PaleVioletRed,
|
||||
"mediumvioletred" | "MediumVioletRed" => Color::MediumVioletRed,
|
||||
"lightsalmon" | "LightSalmon" => Color::LightSalmon,
|
||||
"salmon" | "Salmon" => Color::Salmon,
|
||||
"darksalmon" | "DarkSalmon" => Color::DarkSalmon,
|
||||
"lightcoral" | "LightCoral" => Color::LightCoral,
|
||||
"indianred" | "IndianRed" => Color::IndianRed,
|
||||
"crimson" | "Crimson" => Color::Crimson,
|
||||
"firebrick" | "Firebrick" => Color::Firebrick,
|
||||
"darkred" | "DarkRed" => Color::DarkRed,
|
||||
"red" | "Red" => Color::Red,
|
||||
"orangered" | "OrangeRed" => Color::OrangeRed,
|
||||
"tomato" | "Tomato" => Color::Tomato,
|
||||
"coral" | "Coral" => Color::Coral,
|
||||
"darkorange" | "DarkOrange" => Color::DarkOrange,
|
||||
"orange" | "Orange" => Color::Orange,
|
||||
"yellow" | "Yellow" => Color::Yellow,
|
||||
"lightyellow" | "LightYellow" => Color::LightYellow,
|
||||
"lemonchiffon" | "LemonChiffon" => Color::LemonChiffon,
|
||||
"lightgoldenrodyellow" | "LightGoldenrodYellow" => Color::LightGoldenrodYellow,
|
||||
"papayawhip" | "PapayaWhip" => Color::PapayaWhip,
|
||||
"moccasin" | "Moccasin" => Color::Moccasin,
|
||||
"peachpuff" | "PeachPuff" => Color::PeachPuff,
|
||||
"palegoldenrod" | "PaleGoldenrod" => Color::PaleGoldenrod,
|
||||
"khaki" | "Khaki" => Color::Khaki,
|
||||
"darkkhaki" | "DarkKhaki" => Color::DarkKhaki,
|
||||
"gold" | "Gold" => Color::Gold,
|
||||
"cornsilk" | "Cornsilk" => Color::Cornsilk,
|
||||
"blanchedalmond" | "BlanchedAlmond" => Color::BlanchedAlmond,
|
||||
"bisque" | "Bisque" => Color::Bisque,
|
||||
"navajowhite" | "NavajoWhite" => Color::NavajoWhite,
|
||||
"wheat" | "Wheat" => Color::Wheat,
|
||||
"burlywood" | "Burlywood" => Color::Burlywood,
|
||||
"tan" | "Tan" => Color::Tan,
|
||||
"rosybrown" | "RosyBrown" => Color::RosyBrown,
|
||||
"sandybrown" | "SandyBrown" => Color::SandyBrown,
|
||||
"goldenrod" | "Goldenrod" => Color::Goldenrod,
|
||||
"darkgoldenrod" | "DarkGoldenrod" => Color::DarkGoldenrod,
|
||||
"peru" | "Peru" => Color::Peru,
|
||||
"chocolate" | "Chocolate" => Color::Chocolate,
|
||||
"saddlebrown" | "SaddleBrown" => Color::SaddleBrown,
|
||||
"sienna" | "Sienna" => Color::Sienna,
|
||||
"brown" | "Brown" => Color::Brown,
|
||||
"maroon" | "Maroon" => Color::Maroon,
|
||||
"darkolivegreen" | "DarkOliveGreen" => Color::DarkOliveGreen,
|
||||
"olive" | "Olive" => Color::Olive,
|
||||
"olivedrab" | "OliveDrab" => Color::OliveDrab,
|
||||
"yellowgreen" | "YellowGreen" => Color::YellowGreen,
|
||||
"limegreen" | "LimeGreen" => Color::LimeGreen,
|
||||
"lime" | "Lime" => Color::Lime,
|
||||
"lawngreen" | "LawnGreen" => Color::LawnGreen,
|
||||
"chartreuse" | "Chartreuse" => Color::Chartreuse,
|
||||
"greenyellow" | "GreenYellow" => Color::GreenYellow,
|
||||
"springgreen" | "SpringGreen" => Color::SpringGreen,
|
||||
"mediumspringgreen" | "MediumSpringGreen" => Color::MediumSpringGreen,
|
||||
"lightgreen" | "LightGreen" => Color::LightGreen,
|
||||
"palegreen" | "PaleGreen" => Color::PaleGreen,
|
||||
"darkseagreen" | "DarkSeaGreen" => Color::DarkSeaGreen,
|
||||
"mediumaquamarine" | "MediumAquamarine" => Color::MediumAquamarine,
|
||||
"mediumseagreen" | "MediumSeaGreen" => Color::MediumSeaGreen,
|
||||
"seagreen" | "SeaGreen" => Color::SeaGreen,
|
||||
"forestgreen" | "ForestGreen" => Color::ForestGreen,
|
||||
"green" | "Green" => Color::Green,
|
||||
"darkgreen" | "DarkGreen" => Color::DarkGreen,
|
||||
"aqua" | "Aqua" => Color::Aqua,
|
||||
"cyan" | "Cyan" => Color::Cyan,
|
||||
"lightcyan" | "LightCyan" => Color::LightCyan,
|
||||
"paleturquoise" | "PaleTurquoise" => Color::PaleTurquoise,
|
||||
"aquamarine" | "Aquamarine" => Color::Aquamarine,
|
||||
"turquoise" | "Turquoise" => Color::Turquoise,
|
||||
"mediumturquoise" | "MediumTurquoise" => Color::MediumTurquoise,
|
||||
"darkturquoise" | "DarkTurquoise" => Color::DarkTurquoise,
|
||||
"lightseagreen" | "LightSeaGreen" => Color::LightSeaGreen,
|
||||
"cadetblue" | "CadetBlue" => Color::CadetBlue,
|
||||
"darkcyan" | "DarkCyan" => Color::DarkCyan,
|
||||
"teal" | "Teal" => Color::Teal,
|
||||
"lightsteelblue" | "LightSteelBlue" => Color::LightSteelBlue,
|
||||
"powderblue" | "PowderBlue" => Color::PowderBlue,
|
||||
"lightblue" | "LightBlue" => Color::LightBlue,
|
||||
"skyblue" | "SkyBlue" => Color::SkyBlue,
|
||||
"lightskyblue" | "LightSkyBlue" => Color::LightSkyBlue,
|
||||
"deepskyblue" | "DeepSkyBlue" => Color::DeepSkyBlue,
|
||||
"dodgerblue" | "DodgerBlue" => Color::DodgerBlue,
|
||||
"cornflowerblue" | "CornflowerBlue" => Color::CornflowerBlue,
|
||||
"steelblue" | "SteelBlue" => Color::SteelBlue,
|
||||
"royalblue" | "RoyalBlue" => Color::RoyalBlue,
|
||||
"blue" | "Blue" => Color::Blue,
|
||||
"mediumblue" | "MediumBlue" => Color::MediumBlue,
|
||||
"darkblue" | "DarkBlue" => Color::DarkBlue,
|
||||
"navy" | "Navy" => Color::Navy,
|
||||
"midnightblue" | "MidnightBlue" => Color::MidnightBlue,
|
||||
"lavender" | "Lavender" => Color::Lavender,
|
||||
"thistle" | "Thistle" => Color::Thistle,
|
||||
"plum" | "Plum" => Color::Plum,
|
||||
"violet" | "Violet" => Color::Violet,
|
||||
"orchid" | "Orchid" => Color::Orchid,
|
||||
"fuchsia" | "Fuchsia" => Color::Fuchsia,
|
||||
"magenta" | "Magenta" => Color::Magenta,
|
||||
"mediumorchid" | "MediumOrchid" => Color::MediumOrchid,
|
||||
"mediumpurple" | "MediumPurple" => Color::MediumPurple,
|
||||
"blueviolet" | "BlueViolet" => Color::BlueViolet,
|
||||
"darkviolet" | "DarkViolet" => Color::DarkViolet,
|
||||
"darkorchid" | "DarkOrchid" => Color::DarkOrchid,
|
||||
"darkmagenta" | "DarkMagenta" => Color::DarkMagenta,
|
||||
"purple" | "Purple" => Color::Purple,
|
||||
"indigo" | "Indigo" => Color::Indigo,
|
||||
"darkslateblue" | "DarkSlateBlue" => Color::DarkSlateBlue,
|
||||
"slateblue" | "SlateBlue" => Color::SlateBlue,
|
||||
"mediumslateblue" | "MediumSlateBlue" => Color::MediumSlateBlue,
|
||||
"white" | "White" => Color::White,
|
||||
"snow" | "Snow" => Color::Snow,
|
||||
"honeydew" | "Honeydew" => Color::Honeydew,
|
||||
"mintcream" | "MintCream" => Color::MintCream,
|
||||
"azure" | "Azure" => Color::Azure,
|
||||
"aliceblue" | "AliceBlue" => Color::AliceBlue,
|
||||
"ghostwhite" | "GhostWhite" => Color::GhostWhite,
|
||||
"whitesmoke" | "WhiteSmoke" => Color::WhiteSmoke,
|
||||
"seashell" | "Seashell" => Color::Seashell,
|
||||
"beige" | "Beige" => Color::Beige,
|
||||
"oldlace" | "OldLace" => Color::OldLace,
|
||||
"floralwhite" | "FloralWhite" => Color::FloralWhite,
|
||||
"ivory" | "Ivory" => Color::Ivory,
|
||||
"antiquewhite" | "AntiqueWhite" => Color::AntiqueWhite,
|
||||
"linen" | "Linen" => Color::Linen,
|
||||
"lavenderblush" | "LavenderBlush" => Color::LavenderBlush,
|
||||
"mistyrose" | "MistyRose" => Color::MistyRose,
|
||||
"gainsboro" | "Gainsboro" => Color::Gainsboro,
|
||||
"lightgray" | "LightGray" => Color::LightGray,
|
||||
"silver" | "Silver" => Color::Silver,
|
||||
"darkgray" | "DarkGray" => Color::DarkGray,
|
||||
"gray" | "Gray" => Color::Gray,
|
||||
"dimgray" | "DimGray" => Color::DimGray,
|
||||
"lightslategray" | "LightSlateGray" => Color::LightSlateGray,
|
||||
"slategray" | "SlateGray" => Color::SlateGray,
|
||||
"darkslategray" | "DarkSlateGray" => Color::DarkSlateGray,
|
||||
"black" | "Black" => Color::Black,
|
||||
_ => return Err(format!("{:?} is not a predefined color", s)),
|
||||
};
|
||||
Ok(p)
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,17 +0,0 @@
|
||||
.foo {
|
||||
}
|
||||
|
||||
.bar {
|
||||
}
|
||||
|
||||
.foz {
|
||||
|
||||
|
||||
}
|
||||
|
||||
.baz {
|
||||
display: block;
|
||||
justify-content: space-between;
|
||||
color: red;
|
||||
background-color: #42413d;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user