Commit 48a16913 authored by arturo's avatar arturo

[graph] Node Focus

* #375: rc6.x
parent 8c72c681
Pipeline #2769 failed with stage
in 0 seconds
......@@ -6002,19 +6002,29 @@ h3 {
position: relative;
transition: color 150ms ease-in-out;
}
.b-icon-button--overlay.b-icon-button::before {
.b-icon-button__inner {
z-index: 1;
position: relative;
}
.b-icon-button::before {
left: -10px;
right: -10px;
top: -6px;
right: -6px;
bottom: -6px;
left: -6px;
content: "";
background-color: #212529;
border-radius: 5px;
z-index: -1;
position: absolute;
transition: background-color 150ms ease-in-out;
transition: background-color 150ms ease-in-out, box-shadow 150ms ease-in-out;
}
.b-icon-button--overlay::before {
content: "";
}
.b-icon-button--level-1:hover::before {
background-color: #212529;
}
.b-icon-button--level-2::before {
background-color: #212529;
}
.b-icon-button--overlay:hover.b-icon-button::before {
.b-icon-button--level-2:hover::before {
background-color: #0a0c0d;
}
.b-icon-button--enabled, .b-icon-button--muted, .b-icon-button--idled {
......@@ -6065,6 +6075,9 @@ h3 {
.b-icon-button--enabled.b-icon-button--dark:hover, .b-icon-button--muted.b-icon-button--dark:hover {
color: #b3b3b3;
}
.b-icon-button--enabled.b-icon-button:active::before, .b-icon-button--enabled.b-icon-button--active::before, .b-icon-button--muted.b-icon-button:active::before, .b-icon-button--muted.b-icon-button--active::before {
box-shadow: 0 0 0 0.2rem rgba(52, 58, 64, 0.5);
}
.b-icon-button--idled:hover {
cursor: default;
}
......@@ -7414,6 +7427,7 @@ input[type=range]:-moz-focusring {
flex-grow: 1;
pointer-events: all;
position: relative;
content: layout;
}
.graph-layout__focus__inner {
top: 0;
......@@ -7467,6 +7481,55 @@ input[type=range]:-moz-focusring {
display: none;
}
.graph-doc-focus {
scrollbar-width: none;
overflow-y: scroll;
background-color: #000000;
height: 100%;
position: relative;
}
.graph-doc-focus::-webkit-scrollbar {
display: none;
}
.graph-doc-focus::before {
background: linear-gradient(to top, rgba(0, 0, 0, 0) 0%, black 45%);
content: "";
z-index: 1;
pointer-events: none;
position: sticky;
top: 0;
height: 16px;
width: 100%;
display: block;
}
.graph-doc-focus::after {
background: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, black 45%);
content: "";
z-index: 1;
pointer-events: none;
position: sticky;
bottom: 0;
height: 16px;
width: 100%;
display: block;
}
.graph-doc-focus__header {
padding: 0.75rem 1.25rem;
font-size: 20px;
}
.right-handed .graph-doc-focus__header {
float: right;
}
.left-handed .graph-doc-focus__header {
float: left;
}
.graph-doc-focus__body {
padding-left: 1.25rem;
padding-right: 1.25rem;
}
.graph-sidebar {
scrollbar-width: none;
overflow-y: scroll;
......@@ -7590,6 +7653,22 @@ input[type=range]:-moz-focusring {
.graph-doc-list__item:hover {
background-color: #121212;
}
.graph-doc-list__item--selected::before {
content: "";
position: absolute;
z-index: 1;
width: 2px;
background-color: #0F81C7;
left: 0;
top: 0;
bottom: 0;
}
.graph-doc-list__item--selected:first-child::before {
border-top-left-radius: 0.25rem;
}
.graph-doc-list__item--selected:last-child::before {
border-bottom-left-radius: 0.25rem;
}
.graph-doc-list__item__main {
flex-grow: 1;
padding-right: 1.25rem;
......@@ -7607,6 +7686,15 @@ input[type=range]:-moz-focusring {
color: #CED4DA;
}
.graph-contact-list__item__title, .graph-contact-list__item__subtitle {
line-height: 1.3;
margin-bottom: 2px;
}
.graph-contact-list__item__subtitle {
font-size: 15px;
color: #DEE2E6;
}
.graph-toolbar {
display: flex;
padding: 8px;
......@@ -7938,23 +8026,26 @@ a:focus, a:hover {
visibility: visible;
}
.right-handed .mainleaf:hover .mainleaf__settings-icon {
margin-left: 16px;
margin-left: 18px;
}
.left-handed .mainleaf:hover .mainleaf__settings-icon {
margin-right: 16px;
margin-right: 18px;
}
.right-handed .mainleaf__update-icon {
margin-left: 16px;
margin-left: 18px;
}
.left-handed .mainleaf__update-icon {
margin-right: 16px;
margin-right: 18px;
}
.mainleaf__update-icon.b-icon-button--overlay::before, .mainleaf__settings-icon.b-icon-button--overlay::before {
.mainleaf__update-icon.b-icon-button::before, .mainleaf__settings-icon.b-icon-button::before {
top: -5px;
bottom: -5px;
left: -6px;
right: -6px;
}
.mainleaf__progress-bar {
width: 64px;
......@@ -8910,19 +9001,43 @@ select.form-control {
top: calc( 50% - 50px );
left: calc( 50% - 50px );
}
.phylo__frame {
top: 0;
right: 0;
bottom: 0;
left: 0;
position: absolute;
display: flex;
z-index: 1;
width: 100%;
height: calc(100vh - 56px);
justify-content: flex-end;
pointer-events: none;
}
.right-handed .phylo__frame {
flex-direction: row;
}
.left-handed .phylo__frame {
flex-direction: row-reverse;
}
.phylo__sidebar {
position: fixed;
width: 480px;
height: calc(100vh - 56px);
z-index: 1;
height: inherit;
flex-grow: 0;
pointer-events: all;
}
.right-handed .phylo__sidebar {
right: 0;
.phylo__sidebar__inner {
position: fixed;
height: inherit;
width: inherit;
}
.right-handed .phylo__sidebar__inner {
border-left: 1px solid #dee2e6;
}
.left-handed .phylo__sidebar {
left: 0;
.left-handed .phylo__sidebar__inner {
border-right: 1px solid #dee2e6;
}
......
......@@ -5956,19 +5956,29 @@ h3 {
position: relative;
transition: color 150ms ease-in-out;
}
.b-icon-button--overlay.b-icon-button::before {
.b-icon-button__inner {
z-index: 1;
position: relative;
}
.b-icon-button::before {
left: -10px;
right: -10px;
top: -6px;
right: -6px;
bottom: -6px;
left: -6px;
content: "";
background-color: #F8F9FA;
border-radius: 5px;
z-index: -1;
position: absolute;
transition: background-color 150ms ease-in-out;
transition: background-color 150ms ease-in-out, box-shadow 150ms ease-in-out;
}
.b-icon-button--overlay::before {
content: "";
}
.b-icon-button--level-1:hover::before {
background-color: #F8F9FA;
}
.b-icon-button--level-2::before {
background-color: #F8F9FA;
}
.b-icon-button--overlay:hover.b-icon-button::before {
.b-icon-button--level-2:hover::before {
background-color: #dae0e5;
}
.b-icon-button--enabled, .b-icon-button--muted, .b-icon-button--idled {
......@@ -6019,6 +6029,9 @@ h3 {
.b-icon-button--enabled.b-icon-button--dark:hover, .b-icon-button--muted.b-icon-button--dark:hover {
color: #0a0c0d;
}
.b-icon-button--enabled.b-icon-button:active::before, .b-icon-button--enabled.b-icon-button--active::before, .b-icon-button--muted.b-icon-button:active::before, .b-icon-button--muted.b-icon-button--active::before {
box-shadow: 0 0 0 0.2rem rgba(233, 236, 239, 0.5);
}
.b-icon-button--idled:hover {
cursor: default;
}
......@@ -7367,6 +7380,7 @@ input[type=range]:-moz-focusring {
flex-grow: 1;
pointer-events: all;
position: relative;
content: layout;
}
.graph-layout__focus__inner {
top: 0;
......@@ -7420,6 +7434,55 @@ input[type=range]:-moz-focusring {
display: none;
}
.graph-doc-focus {
scrollbar-width: none;
overflow-y: scroll;
background-color: #fff;
height: 100%;
position: relative;
}
.graph-doc-focus::-webkit-scrollbar {
display: none;
}
.graph-doc-focus::before {
background: linear-gradient(to top, rgba(255, 255, 255, 0) 0%, white 45%);
content: "";
z-index: 1;
pointer-events: none;
position: sticky;
top: 0;
height: 16px;
width: 100%;
display: block;
}
.graph-doc-focus::after {
background: linear-gradient(to bottom, rgba(255, 255, 255, 0) 0%, white 45%);
content: "";
z-index: 1;
pointer-events: none;
position: sticky;
bottom: 0;
height: 16px;
width: 100%;
display: block;
}
.graph-doc-focus__header {
padding: 0.75rem 1.25rem;
font-size: 20px;
}
.right-handed .graph-doc-focus__header {
float: right;
}
.left-handed .graph-doc-focus__header {
float: left;
}
.graph-doc-focus__body {
padding-left: 1.25rem;
padding-right: 1.25rem;
}
.graph-sidebar {
scrollbar-width: none;
overflow-y: scroll;
......@@ -7543,6 +7606,22 @@ input[type=range]:-moz-focusring {
.graph-doc-list__item:hover {
background-color: #FCFCFC;
}
.graph-doc-list__item--selected::before {
content: "";
position: absolute;
z-index: 1;
width: 2px;
background-color: #17a2b8;
left: 0;
top: 0;
bottom: 0;
}
.graph-doc-list__item--selected:first-child::before {
border-top-left-radius: 0.25rem;
}
.graph-doc-list__item--selected:last-child::before {
border-bottom-left-radius: 0.25rem;
}
.graph-doc-list__item__main {
flex-grow: 1;
padding-right: 1.25rem;
......@@ -7560,6 +7639,15 @@ input[type=range]:-moz-focusring {
color: #6C757D;
}
.graph-contact-list__item__title, .graph-contact-list__item__subtitle {
line-height: 1.3;
margin-bottom: 2px;
}
.graph-contact-list__item__subtitle {
font-size: 15px;
color: #495057;
}
.graph-toolbar {
display: flex;
padding: 8px;
......@@ -7891,23 +7979,26 @@ a:focus, a:hover {
visibility: visible;
}
.right-handed .mainleaf:hover .mainleaf__settings-icon {
margin-left: 16px;
margin-left: 18px;
}
.left-handed .mainleaf:hover .mainleaf__settings-icon {
margin-right: 16px;
margin-right: 18px;
}
.right-handed .mainleaf__update-icon {
margin-left: 16px;
margin-left: 18px;
}
.left-handed .mainleaf__update-icon {
margin-right: 16px;
margin-right: 18px;
}
.mainleaf__update-icon.b-icon-button--overlay::before, .mainleaf__settings-icon.b-icon-button--overlay::before {
.mainleaf__update-icon.b-icon-button::before, .mainleaf__settings-icon.b-icon-button::before {
top: -5px;
bottom: -5px;
left: -6px;
right: -6px;
}
.mainleaf__progress-bar {
width: 64px;
......@@ -8863,19 +8954,43 @@ select.form-control {
top: calc( 50% - 50px );
left: calc( 50% - 50px );
}
.phylo__frame {
top: 0;
right: 0;
bottom: 0;
left: 0;
position: absolute;
display: flex;
z-index: 1;
width: 100%;
height: calc(100vh - 56px);
justify-content: flex-end;
pointer-events: none;
}
.right-handed .phylo__frame {
flex-direction: row;
}
.left-handed .phylo__frame {
flex-direction: row-reverse;
}
.phylo__sidebar {
position: fixed;
width: 480px;
height: calc(100vh - 56px);
z-index: 1;
height: inherit;
flex-grow: 0;
pointer-events: all;
}
.right-handed .phylo__sidebar {
right: 0;
.phylo__sidebar__inner {
position: fixed;
height: inherit;
width: inherit;
}
.right-handed .phylo__sidebar__inner {
border-left: 1px solid #dee2e6;
}
.left-handed .phylo__sidebar {
left: 0;
.left-handed .phylo__sidebar__inner {
border-right: 1px solid #dee2e6;
}
......
......@@ -5711,19 +5711,29 @@ h3 {
position: relative;
transition: color 150ms ease-in-out;
}
.b-icon-button--overlay.b-icon-button::before {
.b-icon-button__inner {
z-index: 1;
position: relative;
}
.b-icon-button::before {
left: -10px;
right: -10px;
top: -6px;
right: -6px;
bottom: -6px;
left: -6px;
content: "";
background-color: #F8F9FA;
border-radius: 5px;
z-index: -1;
position: absolute;
transition: background-color 150ms ease-in-out;
transition: background-color 150ms ease-in-out, box-shadow 150ms ease-in-out;
}
.b-icon-button--overlay::before {
content: "";
}
.b-icon-button--level-1:hover::before {
background-color: #F8F9FA;
}
.b-icon-button--level-2::before {
background-color: #F8F9FA;
}
.b-icon-button--overlay:hover.b-icon-button::before {
.b-icon-button--level-2:hover::before {
background-color: #dae0e5;
}
.b-icon-button--enabled, .b-icon-button--muted, .b-icon-button--idled {
......@@ -5774,6 +5784,9 @@ h3 {
.b-icon-button--enabled.b-icon-button--dark:hover, .b-icon-button--muted.b-icon-button--dark:hover {
color: #0a0c0d;
}
.b-icon-button--enabled.b-icon-button:active::before, .b-icon-button--enabled.b-icon-button--active::before, .b-icon-button--muted.b-icon-button:active::before, .b-icon-button--muted.b-icon-button--active::before {
box-shadow: 0 0 0 0.2rem rgba(233, 236, 239, 0.5);
}
.b-icon-button--idled:hover {
cursor: default;
}
......@@ -7123,6 +7136,7 @@ input[type=range]:-moz-focusring {
flex-grow: 1;
pointer-events: all;
position: relative;
content: layout;
}
.graph-layout__focus__inner {
top: 0;
......@@ -7176,6 +7190,55 @@ input[type=range]:-moz-focusring {
display: none;
}
.graph-doc-focus {
scrollbar-width: none;
overflow-y: scroll;
background-color: #fff;
height: 100%;
position: relative;
}
.graph-doc-focus::-webkit-scrollbar {
display: none;
}
.graph-doc-focus::before {
background: linear-gradient(to top, rgba(255, 255, 255, 0) 0%, white 45%);
content: "";
z-index: 1;
pointer-events: none;
position: sticky;
top: 0;
height: 16px;
width: 100%;
display: block;
}
.graph-doc-focus::after {
background: linear-gradient(to bottom, rgba(255, 255, 255, 0) 0%, white 45%);
content: "";
z-index: 1;
pointer-events: none;
position: sticky;
bottom: 0;
height: 16px;
width: 100%;
display: block;
}
.graph-doc-focus__header {
padding: 0.75rem 1.25rem;
font-size: 20px;
}
.right-handed .graph-doc-focus__header {
float: right;
}
.left-handed .graph-doc-focus__header {
float: left;
}
.graph-doc-focus__body {
padding-left: 1.25rem;
padding-right: 1.25rem;
}
.graph-sidebar {
scrollbar-width: none;
overflow-y: scroll;
......@@ -7299,6 +7362,22 @@ input[type=range]:-moz-focusring {
.graph-doc-list__item:hover {
background-color: #FCFCFC;
}
.graph-doc-list__item--selected::before {
content: "";
position: absolute;
z-index: 1;
width: 2px;
background-color: #5c8f94;
left: 0;
top: 0;
bottom: 0;
}
.graph-doc-list__item--selected:first-child::before {
border-top-left-radius: 0.25rem;
}
.graph-doc-list__item--selected:last-child::before {
border-bottom-left-radius: 0.25rem;
}
.graph-doc-list__item__main {
flex-grow: 1;
padding-right: 1.25rem;
......@@ -7316,6 +7395,15 @@ input[type=range]:-moz-focusring {
color: #6C757D;
}
.graph-contact-list__item__title, .graph-contact-list__item__subtitle {
line-height: 1.3;
margin-bottom: 2px;
}
.graph-contact-list__item__subtitle {
font-size: 15px;
color: #495057;
}
.graph-toolbar {
display: flex;
padding: 8px;
......@@ -7647,23 +7735,26 @@ a:focus, a:hover {
visibility: visible;
}
.right-handed .mainleaf:hover .mainleaf__settings-icon {
margin-left: 16px;
margin-left: 18px;
}
.left-handed .mainleaf:hover .mainleaf__settings-icon {
margin-right: 16px;
margin-right: 18px;
}
.right-handed .mainleaf__update-icon {
margin-left: 16px;
margin-left: 18px;
}
.left-handed .mainleaf__update-icon {
margin-right: 16px;
margin-right: 18px;
}
.mainleaf__update-icon.b-icon-button--overlay::before, .mainleaf__settings-icon.b-icon-button--overlay::before {
.mainleaf__update-icon.b-icon-button::before, .mainleaf__settings-icon.b-icon-button::before {
top: -5px;
bottom: -5px;
left: -6px;
right: -6px;
}
.mainleaf__progress-bar {
width: 64px;
......@@ -8619,19 +8710,43 @@ select.form-control {
top: calc( 50% - 50px );
left: calc( 50% - 50px );
}
.phylo__frame {
top: 0;
right: 0;
bottom: 0;
left: 0;
position: absolute;
display: flex;
z-index: 1;
width: 100%;
height: calc(100vh - 56px);
justify-content: flex-end;
pointer-events: none;
}
.right-handed .phylo__frame {
flex-direction: row;
}
.left-handed .phylo__frame {
flex-direction: row-reverse;
}
.phylo__sidebar {
position: fixed;
width: 480px;
height: calc(100vh - 56px);
z-index: 1;
height: inherit;
flex-grow: 0;
pointer-events: all;
}
.right-handed .phylo__sidebar {
right: 0;
.phylo__sidebar__inner {
position: fixed;
height: inherit;
width: inherit;
}
.right-handed .phylo__sidebar__inner {
border-left: 1px solid #dee2e6;
}
.left-handed .phylo__sidebar {
left: 0;
.left-handed .phylo__sidebar__inner {
border-right: 1px solid #dee2e6;
}
......
......@@ -5959,19 +5959,29 @@ h3 {
position: relative;
transition: color 150ms ease-in-out;
}
.b-icon-button--overlay.b-icon-button::before {
.b-icon-button__inner {
z-index: 1;
position: relative;
}
.b-icon-button::before {
left: -10px;
right: -10px;
top: -6px;
right: -6px;
bottom: -6px;
left: -6px;
content: "";
background-color: #F8F9FA;
border-radius: 5px;
z-index: -1;
position: absolute;
transition: background-color 150ms ease-in-out;
transition: background-color 150ms ease-in-out, box-shadow 150ms ease-in-out;
}
.b-icon-button--overlay::before {
content: "";
}
.b-icon-button--level-1:hover::before {
background-color: #F8F9FA;
}
.b-icon-button--level-2::before {
background-color: #F8F9FA;
}
.b-icon-button--overlay:hover.b-icon-button::before {
.b-icon-button--level-2:hover::before {
background-color: #dae0e5;
}
.b-icon-button--enabled, .b-icon-button--muted, .b-icon-button--idled {
......@@ -6022,6 +6032,9 @@ h3 {
.b-icon-button--enabled.b-icon-button--dark:hover, .b-icon-button--muted.b-icon-button--dark:hover {
color: #0a0c0d;
}
.b-icon-button--enabled.b-icon-button:active::before, .b-icon-button--enabled.b-icon-button--active::before, .b-icon-button--muted.b-icon-button:active::before, .b-icon-button--muted.b-icon-button--active::before {
box-shadow: 0 0 0 0.2rem rgba(233, 236, 239, 0.5);
}
.b-icon-button--idled:hover {
cursor: default;
}
......@@ -7371,6 +7384,7 @@ input[type=range]:-moz-focusring {
flex-grow: 1;
pointer-events: all;
position: relative;
content: layout;
}
.graph-layout__focus__inner {
top: 0;
......@@ -7424,6 +7438,55 @@ input[type=range]:-moz-focusring {
display: none;
}
.graph-doc-focus {
scrollbar-width: none;
overflow-y: scroll;
background-color: #fff;
height: 100%;
position: relative;
}
.graph-doc-focus::-webkit-scrollbar {
display: none;
}
.graph-doc-focus::before {
background: linear-gradient(to top, rgba(255, 255, 255, 0) 0%, white 45%);
content: "";
z-index: 1;
pointer-events: none;
position: sticky;
top: 0;
height: 16px;
width: 100%;
display: block;
}
.graph-doc-focus::after {
background: linear-gradient(to bottom, rgba(255, 255, 255, 0) 0%, white 45%);
content: "";
z-index: 1;
pointer-events: none;
position: sticky;
bottom: 0;
height: 16px;
width: 100%;
display: block;
}
.graph-doc-focus__header {
padding: 0.75rem 1.25rem;
font-size: 20px;
}
.right-handed .graph-doc-focus__header {
float: right;
}
.left-handed .graph-doc-focus__header {
float: left;
}
.graph-doc-focus__body {
padding-left: 1.25rem;
padding-right: 1.25rem;
}
.graph-sidebar {
scrollbar-width: none;
overflow-y: scroll;
......@@ -7547,6 +7610,22 @@ input[type=range]:-moz-focusring {
.graph-doc-list__item:hover {
background-color: #FCFCFC;
}
.graph-doc-list__item--selected::before {
content: "";
position: absolute;
z-index: 1;
width: 2px;
background-color: #74DBEF;
left: 0;
top: 0;
bottom: 0;
}
.graph-doc-list__item--selected:first-child::before {
border-top-left-radius: 0.25rem;
}
.graph-doc-list__item--selected:last-child::before {
border-bottom-left-radius: 0.25rem;
}
.graph-doc-list__item__main {
flex-grow: 1;
padding-right: 1.25rem;
......@@ -7564,6 +7643,15 @@ input[type=range]:-moz-focusring {
color: #6C757D;
}
.graph-contact-list__item__title, .graph-contact-list__item__subtitle {
line-height: 1.3;
margin-bottom: 2px;
}
.graph-contact-list__item__subtitle {
font-size: 15px;
color: #495057;
}
.graph-toolbar {
display: flex;
padding: 8px;
......@@ -7895,23 +7983,26 @@ a:focus, a:hover {
visibility: visible;
}
.right-handed .mainleaf:hover .mainleaf__settings-icon {
margin-left: 16px;
margin-left: 18px;
}
.left-handed .mainleaf:hover .mainleaf__settings-icon {
margin-right: 16px;
margin-right: 18px;
}
.right-handed .mainleaf__update-icon {
margin-left: 16px;
margin-left: 18px;
}
.left-handed .mainleaf__update-icon {
margin-right: 16px;
margin-right: 18px;
}
.mainleaf__update-icon.b-icon-button--overlay::before, .mainleaf__settings-icon.b-icon-button--overlay::before {
.mainleaf__update-icon.b-icon-button::before, .mainleaf__settings-icon.b-icon-button::before {
top: -5px;
bottom: -5px;
left: -6px;
right: -6px;
}
.mainleaf__progress-bar {
width: 64px;
......@@ -8867,19 +8958,43 @@ select.form-control {
top: calc( 50% - 50px );
left: calc( 50% - 50px );
}
.phylo__frame {
top: 0;
right: 0;
bottom: 0;
left: 0;
position: absolute;
display: flex;
z-index: 1;
width: 100%;
height: calc(100vh - 56px);
justify-content: flex-end;
pointer-events: none;
}
.right-handed .phylo__frame {
flex-direction: row;
}
.left-handed .phylo__frame {
flex-direction: row-reverse;
}
.phylo__sidebar {
position: fixed;
width: 480px;
height: calc(100vh - 56px);
z-index: 1;
height: inherit;
flex-grow: 0;
pointer-events: all;
}
.right-handed .phylo__sidebar {
right: 0;
.phylo__sidebar__inner {
position: fixed;
height: inherit;
width: inherit;
}
.right-handed .phylo__sidebar__inner {
border-left: 1px solid #dee2e6;
}
.left-handed .phylo__sidebar {
left: 0;
.left-handed .phylo__sidebar__inner {
border-right: 1px solid #dee2e6;
}
......
......@@ -5960,19 +5960,29 @@ h3 {
position: relative;
transition: color 150ms ease-in-out;
}
.b-icon-button--overlay.b-icon-button::before {
.b-icon-button__inner {
z-index: 1;
position: relative;
}
.b-icon-button::before {
left: -10px;
right: -10px;
top: -6px;
right: -6px;
bottom: -6px;
left: -6px;
content: "";
background-color: #F8F9FA;
border-radius: 5px;
z-index: -1;
position: absolute;
transition: background-color 150ms ease-in-out;
transition: background-color 150ms ease-in-out, box-shadow 150ms ease-in-out;
}
.b-icon-button--overlay::before {
content: "";
}
.b-icon-button--level-1:hover::before {
background-color: #F8F9FA;
}
.b-icon-button--level-2::before {
background-color: #F8F9FA;
}
.b-icon-button--overlay:hover.b-icon-button::before {
.b-icon-button--level-2:hover::before {
background-color: #dae0e5;
}
.b-icon-button--enabled, .b-icon-button--muted, .b-icon-button--idled {
......@@ -6023,6 +6033,9 @@ h3 {
.b-icon-button--enabled.b-icon-button--dark:hover, .b-icon-button--muted.b-icon-button--dark:hover {
color: #0a0c0d;
}
.b-icon-button--enabled.b-icon-button:active::before, .b-icon-button--enabled.b-icon-button--active::before, .b-icon-button--muted.b-icon-button:active::before, .b-icon-button--muted.b-icon-button--active::before {
box-shadow: 0 0 0 0.2rem rgba(233, 236, 239, 0.5);
}
.b-icon-button--idled:hover {
cursor: default;
}
......@@ -7372,6 +7385,7 @@ input[type=range]:-moz-focusring {
flex-grow: 1;
pointer-events: all;
position: relative;
content: layout;
}
.graph-layout__focus__inner {
top: 0;
......@@ -7425,6 +7439,55 @@ input[type=range]:-moz-focusring {
display: none;
}
.graph-doc-focus {
scrollbar-width: none;
overflow-y: scroll;
background-color: #fff;
height: 100%;
position: relative;
}
.graph-doc-focus::-webkit-scrollbar {
display: none;
}
.graph-doc-focus::before {
background: linear-gradient(to top, rgba(255, 255, 255, 0) 0%, white 45%);
content: "";
z-index: 1;
pointer-events: none;
position: sticky;
top: 0;
height: 16px;
width: 100%;
display: block;
}
.graph-doc-focus::after {
background: linear-gradient(to bottom, rgba(255, 255, 255, 0) 0%, white 45%);
content: "";
z-index: 1;
pointer-events: none;
position: sticky;
bottom: 0;
height: 16px;
width: 100%;
display: block;
}
.graph-doc-focus__header {
padding: 0.75rem 1.25rem;
font-size: 20px;
}
.right-handed .graph-doc-focus__header {
float: right;
}
.left-handed .graph-doc-focus__header {
float: left;
}
.graph-doc-focus__body {
padding-left: 1.25rem;
padding-right: 1.25rem;
}
.graph-sidebar {
scrollbar-width: none;
overflow-y: scroll;
......@@ -7548,6 +7611,22 @@ input[type=range]:-moz-focusring {
.graph-doc-list__item:hover {
background-color: #FCFCFC;
}
.graph-doc-list__item--selected::before {
content: "";
position: absolute;
z-index: 1;
width: 2px;
background-color: #515151;
left: 0;
top: 0;
bottom: 0;
}
.graph-doc-list__item--selected:first-child::before {
border-top-left-radius: 0.25rem;
}
.graph-doc-list__item--selected:last-child::before {
border-bottom-left-radius: 0.25rem;
}
.graph-doc-list__item__main {
flex-grow: 1;
padding-right: 1.25rem;
......@@ -7565,6 +7644,15 @@ input[type=range]:-moz-focusring {
color: #6C757D;
}
.graph-contact-list__item__title, .graph-contact-list__item__subtitle {
line-height: 1.3;
margin-bottom: 2px;
}
.graph-contact-list__item__subtitle {
font-size: 15px;
color: #495057;
}
.graph-toolbar {
display: flex;
padding: 8px;
......@@ -7896,23 +7984,26 @@ a:focus, a:hover {
visibility: visible;
}
.right-handed .mainleaf:hover .mainleaf__settings-icon {
margin-left: 16px;
margin-left: 18px;
}
.left-handed .mainleaf:hover .mainleaf__settings-icon {
margin-right: 16px;
margin-right: 18px;
}
.right-handed .mainleaf__update-icon {
margin-left: 16px;
margin-left: 18px;
}
.left-handed .mainleaf__update-icon {
margin-right: 16px;
margin-right: 18px;
}
.mainleaf__update-icon.b-icon-button--overlay::before, .mainleaf__settings-icon.b-icon-button--overlay::before {
.mainleaf__update-icon.b-icon-button::before, .mainleaf__settings-icon.b-icon-button::before {
top: -5px;
bottom: -5px;
left: -6px;
right: -6px;
}
.mainleaf__progress-bar {
width: 64px;
......@@ -8868,19 +8959,43 @@ select.form-control {
top: calc( 50% - 50px );
left: calc( 50% - 50px );
}
.phylo__frame {
top: 0;
right: 0;
bottom: 0;
left: 0;
position: absolute;
display: flex;
z-index: 1;
width: 100%;
height: calc(100vh - 56px);
justify-content: flex-end;
pointer-events: none;
}
.right-handed .phylo__frame {
flex-direction: row;
}
.left-handed .phylo__frame {
flex-direction: row-reverse;
}
.phylo__sidebar {
position: fixed;
width: 480px;
height: calc(100vh - 56px);
z-index: 1;
height: inherit;
flex-grow: 0;
pointer-events: all;
}
.right-handed .phylo__sidebar {
right: 0;
.phylo__sidebar__inner {
position: fixed;
height: inherit;
width: inherit;
}
.right-handed .phylo__sidebar__inner {
border-left: 1px solid #dee2e6;
}
.left-handed .phylo__sidebar {
left: 0;
.left-handed .phylo__sidebar__inner {
border-right: 1px solid #dee2e6;
}
......
module Gargantext.Components.App (app) where
import Reactix as R
import Toestand as T
import Gargantext.Prelude
import Gargantext.AsyncTasks as GAT
import Gargantext.Components.App.Data (emptyApp)
import Gargantext.Components.App.Store as AppStore
import Gargantext.Components.Router (router)
import Gargantext.Hooks (useHashRouter)
import Gargantext.Router as Router
import Gargantext.Sessions as Sessions
import Gargantext.Utils.Reactix as R2
import Reactix as R
import Toestand as T
here :: R2.Here
here = R2.here "Gargantext.Components.App"
......@@ -22,8 +21,7 @@ app = R.createElement appCpt
appCpt :: R.Component ()
appCpt = here.component "app" cpt where
cpt _ _ = do
box <- T.useBox emptyApp -- global data
boxes <- T.useFocusedFields box {} -- read-write access for children
boxes <- AppStore.use
-- tasks <- T.useBox Nothing -- storage for asynchronous tasks reductor
R.useEffectOnce' $ do
void $ Sessions.load boxes.sessions
......
module Gargantext.Components.App.Data (App, Boxes, emptyApp) where
module Gargantext.Components.App.Store
( Store
, State
, options
, context
, provide
, use
-- legacy
, Boxes
) where
import Gargantext.Prelude
......@@ -16,11 +25,43 @@ import Gargantext.Sessions (Session, Sessions)
import Gargantext.Sessions as Sessions
import Gargantext.Sessions.Types (OpenNodes(..))
import Gargantext.Types (FrontendError, Handed(RightHanded), SidePanelState(..))
import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.Stores as Stores
import Gargantext.Utils.Toestand as T2
import Reactix as R
import Toestand as T
import Unsafe.Coerce (unsafeCoerce)
type App =
{ backend :: Maybe Backend
here :: R2.Here
here = R2.here "Gargantext.Components.App.Store"
type Store =
( backend :: T.Box (Maybe Backend)
, errors :: T.Box (Array FrontendError)
, forestOpen :: T.Box OpenNodes
, graphVersion :: T2.ReloadS
, handed :: T.Box Handed
, lang :: T.Box Lang.LandingLang
, reloadForest :: T2.ReloadS
, reloadMainPage :: T2.ReloadS
, reloadRoot :: T2.ReloadS
, route :: T.Box AppRoute
, session :: T.Box (Maybe Session)
, sessions :: T.Box Sessions
, showCorpus :: T.Box Boolean
, showLogin :: T.Box Boolean
, showTree :: T.Box Boolean
, sidePanelLists :: T.Box (Maybe (Record ListsT.SidePanel))
, sidePanelTexts :: T.Box (Maybe (Record TextsT.SidePanel))
, sidePanelState :: T.Box SidePanelState
, tasks :: T.Box GAT.Storage
, theme :: T.Box Themes.Theme
, tileAxisXList :: T.Box (Array (Record Tile))
, tileAxisYList :: T.Box (Array (Record Tile))
)
type State =
( backend :: Maybe Backend
, errors :: Array FrontendError
, forestOpen :: OpenNodes
, graphVersion :: T2.Reload
......@@ -42,10 +83,10 @@ type App =
, theme :: Themes.Theme
, tileAxisXList :: Array (Record Tile)
, tileAxisYList :: Array (Record Tile)
}
)
emptyApp :: App
emptyApp =
options :: Record State
options =
{ backend : Nothing
, errors : []
, forestOpen : OpenNodes $ Set.empty
......@@ -70,27 +111,15 @@ emptyApp =
, tileAxisYList : mempty
}
type Boxes =
{ backend :: T.Box (Maybe Backend)
, errors :: T.Box (Array FrontendError)
, forestOpen :: T.Box OpenNodes
, graphVersion :: T2.ReloadS
, handed :: T.Box Handed
, lang :: T.Box Lang.LandingLang
, reloadForest :: T2.ReloadS
, reloadMainPage :: T2.ReloadS
, reloadRoot :: T2.ReloadS
, route :: T.Box AppRoute
, session :: T.Box (Maybe Session)
, sessions :: T.Box Sessions
, showCorpus :: T.Box Boolean
, showLogin :: T.Box Boolean
, showTree :: T.Box Boolean
, sidePanelLists :: T.Box (Maybe (Record ListsT.SidePanel))
, sidePanelTexts :: T.Box (Maybe (Record TextsT.SidePanel))
, sidePanelState :: T.Box SidePanelState
, tasks :: T.Box GAT.Storage
, theme :: T.Box Themes.Theme
, tileAxisXList :: T.Box (Array (Record Tile))
, tileAxisYList :: T.Box (Array (Record Tile))
}
context :: R.Context (Record Store)
context = R.createContext $ unsafeCoerce unit
provide :: Record State -> Array R.Element -> R.Element
provide values = Stores.provideStore here.name values context
use :: R.Hooks (Record Store)
use = Stores.useStore context
------------------------------------------------------
type Boxes = Record Store
......@@ -4,7 +4,7 @@ import Gargantext.Prelude
import Data.Foldable (elem, intercalate)
import Effect (Effect)
import Gargantext.Components.Bootstrap.Types (ComponentStatus(..), Variant(..))
import Gargantext.Components.Bootstrap.Types (ComponentStatus(..), Elevation(..), Variant(..))
import Gargantext.Utils ((?))
import Gargantext.Utils.Reactix as R2
import React.SyntheticEvent as SE
......@@ -22,6 +22,7 @@ type Options =
, status :: ComponentStatus
, title :: String
, overlay :: Boolean
, elevation :: Elevation
, variant :: Variant
)
......@@ -30,7 +31,8 @@ options =
{ className : ""
, status : Enabled
, title : ""
, overlay : false
, overlay : true
, elevation : Level0
, variant : Dark
}
......@@ -50,7 +52,8 @@ component :: R.Component Props
component = R.hooksComponent componentName cpt where
cpt props@{ callback
, status
, name } _ = do
, name
} _ = do
-- Computed
let
wrapperClassName = intercalate " "
......@@ -63,6 +66,7 @@ component = R.hooksComponent componentName cpt where
, props.overlay ?
componentName <> "--overlay" $
""
, componentName <> "--" <> show props.elevation
]
contentClassName = intercalate " "
......@@ -82,11 +86,15 @@ component = R.hooksComponent componentName cpt where
, disabled: elem status [ Disabled, Deferred ]
}
[
H.i
{ title: props.title
, className: contentClassName
}
[]
H.span
{ className: componentName <> "__inner" }
[
H.i
{ title: props.title
, className: contentClassName
}
[]
]
]
-- | Clicked event will effectively be triggered according to the
......
......@@ -5,6 +5,7 @@ module Gargantext.Components.Bootstrap.Types
, SpinnerTheme(..)
, TooltipEffect(..), TooltipPosition(..)
, Position(..)
, Elevation(..)
) where
import Gargantext.Prelude
......@@ -150,7 +151,7 @@ instance Show Position where show = kebabCase <<< genericShow
-- | Position used on React Tooltip
-- |
-- | -- | https://github.com/wwayne/react-tooltip#options
-- | https://github.com/wwayne/react-tooltip#options
data TooltipPosition
= TooltipPosition Position
| AutomaticPosition
......@@ -160,3 +161,18 @@ derive instance Eq TooltipPosition
instance Show TooltipPosition where
show (TooltipPosition a) = (kebabCase <<< genericShow) a
show AutomaticPosition = ""
----------------------------------------------------------------------
-- | Elevarion measure scale values used on various custom components
-- | and properties
-- |
-- | Example: https://material.io/design/environment/elevation.html
data Elevation
= Level0
| Level1
| Level2
derive instance Generic Elevation _
derive instance Eq Elevation
instance Show Elevation where show = kebabCase <<< genericShow
......@@ -25,7 +25,7 @@ import Effect (Effect)
import Effect.Aff (Aff, launchAff_)
import Effect.Class (liftEffect)
import Effect.Timer (setTimeout)
import Gargantext.Components.App.Data (Boxes)
import Gargantext.Components.App.Store (Boxes)
import Gargantext.Components.Bootstrap as B
import Gargantext.Components.Bootstrap.Types (ComponentStatus(..))
import Gargantext.Components.Category (rating)
......
......@@ -9,7 +9,7 @@ import Effect (Effect)
import Effect.Aff (Aff)
import Effect.Class (liftEffect)
import Gargantext.AsyncTasks as GAT
import Gargantext.Components.App.Data (Boxes)
import Gargantext.Components.App.Store (Boxes)
import Gargantext.Components.Forest.Tree.Node.Action.Add (AddNodeValue(..), addNode)
import Gargantext.Components.Forest.Tree.Node.Action.Contact as Contact
import Gargantext.Components.Forest.Tree.Node.Action.Delete (deleteNode, unpublishNode)
......@@ -147,7 +147,7 @@ folderSimpleCpt = here.component "folderSimpleCpt" cpt where
route nId rootId nType sid
| rootId == nodeId = Home
| otherwise = getFolderPath nType sid nId
icon :: FolderStyle -> GT.NodeType -> String
icon FolderUp _ = "fa fa-folder-open"
......@@ -234,7 +234,7 @@ backButtonCpt = R.hooksComponent "backButton" cpt where
cpt _ _ = do
{ goToPreviousPage } <- useLinkHandler
pure $
pure $
H.button {
className: "btn btn-primary"
, on: { click: \_ -> goToPreviousPage unit }
......
......@@ -8,7 +8,7 @@ import Gargantext.Prelude
import Data.Array as A
import Data.Maybe (Maybe(..))
import Gargantext.Components.App.Data (Boxes)
import Gargantext.Components.App.Store (Boxes)
import Gargantext.Components.Bootstrap as B
import Gargantext.Components.Bootstrap.Types (ButtonVariant(..), Position(..), TooltipPosition(..), Variant(..))
import Gargantext.Components.Forest.Tree (treeLoader)
......
......@@ -11,7 +11,7 @@ import Effect (Effect)
import Effect.Aff (Aff)
import Effect.Class (liftEffect)
import Gargantext.AsyncTasks as GAT
import Gargantext.Components.App.Data (Boxes)
import Gargantext.Components.App.Store (Boxes)
import Gargantext.Components.Bootstrap as B
import Gargantext.Components.Forest.Tree.Node (blankNodeSpan, nodeSpan)
import Gargantext.Components.Forest.Tree.Node.Action.Add (AddNodeValue(..), addNode)
......
......@@ -16,9 +16,9 @@ import Effect (Effect)
import Effect.Aff (Aff, launchAff)
import Effect.Class (liftEffect)
import Gargantext.AsyncTasks as GAT
import Gargantext.Components.App.Data (Boxes)
import Gargantext.Components.App.Store (Boxes)
import Gargantext.Components.Bootstrap as B
import Gargantext.Components.Bootstrap.Types (ComponentStatus(..), TooltipEffect(..), Variant(..))
import Gargantext.Components.Bootstrap.Types (ComponentStatus(..), Elevation(..), TooltipEffect(..), Variant(..))
import Gargantext.Components.Forest.Tree.Node.Action.Types (Action(..))
import Gargantext.Components.Forest.Tree.Node.Action.Upload (DroppedFile(..), fileTypeView)
import Gargantext.Components.Forest.Tree.Node.Action.Upload.Types (FileType(..), UploadFileBlob(..))
......@@ -291,6 +291,7 @@ nodeSpanCpt = here.component "nodeSpan" cpt
"check-circle" $
"exclamation-circle"
, callback: const $ T.modify_ (not) folderOpen
, overlay: false
}
]
,
......@@ -331,7 +332,7 @@ nodeSpanCpt = here.component "nodeSpan" cpt
"Each node of the Tree can perform some actions.\n"
<> "Click here to execute one of them."
, variant: Secondary
, overlay: true
, elevation: Level1
}
,
nodePopupView
......@@ -390,6 +391,7 @@ nodeIconCpt = here.component "nodeIcon" cpt where
, callback
, status: isLeaf ? Idled $ Enabled
, variant: isSelected ? Primary $ Dark
, overlay: false
}
]
<> children
......@@ -421,6 +423,7 @@ folderIconCpt = here.component "folderIcon" cpt where
B.iconButton
{ className: "mainleaf__folder-icon"
, name: isOpened ? "caret-down" $ "caret-right"
, overlay: false
, callback
}
......
......@@ -5,7 +5,7 @@ import Gargantext.Prelude
import Data.Maybe (Maybe)
import Effect (Effect)
import Effect.Aff (Aff, launchAff)
import Gargantext.Components.App.Data (Boxes)
import Gargantext.Components.App.Store (Boxes)
import Gargantext.Components.Forest.Tree.Node.Action.Search.SearchBar (searchBar)
import Gargantext.Components.Forest.Tree.Node.Action.Search.SearchField (defaultSearch)
import Gargantext.Components.Forest.Tree.Node.Action.Types (Action(..))
......
module Gargantext.Components.Forest.Tree.Node.Action.Update where
import Gargantext.Components.Forest.Tree.Node.Action.Update.Types
import Gargantext.Prelude
import Gargantext.Components.Forest.Tree.Node.Action.Update.Types (Charts(..), Granularity(..), GraphMetric(..), Method(..), PartitionMethod(..), UpdateNodeParams(..))
import DOM.Simple.Console (log3)
import Data.Either (Either(..))
import Data.Maybe (Maybe(..))
......@@ -80,6 +81,10 @@ updateGraphCpt = here.component "updateGraph" cpt where
methodGraphClustering <- T.useBox Spinglass
methodGraphClustering' <- T.useLive T.unequal methodGraphClustering
let
callback :: Action -> Aff Unit
callback = dispatch >=> \_ -> dispatch ClosePopover
pure $ panel [ -- H.text "Update with"
formChoiceSafe { items: [Order1, Order2]
, default: methodGraphMetric'
......@@ -94,7 +99,7 @@ updateGraphCpt = here.component "updateGraph" cpt where
(submitButton (UpdateNode $ UpdateNodeParamsGraph { methodGraphMetric: methodGraphMetric'
, methodGraphClustering: methodGraphClustering'
}
) dispatch
) callback
)
......@@ -135,7 +140,9 @@ updatePhyloCpt = here.component "updatePhylo" cpt where
Left error -> log3 "[handleFormError]" error r
Right r' -> do
opts <- pure $ options r'
launchAff_ $ dispatch opts
launchAff_ do
dispatch opts
dispatch ClosePopover
where
options :: Phylo.UpdateData -> Action
......
......@@ -5,7 +5,7 @@ import Gargantext.Prelude
import Data.Either (Either)
import Data.Maybe (Maybe(..))
import Effect.Aff (Aff)
import Gargantext.Components.App.Data (Boxes)
import Gargantext.Components.App.Store (Boxes)
import Gargantext.Components.Forest.Tree.Node.Action.Types (Action(..))
import Gargantext.Components.Forest.Tree.Node.Tools (panel, submitButton)
import Gargantext.Config.REST (AffRESTError, RESTError)
......
......@@ -9,7 +9,7 @@ import Reactix as R
import Reactix.DOM.HTML as H
import Toestand as T
import Gargantext.Components.App.Data (Boxes)
import Gargantext.Components.App.Store (Boxes)
import Gargantext.Components.Forest.Tree.Node.Action.Add (addNodeView)
import Gargantext.Components.Forest.Tree.Node.Action.Contact as Contact
import Gargantext.Components.Forest.Tree.Node.Action.Delete (actionDelete)
......
......@@ -4,7 +4,7 @@ import DOM.Simple as DOM
import Data.Maybe (Maybe)
import Effect (Effect)
import Effect.Aff (Aff)
import Gargantext.Components.App.Data (Boxes)
import Gargantext.Components.App.Store (Boxes)
import Gargantext.Components.Forest.Tree.Node.Action.Types (Action)
import Gargantext.Components.Forest.Tree.Node.Settings (NodeAction)
import Gargantext.Prelude (Unit)
......@@ -32,5 +32,3 @@ type NodePopupS =
, name :: Name
, nodeType :: GT.NodeType
)
......@@ -7,7 +7,7 @@ import Data.Array as A
import Data.Foldable (intercalate)
import Data.Maybe (Maybe(..))
import Data.Tuple.Nested ((/\))
import Gargantext.Components.App.Data (Boxes)
import Gargantext.Components.App.Store (Boxes)
import Gargantext.Components.Forest.Tree.Node.Action (Props, subTreeOut, setTreeOut)
import Gargantext.Components.Forest.Tree.Node.Action.Types (Action)
import Gargantext.Components.Forest.Tree.Node.Tools.FTree (FTree, LNode(..), NTree(..))
......
......@@ -6,7 +6,7 @@ import Data.Maybe (Maybe(..))
import Effect.Aff (Aff, launchAff_)
import Effect.Class (liftEffect)
import Gargantext.Components.Bootstrap as B
import Gargantext.Components.Bootstrap.Types (ComponentStatus(..), Variant(..))
import Gargantext.Components.Bootstrap.Types (ComponentStatus(..), Elevation(..), Variant(..))
import Gargantext.Components.GraphExplorer.API as GraphAPI
import Gargantext.Sessions (Session)
import Gargantext.Types as GT
......@@ -62,7 +62,7 @@ graphUpdateButtonCpt = here.component "graphUpdateButton" cpt
B.iconButton
{ className: "mainleaf__update-icon"
, variant: Secondary
, overlay: true
, elevation: Level1
, status: enabled' ? Enabled $ Disabled
, callback: const $ onClick enabled' enabled
, name: "refresh"
......
......@@ -5,6 +5,9 @@ module Gargantext.Components.GraphExplorer.Frame.DocFocus
import Gargantext.Prelude
import Data.Maybe (Maybe(..))
import Effect (Effect)
import Gargantext.Components.Bootstrap as B
import Gargantext.Components.Bootstrap.Types (Elevation(..))
import Gargantext.Components.GraphExplorer.Types (GraphSideDoc(..))
import Gargantext.Components.Nodes.Corpus.Document (documentMainLayout)
import Gargantext.Sessions (Session)
......@@ -19,6 +22,7 @@ here = R2.here "Gargantext.Components.GraphExplorer.Frame.DocFocus"
type Props =
( graphSideDoc :: GraphSideDoc
, session :: Session
, closeCallback :: Unit -> Effect Unit
)
docFocus :: R2.Leaf Props
......@@ -28,6 +32,7 @@ docFocusCpt :: R.Component Props
docFocusCpt = here.component "main" cpt where
cpt { graphSideDoc: GraphSideDoc { docId, listId, corpusId }
, session
, closeCallback
} _ = do
......@@ -36,11 +41,22 @@ docFocusCpt = here.component "main" cpt where
pure $
H.div
{ className: "graph-layout__focus" }
{ className: "graph-doc-focus" }
[
H.div
{ className: "graph-layout__focus__inner" }
{ className: "graph-doc-focus__header" }
[
B.iconButton
{ name: "times"
, elevation: Level2
, callback: closeCallback
}
]
,
H.div
{ className: "graph-doc-focus__body" }
[
-- print the document node
documentMainLayout
{ listId
, mCorpusId: Just corpusId
......
......@@ -12,7 +12,8 @@ import Data.Nullable (null, Nullable)
import Data.Sequence as Seq
import Data.Set as Set
import Data.Tuple (Tuple(..))
import Gargantext.Components.App.Data (Boxes)
import Effect (Effect)
import Gargantext.Components.App.Store as AppStore
import Gargantext.Components.Bootstrap as B
import Gargantext.Components.GraphExplorer.Frame.DocFocus (docFocus)
import Gargantext.Components.GraphExplorer.Resources as Graph
......@@ -24,27 +25,25 @@ import Gargantext.Components.GraphExplorer.Types (GraphSideDoc)
import Gargantext.Components.GraphExplorer.Types as GET
import Gargantext.Config (defaultFrontends)
import Gargantext.Data.Louvain as Louvain
import Gargantext.Hooks.Session (useSession)
import Gargantext.Hooks.Sigmax as Sigmax
import Gargantext.Hooks.Sigmax.Types as SigmaxT
import Gargantext.Sessions (Session)
import Gargantext.Types as GT
import Gargantext.Types as Types
import Gargantext.Utils ((?))
import Gargantext.Utils.Range as Range
import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.Stores as Stores
import Math as Math
import Partial.Unsafe (unsafePartial)
import Reactix as R
import Reactix.DOM.HTML as H
import Toestand as T
here :: R2.Here
here = R2.here "Gargantext.Components.GraphExplorer.Layout"
type Props =
( session :: Session
, boxes :: Boxes
, sigmaRef :: R.Ref Sigmax.Sigma
( sigmaRef :: R.Ref Sigmax.Sigma
)
layout :: R2.Leaf Props
......@@ -52,19 +51,21 @@ layout = R2.leaf layoutCpt
layoutCpt :: R.Memo Props
layoutCpt = R.memo' $ here.component "explorerWriteGraph" cpt where
cpt props@{ boxes
, session
, sigmaRef
} _ = do
cpt { sigmaRef
} _ = do
-- | States
-- |
{ reloadForest
} <- AppStore.use
{ showSidebar
, showDoc
, mMetaData
, showControls
, graphId
} <- Stores.useStore GraphStore.context
} <- GraphStore.use
session <- useSession
showSidebar' <- R2.useLive' showSidebar
showDoc' <- R2.useLive' showDoc
......@@ -103,6 +104,12 @@ layoutCpt = R.memo' $ here.component "explorerWriteGraph" cpt where
-- T.write_ Graph.Init controls.graphStage
-- T.write_ Types.InitialClosed controls.sidePanelState
-- | Computed
-- |
let
closeDoc :: Unit -> Effect Unit
closeDoc _ = T.write_ Nothing showDoc
-- | Render
-- |
......@@ -128,12 +135,19 @@ layoutCpt = R.memo' $ here.component "explorerWriteGraph" cpt where
-- Doc focus
R2.fromMaybe_ showDoc' \(graphSideDoc :: GraphSideDoc) ->
docFocus
{ session
, graphSideDoc
}
H.div
{ className: "graph-layout__focus" }
[
H.div
{ className: "graph-layout__focus__inner" }
[
docFocus
{ session
, graphSideDoc
, closeCallback: closeDoc
}
]
]
,
-- Sidebar
H.div
......@@ -155,8 +169,7 @@ layoutCpt = R.memo' $ here.component "explorerWriteGraph" cpt where
Just metaData ->
GES.sidebar
{ boxes
, frontends: defaultFrontends
{ frontends: defaultFrontends
, metaData
, session
}
......@@ -173,7 +186,7 @@ layoutCpt = R.memo' $ here.component "explorerWriteGraph" cpt where
}
[
Controls.controls
{ reloadForest: boxes.reloadForest
{ reloadForest: reloadForest
, session
, sigmaRef
}
......@@ -186,8 +199,7 @@ layoutCpt = R.memo' $ here.component "explorerWriteGraph" cpt where
}
[
graphView
{ boxes: props.boxes
, elRef: graphRef
{ elRef: graphRef
, sigmaRef
}
]
......@@ -196,8 +208,7 @@ layoutCpt = R.memo' $ here.component "explorerWriteGraph" cpt where
--------------------------------------------------------------
type GraphProps =
( boxes :: Boxes
, elRef :: R.Ref (Nullable Element)
( elRef :: R.Ref (Nullable Element)
, sigmaRef :: R.Ref Sigmax.Sigma
)
......@@ -205,8 +216,7 @@ graphView :: R2.Leaf GraphProps
graphView = R2.leaf graphViewCpt
graphViewCpt :: R.Memo GraphProps
graphViewCpt = R.memo' $ here.component "graphView" cpt where
cpt { boxes
, elRef
cpt { elRef
, sigmaRef
} _ = do
-- | States
......@@ -219,7 +229,7 @@ graphViewCpt = R.memo' $ here.component "graphView" cpt where
, showEdges
, showLouvain
, graph
} <- Stores.useStore GraphStore.context
} <- GraphStore.use
edgeConfluence' <- R2.useLive' edgeConfluence
edgeWeight' <- R2.useLive' edgeWeight
......@@ -254,8 +264,7 @@ graphViewCpt = R.memo' $ here.component "graphView" cpt where
pure $
Graph.drawGraph
{ boxes
, elRef
{ elRef
, forceAtlas2Settings: Graph.forceAtlas2Settings
, sigmaRef
, sigmaSettings: Graph.sigmaSettings
......@@ -314,10 +323,10 @@ convert (GET.GraphData r) = Tuple r.metaData $ SigmaxT.Graph {nodes, edges}
-- | See sigmajs/plugins/sigma.renderers.customShapes/shape-library.js
modeGraphType :: Types.Mode -> String
modeGraphType Types.Authors = "square"
modeGraphType Types.Institutes = "equilateral"
modeGraphType Types.Sources = "star"
modeGraphType Types.Terms = "def"
modeGraphType Types.Authors = "square"
modeGraphType Types.Institutes = "equilateral"
modeGraphType Types.Sources = "star"
modeGraphType Types.Terms = "def"
--------------------------------------------------------------
......
......@@ -12,7 +12,7 @@ import DOM.Simple.Types (Element)
import Data.Either (Either(..))
import Data.Maybe (Maybe(..))
import Data.Nullable (Nullable)
import Gargantext.Components.App.Data (Boxes)
import Gargantext.Components.App.Store as AppStore
import Gargantext.Components.GraphExplorer.Store as GraphStore
import Gargantext.Components.GraphExplorer.Types as GET
import Gargantext.Components.Themes (darksterTheme)
......@@ -22,7 +22,6 @@ import Gargantext.Hooks.Sigmax.Sigma as Sigma
import Gargantext.Hooks.Sigmax.Types as SigmaxTypes
import Gargantext.Utils (getter)
import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.Stores as Stores
import Reactix as R
import Record (merge)
import Toestand as T
......@@ -31,8 +30,7 @@ here :: R2.Here
here = R2.here "Gargantext.Components.Graph"
type Props sigma forceatlas2 =
( boxes :: Boxes
, elRef :: R.Ref (Nullable Element)
( elRef :: R.Ref (Nullable Element)
, forceAtlas2Settings :: forceatlas2
, sigmaRef :: R.Ref Sigmax.Sigma
, sigmaSettings :: sigma
......@@ -48,11 +46,12 @@ drawGraphCpt = R.memo' $ here.component "graph" cpt where
-- |
cpt { elRef
, sigmaRef
, boxes
, forceAtlas2Settings: fa2
, transformedGraph
} _ = do
boxes <- AppStore.use
{ showEdges
, graphStage
, graph
......@@ -60,7 +59,7 @@ drawGraphCpt = R.memo' $ here.component "graph" cpt where
, selectedNodeIds
, multiSelectEnabled
, hyperdataGraph
} <- Stores.useStore GraphStore.context
} <- GraphStore.use
showEdges' <- R2.useLive' showEdges
graphStage' <- R2.useLive' graphStage
......
module Gargantext.Components.GraphExplorer.Sidebar.ContactList
( contactListWrapper
) where
import Gargantext.Prelude
import Data.Array (concat, head)
import Data.Foldable (intercalate)
import Data.Map as Map
import Data.Maybe (Maybe(..))
import Data.Sequence as Seq
import Data.Set as Set
import Data.Tuple.Nested ((/\))
import Gargantext.Components.Bootstrap as B
import Gargantext.Components.FacetsTable (ContactsView(..), Rows(..), initialPagePath, loadPage)
import Gargantext.Components.GraphExplorer.Store as GraphStore
import Gargantext.Components.GraphExplorer.Types (CorpusId, ListId)
import Gargantext.Components.GraphExplorer.Types as GET
import Gargantext.Components.RandomText (words)
import Gargantext.Components.Search (HyperdataRowContact(..), SearchQuery(..), SearchType(..))
import Gargantext.Config (defaultFrontends)
import Gargantext.Config.REST (RESTError(..))
import Gargantext.Ends (Frontends, url)
import Gargantext.Hooks.Loader (useLoaderEffect)
import Gargantext.Hooks.Session (useSession)
import Gargantext.Hooks.Sigmax.Types as SigmaxT
import Gargantext.Hooks.UpdateEffect (useUpdateEffect1')
import Gargantext.Routes as Routes
import Gargantext.Sessions (Session, sessionId)
import Gargantext.Utils (nbsp)
import Gargantext.Utils.Reactix as R2
import Reactix as R
import Reactix.DOM.HTML as H
import Toestand as T
here :: R2.Here
here = R2.here "Gargantext.Components.GraphExplorer.Sidebar.ContactList"
type Props =
( metaData :: GET.MetaData
)
contactListWrapper :: R2.Leaf Props
contactListWrapper = R2.leaf contactListWrapperCpt
contactListWrapperCpt :: R.Component Props
contactListWrapperCpt = here.component "wrapper" cpt where
cpt { metaData: GET.MetaData metaData
} _ = do
-- | States
-- |
session <- useSession
{ graph
, selectedNodeIds
} <- GraphStore.use
graph' <- R2.useLive' graph
selectedNodeIds' <- R2.useLive' selectedNodeIds
query' /\ query <- R2.useBox' Nothing
-- | Helpers
-- |
let
frontends = defaultFrontends
nodesMap = SigmaxT.nodesGraphMap graph'
toSearchQuery ids = SearchQuery
{ expected: SearchContact
, query: concat $ toQuery <$> Set.toUnfoldable ids
}
toQuery id = case Map.lookup id nodesMap of
Nothing -> []
Just n -> words n.label
-- | Hooks
-- |
R.useEffect1' selectedNodeIds' $
T.write_ (selectedNodeIds' # toSearchQuery >>> Just) query
-- | Render
-- |
pure $
R.fragment
[
case (head metaData.corpusId) /\ query' of
(Just corpusId) /\ (Just q') ->
contactList
{ frontends
, query: q'
, session
, corpusId
, listId: metaData.list.listId
}
_ /\ _ ->
B.caveat
{}
[
H.text "You can link an annuaire to retrieve relative contacts about your selection"
]
]
-------------------------------------------------------------------
type ListProps =
( query :: SearchQuery
, corpusId :: CorpusId
, listId :: ListId
, frontends :: Frontends
, session :: Session
)
contactList :: R2.Leaf ListProps
contactList = R2.leaf contactListCpt
contactListCpt :: R.Component ListProps
contactListCpt = here.component "main" cpt where
-- | Helpers
-- |
errorHandler err = do
here.warn2 "[pageLayout] RESTError" err
case err of
ReadJSONError err' ->
here.warn2 "[pageLayout] ReadJSONError" $ show err'
_ -> pure unit
-- | Component
-- |
cpt { frontends
, query
, session
, corpusId: nodeId
, listId
} _ = do
-- | States
-- |
path' /\ path
<- R2.useBox' $ initialPagePath { nodeId, listId, query, session }
state' /\ state <-
R2.useBox' Nothing
rows' /\ rows <-
R2.useBox' Nothing
-- | Hooks
-- |
useLoaderEffect
{ errorHandler
, state
, loader: loadPage
, path: path'
}
-- | Effects
-- |
-- (on query change, reload fetched docs)
useUpdateEffect1' query $
flip T.write_ path $ initialPagePath { nodeId, listId, query, session }
-- (on fetch success, extract existing docs)
useUpdateEffect1' state' case state' of
Nothing -> T.write_ (Just Seq.empty) rows
Just r -> case r of
Contacts { contacts } -> T.write_ (Just contacts) rows
_ -> T.write_ (Just Seq.empty) rows
-- | Render
-- |
pure $
R2.fromMaybe_ rows' \results ->
R.fragment
[
R2.if' (results == Seq.empty) $
B.caveat
{}
[
H.text "No contact found in your corpus for your selected terms"
]
,
R2.if' (not $ eq results Seq.empty) $
H.ul
{ className: intercalate " "
[ "graph-contact-list"
, "list-group"
]
} $
Seq.toUnfoldable $ flip Seq.map results \r ->
item
{ frontends
, session
, contactView: (r :: ContactsView)
}
]
---------------------------------------------------------
type ItemProps =
( contactView :: ContactsView
, frontends :: Frontends
, session :: Session
)
item :: R2.Leaf ItemProps
item = R2.leaf itemCpt
itemCpt :: R.Component ItemProps
itemCpt = here.component "item" cpt where
cpt { contactView: ContactsView
{ id
, annuaireId
, hyperdata: HyperdataRowContact
{ firstname
, lastname
, labs
}
}
, frontends
, session
} _ = do
-- Computed
let
-- Creating a href link
contactUrl id'
= url frontends $ Routes.ContactPage (sessionId session) annuaireId id'
-- Render
pure $
H.div
{ className: intercalate " "
[ "graph-contact-list__item"
, "list-group-item"
]
}
[
H.a
{ className: "graph-contact-list__item__title"
, target: "_blank"
, href: contactUrl id
}
[
H.text $ firstname
,
H.text $ nbsp 1
,
H.text $ lastname
]
,
B.div'
{ className: "graph-contact-list__item__subtitle" }
labs
]
module Gargantext.Components.GraphExplorer.Sidebar.DocList
( docList
( docListWrapper
) where
import Gargantext.Prelude
import Data.Array (concat, head)
import Data.Foldable (intercalate)
import Data.Map as Map
import Data.Maybe (Maybe(..))
import Data.Sequence as Seq
import Data.Set as Set
import Data.Tuple.Nested ((/\))
import Effect (Effect)
import Gargantext.Components.Bootstrap as B
import Gargantext.Components.Bootstrap.Types (Variant(..))
import Gargantext.Components.FacetsTable (DocumentsView(..), PagePath, Rows(..), initialPagePath, loadPage, publicationDate)
import Gargantext.Components.GraphExplorer.Types (GraphSideCorpus(..), GraphSideDoc(..), DocId)
import Gargantext.Components.Search (SearchQuery)
import Gargantext.Components.FacetsTable (DocumentsView(..), Rows(..), initialPagePath, loadPage, publicationDate)
import Gargantext.Components.GraphExplorer.Store as GraphStore
import Gargantext.Components.GraphExplorer.Types (CorpusId, DocId, GraphSideDoc(..), ListId)
import Gargantext.Components.GraphExplorer.Types as GET
import Gargantext.Components.RandomText (words)
import Gargantext.Components.Search (SearchQuery(..), SearchType(..))
import Gargantext.Config.REST (RESTError(..))
import Gargantext.Ends (Frontends)
import Gargantext.Hooks.Loader (useLoaderEffect)
import Gargantext.Hooks.Session (useSession)
import Gargantext.Hooks.Sigmax.Types as SigmaxT
import Gargantext.Hooks.UpdateEffect (useUpdateEffect1')
import Gargantext.Sessions (Session)
import Gargantext.Utils ((?))
......@@ -28,18 +35,90 @@ import Toestand as T
here :: R2.Here
here = R2.here "Gargantext.Components.GraphExplorer.Sidebar.DocList"
type TabsProps =
( frontends :: Frontends
, query :: SearchQuery
type Props =
( metaData :: GET.MetaData
)
docListWrapper :: R2.Leaf Props
docListWrapper = R2.leaf docListWrapperCpt
docListWrapperCpt :: R.Component Props
docListWrapperCpt = here.component "wrapper" cpt where
cpt { metaData: GET.MetaData metaData
} _ = do
-- | States
-- |
session <- useSession
{ showDoc
, graph
, selectedNodeIds
} <- GraphStore.use
graph' <- R2.useLive' graph
selectedNodeIds' <- R2.useLive' selectedNodeIds
query' /\ query <- R2.useBox' Nothing
-- | Helpers
-- |
let
nodesMap = SigmaxT.nodesGraphMap graph'
toSearchQuery ids = SearchQuery
{ expected: SearchDoc
, query: concat $ toQuery <$> Set.toUnfoldable ids
}
toQuery id = case Map.lookup id nodesMap of
Nothing -> []
Just n -> words n.label
-- | Hooks
-- |
R.useEffect1' selectedNodeIds' $
T.write_ (selectedNodeIds' # toSearchQuery >>> Just) query
-- | Render
-- |
pure $
R.fragment
[
case (head metaData.corpusId) /\ query' of
(Just corpusId) /\ (Just q') ->
docList
{ query: q'
, session
, corpusId
, listId: metaData.list.listId
, showDoc
}
_ /\ _ ->
B.caveat
{}
[
H.text "You can link a corpus to retrieve relative documents about your selection"
]
]
-------------------------------------------------------------------
type ListProps =
( query :: SearchQuery
, corpusId :: CorpusId
, listId :: ListId
, session :: Session
, graphSideCorpus :: GraphSideCorpus
, showDoc :: T.Box (Maybe GraphSideDoc)
)
docList :: R2.Leaf TabsProps
docList :: R2.Leaf ListProps
docList = R2.leaf docListCpt
docListCpt :: R.Component TabsProps
docListCpt :: R.Component ListProps
docListCpt = here.component "main" cpt where
-- | Helpers
-- |
......@@ -51,13 +130,10 @@ docListCpt = here.component "main" cpt where
_ -> pure unit
-- | Component
-- |
cpt { frontends
, query
cpt { query
, session
, graphSideCorpus: GraphSideCorpus
{ corpusId: nodeId
, listId
}
, corpusId: nodeId
, listId
, showDoc
} _ = do
-- | States
......@@ -146,7 +222,7 @@ docListCpt = here.component "main" cpt where
B.caveat
{}
[
H.text "No docs found in your corpus for your selected terms"
H.text "No document found in your corpus for your selected terms"
]
,
R2.if' (not $ eq results Seq.empty) $
......@@ -160,10 +236,7 @@ docListCpt = here.component "main" cpt where
Seq.toUnfoldable $ flip Seq.map results \r ->
item
{ frontends
, path: path'
, session
, documentView: (r :: DocumentsView)
{ documentView: (r :: DocumentsView)
, callback: callback showDoc'
, isSelected: isSelected showDoc' (r :: DocumentsView)
}
......@@ -174,9 +247,6 @@ docListCpt = here.component "main" cpt where
type ItemProps =
( documentView :: DocumentsView
, frontends :: Frontends
, session :: Session
, path :: PagePath
, callback :: DocId -> Effect Unit
, isSelected :: Boolean
)
......@@ -189,9 +259,6 @@ itemCpt = here.component "item" cpt where
cpt { documentView: dv@(DocumentsView { id, title, source })
, callback
, isSelected
-- , frontends
-- , path
-- , session
} _ = do
-- Computed
-- let
......@@ -199,13 +266,13 @@ itemCpt = here.component "item" cpt where
-- documentUrl id' { listId, nodeId } =
-- url frontends $ Routes.CorpusDocument (sessionId session) nodeId listId id'
-- Render
pure $
H.div
{ className: intercalate " "
[ "graph-doc-list__item"
, isSelected ? "graph-doc-list__item--selected" $ ""
, "list-group-item"
]
, on: { click: \_ -> callback id }
......
......@@ -5,7 +5,7 @@ module Gargantext.Components.GraphExplorer.Sidebar
import Gargantext.Prelude
import Control.Parallel (parTraverse)
import Data.Array (concat, head, last, mapWithIndex)
import Data.Array (last, mapWithIndex)
import Data.Array as A
import Data.Either (Either(..))
import Data.Foldable (intercalate)
......@@ -19,17 +19,16 @@ import Data.Tuple.Nested ((/\))
import Effect (Effect)
import Effect.Aff (launchAff_)
import Effect.Class (liftEffect)
import Gargantext.Components.App.Data (Boxes)
import Gargantext.Components.App.Store as AppStore
import Gargantext.Components.Bootstrap as B
import Gargantext.Components.Bootstrap.Types (ButtonVariant(..), Variant(..))
import Gargantext.Components.GraphExplorer.Sidebar.DocList (docList)
import Gargantext.Components.GraphExplorer.Sidebar.ContactList (contactListWrapper)
import Gargantext.Components.GraphExplorer.Sidebar.DocList (docListWrapper)
import Gargantext.Components.GraphExplorer.Sidebar.Legend as Legend
import Gargantext.Components.GraphExplorer.Store as GraphStore
import Gargantext.Components.GraphExplorer.Types as GET
import Gargantext.Components.Lang (Lang(..))
import Gargantext.Components.NgramsTable.Core as NTC
import Gargantext.Components.RandomText (words)
import Gargantext.Components.Search (SearchType(..), SearchQuery(..))
import Gargantext.Config.REST (AffRESTError)
import Gargantext.Data.Array (mapMaybe)
import Gargantext.Ends (Frontends)
......@@ -38,7 +37,6 @@ import Gargantext.Sessions (Session)
import Gargantext.Types (CTabNgramType, FrontendError(..), NodeID, TabSubType(..), TabType(..), TermList(..), modeTabType)
import Gargantext.Utils (nbsp)
import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.Stores as Stores
import Gargantext.Utils.Toestand as T2
import Math as Math
import Partial.Unsafe (unsafePartial)
......@@ -51,8 +49,7 @@ here :: R2.Here
here = R2.here "Gargantext.Components.GraphExplorer.Sidebar"
type Props =
( boxes :: Boxes
, metaData :: GET.MetaData
( metaData :: GET.MetaData
, session :: Session
, frontends :: Frontends
)
......@@ -65,7 +62,7 @@ sidebarCpt = here.component "sidebar" cpt where
cpt props _ = do
-- States
{ sideTab
} <- Stores.useStore GraphStore.context
} <- GraphStore.use
sideTab' <- R2.useLive' sideTab
......@@ -128,7 +125,7 @@ sideTabDataCpt = here.component "sideTabData" cpt where
-- States
{ selectedNodeIds
, graph
} <- Stores.useStore GraphStore.context
} <- GraphStore.use
selectedNodeIds' <- R2.useLive' selectedNodeIds
graph' <- R2.useLive' graph
......@@ -171,12 +168,7 @@ sideTabDataCpt = here.component "sideTabData" cpt where
sideBarTabSeparator
,
docListWrapper
{ frontends: props.frontends
, metaData: props.metaData
, nodesMap: SigmaxT.nodesGraphMap graph'
, searchType: SearchDoc
, selectedNodeIds: selectedNodeIds'
, session: props.session
{ metaData: props.metaData
}
]
]
......@@ -188,11 +180,11 @@ sideTabCommunity = R2.leaf sideTabCommunityCpt
sideTabCommunityCpt :: R.Component Props
sideTabCommunityCpt = here.component "sideTabCommunity" cpt where
cpt props@{ frontends } _ = do
cpt props _ = do
-- States
{ selectedNodeIds
, graph
} <- Stores.useStore GraphStore.context
} <- GraphStore.use
selectedNodeIds' <- R2.useLive' selectedNodeIds
graph' <- R2.useLive' graph
......@@ -234,13 +226,8 @@ sideTabCommunityCpt = here.component "sideTabCommunity" cpt where
,
sideBarTabSeparator
,
docListWrapper
{ frontends
, metaData: props.metaData
, nodesMap: SigmaxT.nodesGraphMap graph'
, searchType: SearchContact
, selectedNodeIds: selectedNodeIds'
, session: props.session
contactListWrapper
{ metaData: props.metaData
}
]
]
......@@ -274,7 +261,7 @@ selectedNodesCpt = here.component "selectedNodes" cpt where
-- States
{ selectedNodeIds
, graph
} <- Stores.useStore GraphStore.context
} <- GraphStore.use
selectedNodeIds' <- R2.useLive' selectedNodeIds
graph' <- R2.useLive' graph
......@@ -353,7 +340,7 @@ neighborhoodCpt = R.memo' $ here.component "neighborhood" cpt where
-- States
{ selectedNodeIds
, graph
} <- Stores.useStore GraphStore.context
} <- GraphStore.use
selectedNodeIds' <-
R2.useLive' selectedNodeIds
......@@ -482,21 +469,21 @@ updateTermButton = R2.component updateTermButtonCpt
updateTermButtonCpt :: R.Component UpdateTermButtonProps
updateTermButtonCpt = here.component "updateTermButton" cpt where
cpt { boxes:
{ errors
, reloadForest
}
, variant
cpt { variant
, metaData
, nodesMap
, rType
, session
} children = do
-- States
{ errors
, reloadForest
} <- AppStore.use
{ removedNodeIds
, selectedNodeIds
, graphId
} <- Stores.useStore GraphStore.context
} <- GraphStore.use
selectedNodeIds' <- R2.useLive' selectedNodeIds
graphId' <- R2.useLive' graphId
......@@ -612,80 +599,6 @@ sendPatch termList session (GET.MetaData metaData) node = do
patch_list :: NTC.Replace TermList
patch_list = NTC.Replace { new: termList, old: MapTerm }
---------------------------------------------------------
type DocListWrapper =
( frontends :: Frontends
, metaData :: GET.MetaData
, nodesMap :: SigmaxT.NodesMap
, searchType :: SearchType
, selectedNodeIds :: SigmaxT.NodeIds
, session :: Session
)
docListWrapper :: R2.Leaf DocListWrapper
docListWrapper = R2.leaf docListWrapperCpt
docListWrapperCpt :: R.Component DocListWrapper
docListWrapperCpt = here.component "docListWrapper" cpt where
cpt { frontends
, metaData: GET.MetaData metaData
, nodesMap
, searchType
, selectedNodeIds
, session
} _ = do
-- States
{ showDoc
} <- Stores.useStore GraphStore.context
query /\ queryBox <- R2.useBox' Nothing
-- Helpers
let
toSearchQuery ids = SearchQuery
{ expected: searchType
, query: concat $ toQuery <$> Set.toUnfoldable ids
}
toQuery id = case Map.lookup id nodesMap of
Nothing -> []
Just n -> words n.label
toGraphSideCorpus corpusId = GET.GraphSideCorpus
{ corpusId
, corpusLabel: metaData.title
, listId : metaData.list.listId
}
-- Hooks
R.useEffect1' selectedNodeIds $
T.write_ (selectedNodeIds # toSearchQuery >>> Just) queryBox
-- Render
pure $
R.fragment
[
case (head metaData.corpusId) /\ query of
(Just corpusId) /\ (Just query') ->
docList
{ frontends
, query: query'
, session
, graphSideCorpus: toGraphSideCorpus corpusId
, showDoc
}
_ /\ _ ->
B.caveat
{}
[
H.text "You can link a corpus to your Graph to retrieve relative documents when selecting nodes"
]
]
------------------------------------------------------------------------
......
......@@ -4,6 +4,7 @@ module Gargantext.Components.GraphExplorer.Store
, options
, context
, provide
, use
) where
import Gargantext.Prelude
......@@ -120,3 +121,6 @@ context = R.createContext $ unsafeCoerce unit
provide :: Record State -> Array R.Element -> R.Element
provide values = Stores.provideStore here.name values context
use :: R.Hooks (Record Store)
use = Stores.useStore context
......@@ -24,7 +24,6 @@ import Gargantext.Sessions (Session)
import Gargantext.Types as GT
import Gargantext.Utils.Range as Range
import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.Stores as Stores
import Gargantext.Utils.Toestand as T2
import Reactix as R
import Reactix.DOM.HTML as H
......@@ -66,7 +65,7 @@ controlsCpt = R.memo' $ here.component "controls" cpt where
, sideTab
, mouseSelectorSize
, labelSize
} <- Stores.useStore GraphStore.context
} <- GraphStore.use
forceAtlasState' <- R2.useLive' forceAtlasState
graph' <- R2.useLive' graph
......
......@@ -9,7 +9,6 @@ import Gargantext.Components.GraphExplorer.Topbar.Search (nodeSearchControl)
import Gargantext.Types as GT
import Gargantext.Utils ((?))
import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.Stores as Stores
import Reactix as R
import Reactix.DOM.HTML as H
import Toestand as T
......@@ -29,7 +28,7 @@ component = here.component "topBar" cpt where
, selectedNodeIds
, showControls
, showSidebar
} <- Stores.useStore GraphStore.context
} <- GraphStore.use
graph' <- R2.useLive' graph
showControls' <- R2.useLive' showControls
......
......@@ -25,7 +25,7 @@ import Data.Tuple (Tuple(..))
import Data.Tuple.Nested ((/\))
import Effect (Effect)
import Effect.Aff (Aff)
import Gargantext.Components.App.Data (Boxes)
import Gargantext.Components.App.Store (Boxes)
import Gargantext.Components.NgramsTable.Components as NTC
import Gargantext.Components.NgramsTable.Core (Action(..), CoreAction(..), CoreState, Dispatch, NgramsElement(..), NgramsPatch(..), NgramsTable, NgramsTerm, PageParams, PatchMap(..), Versioned(..), VersionedNgramsTable, VersionedWithCountNgramsTable, _NgramsElement, _NgramsRepoElement, _NgramsTable, _children, _list, _ngrams, _ngrams_repo_elements, _ngrams_scores, _occurrences, _root, addNewNgramA, applyNgramsPatches, applyPatchSet, chartsAfterSync, commitPatch, convOrderBy, coreDispatch, filterTermSize, fromNgramsPatches, ngramsRepoElementToNgramsElement, ngramsTermText, normNgram, patchSetFromMap, replace, setTermListA, singletonNgramsTablePatch, syncResetButtons, toVersioned)
import Gargantext.Components.NgramsTable.Loader (useLoaderWithCacheAPI)
......
......@@ -8,7 +8,7 @@ import Data.Maybe (Maybe(..))
import Data.Show.Generic (genericShow)
import Data.Tuple.Nested ((/\))
import Effect.Aff (Aff)
import Gargantext.Components.App.Data (Boxes)
import Gargantext.Components.App.Store (Boxes)
import Gargantext.Components.DocsTable as DT
import Gargantext.Components.DocsTable.Types (Year)
import Gargantext.Components.GraphQL.User (UserInfo)
......
......@@ -11,7 +11,7 @@ import Data.Maybe (Maybe(..), fromMaybe)
import Effect (Effect)
import Effect.Aff (launchAff_)
import Effect.Class (liftEffect)
import Gargantext.Components.App.Data (Boxes)
import Gargantext.Components.App.Store (Boxes)
import Gargantext.Components.GraphQL.User (UserInfo)
import Gargantext.Components.Nodes.Annuaire.Tabs as Tabs
import Gargantext.Components.Nodes.Annuaire.User.Contact (getUserInfoWithReload, saveUserInfo, contactInfos)
......
......@@ -13,7 +13,7 @@ import Data.Maybe (Maybe(..), fromMaybe)
import Effect (Effect)
import Effect.Aff (launchAff_)
import Effect.Class (liftEffect)
import Gargantext.Components.App.Data (Boxes)
import Gargantext.Components.App.Store (Boxes)
import Gargantext.Components.GraphQL (getClient)
import Gargantext.Components.GraphQL.Endpoints (getUserInfo)
import Gargantext.Components.GraphQL.User (UserInfo, _ui_cwCity, _ui_cwCountry, _ui_cwFirstName, _ui_cwLabTeamDeptsFirst, _ui_cwLastName, _ui_cwOffice, _ui_cwOrganizationFirst, _ui_cwRole, _ui_cwTouchMail, _ui_cwTouchPhone)
......
......@@ -7,7 +7,7 @@ import Data.Generic.Rep (class Generic)
import Data.Maybe (Maybe(..))
import Data.Show.Generic (genericShow)
import Data.Tuple.Nested ((/\))
import Gargantext.Components.App.Data (Boxes)
import Gargantext.Components.App.Store (Boxes)
import Gargantext.Components.DocsTable as DT
import Gargantext.Components.DocsTable.Types (Year)
import Gargantext.Components.NgramsTable as NT
......
......@@ -10,7 +10,7 @@ import Data.Show.Generic (genericShow)
import Effect (Effect)
import Effect.Aff (throwError)
import Effect.Exception (error)
import Gargantext.Components.App.Data (Boxes)
import Gargantext.Components.App.Store (Boxes)
import Gargantext.Components.CodeEditor as CE
import Gargantext.Components.FolderView as FV
import Gargantext.Components.InputWithEnter (inputWithEnter)
......
......@@ -7,7 +7,7 @@ import Data.Maybe (Maybe(..), fromMaybe)
import Data.Ord.Generic (genericCompare)
import Data.Show.Generic (genericShow)
import Effect (Effect)
import Gargantext.Components.App.Data (Boxes)
import Gargantext.Components.App.Store (Boxes)
import Gargantext.Components.Charts.Options.Type (EChartsInstance, MouseEvent)
import Gargantext.Components.Nodes.Corpus.Chart.Histo (histo)
import Gargantext.Components.Nodes.Corpus.Chart.Metrics (metrics)
......
......@@ -3,7 +3,7 @@ module Gargantext.Components.Nodes.Corpus.Chart.Types where
import Data.Maybe (Maybe)
import Data.Tuple (Tuple)
import Effect (Effect)
import Gargantext.Components.App.Data (Boxes)
import Gargantext.Components.App.Store (Boxes)
import Gargantext.Components.Charts.Options.Type (EChartsInstance, MouseEvent)
import Gargantext.Prelude (Unit)
import Gargantext.Sessions (Session)
......
......@@ -6,7 +6,7 @@ import Data.Maybe (Maybe(..))
import Effect (Effect)
import Effect.Aff (launchAff_)
import Effect.Class (liftEffect)
import Gargantext.Components.App.Data (Boxes)
import Gargantext.Components.App.Store (Boxes)
import Gargantext.Components.Node (NodePoly(..))
import Gargantext.Components.Nodes.Corpus (fieldsCodeEditor, loadCorpusWithReload, saveCorpus)
import Gargantext.Components.Nodes.Corpus.Types (Hyperdata(..))
......
......@@ -7,7 +7,7 @@ import Data.Maybe (Maybe(..), fromMaybe)
import Effect (Effect)
import Effect.Aff (launchAff_)
import Effect.Class (liftEffect)
import Gargantext.Components.App.Data (Boxes)
import Gargantext.Components.App.Store (Boxes)
import Gargantext.Components.Nodes.Corpus (fieldsCodeEditor)
import Gargantext.Components.Nodes.Corpus.Chart.Predefined as P
import Gargantext.Components.Nodes.Dashboard.Types as DT
......
......@@ -7,23 +7,22 @@ import Gargantext.Prelude
import DOM.Simple (document, querySelector)
import Data.Maybe (Maybe(..), isJust)
import Data.Tuple.Nested ((/\))
import Gargantext.Components.App.Data (Boxes)
import Gargantext.Components.Bootstrap as B
import Gargantext.Components.PhyloExplorer.API (get)
import Gargantext.Components.PhyloExplorer.Layout (layout)
import Gargantext.Components.PhyloExplorer.Store as PhyloStore
import Gargantext.Components.PhyloExplorer.Types (PhyloDataSet)
import Gargantext.Config.REST (logRESTError)
import Gargantext.Hooks.Loader (useLoaderEffect)
import Gargantext.Sessions (Session)
import Gargantext.Hooks.Session (useSession)
import Gargantext.Types (NodeID)
import Gargantext.Utils.Reactix as R2
import Reactix as R
import Reactix.DOM.HTML as H
import Record as Record
type MainProps =
( nodeId :: NodeID
, session :: Session
, boxes :: Boxes
)
here :: R2.Here
......@@ -34,14 +33,13 @@ phyloLayout = R2.leaf phyloLayoutCpt
phyloLayoutCpt :: R.Component MainProps
phyloLayoutCpt = here.component "main" cpt where
cpt { nodeId, session } _ = do
cpt { nodeId } _ = do
-- | States
-- |
session <- useSession
state' /\ state <- R2.useBox' Nothing
-- | Computed
-- |
let
......@@ -49,8 +47,8 @@ phyloLayoutCpt = here.component "main" cpt where
errorHandler = logRESTError here "[phylo]"
handler (phyloDataSet :: PhyloDataSet) =
layout
{ nodeId
hydrateStore
{ phyloId: nodeId
, phyloDataSet
}
......@@ -65,6 +63,7 @@ phyloLayoutCpt = here.component "main" cpt where
, state
}
-- @XXX: Runtime odd behavior
-- cannot use the `useEffect` + its cleanup function within the
-- same `Effect`, otherwise the below cleanup example will be
......@@ -126,3 +125,40 @@ phyloLayoutCpt = here.component "main" cpt where
, defaultSlot:
R2.fromMaybe_ state' handler
}
--------------------------------------------------------
type HydrateStoreProps =
( phyloDataSet :: PhyloDataSet
, phyloId :: NodeID
)
hydrateStore :: R2.Leaf HydrateStoreProps
hydrateStore = R2.leaf hydrateStoreCpt
hydrateStoreCpt :: R.Component HydrateStoreProps
hydrateStoreCpt = here.component "layout" cpt where
cpt { phyloDataSet
, phyloId
} _ = do
-- | Computed
-- |
let
state :: Record PhyloStore.State
state =
-- Data
{ phyloDataSet
, phyloId
-- (default options)
} `Record.merge` PhyloStore.options
-- | Render
-- |
pure $
PhyloStore.provide
state
[
layout
{}
]
......@@ -10,7 +10,7 @@ import Data.Maybe (Maybe(..), isJust, maybe)
import Data.Sequence as Seq
import Data.Tuple (Tuple(..))
import Data.Tuple.Nested ((/\))
import Gargantext.Components.App.Data (Boxes)
import Gargantext.Components.App.Store as AppStore
import Gargantext.Components.Bootstrap as B
import Gargantext.Components.GraphExplorer.API as GraphAPI
import Gargantext.Components.GraphExplorer.Layout (convert, layout)
......@@ -18,9 +18,9 @@ import Gargantext.Components.GraphExplorer.Store as GraphStore
import Gargantext.Components.GraphExplorer.Types as GET
import Gargantext.Config.REST (logRESTError)
import Gargantext.Hooks.Loader (useLoaderEffect)
import Gargantext.Hooks.Session (useSession)
import Gargantext.Hooks.Sigmax as Sigmax
import Gargantext.Hooks.Sigmax.Types as SigmaxT
import Gargantext.Sessions (Session)
import Gargantext.Utils.Range as Range
import Gargantext.Utils.Reactix as R2
import Reactix as R
......@@ -29,27 +29,28 @@ import Record as Record
type Props =
( key :: String
, session :: Session
, boxes :: Boxes
, graphId :: GET.GraphId
( graphId :: GET.GraphId
)
here :: R2.Here
here = R2.here "Gargantext.Components.Nodes.Corpus.Graph"
graphLayout :: R2.Leaf Props
graphLayout :: R2.Leaf ( key :: String | Props )
graphLayout = R2.leaf graphLayoutCpt
graphLayoutCpt :: R.Component Props
graphLayoutCpt :: R.Component ( key :: String | Props )
graphLayoutCpt = here.component "explorerLayout" cpt where
cpt props@{ boxes: { graphVersion }, graphId, session } _ = do
cpt { graphId } _ = do
-- | States
-- |
{ graphVersion
} <- AppStore.use
session <- useSession
graphVersion' <- R2.useLive' graphVersion
state' /\ state <- R2.useBox' Nothing
-- | Hooks
-- |
useLoaderEffect
......@@ -118,37 +119,32 @@ graphLayoutCpt = here.component "explorerLayout" cpt where
where
errorHandler = logRESTError here "[explorerLayout]"
handler loaded@(GET.HyperdataGraph { graph: hyperdataGraph }) =
initGraph { graph
, hyperdataGraph: loaded
, mMetaData
, session
, boxes: props.boxes
, graphId
}
hydrateStore
{ graph
, hyperdataGraph: loaded
, mMetaData
, graphId
}
where
Tuple mMetaData graph = convert hyperdataGraph
--------------------------------------------------------
type InitGraphProps =
type HydrateStoreProps =
( mMetaData :: Maybe GET.MetaData
, graph :: SigmaxT.SGraph
, hyperdataGraph :: GET.HyperdataGraph
, session :: Session
, boxes :: Boxes
, graphId :: GET.GraphId
)
initGraph :: R2.Leaf InitGraphProps
initGraph = R2.leaf initGraphCpt
hydrateStore:: R2.Leaf HydrateStoreProps
hydrateStore = R2.leaf hydrateStoreCpt
initGraphCpt :: R.Component InitGraphProps
initGraphCpt = here.component "initGraph" cpt where
cpt { boxes
, mMetaData
hydrateStoreCpt :: R.Component HydrateStoreProps
hydrateStoreCpt = here.component "hydrateStore" cpt where
cpt { mMetaData
, graph
, graphId
, session
, hyperdataGraph
} _ = do
-- | Computed
......@@ -186,15 +182,11 @@ initGraphCpt = here.component "initGraph" cpt where
-- | Render
-- |
pure $
GraphStore.provide
state
[
layout
{ session
, boxes
, sigmaRef
}
{ sigmaRef }
]
......@@ -5,7 +5,7 @@ import Gargantext.Prelude
import Data.Maybe (Maybe(..))
import Data.Newtype (class Newtype)
import Effect (Effect)
import Gargantext.Components.App.Data (Boxes)
import Gargantext.Components.App.Store (Boxes)
import Gargantext.Components.Data.Landing (BlockText(..), BlockTexts(..), Button(..), LandingData(..))
import Gargantext.Components.FolderView as FV
import Gargantext.Components.Lang (LandingLang(..))
......
......@@ -4,7 +4,7 @@ import Gargantext.Prelude
import Effect (Effect)
import Effect.Aff (launchAff_)
import Gargantext.Components.App.Data (Boxes)
import Gargantext.Components.App.Store (Boxes)
import Gargantext.Components.NgramsTable.Loader (clearCache)
import Gargantext.Components.Node (NodePoly(..))
import Gargantext.Components.Nodes.Corpus (loadCorpusWithChild)
......
......@@ -6,7 +6,7 @@ import Data.Array as A
import Data.Maybe (Maybe(..), fromMaybe)
import Data.Tuple.Nested ((/\))
import Effect.Class (liftEffect)
import Gargantext.Components.App.Data (Boxes)
import Gargantext.Components.App.Store (Boxes)
import Gargantext.Components.NgramsTable as NT
import Gargantext.Components.NgramsTable.Core as NTC
import Gargantext.Components.Nodes.Corpus.Chart.Metrics (metrics)
......
......@@ -7,7 +7,7 @@ import Data.Maybe (Maybe(..))
import Data.Show.Generic (genericShow)
import Data.Tuple.Nested ((/\))
import Effect.Aff (launchAff_)
import Gargantext.Components.App.Data (Boxes)
import Gargantext.Components.App.Store (Boxes)
import Gargantext.Components.Charts.Options.ECharts (dispatchAction)
import Gargantext.Components.Charts.Options.Type (EChartsInstance, EChartActionData)
import Gargantext.Components.DocsTable as DT
......@@ -108,7 +108,7 @@ textsLayoutWithKeyCpt = here.component "textsLayoutWithKey" cpt
let NodePoly { name, date, hyperdata } = corpusNode
R.fragment
[ Table.tableHeaderWithRenameLayout {
[ Table.tableHeaderWithRenameLayout {
cacheState
, name
, date
......
......@@ -4,33 +4,31 @@ module Gargantext.Components.PhyloExplorer.DetailsTab
import Gargantext.Prelude
import Gargantext.Components.PhyloExplorer.Store as PhyloStore
import Gargantext.Components.PhyloExplorer.Types (PhyloDataSet(..))
import Gargantext.Utils (nbsp)
import Gargantext.Utils.Reactix as R2
import Reactix as R
import Reactix.DOM.HTML as H
type Props =
( key :: String
here :: R2.Here
here = R2.here "Gargantext.Components.PhyloExplorer.SideBar.DetailsTab"
, docCount :: Int
, foundationCount :: Int
, periodCount :: Int
, termCount :: Int
, groupCount :: Int
, branchCount :: Int
)
detailsTab :: R2.Leaf Props
detailsTab :: R2.Leaf ( key :: String )
detailsTab = R2.leaf detailsTabCpt
componentName :: String
componentName = "Gargantext.Components.PhyloExplorer.SideBar.DetailsTab"
detailsTabCpt :: R.Component Props
detailsTabCpt = R.hooksComponent componentName cpt where
cpt props _ =
detailsTabCpt :: R.Component ( key :: String )
detailsTabCpt = here.component "" cpt where
cpt _ _ = do
-- | States
-- |
store <- PhyloStore.use
(PhyloDataSet o) <- R2.useLive' store.phyloDataSet
-- Render
-- | Render
-- |
pure $
H.div
......@@ -40,21 +38,21 @@ detailsTabCpt = R.hooksComponent componentName cpt where
H.ul
{ className: "phylo-details-tab__counter" }
[
detailsCount props.docCount "docs"
detailsCount o.nbDocs "docs"
,
detailsCount props.foundationCount "foundations"
detailsCount o.nbFoundations "foundations"
,
detailsCount props.periodCount "periods"
detailsCount o.nbPeriods "periods"
]
,
H.ul
{ className: "phylo-details-tab__counter" }
[
detailsCount props.termCount "terms"
detailsCount o.nbTerms "terms"
,
detailsCount props.groupCount "groups"
detailsCount o.nbGroups "groups"
,
detailsCount props.branchCount "branches"
detailsCount o.nbBranches "branches"
]
,
H.hr
......
module Gargantext.Components.PhyloExplorer.Sidebar.DocList
where
{-
import Gargantext.Prelude
import Control.Parallel (parTraverse)
import Data.Array (concat, head, last, mapWithIndex)
import Data.Array as A
import Data.Either (Either(..))
import Data.Foldable (intercalate)
import Data.Foldable as F
import Data.Int (fromString)
import Data.Map as Map
import Data.Maybe (Maybe(..), fromJust)
import Data.Sequence as Seq
import Data.Set as Set
import Data.Tuple.Nested ((/\))
import Effect (Effect)
import Effect.Aff (launchAff_)
import Effect.Class (liftEffect)
import Gargantext.Components.App.Store as AppStore
import Gargantext.Components.Bootstrap as B
import Gargantext.Components.Bootstrap.Types (ButtonVariant(..), Variant(..))
import Gargantext.Components.GraphExplorer.Sidebar.DocList (docList)
import Gargantext.Components.GraphExplorer.Sidebar.Legend as Legend
import Gargantext.Components.GraphExplorer.Store as GraphStore
import Gargantext.Components.GraphExplorer.Types as GET
import Gargantext.Components.Lang (Lang(..))
import Gargantext.Components.NgramsTable.Core as NTC
import Gargantext.Components.PhyloExplorer.Store as PhyloStore
import Gargantext.Components.RandomText (words)
import Gargantext.Components.Search (SearchQuery(..), SearchType(..))
import Gargantext.Config (defaultFrontends)
import Gargantext.Config.REST (AffRESTError)
import Gargantext.Data.Array (mapMaybe)
import Gargantext.Ends (Frontends)
import Gargantext.Hooks.Session (useSession)
import Gargantext.Hooks.Sigmax.Types as SigmaxT
import Gargantext.Sessions (Session)
import Gargantext.Types (CTabNgramType, FrontendError(..), NodeID, TabSubType(..), TabType(..), TermList(..), modeTabType)
import Gargantext.Utils (getter, nbsp)
import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.Toestand as T2
import Math as Math
import Partial.Unsafe (unsafePartial)
import Reactix as R
import Reactix.DOM.HTML as H
import Record as Record
import Toestand as T
here :: R2.Here
here = R2.here "Gargantext.Components.PhyloExplorer.Sidebar.DocList"
docListWrapper :: R2.Leaf ()
docListWrapper = R2.leaf docListWrapperCpt
docListWrapperCpt :: R.Memo ()
docListWrapperCpt = R.memo' $ here.component "wrapper" cpt where
cpt _ _ = do
-- | States
-- |
store <- PhyloStore.use
extractedTerms <- R2.useLive' store.extractedTerms
query' /\ query <- R2.useBox' Nothing
-- | Helpers
-- |
let
toSearchQuery ids = SearchQuery
{ expected: SearchDoc
, query: map (getter _.label) ids
}
searchQuery
= extractedTerms
# toSearchQuery
# Just
# flip T.write_ query
-- | Render
--
pure $
docList
{ searchQuery }
--------------------------------------------------------------
type ListProps =
( searchQuery :: SearchQuery
)
docList :: R2.Leaf TabsProps
docList = R2.leaf docListCpt
docListCpt :: R.Component TabsProps
docListCpt = here.component "main" cpt where
-- | Helpers
-- |
errorHandler err = do
here.warn2 "[pageLayout] RESTError" err
case err of
ReadJSONError err' ->
here.warn2 "[pageLayout] ReadJSONError" $ show err'
_ -> pure unit
-- | Component
-- |
cpt { searchQuery
} _ = do
-- | States
-- |
path' /\ path
<- R2.useBox' $ initialPagePath { nodeId, listId, query, session }
state' /\ state <-
R2.useBox' Nothing
rows' /\ rows <-
R2.useBox' Nothing
showDoc' <-
R2.useLive' showDoc
-- | Hooks
-- |
useLoaderEffect
{ errorHandler
, state
, loader: loadPage
, path: path'
}
-- | Effects
-- |
-- (on query change, reload fetched docs)
useUpdateEffect1' query $
flip T.write_ path $ initialPagePath { nodeId, listId, query, session }
-- (on fetch success, extract existing docs)
useUpdateEffect1' state' case state' of
Nothing -> T.write_ (Just Seq.empty) rows
Just r -> case r of
Docs { docs } -> T.write_ (Just docs) rows
_ -> T.write_ (Just Seq.empty) rows
-- | Computed
-- |
let
-- callback :: Maybe GraphSideDoc -> DocId -> Effect Unit
-- callback
-- Nothing
-- new
-- = setGraphSideDoc new # Just # flip T.write_ showDoc
-- callback
-- (Just (GraphSideDoc { docId }))
-- new
-- | docId == new = T.write_ Nothing showDoc
-- | otherwise = setGraphSideDoc new # Just # flip T.write_ showDoc
-- setGraphSideDoc :: DocId -> GraphSideDoc
-- setGraphSideDoc docId = GraphSideDoc
-- { docId
-- , listId
-- , corpusId: nodeId
-- }
-- isSelected :: Maybe GraphSideDoc -> DocumentsView -> Boolean
-- isSelected
-- (Just (GraphSideDoc { docId }))
-- (DocumentsView { id })
-- = docId == id
-- isSelected
-- _
-- _
-- = false
-- | Render
-- |
pure $
R2.fromMaybe_ rows' \results ->
R.fragment
[
R2.if' (results == Seq.empty) $
B.caveat
{}
[
H.text "No docs found in your corpus for your selected terms"
]
,
R2.if' (not $ eq results Seq.empty) $
H.ul
{ className: intercalate " "
[ "graph-doc-list"
, "list-group"
]
} $
Seq.toUnfoldable $ flip Seq.map results \r ->
item
{ frontends
, path: path'
, session
, documentView: (r :: DocumentsView)
, callback: callback showDoc'
, isSelected: isSelected showDoc' (r :: DocumentsView)
}
]
---------------------------------------------------------
type ItemProps =
( documentView :: DocumentsView
, frontends :: Frontends
, session :: Session
, path :: PagePath
, callback :: DocId -> Effect Unit
, isSelected :: Boolean
)
item :: R2.Leaf ItemProps
item = R2.leaf itemCpt
itemCpt :: R.Component ItemProps
itemCpt = here.component "item" cpt where
cpt { documentView: dv@(DocumentsView { id, title, source })
, callback
, isSelected
-- , frontends
-- , path
-- , session
} _ = do
-- Computed
-- let
-- Creating a href link
-- documentUrl id' { listId, nodeId } =
-- url frontends $ Routes.CorpusDocument (sessionId session) nodeId listId id'
-- Render
pure $
H.div
{ className: intercalate " "
[ "graph-doc-list__item"
, isSelected ? "graph-doc-list__item--selected" $ ""
, "list-group-item"
]
, on: { click: \_ -> callback id }
}
[
B.ripple
{ variant: Dark }
[
H.div
{ className: "graph-doc-list__item__main" }
[
B.div'
{ className: "graph-doc-list__item__title" }
title
,
B.div'
{ className: "graph-doc-list__item__source" }
source
,
B.div'
{ className: "graph-doc-list__item__date" } $
publicationDate dv
]
,
H.div
{ className: "graph-doc-list__item__aside" }
[
B.icon
{ name: "eye-slash"
, className: intercalate " "
[ "text-info"
, isSelected ? "visible" $ "hidden"
]
}
]
]
]
......@@ -12,7 +12,8 @@ import Data.Tuple.Nested ((/\))
import Effect (Effect)
import Gargantext.Components.Bootstrap as B
import Gargantext.Components.Bootstrap.Types (ButtonVariant(..), Variant(..))
import Gargantext.Components.PhyloExplorer.Types (ExtractedTerm(..), ExtractedCount(..))
import Gargantext.Components.PhyloExplorer.Store as PhyloStore
import Gargantext.Components.PhyloExplorer.Types (ExtractedCount(..), ExtractedTerm(..))
import Gargantext.Utils (nbsp, (?))
import Gargantext.Utils.Reactix as R2
import Reactix as R
......@@ -21,12 +22,6 @@ import Toestand as T
type Props =
( key :: String
, extractedTerms :: Array ExtractedTerm
, extractedCount :: Maybe ExtractedCount
, selectedTerm :: Maybe String
, selectedBranch :: Maybe String
, selectedSource :: Maybe String
, selectTermCallback :: String -> Effect Unit
)
......@@ -39,17 +34,18 @@ componentName = "Gargantext.Components.PhyloExplorer.SideBar.SelectionTab"
component :: R.Component Props
component = R.hooksComponent componentName cpt where
cpt { selectTermCallback
, extractedTerms
, extractedCount
, selectedTerm
, selectedBranch
, selectedSource
} _ = do
-- | State
-- |
store <- PhyloStore.use
-- State
--------
extractedTerms <- R2.useLive' store.extractedTerms
extractedCount <- R2.useLive' store.extractedCount
selectedTerm <- R2.useLive' store.selectedTerm
selectedBranch <- R2.useLive' store.selectedBranch
selectedSource <- R2.useLive' store.selectedSource
showMore /\ showMoreBox <- R2.useBox' false
showMore' /\ showMore <- R2.useBox' false
let
haveSelection
......@@ -63,18 +59,17 @@ component = R.hooksComponent componentName cpt where
truncateResults
= termCount > maxTruncateResult
&& not showMore
&& not showMore'
-- Effects
----------
-- | Effects
-- |
-- reset "show more" button to hidding mode on selected terms change
R.useEffect1' extractedTerms $
T.write_ false showMoreBox
-- Render
---------
T.write_ false showMore
-- | Render
-- |
pure $
H.div
......@@ -293,7 +288,7 @@ component = R.hooksComponent componentName cpt where
B.button
{ variant: ButtonVariant Light
, callback: \_ -> T.modify_ not showMoreBox
, callback: \_ -> T.modify_ not showMore
, block: true
, className: "phylo-selection-tab__selection__show-more"
}
......@@ -303,6 +298,19 @@ component = R.hooksComponent componentName cpt where
]
]
]
-- ,
-- (separator)
-- R2.if' (not null extractedTerms) $
-- H.div
-- { className: "phylo-selection-tab__separator" }
-- [
-- B.icon
-- { name: "angle-down" }
-- ]
-- ,
-- Extracted Docs
-- R2.if' (not null extractedTerms) $
]
termFontSize :: Number -> String
......@@ -321,7 +329,7 @@ detailsCount value label weighty =
H.span
{ className: intercalate " "
[ "phylo-selection-tab__counter__value"
, weighty ? "font-weight-bold" $ ""
, weighty ? "text-bold" $ ""
]
}
[
......@@ -331,7 +339,7 @@ detailsCount value label weighty =
H.span
{ className: intercalate " "
[ "phylo-selection-tab__counter__label"
, weighty ? "font-weight-bold" $ ""
, weighty ? "text-bold" $ ""
]
}
[
......
......@@ -4,35 +4,19 @@ module Gargantext.Components.PhyloExplorer.SideBar
import Gargantext.Prelude
import Data.Maybe (Maybe)
import Data.Tuple.Nested ((/\))
import Effect (Effect)
import Gargantext.Components.Bootstrap as B
import Gargantext.Components.PhyloExplorer.DetailsTab (detailsTab)
import Gargantext.Components.PhyloExplorer.SelectionTab (selectionTab)
import Gargantext.Components.PhyloExplorer.Types (ExtractedCount, ExtractedTerm, TabView(..))
import Gargantext.Types (NodeID)
import Gargantext.Components.PhyloExplorer.Store as PhyloStore
import Gargantext.Components.PhyloExplorer.Types (TabView(..))
import Gargantext.Utils.Reactix as R2
import Reactix as R
import Reactix.DOM.HTML as H
import Toestand as T
type Props =
( nodeId :: NodeID
, docCount :: Int
, foundationCount :: Int
, periodCount :: Int
, termCount :: Int
, groupCount :: Int
, branchCount :: Int
, selectedTerm :: Maybe String
, selectedBranch :: Maybe String
, selectedSource :: Maybe String
, extractedTerms :: Array ExtractedTerm
, extractedCount :: Maybe ExtractedCount
, selectTermCallback :: String -> Effect Unit
( selectTermCallback :: String -> Effect Unit
)
sideBar :: R2.Leaf Props
......@@ -44,14 +28,22 @@ componentName = "Gargantext.Components.PhyloExplorer.SideBar"
component :: R.Component Props
component = R.hooksComponent componentName cpt where
cpt props _ = do
-- States
tabView /\ tabViewBox <- R2.useBox' DetailsTab
-- | States
-- |
{ sideBarTabView
, phyloId
} <- PhyloStore.use
-- Computed
sideBarTabView' <- R2.useLive' sideBarTabView
phyloId' <- R2.useLive' phyloId
-- | Computed
-- |
let
tabList = [ DetailsTab, SelectionTab ]
-- Render
-- | Render
-- |
pure $
H.div
......@@ -59,33 +51,21 @@ component = R.hooksComponent componentName cpt where
[
-- Menu
B.tabs
{ value: tabView
{ value: sideBarTabView'
, list: tabList
, callback: flip T.write_ tabViewBox
, callback: flip T.write_ sideBarTabView
}
,
-- Content
case tabView of
case sideBarTabView' of
DetailsTab ->
detailsTab
{ key: (show props.nodeId) <> "-details"
, docCount: props.docCount
, foundationCount: props.foundationCount
, periodCount: props.periodCount
, termCount: props.termCount
, groupCount: props.groupCount
, branchCount: props.branchCount
}
{ key: (show phyloId') <> "-details" }
SelectionTab ->
selectionTab
{ key: (show props.nodeId) <> "-selection"
, extractedTerms: props.extractedTerms
, extractedCount: props.extractedCount
, selectedTerm: props.selectedTerm
, selectedBranch: props.selectedBranch
, selectedSource: props.selectedSource
{ key: (show phyloId') <> "-selection"
, selectTermCallback: props.selectTermCallback
}
]
module Gargantext.Components.PhyloExplorer.Store
( Store
, State
, options
, context
, provide
, use
) where
import Gargantext.Prelude
import Data.Maybe (Maybe(..))
import Gargantext.Components.PhyloExplorer.Types (DisplayView(..), ExtractedCount, ExtractedTerm, FrameDoc, PhyloDataSet, Source, TabView(..), Term)
import Gargantext.Types (NodeID, SidePanelState(..))
import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.Stores as Stores
import Reactix as R
import Toestand as T
import Unsafe.Coerce (unsafeCoerce)
here :: R2.Here
here = R2.here "Gargantext.Components.GraphExplorer.Store"
type Store =
-- Data
( phyloDataSet :: T.Box PhyloDataSet
, phyloId :: T.Box NodeID
, isBuilt :: T.Box Boolean
-- Layout
, toolBarDisplayed :: T.Box Boolean
, isIsolineDisplayed :: T.Box Boolean
, sideBarDisplayed :: T.Box SidePanelState
, sideBarTabView :: T.Box TabView
, frameDoc :: T.Box (Maybe FrameDoc)
-- Topbar
, source :: T.Box String
, sources :: T.Box (Array Source)
, terms :: T.Box (Array Term)
, search :: T.Box String
, result :: T.Box (Maybe Term)
-- Sidebar
, extractedTerms :: T.Box (Array ExtractedTerm)
, selectedTerm :: T.Box (Maybe String)
, selectedBranch :: T.Box (Maybe String)
, selectedSource :: T.Box (Maybe String)
, extractedCount :: T.Box (Maybe ExtractedCount)
-- Toolbar
, displayView :: T.Box DisplayView
)
type State =
-- Data
( phyloDataSet :: PhyloDataSet
, phyloId :: NodeID
, isBuilt :: Boolean
-- Layout
, toolBarDisplayed :: Boolean
, isIsolineDisplayed :: Boolean
, sideBarDisplayed :: SidePanelState
, sideBarTabView :: TabView
, frameDoc :: Maybe FrameDoc
-- Topbar
, source :: String
, sources :: Array Source
, terms :: Array Term
, search :: String
, result :: Maybe Term
-- Sidebar
, extractedTerms :: Array ExtractedTerm
, selectedTerm :: Maybe String
, selectedBranch :: Maybe String
, selectedSource :: Maybe String
, extractedCount :: Maybe ExtractedCount
-- Toolbar
, displayView :: DisplayView
)
options ::
{ isBuilt :: Boolean
-- Layout
, toolBarDisplayed :: Boolean
, isIsolineDisplayed :: Boolean
, sideBarDisplayed :: SidePanelState
, sideBarTabView :: TabView
, frameDoc :: Maybe FrameDoc
-- Topbar
, source :: String
, sources :: Array Source
, terms :: Array Term
, search :: String
, result :: Maybe Term
-- Sidebar
, extractedTerms :: Array ExtractedTerm
, selectedTerm :: Maybe String
, selectedBranch :: Maybe String
, selectedSource :: Maybe String
, extractedCount :: Maybe ExtractedCount
-- Toolbar
, displayView :: DisplayView
}
options =
-- Data
{ isBuilt : false
-- Layout
, toolBarDisplayed : false
, isIsolineDisplayed : false
, sideBarDisplayed : InitialClosed
, sideBarTabView : DetailsTab
, frameDoc : Nothing
-- Topbar
, source : ""
, sources : mempty
, terms : mempty
, search : ""
, result : Nothing
-- Sidebar
, extractedTerms : mempty
, selectedTerm : Nothing
, selectedBranch : Nothing
, selectedSource : Nothing
, extractedCount : Nothing
-- Toolbar
, displayView : HeadingMode
}
context :: R.Context (Record Store)
context = R.createContext $ unsafeCoerce unit
provide :: Record State -> Array R.Element -> R.Element
provide values = Stores.provideStore here.name values context
use :: R.Hooks (Record Store)
use = Stores.useStore context
......@@ -7,6 +7,7 @@ import Gargantext.Prelude
import Effect (Effect)
import Gargantext.Components.Bootstrap as B
import Gargantext.Components.Bootstrap.Types (ButtonVariant(..), Variant(..))
import Gargantext.Components.PhyloExplorer.Store as PhyloStore
import Gargantext.Components.PhyloExplorer.Types (DisplayView(..))
import Gargantext.Utils ((?))
import Gargantext.Utils.Reactix as R2
......@@ -16,10 +17,8 @@ import Toestand as T
type Props =
( resetViewCallback :: Unit -> Effect Unit
, displayView :: DisplayView
, changeViewCallback :: DisplayView -> Effect Unit
, exportCallback :: Unit -> Effect Unit
, isolineBox :: T.Box Boolean
, unselectCallback :: Unit -> Effect Unit
)
......@@ -32,16 +31,19 @@ toolBar = R2.leaf component
component :: R.Component Props
component = here.component "main" cpt where
cpt { resetViewCallback
, displayView
, changeViewCallback
, exportCallback
, isolineBox
, unselectCallback
} _ = do
-- States
isIsolineDisplayed <- R2.useLive' isolineBox
-- | States
{ isIsolineDisplayed
, displayView
} <- PhyloStore.use
-- Render
displayView' <- R2.useLive' displayView
isIsolineDisplayed' <- R2.useLive' isIsolineDisplayed
-- | Render
pure $
H.div
......@@ -76,7 +78,7 @@ component = here.component "main" cpt where
{ title: "Show emergence label only"
, callback: \_ -> changeViewCallback HeadingMode
, variant: OutlinedButtonVariant Secondary
, className: displayView == HeadingMode ?
, className: displayView' == HeadingMode ?
"active" $
""
}
......@@ -89,7 +91,7 @@ component = here.component "main" cpt where
{ title: "Show node inner labels"
, callback: \_ -> changeViewCallback LabelMode
, variant: OutlinedButtonVariant Secondary
, className: displayView == LabelMode ?
, className: displayView' == LabelMode ?
"active" $
""
}
......@@ -122,8 +124,8 @@ component = here.component "main" cpt where
[
-- Isoline button
B.button
{ callback: \_ -> T.modify_ not isolineBox
, variant: isIsolineDisplayed ?
{ callback: \_ -> T.modify_ not isIsolineDisplayed
, variant: isIsolineDisplayed' ?
ButtonVariant Secondary $
OutlinedButtonVariant Secondary
}
......
......@@ -8,6 +8,7 @@ import Data.Maybe (Maybe(..))
import Effect (Effect)
import Gargantext.Components.Bootstrap as B
import Gargantext.Components.Bootstrap.Types (ButtonVariant(..), ComponentStatus(..), Variant(..))
import Gargantext.Components.PhyloExplorer.Store as PhyloStore
import Gargantext.Components.PhyloExplorer.Types (Term(..), Source(..))