Compare commits

148 Commits
Author SHA1 Message Date
bachir a6285f24c8 #2164 2023-06-23 15:17:07 +02:00
bachir cbf33f8b24 #2092 phone burger menu, text tei fix 2023-06-21 20:18:52 +02:00
bachir abd7379dc2 #2164 2023-06-20 17:09:27 +02:00
bachir a423cecec3 #2082 lien biblio 2023-06-20 16:39:32 +02:00
bachir 665ddcebc3 #2092 2023-06-20 16:28:30 +02:00
bachir 8d155ca089 #2162 2023-06-20 16:23:52 +02:00
bachir de1c8d0f81 #2075 2023-06-20 14:53:36 +02:00
bachir b3a7ccc3fc #2067 2023-06-20 12:58:16 +02:00
bachir 54c36dad11 #2164 2023-06-20 12:49:43 +02:00
bachir 41d39bb088 #2064 fixed index loading 2023-06-20 12:17:01 +02:00
bachir 0a29027737 #2095 2023-06-20 11:21:34 +02:00
bachir 005d8b43f7 #2095 2023-06-20 11:20:33 +02:00
bachir 9c13960b22 #2095 2023-06-20 11:17:25 +02:00
bachir 0699704246 #2070 2023-06-20 11:05:12 +02:00
bachir 2163358895 #2093 2023-06-20 10:33:40 +02:00
bachir 58a67f0a5d #2075 2023-06-20 10:31:53 +02:00
bachir 60b6ca9c60 #2067 webkit bugfix 2023-06-20 10:26:39 +02:00
bachir 9214d71439 #2165 2023-06-20 10:20:17 +02:00
bachir a2fb9724c4 #2163 2023-06-20 09:54:55 +02:00
bachir 583869773d #2162 2023-06-20 09:40:47 +02:00
bachir 2dccff4fb8 #2092 responsive 2023-06-19 22:36:36 +02:00
bachir 24aaa7b2c3 #2068 page de titre 2023-06-19 17:37:19 +02:00
bachir 650eb4f191 #2085 link line-height 2023-06-19 16:27:37 +02:00
bachir 38e874613d #2085 <sup> line-height 2023-06-19 16:24:13 +02:00
bachir ea111c2af1 #2161 bug fixe 2023-06-19 16:17:41 +02:00
bachir 9543bb863c #2065 2023-06-19 10:23:47 +02:00
bachir 58088eb64e #2083 marques d'entités 2023-06-19 10:10:55 +02:00
bachir d2da431abd #2076 2023-06-19 09:47:00 +02:00
bachir 7192d2f12d #2091 index œuvres 2023-06-19 09:40:24 +02:00
bachir 42d3fae00a #2090 index lieu 2023-06-19 09:29:21 +02:00
bachir d4b48b53cc #2089 #2088 #2087 more css 2023-06-19 09:20:05 +02:00
bachir 1be07149dc #2089 Étiquettes index de personnes 2023-06-18 22:59:20 +02:00
bachir d4e66bfaca #2088 Étiquettes et présentation des manifestations 2023-06-18 22:32:24 +02:00
bachir 0151b9fac4 #2073 vs_sselected font-family 2023-06-18 21:55:14 +02:00
bachir 4f6fad21e3 #2080 results details 2023-06-18 21:49:39 +02:00
bachir 541f4df2d4 #2087 biblio expression 2023-06-18 18:49:29 +02:00
bachir 334e4edfda #2067 biblio affichage 2023-06-18 18:27:57 +02:00
bachir 8aba8e5fb2 #2066 biblio manif & expre quantity 2023-06-18 18:21:25 +02:00
bachir fe556f5375 #2082 presentation notice textes 2023-06-18 18:08:03 +02:00
bachir 5cdf290659 #2084 #2085 statics css 2023-06-18 17:49:03 +02:00
bachir ed662f22c9 #2097 static toc 2023-06-18 17:24:56 +02:00
bachir e79759237b #2095 Révision de la page corpus 2023-06-18 16:10:46 +02:00
bachir f7a86556b2 #2075 Unifier la hauteur des input 2023-06-15 23:05:58 +02:00
bachir 9ca7df2734 #2079 Supprimer l’affichage des filtres de recherche quand on ferme le tiroir de recherche 2023-06-15 22:44:35 +02:00
bachir 82a4e40ccc some fixes 2023-06-15 22:33:16 +02:00
bachir 2dc06a87fc #2093 images in statics 2023-06-15 16:39:34 +02:00
bachir d76c8b502a #2077 Rythmer les Tables des matières 2023-06-14 11:53:04 +02:00
bachir d9402c6145 #2072 Mise en forme de la pagination 2023-06-14 11:30:50 +02:00
bachir 66d8cb4343 #2086 Unifier titres de la biblio avec les autres pages 2023-06-14 10:49:52 +02:00
bachir 28ddeb405f #2069 Raccourcir les titres dans la toc 2023-06-14 10:34:26 +02:00
bachir e28d128a3a #2081 2023-06-09 15:13:56 +02:00
bachir 1bc03bb2f3 #2078 2023-06-09 15:10:37 +02:00
bachir 3753216bd0 #2070 2023-06-09 14:59:33 +02:00
bachir 78b3ec468b #2094 2023-06-09 14:29:13 +02:00
bachir 18c4c331f2 #2064 2023-03-08 20:36:36 +01:00
bachir 5bda8d9c36 #2065 2023-03-08 19:50:10 +01:00
bachir f469d37491 #2074 2023-03-08 19:46:45 +01:00
bachir 0c39ea57ee #2071 2023-03-08 19:43:22 +01:00
bachir df0569b203 #2063 2023-03-08 19:33:44 +01:00
bachir 15704905fb fixed result item link #2062 2023-03-02 22:51:36 +01:00
bachir 053216a7ce corpus notices #1942 2023-03-02 22:32:43 +01:00
bachir 1f106b3842 metada are populated for texts & indexes #1796 2023-03-02 22:09:53 +01:00
bachir f903424ddb corpus index filtering ok #1801 2023-03-01 22:00:43 +01:00
bachir 249d7fdb02 started corpus indexes filters #1801 2023-03-01 18:41:25 +01:00
bachir 7dbb43e0ed htaccess for routing #2054 2023-02-28 16:58:43 +01:00
bachir be534559aa shortening search result title #1250 2023-02-28 16:27:06 +01:00
bachir dda83a434a fixed overlapping paginations 2023-02-28 16:13:22 +01:00
bachir 01cd27353a toc levels improvement #1255 #1933 2023-02-28 15:53:47 +01:00
bachir 67d890a365 search filters quantity between [] #1802 2023-02-28 15:53:10 +01:00
bachir a4f9114b7c fixed textId #2057 2023-02-28 10:14:29 +01:00
bachir e424f3c270 redirecting /items/[UUID] to /texts/[TEXTID]/[UUID] #2057 2023-02-27 18:25:03 +01:00
bachir 015ef01f37 added quantity to search filters (facettes) #1802 2023-02-27 18:23:58 +01:00
bachir 718fc765ab redirecting /items/[UUID] to /texts/[TEXTID]/[UUID] #2057 2023-02-27 17:33:08 +01:00
bachir bfcad2d728 fixed bad links href #2055 2023-02-27 17:00:54 +01:00
bachir 232b44f3c6 displaying TOC items types & item without titles #1255 2023-02-20 16:51:52 +01:00
bachir 877d10b4d2 webpack minimze & npm update 2023-02-19 21:57:20 +01:00
bachir 083f620527 finished logos on home page #1258 2023-02-19 21:29:28 +01:00
bachir 4b2558fd94 home display 2023-02-19 21:23:57 +01:00
bachir 58523311a2 finished logos on home page #1258 2023-02-19 21:19:44 +01:00
bachir acc36bb1e9 started logos on home page #1258 2023-02-19 20:58:07 +01:00
bachir 6229131748 text styles : list #1253 2023-02-18 21:30:25 +01:00
bachir b3c182abba text styles : blockquote #1253 2023-02-18 21:26:20 +01:00
bachir 53093d3110 toc titles hierarchy #1254 2023-02-18 21:20:27 +01:00
bachir aa0382338c fixed mdi icon size in texts #1941 2023-02-18 21:12:26 +01:00
bachir 8494e5a0e2 better css for home 2023-02-18 18:38:22 +01:00
bachir ac853527fb home teasers and static pages #796 2023-02-17 23:04:15 +01:00
bachir 9c8bf3f38f close history panel when scrolling text #851 2023-02-17 21:23:45 +01:00
bachir f0a6f60314 better nominum left sidebar display #1253 2023-02-17 17:34:46 +01:00
bachir 9de4647995 index item moved authorities to left sidebar #1939 2023-02-17 17:16:56 +01:00
bachir 44e08dac54 added missing fields in bibliographie/manifestations/item (lieu, edition, extent, tei #1937 2023-02-17 17:04:10 +01:00
bachir 86d7cf8a10 fixed https for prod api 2022-11-02 21:53:27 +01:00
bachir 83fe5e48fd npm update vue-webpack-4 2022-06-23 12:58:20 +02:00
bachir 10a23ab4b7 updated node to 16 2022-06-23 12:45:49 +02:00
bachir 044be64157 no weight, no color for index item in text #1243 2022-05-13 16:53:08 +02:00
bachir b1424982f5 icons for index item in text #1265 2022-05-13 16:48:52 +02:00
bachir b958a09cfa index -> text : highlight item in text with id #806 2022-05-13 15:27:58 +02:00
bachir 10c4abfa82 bibliography improvment #1257 2022-04-07 22:49:12 +02:00
bachir ff79fa47d9 typo style #850 2022-04-07 12:42:54 +02:00
bachir 505919b50b replaced node-sass by sass, fixed vuesweetalert display #1857 2022-04-07 12:27:51 +02:00
bachir 8e25388ba9 micro fixes 2022-04-07 10:54:22 +02:00
bachir 8f5c72e43b index items ligne de base 2022-03-18 15:37:14 +01:00
bachir c30aa42b1d fixed infinite loading top 2022-03-18 15:21:38 +01:00
bachir 2d50e7f48a fixed loupe alignement #1249 2022-03-17 19:05:13 +01:00
bachir a1925aaf17 fixed search form inputs width #832 2022-03-17 18:40:09 +01:00
bachir a1c3382a6c fixe ios wrong height:100vh #831 2022-03-17 18:35:04 +01:00
bachir 2b40b9910d responsive for landscape #830 2022-03-17 18:27:28 +01:00
bachir 006dd606ea limited root layout to max-width:1920px; #1251 2022-03-17 16:34:18 +01:00
bachir 00df4dbaf8 all client path match api path #793 2022-03-17 15:46:51 +01:00
bachir 9d454fb259 updated texts (ex editions) path to match api 2022-03-17 15:39:04 +01:00
bachir deb3bf1d99 improved index lists #1259 2022-03-10 21:47:52 +01:00
bachir 9f806420d5 redesigned index nominum item page 2022-03-10 18:07:38 +01:00
bachir 1ca1469233 inversed history 2022-03-10 15:48:48 +01:00
bachir cae01c650b webpack compile warnings 2022-03-10 10:35:16 +01:00
bachir 36e90dbad4 npm update 2022-03-10 10:13:55 +01:00
bachir 4ec12bbaec edition more info on header 2022-03-04 17:23:07 +01:00
bachir 848349c1f3 added exctract coming from niminum index #765 2022-03-04 15:31:34 +01:00
bachir 27455eb300 marked extract of search on text (scrolling is not working yet 2022-03-04 00:15:36 +01:00
bachir 0d3947cf25 better pagination #1256 2022-03-03 18:30:03 +01:00
bachir 516a0ac69f biblio & manif link in edition's header #1795 2022-03-03 17:59:53 +01:00
bachir e461b49c54 using url provided by api for copy popup #1266 2022-03-03 17:28:05 +01:00
bachir 2af7fe6a0f fixed pageNum tags display 2022-03-03 17:18:10 +01:00
bachir 296bcd10b5 forgot hover on ref copy popup 2022-03-03 17:09:34 +01:00
bachir b0eba282b7 copy reference popup #1241 2022-03-03 16:36:27 +01:00
bachir ae91e8bf1e click toc add item to history #810 2022-02-03 20:17:08 +01:00
bachir 561038ef36 gouttière pagination #1240 2022-02-03 19:54:47 +01:00
bachir 1ee582a420 better typo on texts 2022-01-20 18:34:44 +01:00
bachir 257efc35f9 grille de ligne de base 2022-01-20 17:30:07 +01:00
bachir fa6f051051 list corpus added texts #1260 2022-01-20 16:31:36 +01:00
bachir e1d126c0fc dans les œuvres #1249 2021-11-29 16:03:51 +01:00
bachir c49b1315b7 home static lorem ipsum #1248 2021-11-29 14:22:42 +01:00
bachir 7896cd6340 changed client port 2021-11-29 14:22:12 +01:00
bachir cbdcd50a34 readme 2021-11-23 19:05:11 +01:00
bachir b708cfc80f typo fix #853 2020-07-31 16:52:03 +02:00
bachir 27eeb792b0 images #825 #784 #783 2020-07-31 13:12:45 +02:00
bachir 71555de31c filter search by text #833 #828 2020-07-31 11:49:57 +02:00
bachir 2b246ae2e5 index items infos displayed #798 2020-07-30 11:09:07 +02:00
bachir c202beb419 fix #808, auto close results trail 2020-07-29 19:16:03 +02:00
bachir 5196e7146e fix history nav content 2020-07-29 19:15:35 +02:00
bachir 79943af82e fix header menu submenu #827 2020-07-29 19:03:59 +02:00
bachir 91875258de fix #829 2020-07-29 18:19:26 +02:00
bachir 606d6e98a3 copy to clipboard text item url #782 2020-07-29 18:15:29 +02:00
bachir 68064c916a bugfix: webkit scroll #826 2020-07-29 16:44:50 +02:00
bachir 196c02d0fc testing -webkit-overflow-scrolling 2020-07-29 11:14:21 +02:00
bachir 7cff622e14 added some transitions 2020-07-28 13:10:20 +02:00
bachir 15a923a229 bugfix infinite loader on init 2020-07-28 12:02:11 +02:00
bachir b719b06a8e nicer loader indicator 2020-07-28 12:01:35 +02:00
bachir e9e77c15ae tei front page styling #790 2020-07-28 11:11:44 +02:00
bachir 076864cd56 bug fix #789: no more columns on desktop 2020-07-28 10:31:11 +02:00
60 changed files with 25750 additions and 6030 deletions
+1 -1
View File
@@ -4,7 +4,7 @@
#### clone this repos #### clone this repos
#### install #### install
``` ```
npm install npm ci
``` ```
#### run dev #### run dev
``` ```
+1404 -256
View File
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -1,7 +1,8 @@
$bleuroi: rgb(61,82,102); $bleuroi: rgb(61,82,102);
$bleuroilight: lighten(rgb(61,82,102), 30%); $bleuroilight: lighten(rgb(61,82,102), 30%);
$gris: rgb(200,204,204);
$grisclair: rgb(230,234,234); $grisclair: rgb(230,234,234);
$gris: rgb(190,194,194);
$grismoyen: rgb(150,150,160);
$grisfonce: rgb(57,57,64); $grisfonce: rgb(57,57,64);
$or: rgb(179,161,125); $or: rgb(179,161,125);
$rouge: rgb(204,61,82); $rouge: rgb(204,61,82);
+72 -1
View File
@@ -4,6 +4,7 @@
// @import '../fonts/notosans/notosans-condensed.css'; // @import '../fonts/notosans/notosans-condensed.css';
// @import '../fonts/notosans/notosans-extracondensed.css'; // @import '../fonts/notosans/notosans-extracondensed.css';
@mixin fontsans { @mixin fontsans {
font-family: "noto_sans"; font-family: "noto_sans";
} }
@@ -27,13 +28,13 @@ footer[role="tools"] .row>header,
footer[role="tools"] .row>nav{ footer[role="tools"] .row>nav{
@include fontsans; @include fontsans;
} }
@mixin title1blue { @mixin title1blue {
@include fontserif; @include fontserif;
font-size: 2.268em; font-size: 2.268em;
color: $bleuroi; color: $bleuroi;
font-weight: 400; font-weight: 400;
margin:0; margin:0;
line-height: $base-line * 1.5;
} }
@mixin title1black { @mixin title1black {
@@ -42,6 +43,7 @@ footer[role="tools"] .row>nav{
color: $grisfonce; color: $grisfonce;
font-weight: 400; font-weight: 400;
margin:0; margin:0;
line-height: $base-line;
} }
@mixin title2black { @mixin title2black {
@@ -50,6 +52,16 @@ footer[role="tools"] .row>nav{
color: $grisfonce; color: $grisfonce;
font-weight: 400; font-weight: 400;
margin:0; margin:0;
line-height: $base-line / 2;
}
@mixin title2blue {
@include fontserif;
font-size: 1.134em;
color: $grisfonce;
font-weight: 400;
margin:0;
line-height: $base-line / 2;
} }
@mixin title3black { @mixin title3black {
@@ -58,4 +70,63 @@ footer[role="tools"] .row>nav{
color: $grisfonce; color: $grisfonce;
font-weight: 400; font-weight: 400;
margin:0; margin:0;
line-height: $base-line / 2;
}
@mixin title4black {
@include fontserif;
font-size: 0.882em;;
color: $grisfonce;
font-weight: 400;
margin:0;
line-height: $base-line / 2;
}
@mixin title4grey {
@include fontserif;
font-size: 0.882em;;
color: $gris;
font-weight: 400;
margin:0;
}
// TEI
@mixin teititlefrontblue {
@include fontserif;
font-size: 2.6em;
color: $bleuroi;
font-weight: 400;
margin:0;
text-align: center;
line-height: $base-line * 1.5;
}
@mixin teititle1blue {
@include fontserif;
font-size: 1.8em;
color: $bleuroi;
font-weight: 400;
margin:0;
line-height: $base-line;
}
@mixin titleSansRed {
font-family: "noto_sans";
color: $rouge;
font-weight: 400;
line-height: $base-line;
}
@mixin fontcaption {
@include fontsans;
font-size: 0.756em;
line-height: 1.1em;
}
@mixin labeurfont {
@include fontserif;
font-size: 1.134em;
font-weight: 400;
line-height: $base-line;
} }
+27 -5
View File
@@ -6,7 +6,7 @@
flex-direction: row; flex-direction: row;
flex-wrap: nowrap; flex-wrap: nowrap;
align-items: stretch; align-items: stretch;
@media only screen and (max-width: $small-bp) { @media only screen and (max-width: $small-bp), (orientation: portrait) {
flex-wrap:wrap; flex-wrap:wrap;
} }
} }
@@ -18,12 +18,34 @@
@include row; @include row;
} }
%col-reset { // small
box-sizing: border-box; .small-row {
@media only screen and (max-width: $small-bp), (orientation: portrait) {
@include row;
}
} }
// medium
.med-row {
@media only screen and (min-width: $small-bp+1) and (max-width: $med-bp) {
@include row;
}
}
// large
.large-row {
@media only screen and (min-width: $med-bp+1) {
@include row;
}
}
// %col-reset {
// box-sizing: border-box;
// }
@mixin col($col, $offset: 0, $sum: $default_sum, $gap: $default_gap, $align: top) { @mixin col($col, $offset: 0, $sum: $default_sum, $gap: $default_gap, $align: top) {
@extend %col-reset; // @extend %col-reset;
box-sizing: border-box;
padding-left: $gap*$offset; padding-left: $gap*$offset;
@if $col == $default_sum { @if $col == $default_sum {
// if last col, then no gap // if last col, then no gap
@@ -47,7 +69,7 @@
// small // small
.small-col-#{$c} { .small-col-#{$c} {
@media only screen and (max-width: $small-bp) { @media only screen and (max-width: $small-bp), (orientation: portrait) {
@include col($c); @include col($c);
} }
} }
+49 -13
View File
@@ -18,56 +18,92 @@ body{
display: flex; display: flex;
flex-direction: column; flex-direction: column;
width: 100vw; width: 100vw;
max-width: 1920px;
height:100vh; height:100vh;
// ? https://www.bram.us/2020/05/06/100vh-in-safari-on-ios/
@supports (-webkit-touch-callout: none) {
height: -webkit-fill-available;
}
margin:0 auto;
%layout-element{ %layout-element{
width:100vw; width:100vw;
max-width: 1920px;
box-sizing:border-box; box-sizing:border-box;
} }
header[role="banner"]{ header[role="banner"]{
z-index:10;
flex: 0 0 auto; flex: 0 0 auto;
@extend %layout-element; @extend %layout-element;
padding:1em $side-padding 0 $side-padding; padding:1em $side-padding 1em $side-padding;
@media only screen and (max-width: $small-bp) { @media only screen and (max-width: $small-bp), (orientation: portrait) {
padding:1em $side-padding/2 0 $side-padding/2; padding:1em $side-padding/2 0 $side-padding/2;
} }
// iphone
@media only screen and (max-width: $iphone-bp), (orientation: portrait) {
padding:1em $side-padding/2 1em $side-padding/2;
}
} }
section[role="main-content"]{ section[role="main-content"]{
display: flex;
flex:1 1 auto; flex:1 1 auto;
@extend %layout-element; @extend %layout-element;
overflow: hidden; overflow: hidden;
position: relative;
>.wrapper{ >.wrapper{
position: relative; position: relative;
padding:0 $side-padding 0 $side-padding; padding:0 $side-padding 0 $side-padding;
height:100%; max-height:100%; // height:100%; max-height:100%;
display: flex;
flex: 1;
overflow-y: hidden; overflow-y: hidden;
overflow-x: hidden; overflow-x: hidden;
@media only screen and (max-width: $small-bp) { >*{
@include fade-transition;
}
@media only screen and (max-width: $small-bp), (orientation: portrait) {
overflow-y: auto; overflow-y: auto;
padding:0 $side-padding/2 0 $side-padding/2; padding:0 $side-padding/2 0 $side-padding/2;
} }
// iphone
@media only screen and (max-width: $iphone-bp), (orientation: portrait) {
// padding:0 $side-padding/4 0 $side-padding/4;
}
} }
.main-content-layout{ .main-content-layout{
height: 100%; position: relative;
>header, // https://stackoverflow.com/a/33644245
>section, display: flex;
>nav{ flex: 1;
>section{
max-height: 100%; max-height: 100%;
padding-top:1em;
padding-bottom:1em;
} }
>header,
>section, >section>.wrapper,
>nav{
box-sizing: border-box;
max-height: 100%;
padding-top:$base-line;
}
>section>.wrapper,
>nav{ >nav{
overflow-x: hidden; overflow-x: hidden;
overflow-y: auto; overflow-y: auto;
-webkit-overflow-scrolling: touch;
} }
} }
@media only screen and (max-width: $small-bp) { @media only screen and (max-width: $small-bp), (orientation: portrait) {
.main-content-layout{ .main-content-layout{
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
} }
@media (orientation: portrait) {
.main-content-layout{
display: flex;
flex-direction: column;
flex-wrap: nowrap;
}
}
} }
footer[role="tools"]{ footer[role="tools"]{
flex:0 0 auto; flex:0 0 auto;
+3
View File
@@ -22,6 +22,9 @@ li{
list-style: none; list-style: none;
} }
sup{
line-height: 0;
}
.visualy-hidden { .visualy-hidden {
position: absolute !important; position: absolute !important;
clip: rect(1px, 1px, 1px, 1px); clip: rect(1px, 1px, 1px, 1px);
+20
View File
@@ -45,3 +45,23 @@
transition: all 200ms ease-in-out; transition: all 200ms ease-in-out;
} }
} }
.fade-enter-active{
transition: all 300ms ease-in-out;
}
.fade-leave-active{
transition: all 200ms ease-in-out;
}
.fade-enter,
.fade-leave-active {
opacity: 0
}
// .edition-texts-enter-active, .edition-texts-leave-active {
// transition: all 1s;
// }
// .edition-texts-enter, .edition-texts-leave-to /* .list-leave-active below version 2.1.8 */ {
// max-height: 0;
// // transform: translateY(30px);
// }
+3
View File
@@ -1,9 +1,12 @@
$base_font_size:16px; $base_font_size:16px;
$base-line:28px;
// grid // grid
$default_gap: 1em; $default_gap: 1em;
$default_sum: 12; // total number of columns $default_sum: 12; // total number of columns
$iphone-bp: 428px;
$small-bp:768px; $small-bp:768px;
$med-bp:1080px; $med-bp:1080px;
$ipad-bp: 1536px;
$large-bp:1900px; $large-bp:1900px;
+7 -5
View File
@@ -74,10 +74,12 @@ module.exports = {
}), }),
new HtmlWebpackHarddiskPlugin(), new HtmlWebpackHarddiskPlugin(),
new VueLoaderPlugin(), new VueLoaderPlugin(),
new CopyWebpackPlugin([{ new CopyWebpackPlugin([
from: utils.resolve('static/img'), {
to: utils.resolve('dist/static/img'), from: utils.resolve('static/img'),
toType: 'dir' to: utils.resolve('dist/static/img'),
}]) toType: 'dir'
}
])
] ]
} }
+1 -1
View File
@@ -5,7 +5,7 @@ const merge = require('webpack-merge')
const baseConfig = require('./webpack.config.base') const baseConfig = require('./webpack.config.base')
const PORT = 8988 const PORT = 8998
module.exports = merge(baseConfig, { module.exports = merge(baseConfig, {
mode: 'development', mode: 'development',
+32 -18
View File
@@ -1,36 +1,45 @@
'use strict' 'use strict'
const webpack = require('webpack') const webpack = require('webpack')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const merge = require('webpack-merge') const merge = require('webpack-merge')
const baseConfig = require('./webpack.config.base') const baseConfig = require('./webpack.config.base')
const MiniCssExtractPlugin = require('mini-css-extract-plugin') const MiniCssExtractPlugin = require('mini-css-extract-plugin')
// const UglifyJSPlugin = require('uglifyjs-webpack-plugin') const utils = require('./utils')
const UglifyJSPlugin = require('uglifyjs-webpack-plugin')
// ERROR in vendor.js from UglifyJs // ERROR in vendor.js from UglifyJs
// RangeError: Maximum call stack size exceeded // RangeError: Maximum call stack size exceeded
module.exports = merge(baseConfig, { module.exports = merge(baseConfig, {
mode: 'production', mode: 'production',
// resolve: {
// alias: {
// 'static': utils.resolve('static')
// }
// },
output: { output: {
publicPath: '/' publicPath: '/'
}, },
optimization: { optimization: {
// minimizer: [ minimize: true,
// new UglifyJSPlugin({ minimizer: [
// uglifyOptions: { new UglifyJSPlugin({
// // Eliminate comments uglifyOptions: {
// comments: false, // Eliminate comments
// // remove warnings comments: false,
// warnings: false, // remove warnings
// minimize: false, // warnings: false,
// mangle: false, minimize: false,
// compress: { mangle: false,
// // Drop console statements compress: {
// drop_console: true, // Drop console statements
// } drop_console: true,
// } }
// }) }
// ], })
],
splitChunks: { splitChunks: {
cacheGroups: { cacheGroups: {
commons: { commons: {
@@ -65,6 +74,11 @@ module.exports = merge(baseConfig, {
}), }),
new webpack.DefinePlugin({ new webpack.DefinePlugin({
"process.env": "'prod'" "process.env": "'prod'"
}) }),
new CopyWebpackPlugin([{
from: utils.resolve('static/.htaccess'),
to: utils.resolve('dist/.htaccess'),
toType: 'file'
}])
] ]
}) })
+1 -1
View File
@@ -5,7 +5,7 @@
<meta name="viewport" content="width=device-width,initial-scale=1.0"> <meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Les Guides de Paris</title> <title>Les Guides de Paris</title>
</head> </head>
<body> <body tabindex="-1">
<div id="app"></div> <div id="app"></div>
</body> </body>
</html> </html>
+21605 -5236
View File
File diff suppressed because it is too large Load Diff
+32 -28
View File
@@ -18,59 +18,63 @@
"author": "Daniel Cook", "author": "Daniel Cook",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@popperjs/core": "^2.4.4", "@popperjs/core": "^2.11.2",
"@sweetalert2/themes": "^5.0.10",
"axios": "^0.18.1", "axios": "^0.18.1",
"vue": "^2.6.10", "truncate-html": "^1.0.4",
"vue": "^2.6.14",
"vue-clipboard2": "^0.3.3",
"vue-infinite-loading": "^2.4.5", "vue-infinite-loading": "^2.4.5",
"vue-meta": "^1.6.0", "vue-meta": "^1.6.0",
"vue-router": "^3.1.3", "vue-router": "^3.5.3",
"vue-scrollto": "^2.18.1", "vue-scrollto": "^2.20.0",
"vue-select": "^3.10.7", "vue-select": "^3.18.3",
"vue2-touch-events": "^2.2.1", "vue2-touch-events": "^2.3.2",
"vuex": "^3.1.1", "vuex": "^3.6.2",
"vuex-router-sync": "^5.0.0" "vuex-router-sync": "^5.0.0"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.6.0", "@babel/core": "^7.17.5",
"@babel/preset-env": "^7.6.0", "@babel/preset-env": "^7.16.11",
"@vue/test-utils": "^1.0.0-beta.29", "@vue/test-utils": "^1.3.0",
"babel-core": "^7.0.0-bridge.0", "babel-core": "^7.0.0-bridge.0",
"babel-eslint": "^10.0.3", "babel-eslint": "^10.1.0",
"babel-jest": "^24.9.0", "babel-jest": "^24.9.0",
"babel-loader": "^8.0.6", "babel-loader": "^8.2.3",
"copy-webpack-plugin": "^5.0.4", "copy-webpack-plugin": "^5.1.2",
"css-loader": "^2.1.1", "css-loader": "^2.1.1",
"eslint": "^5.16.0", "eslint": "^5.16.0",
"eslint-config-standard": "^12.0.0", "eslint-config-standard": "^12.0.0",
"eslint-loader": "^2.2.1", "eslint-loader": "^2.2.1",
"eslint-plugin-import": "^2.18.2", "eslint-plugin-import": "^2.25.4",
"eslint-plugin-node": "^8.0.1", "eslint-plugin-node": "^8.0.1",
"eslint-plugin-promise": "^4.2.1", "eslint-plugin-promise": "^4.3.1",
"eslint-plugin-standard": "^4.0.1", "eslint-plugin-standard": "^4.1.0",
"eslint-plugin-vue": "^5.2.3", "eslint-plugin-vue": "^5.2.3",
"eslint-plugin-vue-a11y": "0.0.28", "eslint-plugin-vue-a11y": "0.0.28",
"file-loader": "^4.2.0", "file-loader": "^4.3.0",
"html-webpack-harddisk-plugin": "^1.0.1", "html-webpack-harddisk-plugin": "^1.0.2",
"html-webpack-plugin": "^3.2.0", "html-webpack-plugin": "^3.2.0",
"jest": "^24.9.0", "jest": "^24.9.0",
"jest-serializer-vue": "^2.0.2", "jest-serializer-vue": "^2.0.2",
"mini-css-extract-plugin": "^0.5.0", "mini-css-extract-plugin": "^0.5.0",
"node-sass": "^4.12.0", "sass": "^1.50.0",
"sass-loader": "^7.3.1", "sass-loader": "^7.3.1",
"style-loader": "^0.23.1", "style-loader": "^0.23.1",
"stylus": "^0.54.7", "stylus": "^0.54.8",
"stylus-loader": "^3.0.2", "stylus-loader": "^3.0.2",
"uglify-es": "^3.3.9", "uglify-es": "^3.3.9",
"uglifyjs-webpack-plugin": "^2.2.0", "uglifyjs-webpack-plugin": "^2.2.0",
"url-loader": "^1.1.2", "url-loader": "^1.1.2",
"vue-jest": "^3.0.5", "vue-jest": "^3.0.7",
"vue-loader": "^15.7.1", "vue-loader": "^15.9.8",
"vue-server-renderer": "^2.6.10", "vue-server-renderer": "^2.6.14",
"vue-style-loader": "^4.1.2", "vue-style-loader": "^4.1.3",
"vue-template-compiler": "^2.6.10", "vue-sweetalert2": "^5.0.2",
"webpack": "^4.40.2", "vue-template-compiler": "^2.6.14",
"webpack-cli": "^3.3.9", "webpack": "^4.46.0",
"webpack-dev-server": "^3.8.1", "webpack-cli": "^3.3.12",
"webpack-dev-server": "^3.11.3",
"webpack-merge": "^4.2.2" "webpack-merge": "^4.2.2"
} }
} }
+16 -2
View File
@@ -13,7 +13,9 @@
</header> </header>
<section role="main-content"> <section role="main-content">
<div class="wrapper"> <div class="wrapper">
<RouterView /> <transition name="fade" mode="out-in">
<RouterView />
</transition>
</div> </div>
</section> </section>
<footer role="tools"> <footer role="tools">
@@ -22,6 +24,17 @@
<div id="footer-bottom" class="row"> <div id="footer-bottom" class="row">
<FooterTabs /> <FooterTabs />
<Search /> <Search />
<div
v-if="$route.name === 'home' && (!searchResults || !searchResults.length)"
id="logos"
class="small-col-12 med-col-7 large-col-7"
>
<div class="wrapper">
<img src="/static/img/logos/labex.jpg" alt="Labex">
<img src="/static/img/logos/PIA logo.png" alt="PIA">
<img src="/static/img/logos/Logo-HAR-Unite-de-recherche.png" alt="HAR">
</div>
</div>
</div> </div>
</footer> </footer>
</div> </div>
@@ -56,7 +69,8 @@ export default {
computed: { computed: {
...mapState({ ...mapState({
resultsOpened: state => state.Search.opened, resultsOpened: state => state.Search.opened,
editionslist: state => state.Corpus.editionslist editionslist: state => state.Corpus.editionslist,
searchResults: state => state.Corpus.results
}) })
}, },
created () { created () {
+2 -1
View File
@@ -21,6 +21,7 @@ export const REST = axios.create({
crossorigin: true, crossorigin: true,
headers: { headers: {
'Accept': 'application/json' 'Accept': 'application/json'
// 'Access-Control-Allow-Credentials': true // 'Access-Control-Allow-Origin': '*'
// 'Access-Control-Allow-Credentials':
} }
}) })
+137
View File
@@ -0,0 +1,137 @@
<template>
<div>
<div
v-for="(opts, key) in options"
:key="key"
>
<v-select
:id="key"
type="select"
:placeholder="placeholders[key]"
append-to-body
:calculate-position="dropDownMenuPos"
:options="opts"
:clearable="true"
:value="getSeletedValue(key)"
@input="onClickIndexItem"
>
<template v-slot:option="option">
<span v-html="option.label" />
</template>
</v-select>
</div>
</div>
</template>
<script>
import { createPopper } from '@popperjs/core'
export default {
name: 'EdIndexes',
props: {
indexes: Object
},
data: () => ({
options: {},
indexes_keys: [],
persons_selected: null,
objects_selected: null,
places_selected: null,
placeholders: {
objects: 'Filtrer par œuvres',
persons: 'Filtrer par personnes',
places: 'Filtrer par lieux'
}
}),
watch: {
persons_selected (n, o) {
console.log('EdIndexes watch persons_selected', o, n)
}
},
created () {
this.parseIndexesToOptions()
},
methods: {
parseIndexesToOptions () {
console.log('EdIndexes parseIndexesToOptions', this.indexes)
Object.keys(this.indexes).forEach(key => {
// console.log('OPTION', key)
this.indexes_keys.push(key)
this.options[key] = []
Object.keys(this.indexes[key]).forEach(uuid => {
// console.log('OPTIONS ITEM', key, uuid)
this.options[key].push({
code: uuid,
label: `${this.indexes[key][uuid].title} [${this.indexes[key][uuid].quantity}]`,
index: key
})
})
if (!this.options[key].length) {
delete this.options[key]
}
})
},
dropDownMenuPos (dropdownList, component, { width }) {
/**
* We need to explicitly define the dropdown width since
* it is usually inherited from the parent with CSS.
*/
dropdownList.style.width = width
/**
* Here we position the dropdownList relative to the $refs.toggle Element.
*
* The 'offset' modifier aligns the dropdown so that the $refs.toggle and
* the dropdownList overlap by 1 pixel.
*
* The 'toggleClass' modifier adds a 'drop-up' class to the Vue Select
* wrapper so that we can set some styles for when the dropdown is placed
* above.
*/
const popper = createPopper(component.$refs.toggle, dropdownList, {
placement: 'top',
modifiers: [
{
name: 'offset',
options: {
offset: [0, -1]
}
},
{
name: 'toggleClass',
enabled: true,
phase: 'write',
fn ({ state }) {
component.$el.classList.toggle('drop-up', state.placement === 'top')
}
}]
})
/**
* To prevent memory leaks Popper needs to be destroyed.
* If you return function, it will be called just before dropdown is removed from DOM.
*/
return () => popper.destroy()
},
getSeletedValue (key) {
return this[`${key}_selected`]
},
onClickIndexItem (o) {
console.log('onClickIndexItem', o)
this.indexes_keys.forEach(key => {
if (o && key === o.index) {
this[`${key}_selected`] = o
} else {
this[`${key}_selected`] = null
}
})
// this.page_selected = o
this.$emit('onClickIndexItem', o)
}
}
}
</script>
<style lang="scss" scoped>
</style>
+23 -6
View File
@@ -17,8 +17,8 @@
@input="onClickPaginationItem" @input="onClickPaginationItem"
> >
<template v-slot:option="option"> <template v-slot:option="option">
<span v-for="l in option.level" :key="l" class="op-tab" /> <span v-for="l in option.level" :key="l" class="op-tab">&nbsp;</span>
{{ option.label }} <span v-html="option.label" />
</template> </template>
</v-select> </v-select>
</div> </div>
@@ -46,10 +46,11 @@ export default {
// } // }
// }, // },
methods: { methods: {
parsePagesToOptions (p, i = 0, l = 0) { parsePagesToOptions (p, vol = null, i = 0, l = 0) {
// console.log('EdPagination parsePagesToOptions', p) console.log('EdPagination parsePagesToOptions', p)
for (var j = 0; j < p.length; j++) { for (var j = 0; j < p.length; j++) {
// if it is just a section without page like a volume // if it is just a section without page like a volume
// not used anymore
if (p[j].text) { if (p[j].text) {
this.options.push({ this.options.push({
key: i, key: i,
@@ -59,18 +60,34 @@ export default {
level: l level: l
}) })
} }
// if its a volume
if (p[j].vol) {
this.options.push({
code: p[j].vol.label,
label: `<h3 class="vol-label">${p[j].vol.label}</h3>`,
disabled: true,
level: l
})
}
// if it's a real page break // if it's a real page break
if (p[j].pageBreak) { if (p[j].pageBreak) {
let label
if (vol) {
label = `${vol.unit}${vol.n} page ${p[j].pageNum}`
} else {
label = p[j].pageNum
}
this.options.push({ this.options.push({
key: i, key: i,
code: p[j].pageBreak, code: p[j].pageBreak,
label: p[j].pageNum, label: label,
uuid: p[j].uuid, uuid: p[j].uuid,
level: l level: l
}) })
} }
if (p[j].pages && p[j].pages.length) { if (p[j].pages && p[j].pages.length) {
this.parsePagesToOptions(p[j].pages, i++, l + 1) this.parsePagesToOptions(p[j].pages, p[j].vol, i++, l + 1)
} else { } else {
i++ i++
} }
+151 -35
View File
@@ -1,58 +1,130 @@
<template>
<div class="text-wrapper">
<EdTextRefLink :uuid="uuid" :url="url" />
<div
class="tei"
:class="{ active: uuid === textid }"
:data-uuid="uuid"
v-html="teiparsed"
/>
</div>
</template>
<script> <script>
import Vue from 'vue' // import Vue from 'vue'
import EdTextRefLink from './EdTextRefLink'
export default { export default {
name: 'EdText', name: 'EdText',
components: {
EdTextRefLink
},
props: { props: {
tei: String, tei: String,
uuid: String, uuid: String,
textid: String textid: String,
extractid: String,
url: String
}, },
data: () => ({ data: () => ({
template: null, template: null,
html: null, html: null,
pages: [] pages: [],
teiparsed: null
}), }),
watch: { watch: {
tei: function (newtei, oldtei) { tei: function (newtei, oldtei) {
// console.log('tei watcher', oldtei, newtei) // console.log('tei watcher', oldtei, newtei)
// we need this watcher to update display as route is changing // we need this watcher to update display as route is changing
this.buildTemplate() // this.buildTemplate()
this.parseTei()
} }
}, },
beforeMount () { beforeMount () {
// console.log('EdText beforeMount') // console.log('EdText beforeMount', this.tei)
if (this.tei) { if (this.tei) {
this.buildTemplate() // this.buildTemplate()
this.parseTei()
} }
}, },
// mounted () { // mounted () {
// this.$emit('onNewPageBreaks', this.pages) // this.$emit('onNewPageBreaks', this.pages)
// }, // },
methods: { methods: {
buildTemplate () { // buildTemplate () {
// console.log('EdText buildTemplate: tei', this.tei) // // console.log('EdText buildTemplate: tei', this.tei)
// to get Vue.compile working we have to use the full build of vuejs // // to get Vue.compile working we have to use the full build of vuejs
// https://vuejs.org/v2/guide/installation.html#Explanation-of-Different-Builds // // https://vuejs.org/v2/guide/installation.html#Explanation-of-Different-Builds
// in /build/webpack.config.base.js alias -> 'vue': 'vue/dist/vue.js', // // in /build/webpack.config.base.js alias -> 'vue': 'vue/dist/vue.js',
this.buildHtml() // this.buildHtml()
this.template = Vue.compile(this.html) // this.template = Vue.compile(this.html)
this.$options.staticRenderFns = [] // this.$options.staticRenderFns = []
this._staticTrees = [] // this._staticTrees = []
this.template.staticRenderFns.map(fn => (this.$options.staticRenderFns.push(fn))) // this.template.staticRenderFns.map(fn => (this.$options.staticRenderFns.push(fn)))
}, // },
buildHtml () { // buildHtml () {
this.html = `<div` + // this.html = `<div` +
` class="tei${this.uuid === this.textid ? ' active' : ''}"` + // ` class="tei${this.uuid === this.textid ? ' active' : ''}"` +
` data-uuid="${this.uuid}"` + // ` data-uuid="${this.uuid}"` +
`>${this.tei}</div>` // `>` +
// `<a` +
// ` href="http://${window.apipath}/items/${this.uuid}"` +
// ` title="Copy to clipboard ${this.uuid}"` +
// ` class="text-item-link"` +
// ` @click.prevent="onClickCopyClipboard"` +
// `>` +
// `<span class="mdi mdi-open-in-new" />` +
// `</a>` +
// `${this.tei}</div>`
// this.parseLinks()
// this.parseFigures()
// // this.parsePageBreaks()
// // console.log('EdText: builded html', this.html)
// },
parseTei () {
this.teiparsed = this.tei
this.parseIndexItems()
this.parseLinks() this.parseLinks()
// this.parsePageBreaks() this.parseFigures()
// console.log('EdText: builded html', this.html)
if (this.textid === this.uuid) {
this.parseExtract()
}
},
parseIndexItems () {
let items = this.teiparsed.match(/<span[^>]*class="(persName|objectName|placeName)"[^>]*>[^<]+<\/span>/g)
console.log('items', items)
if (items) {
let itemparts, icon, newspan
for (var i = 0; i < items.length; i++) {
itemparts = RegExp(/(<span[^>]*class="([^"]+)"[^>]*>)(.+)<\/span>/g).exec(items[i], 'g')
// console.log('itemparts', itemparts)
switch (itemparts[2]) {
case 'placeName':
icon = '<span class="index-item-icon mdi mdi-map-marker"></span>'
break
case 'objectName':
icon = '<span class="index-item-icon mdi mdi-card-bulleted"></span>'
break
case 'persName':
icon = '<span class="index-item-icon mdi mdi-account"></span>'
break
}
// newspan = `${items[i]}&nbsp;${icon}`
// newspan = `<span class="no-wrap">${items[i]}&nbsp;${icon}</span>`
// newspan = `${itemparts[1]}${itemparts[3]}${'&#160;'}${icon}</span>`
let words = itemparts[3].split(' ')
let lastword = words.splice(words.length - 1, 1)
newspan = `${itemparts[1]}${words.join(' ')} <span class="no-wrap">${lastword}&nbsp;${icon}</span></span>`
this.teiparsed = this.teiparsed.replace(items[i], newspan)
}
}
}, },
parseLinks () { parseLinks () {
let links = this.html.match(/<a[^<]+<\/a>/g) let links = this.teiparsed.match(/<a[^<]+<\/a>/g)
// console.log('links', links) // console.log('links', links)
if (links) { if (links) {
// let domparser = new DOMParser() // let domparser = new DOMParser()
@@ -81,15 +153,51 @@ export default {
` v-touch:tap.prevent="onTapLink"` + ` v-touch:tap.prevent="onTapLink"` +
` v-touch-class="'tapped'"` + ` v-touch-class="'tapped'"` +
`>${linkparts[4]}` + `>${linkparts[4]}` +
`<sup class="mdi mdi-message-text-outline" />` + // `<sup class="mdi mdi-message-text-outline" />` +
`</a>` `</a>`
// console.log('newlink', newlink) // console.log('newlink', newlink)
this.html = this.html.replace(links[i], newlink) this.teiparsed = this.teiparsed.replace(links[i], newlink)
} }
} }
// console.log('this.html', this.html) // console.log('this.html', this.html)
} }
}, },
parseFigures () {
// console.log('parseFigures this.tei', this.teiparsed)
let imgs = this.teiparsed.match(/<img[^>]*>/g)
console.log('imgs', imgs)
if (imgs) {
let imgparts, newsrc, newimg
for (var i = 0; i < imgs.length; i++) {
// console.log(`link ${i}:`, links[i])
imgparts = RegExp(/<img src="(.+)" alt="(.+)">/g).exec(imgs[i], 'g')
console.log('imgparts', imgparts)
if (!imgparts) {
console.warn(`img ${i} malformed:`, imgs[i])
} else {
newsrc = `${imgparts[1]}/full/1000,/0/native.jpg`
newimg = `<img` +
` src="${newsrc}"` +
` alt="${imgparts[2]}"` +
`/>`
// console.log('newlink', newlink)
this.teiparsed = this.teiparsed.replace(imgs[i], newimg)
}
}
}
},
parseExtract () {
console.log('Parse extract', this.extractid)
// let regexp = RegExp(this.extract, 'gim')
let regexp = RegExp(`<span[^>]* id="${this.extractid}"[^>]*>[^<]*</span>`)
// let regexp = RegExp(`<(\w+)((?:\s+\w+(?:\s*=\s*(?:"[\s\S]*?"|'[\s\S]*?'|[^'">\s]+))?)+\s*|\s*)>([\s\S]*?)<\/\1>`)
let index = 0
function marking (str) {
index++
return `<mark class="extract" id="mark-${index}">${str}</mark>`
}
this.teiparsed = this.teiparsed.replace(regexp, marking)
},
// parsePageBreaks () { // parsePageBreaks () {
// let pbs = this.html.match(/<span role="pageBreak"[^>]+><\/span>/g) // let pbs = this.html.match(/<span role="pageBreak"[^>]+><\/span>/g)
// console.log('pagebreaks', pbs) // console.log('pagebreaks', pbs)
@@ -144,15 +252,23 @@ export default {
// console.log('EdText onLeaveLink(e)', e) // console.log('EdText onLeaveLink(e)', e)
this.$emit('onLeaveLink') this.$emit('onLeaveLink')
} }
}, // ,
render (h) { // onClickCopyClipboard (e) {
// console.log('EdText render()') // e.preventDefault()
if (!this.template) { // console.log('onClickCopyClipboard', e)
return h('span', 'Loading ...') // // navigator.clipboard.writeText(e.target.getAttribute('href'))
} else { // this.$copyText(e.target.getAttribute('href'))
return this.template.render.call(this) // return false
} // }
} }
// render (h) {
// // console.log('EdText render()')
// if (!this.template) {
// return h('span', 'Chargement ...')
// } else {
// return this.template.render.call(this)
// }
// }
} }
</script> </script>
+84
View File
@@ -0,0 +1,84 @@
<template>
<div class="textrefcopylink">
<span class="mdi mdi-open-in-new" />
<div class="popup">
<button
v-clipboard:copy="uuid"
v-clipboard:success="onCopy"
v-clipboard:error="onError"
type="button"
:title="btnuuidtitle"
class="copy-btn"
>
<!-- todo better label -->
{{ uuid }} <span class="mdi mdi-clipboard-outline" />
</button>
<button
v-clipboard:copy="linkhref"
v-clipboard:success="onCopy"
v-clipboard:error="onError"
type="button"
:title="btnurltitle"
class="copy-btn"
>
{{ linkhref }} <span class="mdi mdi-clipboard-outline" />
</button>
</div>
</div>
</template>
<script>
export default {
name: 'EdTextRefLink',
props: {
uuid: String,
url: String
},
computed: {
linkhref () {
// return `${window.apipath}/items/${this.uuid}`
return this.url
},
btnuuidtitle () {
return `Copy to clipboard ${this.uuid}`
},
btnurltitle () {
return `Copy to clipboard ${this.url}`
}
},
methods: {
onCopy (e) {
this.$swal({
text: `copié dans le press papier : ${e.text}`,
toast: false,
position: 'bottom-end',
timer: 2000,
icon: null,
backdrop: false,
showConfirmButton: false
})
},
onError (e) {
this.$swal('erreur')
}
// onClickCopyClipboard (e, s) {
// e.preventDefault()
// console.log('onClickCopyClipboard', s, e)
// // navigator.clipboard.writeText(e.target.getAttribute('href'))
// this.$copyText(s === 'ref' ? this.uuid : this.linkhref)
// .then(function (r) {
// console.log(this, r)
// // alert('Copied')
// this.$swal(`${s === 'ref' ? this.uuid : this.linkhref} copied`)
// }, function (r) {
// console.log(r)
// alert('Can not copy')
// })
// return false
// }
}
}
</script>
<style lang="scss" scoped>
</style>
+3 -1
View File
@@ -10,6 +10,7 @@
:level="1" :level="1"
:editionid="$route.params.id" :editionid="$route.params.id"
:loadedtextsuuids="loadedtextsuuids" :loadedtextsuuids="loadedtextsuuids"
:selectedindex="selectedindex"
@onClickTocItem="onClickTocItem" @onClickTocItem="onClickTocItem"
@onScrollToRef="onScrollToRef" @onScrollToRef="onScrollToRef"
/> />
@@ -29,7 +30,8 @@ export default {
}, },
props: { props: {
toc: Array, toc: Array,
loadedtextsuuids: Array loadedtextsuuids: Array,
selectedindex: Object
}, },
// watch: { // watch: {
// reftoscrollto: function (newref, oldref) { // reftoscrollto: function (newref, oldref) {
+128
View File
@@ -0,0 +1,128 @@
<template>
<section :class="{opened: isopened}">
<h4>
<a
v-if="oc.title"
:href="'/edition/'+oc.ed.uuid+'/'+oc.uuid+'/'+form"
:uuid="oc.uuid"
:eduuid="oc.ed.uuid"
:form="form"
@click.prevent="onGoToText"
@keyup.enter="onGoToText"
>
<span v-html="oc.title" /> <span v-if="oc.ed.uuid" class="edition">({{ editionTitle }})</span>
<!-- <span v-if="oc.form" class="form">( "{{ oc.form }}" )</span> -->
</a>
</h4>
<!-- <span
class="open-close"
@click.prevent="onOpenPreview"
@keyup.enter="onOpenPreview"
>
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="10" role="presentation" class="vs__open-indicator">
<path d="M9.211364 7.59931l4.48338-4.867229c.407008-.441854.407008-1.158247 0-1.60046l-.73712-.80023c-.407008-.441854-1.066904-.441854-1.474243 0L7 5.198617 2.51662.33139c-.407008-.441853-1.066904-.441853-1.474243 0l-.737121.80023c-.407008.441854-.407008 1.158248 0 1.600461l4.48338 4.867228L7 10l2.211364-2.40069z" />
</svg>
</span> -->
<!-- <div v-if="content" class="text" v-html="tei" /> -->
<!-- <a
v-if="content"
class="lire-plus"
:href="'/edition/'+ed.item+'/'+oc.uuid"
:uuid="oc.uuid"
:eduuid="ed.item"
@click.prevent="onGoToText"
@keyup.enter="onGoToText"
>
lire plus
</a> -->
</section>
</template>
<script>
// import { REST } from 'api/rest-axios'
import { mapState, mapActions } from 'vuex'
export default {
name: 'Occurence',
props: {
form: String,
oc: Object
},
data: () => ({
content: null,
isopened: false,
tei: ''
}),
computed: {
...mapState({
editionsbyuuid: state => state.Corpus.editionsbyuuid
}),
editionTitle () {
return this.editionsbyuuid[this.oc.ed.uuid].title
}
},
created () {
console.log('occurence beforeCreate')
// REST.get(`${window.apipath}/items/` + this.oc.uuid, {})
// .then(({ data }) => {
// console.log('occurence text REST: data', data)
// if (data.content) {
// this.content = data.content
// const subString = this.content.tei.substr(0, 500)
// this.tei = subString.substr(0, subString.lastIndexOf(' ')) + ' &hellip;'
// }
// })
// .catch((error) => {
// console.warn('Issue with nominum', error)
// Promise.reject(error)
// })
},
methods: {
...mapActions({
addHistoryItem: 'History/addItem'
}),
onGoToText (e) {
console.log('clicked on text occurence', e, this.oc.title, this.oc.ed)
if (e.target.getAttribute('eduuid')) {
this.addHistoryItem({
id: e.target.getAttribute('eduuid'),
textid: e.target.getAttribute('uuid'),
title: this.oc.title,
editionTitle: this.editionTitle
})
// if (e.target.getAttribute('form')) {
// this.$router.push({
// name: `editiontext`,
// params: {
// id: e.target.getAttribute('eduuid'),
// textid: e.target.getAttribute('uuid')
// }
// })
// } else {
this.$router.push({
name: `editiontextextract`,
params: {
id: e.target.getAttribute('eduuid'),
textid: e.target.getAttribute('uuid'),
extract: e.target.getAttribute('form')
}
})
// }
} else {
this.$router.push({
name: `edition`,
params: {
id: e.target.getAttribute('uuid')
}
})
}
},
onOpenPreview (e) {
this.isopened = !this.isopened
}
}
}
</script>
<style lang="scss" scoped>
</style>
+8 -4
View File
@@ -2,7 +2,7 @@
<article class="result item"> <article class="result item">
<h1> <h1>
<a <a
:href="'/edition/'+item.id+'/'+item.textid" :href="'/texts/'+item.id+'/'+item.textid"
@click.prevent="onclick" @click.prevent="onclick"
@keyup.enter="onclick" @keyup.enter="onclick"
v-html="item.title" v-html="item.title"
@@ -10,15 +10,19 @@
</h1> </h1>
<h2> <h2>
<a <a
:href="'/edition/'+item.id+'/'+item.textid" :href="'/texts/'+item.id+'/'+item.textid"
@click.prevent="onclick" @click.prevent="onclick"
@keyup.enter="onclick" @keyup.enter="onclick"
v-html="item.editionTitle" v-html="item.editionTitle"
/> />
</h2> </h2>
<!-- <p v-if="preview" class="preview" v-html="preview" /> --> <!-- <p v-if="preview" class="preview" v-html="preview" /> -->
<aside> <aside
<span>Pagination</span> | <span>Nbr mots</span> v-if="item.pages || item.size"
>
<span v-if="item.pages && item.pages.range">{{ item.pages.prefix }} {{ item.pages.range }}</span>
<span v-if="item.pages && item.size && item.pages.range && item.size.quantity"> | </span>
<span v-if="item.size && item.size.quantity">{{ item.size.quantity }} {{ item.size.unit }}</span>
</aside> </aside>
</article> </article>
</template> </template>
+67 -33
View File
@@ -1,56 +1,90 @@
<template> <template>
<section class="occurences"> <div>
<ul> <div class="tabs">
<li <span
v-for="ed in content.occurences" v-if="content.occurences"
:key="ed.item" class="tab"
> :class="{ active: tab === 'occurences' }"
<h3> @click.prevent="onclickTab('occurences')"
<a @keyup.enter="onclickTab('occurences')"
:href="'/edition/'+ed.item" >Occurences</span>
:uuid="ed.item" <span
@click.prevent="onclick" v-if="content.attestedForms"
@keyup.enter="onclick" class="tab"
> :class="{ active: tab === 'formes' }"
{{ ed.item }} @click.prevent="onclickTab('formes')"
</a> @keyup.enter="onclickTab('formes')"
</h3> >Formes attestées</span>
<ul> </div>
<li <section v-if="content.occurences" v-show="tab === 'occurences'" class="occurences">
v-for="oc in ocAsArray(ed.occurences)" <ul>
:key="oc.id" <li
> v-for="ed in content.occurences"
<!-- <li :key="ed.item"
v-for="oc in ed.occurences" >
:key="oc.uuid" <h3>
> --> <a
<occurence :ed="ed" :oc="oc" /> :href="'/texts/'+ed.item"
</li> :uuid="ed.item"
</ul> v-html="ed.biblio"
</li> />
</ul> </h3>
</section> <ul>
<li
v-for="oc in ocAsArray(ed.occurences)"
:key="oc.id"
>
<!-- <li
v-for="oc in ed.occurences"
:key="oc.uuid"
> -->
<occurence v-if="oc.title" :ed="ed" :oc="oc" />
</li>
</ul>
</li>
</ul>
</section>
<section v-if="content.attestedForms" v-show="tab === 'formes'" class="attested-forms-occurences">
<!-- <h3>Attested forms</h3> -->
<ul>
<li v-for="(af, i) in content.attestedForms" :key="i">
<h3 class="form">{{ af.title }}</h3>
<ul>
<li v-for="(oc, j) in af.occurences" :key="j">
<forme :form="af.title" :oc="oc" />
</li>
</ul>
</li>
</ul>
</section>
</div>
</template> </template>
<script> <script>
import Occurence from './Occurence' import Occurence from './Occurence'
import Forme from './Forme'
export default { export default {
name: 'IndexItemOcurrences', name: 'IndexItemOcurrences',
components: { components: {
Occurence Occurence,
Forme
}, },
props: { props: {
content: Object content: Object
}, },
data: () => ({ data: () => ({
tab: 'occurences'
}), }),
methods: { methods: {
ocAsArray (oc) { ocAsArray (oc) {
// not necesseary anymore (KB #758) // not necesseary anymore (KB #758)
console.log('Array.isArray(oc)', Array.isArray(oc)) console.log('Array.isArray(oc)', Array.isArray(oc))
return Array.isArray(oc) ? oc : [oc] return Array.isArray(oc) ? oc : [oc]
},
onclickTab (tab) {
this.tab = tab
} }
} }
} }
+3 -3
View File
@@ -6,10 +6,10 @@
:href="item.url" :href="item.url"
@click.prevent="onclick" @click.prevent="onclick"
@keyup.enter="onclick" @keyup.enter="onclick"
v-html="item.title" >
/> <span class="title" v-html="item.title" /> <span class="quantity">[{{ item.texts.length }}]</span>
</a>
</h1> </h1>
<p>{{ item.type }}</p>
</header> </header>
</article> </article>
</template> </template>
+3 -5
View File
@@ -6,12 +6,10 @@
:href="item.url" :href="item.url"
@click.prevent="onclick" @click.prevent="onclick"
@keyup.enter="onclick" @keyup.enter="onclick"
v-html="item.title" >
/> <span class="title" v-html="item.title" /> <span class="quantity">[{{ item.texts.length }}]</span>
</a>
</h1> </h1>
<p v-if="item.birth && item.death">
<span>{{ item.birth }}</span> -- <span>{{ item.death }}</span>
</p>
</header> </header>
</article> </article>
</template> </template>
+28 -14
View File
@@ -2,13 +2,15 @@
<section :class="{opened: isopened}"> <section :class="{opened: isopened}">
<h4> <h4>
<a <a
:href="'/edition/'+ed.item+'/'+oc.uuid" :href="'/texts/'+ed.item+'/'+oc.uuid+'/'+oc.ids[0]"
:uuid="oc.uuid" :uuid="oc.uuid"
:eduuid="ed.item" :eduuid="ed.item"
@click.prevent="onGoToText" :form="oc.form"
@keyup.enter="onGoToText" :ocid="oc.ids[0]"
@click.prevent="onGoToText($event, ed.item, oc.uuid, oc.ids[0])"
@keyup.enter="onGoToText($event, ed.item, oc.uuid, oc.ids[0])"
> >
{{ oc.title }} <span v-html="oc.title" /> <span v-if="oc.form" class="form" v-html="'( &laquo;'+oc.form+'&raquo; )'" />
</a> </a>
</h4> </h4>
<!-- <span <!-- <span
@@ -78,28 +80,40 @@ export default {
...mapActions({ ...mapActions({
addHistoryItem: 'History/addItem' addHistoryItem: 'History/addItem'
}), }),
onGoToText (e) { onGoToText (e, edid, textid, ocid) {
console.log('clicked on text occurence', e, this.oc.title, this.ed) console.log('clicked on text occurence', e, edid, textid, ocid)
if (e.target.getAttribute('eduuid')) { if (textid) {
this.addHistoryItem({ this.addHistoryItem({
id: e.target.getAttribute('eduuid'), id: edid,
textid: e.target.getAttribute('uuid'), textid: textid,
title: this.oc.title, title: this.oc.title,
editionTitle: this.editionTitle editionTitle: this.editionTitle,
ocid: ocid
}) })
// if (e.target.getAttribute('form')) {
// this.$router.push({
// name: `editiontext`,
// params: {
// id: e.target.getAttribute('eduuid'),
// textid: e.target.getAttribute('uuid')
// }
// })
// } else {
this.$router.push({ this.$router.push({
name: `editiontext`, name: `editiontextextract`,
params: { params: {
id: e.target.getAttribute('eduuid'), id: edid,
textid: e.target.getAttribute('uuid') textid: textid,
ocid: ocid
} }
}) })
// }
} else { } else {
this.$router.push({ this.$router.push({
name: `edition`, name: `edition`,
params: { params: {
id: e.target.getAttribute('uuid') id: edid
} }
}) })
} }
+1 -1
View File
@@ -9,7 +9,7 @@
@click.prevent="onclick" @click.prevent="onclick"
@keyup.enter="onclick" @keyup.enter="onclick"
> >
{{ item.title }} <span class="title" v-html="item.title" /> <span class="quantity">[{{ item.texts.length }}]</span>
</a> </a>
<span v-else class="red"> <span v-else class="red">
{{ item.title }} {{ item.title }}
+32 -14
View File
@@ -2,15 +2,15 @@
<article class="result item"> <article class="result item">
<h1> <h1>
<a <a
:href="'/edition/'+result.textId+'/'+result.uuid" :href="'/texts/'+result.textId+'/'+result.uuid+'/'+searchedkeys"
@click.prevent="onclick" @click.prevent="onclick"
@keyup.enter="onclick" @keyup.enter="onclick"
v-html="result.title" v-html="shorted_title"
/> />
</h1> </h1>
<h2> <h2>
<a <a
:href="'/edition/'+result.textId+'/'+result.uuid" :href="'/texts/'+result.textId+'/'+result.uuid+'/'+searchedkeys"
@click.prevent="onclick" @click.prevent="onclick"
@keyup.enter="onclick" @keyup.enter="onclick"
v-html="editionTitle" v-html="editionTitle"
@@ -33,6 +33,9 @@ export default {
result: { result: {
type: Object, type: Object,
required: true required: true
},
searchedkeys: {
type: String
} }
}, },
// data: () => ({ // data: () => ({
@@ -46,14 +49,25 @@ export default {
return this.editionsbyuuid[this.result.textId].title return this.editionsbyuuid[this.result.textId].title
} }
}, },
// created () { created () {
let max = 40
if (this.result.title) {
if (this.result.title.length > max) {
let subString = this.result.title.substr(0, max)
this.shorted_title = subString.substr(0, subString.lastIndexOf(' ')) + '&nbsp&hellip;'
} else {
this.shorted_title = this.result.title
}
} else {
console.warn(`no result title for ${this.result.uuid}`, this.result)
}
// if (this.result.extract) { // if (this.result.extract) {
// const subString = this.result.extract.substr(0, 80) // const subString = this.result.extract.substr(0, 80)
// this.preview = subString.substr(0, subString.lastIndexOf(' ')) + ' &hellip;' // this.preview = subString.substr(0, subString.lastIndexOf(' ')) + ' &hellip;'
// } else { // } else {
// console.warn(`No extract for ${this.result.textId}/${this.result.uuid}`) // console.warn(`No extract for ${this.result.textId}/${this.result.uuid}`)
// } // }
// }, },
methods: { methods: {
...mapActions({ ...mapActions({
addHistoryItem: 'History/addItem' addHistoryItem: 'History/addItem'
@@ -63,16 +77,20 @@ export default {
this.addHistoryItem({ this.addHistoryItem({
id: this.result.textId, id: this.result.textId,
textid: this.result.uuid, textid: this.result.uuid,
title: this.result.title[0], title: this.result.title,
editionTitle: this.editionTitle editionTitle: this.editionTitle,
}) pages: this.result.pages,
this.$router.push({ size: this.result.size
name: `editiontext`,
params: {
id: this.result.textId,
textid: this.result.uuid
}
}) })
// this.$router.push({
// name: `editiontextextract`,
// params: {
// id: this.result.textId,
// textid: this.result.uuid,
// extract: this.searchedkeys
// }
// })
this.$router.push({ path: `/texts/${this.result.textId}/${this.result.uuid}/${this.searchedkeys}` })
} }
} }
} }
+94 -11
View File
@@ -2,27 +2,47 @@
<section <section
:uuid="item.uuid" :uuid="item.uuid"
:level="level" :level="level"
:type="item.type"
class="tocitem"
:class="{
active: isActive,
loaded: isLoaded,
notitle: noTitle,
init_opened: isInitOpened,
opened: isOpened,
disabled: isDisabled
}"
> >
<component <component
:is="titlelevel" :is="titlelevel"
v-if="title" v-if="title"
class="toc-title" class="toc-title"
:uuid="item.uuid" :uuid="item.uuid"
:class="{active: isActive, loaded: isLoaded}" :class="{
active: isActive,
loaded: isLoaded,
notitle: noTitle,
init_opened: isInitOpened,
opened: isOpened,
disabled: isDisabled
}"
:type="item.type"
:level="level"
> >
<a <a
:href="'/edition/'+editionid+'/'+item.uuid" :href="'/texts/'+editionid+'/'+item.uuid"
:uuid="item.uuid" :uuid="item.uuid"
@click.prevent="onclick" @click.prevent="onclick"
@keyup.enter="onclick" @keyup.enter="onclick"
> v-html="title"
{{ title }} />
</a>
</component> </component>
<ul <ul
v-if="children.length" v-if="children.length"
class="toc-list" class="toc-list"
:class="{opened: isOpened}" :level="level"
:type="item.type"
:class="{init_opened: isInitOpened, opened: isOpened}"
> >
<li v-for="child in children" :key="child.uuid"> <li v-for="child in children" :key="child.uuid">
<TocItem <TocItem
@@ -30,6 +50,7 @@
:level="nextLevel" :level="nextLevel"
:editionid="editionid" :editionid="editionid"
:loadedtextsuuids="loadedtextsuuids" :loadedtextsuuids="loadedtextsuuids"
:selectedindex="selectedindex"
@onClickTocItem="onClickTocItem" @onClickTocItem="onClickTocItem"
@onScrollToRef="onScrollToRef" @onScrollToRef="onScrollToRef"
/> />
@@ -42,6 +63,8 @@
import TocItem from './TocItem' import TocItem from './TocItem'
import { mapState, mapActions } from 'vuex'
export default { export default {
name: 'TocItem', name: 'TocItem',
components: { components: {
@@ -51,12 +74,21 @@ export default {
item: Object, item: Object,
level: Number, level: Number,
editionid: String, editionid: String,
loadedtextsuuids: Array loadedtextsuuids: Array,
selectedindex: Object
}, },
data: () => ({ data: () => ({
isOpened: false isInitOpened: false,
isOpened: false,
noTitle: false
}), }),
computed: { computed: {
...mapState({
editionsbyuuid: state => state.Corpus.editionsbyuuid
}),
editionTitle () {
return this.editionsbyuuid[this.editionid].title
},
children () { children () {
// check if children exists and if it is an array // check if children exists and if it is an array
// this shoudn't be necessary // this shoudn't be necessary
@@ -65,9 +97,13 @@ export default {
title () { title () {
// this shoudn't be necessary // this shoudn't be necessary
if (this.item.title && Array.isArray(this.item.title)) { if (this.item.title && Array.isArray(this.item.title)) {
return this.item.title.join(' ') return this.truncate(this.item.title.join(' '), 80, true)
} else if (this.item.title) {
return this.truncate(this.item.title, 80, true)
} else { } else {
return this.item.title // console.log('TOC no title', this.item)
// return this.item.type
return null
} }
}, },
titlelevel () { titlelevel () {
@@ -89,6 +125,16 @@ export default {
// but not for isOpened (had to use a watcher + beforeMount) // but not for isOpened (had to use a watcher + beforeMount)
// don't now why ? // don't now why ?
return this.loadedtextsuuids.indexOf(this.item.uuid) !== -1 return this.loadedtextsuuids.indexOf(this.item.uuid) !== -1
},
isDisabled () {
let disabled = false
if (this.selectedindex &&
(!this.flat_indexes.length || this.flat_indexes.indexOf(this.selectedindex.code) === -1)
) {
// console.log('tocitem disabled ?', this.selectedindex.code)
disabled = true
}
return disabled
} }
}, },
watch: { watch: {
@@ -104,14 +150,51 @@ export default {
} }
} }
}, },
created () {
console.log('TocItem created', this.item)
this.flat_indexes = []
Object.keys(this.item.indexes[0]).forEach(index => {
this.item.indexes[0][index].forEach(element => {
this.flat_indexes.push(element.uuid)
})
})
// console.log('tocItem created flat_indexes', this.flat_indexes)
},
beforeMount () { beforeMount () {
if (typeof this.$route.params.textid !== 'undefined') { if (typeof this.$route.params.textid !== 'undefined') {
this.isOpened = this.$route.params.textid.indexOf(this.item.uuid) >= 0 this.isOpened = this.$route.params.textid.indexOf(this.item.uuid) >= 0
} }
// if (this.level <= 2 && ['book', 'volume'].indexOf(this.item.type) === -1) {
if (this.level === 1 ||
(this.level === 2 && ['part', 'book', 'volume', 'front', 'body', 'back', 'div'].indexOf(this.item.type) >= 0)
) {
this.isInitOpened = true
}
if (!this.item.title) {
this.noTitle = true
}
}, },
methods: { methods: {
...mapActions({
addHistoryItem: 'History/addItem'
}),
truncate (str, n, useWordBoundary) {
if (str.length <= n) { return str }
const subString = str.slice(0, n - 1) // the original check
return (useWordBoundary
? subString.slice(0, subString.lastIndexOf(' '))
: subString) + '&nbsp;...'
},
onclick (e) { onclick (e) {
// console.log('clicked on toc text', this.editionid, e) console.log('clicked on toc text', this.item, e)
this.addHistoryItem({
id: this.editionid,
textid: this.item.uuid,
title: this.item.title,
editionTitle: this.editionTitle,
pages: this.item.pages,
size: this.item.size
})
this.$emit('onClickTocItem', e.target.getAttribute('uuid')) this.$emit('onClickTocItem', e.target.getAttribute('uuid'))
}, },
onClickTocItem (uuid) { onClickTocItem (uuid) {
+34 -5
View File
@@ -3,12 +3,20 @@
:id="id" :id="id"
class="full-width med-row large-row main-content-layout" class="full-width med-row large-row main-content-layout"
> >
<header class="med-col-3 large-col-3"> <header class="med-col-3 large-col-3" :class="{ opened: headeropened }">
<slot name="header" /> <slot name="header" />
</header> </header>
<section ref="scrollablecenter" class="med-col-6 large-col-6" @scroll.passive="onScrollCenter"> <section
<slot /> class="med-col-6 large-col-6"
>
<div
ref="scrollablecenter"
class="wrapper"
@scroll.passive="onScrollCenter"
>
<slot />
</div>
</section> </section>
<nav class="med-col-3 large-col-3" :class="{ opened: navopened }"> <nav class="med-col-3 large-col-3" :class="{ opened: navopened }">
@@ -27,6 +35,7 @@ export default {
required: true required: true
}, },
reftoscrollto: { type: String }, reftoscrollto: { type: String },
headeropened: { type: Boolean },
navopened: { type: Boolean } navopened: { type: Boolean }
}, },
watch: { watch: {
@@ -35,15 +44,35 @@ export default {
this.scrollToRef() this.scrollToRef()
} }
}, },
mounted () {
console.log('mounted')
this.scrollToRef()
},
methods: { methods: {
onScrollCenter (e) { onScrollCenter (e) {
// console.log('mainLayout onScrollCenter: e', e) console.log('mainLayout onScrollCenter: e', e)
this.$emit('onCenterScrolled', e) this.$emit('onCenterScrolled', e)
// attribute scrollToRef is created then removed by this.$scrollTo()
// we want to close the history panle only when user scroll the center
// not when we click on toc item
if (!e.currentTarget.hasAttribute('scrollToRef')) {
this.$store.commit('History/setOpened', false)
}
}, },
scrollToRef () { scrollToRef () {
console.log('scrollToRef', this.reftoscrollto, this.$refs) console.log('scrollToRef', this.reftoscrollto, this.$refs)
this.$scrollTo(this.reftoscrollto, 500, { this.$scrollTo(this.reftoscrollto, 500, {
container: this.$refs.scrollablecenter container: this.$refs.scrollablecenter,
onStart: function (e) {
console.log('$scrollTo start', e, this)
this.setAttribute('scrollToRef', true)
}.bind(this.$refs.scrollablecenter),
onDone: function (e) {
setTimeout(function () {
console.log('$scrollTo done', e, this)
this.removeAttribute('scrollToRef')
}.bind(this), 100)
}.bind(this.$refs.scrollablecenter)
}) })
} }
} }
+7 -1
View File
@@ -24,7 +24,7 @@
@click.prevent="openResults" @click.prevent="openResults"
@keydown.enter.prevent="openResults" @keydown.enter.prevent="openResults"
> >
Resultas Resultats
</span> </span>
</transition> </transition>
</div> </div>
@@ -53,6 +53,12 @@ export default {
historyItems: state => state.History.items historyItems: state => state.History.items
}) })
}, },
watch: {
$route (n, o) {
// console.log('route changed')
this.resultsOpened = false
}
},
methods: { methods: {
openResults () { openResults () {
this.resultsOpened = true this.resultsOpened = true
+32 -12
View File
@@ -1,27 +1,37 @@
<template> <template>
<nav id="header-menu"> <nav id="header-menu" ref="header_menu">
<ul v-if="corpusLoaded"> <!-- <span v-if="!corpusLoaded" class="loading">Chargement ...</span> -->
<li><router-link to="/corpus">Corpus</router-link></li> <span
<li :class="{ opened: indexOpened }"> class="mdi mdi-menu burger-btn"
@click.prevent="onClickBTN"
@keyup.enter="onClickBTN"
/>
<ul>
<li>
<span v-if="!corpusLoaded" class="loading">Chargement ...</span>
<router-link v-else to="/corpus">Corpus</router-link>
</li>
<li class="has-submenu" :class="{ opened: indexOpened }">
<!-- tabindex="-1" -->
<span <span
@click.prevent="onClickIndex" @click.prevent="onClickIndex"
@keyup.enter="onClickIndex" @keyup.enter="onClickIndex"
> >
Indexs Index
</span> </span>
<ul> <ul>
<li><router-link to="/nominum">Personnes</router-link></li> <li><router-link to="/indexNominum">Personnes</router-link></li>
<li><router-link to="/locorum">Lieux</router-link></li> <li><router-link to="/indexLocorum">Lieux</router-link></li>
<li><router-link to="/operum">Œuvres</router-link></li> <li><router-link to="/indexOperum">Œuvres</router-link></li>
</ul> </ul>
</li> </li>
<li><router-link to="/bibliographie">Bibliographie</router-link></li> <li><router-link to="/bibliography">Bibliographie</router-link></li>
<li><a href="#">Blog</a></li> <li><router-link to="/schema">Schema</router-link></li>
<li> <!-- <li>
<a href="#" class="mdi mdi-login-variant" title="connexion"> <a href="#" class="mdi mdi-login-variant" title="connexion">
<span class="visualy-hidden">connexion</span> <span class="visualy-hidden">connexion</span>
</a> </a>
</li> </li> -->
</ul> </ul>
</nav> </nav>
</template> </template>
@@ -40,10 +50,20 @@ export default {
corpusLoaded: state => state.Corpus.corpusLoaded corpusLoaded: state => state.Corpus.corpusLoaded
}) })
}, },
watch: {
$route (n, o) {
// console.log('route changed')
this.indexOpened = false
this.$refs.header_menu.classList.remove('opened')
}
},
methods: { methods: {
onClickIndex (e) { onClickIndex (e) {
console.log('onClickIndex') console.log('onClickIndex')
this.indexOpened = !this.indexOpened this.indexOpened = !this.indexOpened
},
onClickBTN () {
this.$refs.header_menu.classList.toggle('opened')
} }
} }
} }
+1 -1
View File
@@ -20,7 +20,7 @@
<nav class="col-1 tools"> <nav class="col-1 tools">
<span <span
class="mdi mdi-close" class="mdi mdi-close"
title="close" title="Fermer l'historique de consultation"
@click.prevent="close" @click.prevent="close"
@keydown.enter.prevent="close" @keydown.enter.prevent="close"
/> />
+8 -6
View File
@@ -8,8 +8,10 @@
> >
<header class="small-col-12 med-col-1 large-col-1"> <header class="small-col-12 med-col-1 large-col-1">
<h2>Resultats</h2> <h2>Resultats</h2>
<span class="search-keys">{{ searchedKeys }}</span> <div class="results-details">
<span v-if="resultsQuantity" class="results-count">{{ resultsCount }}</span> <span class="search-keys">{{ searchedKeys }}</span>
<span v-if="resultsQuantity" class="results-count">{{ resultsCount }}</span>
</div>
<v-select <v-select
id="sorting" id="sorting"
type="select" type="select"
@@ -25,7 +27,7 @@
<div class="wrapper"> <div class="wrapper">
<ul v-if="results.length"> <ul v-if="results.length">
<li v-for="result in results" :key="result.uuid" class="result"> <li v-for="result in results" :key="result.uuid" class="result">
<ResultItem :result="result" /> <ResultItem :result="result" :searchedkeys="searchedKeys" />
</li> </li>
<infinite-loading <infinite-loading
v-if="offset < resultsQuantity.quantity" v-if="offset < resultsQuantity.quantity"
@@ -38,7 +40,7 @@
<nav class="col-1 tools"> <nav class="col-1 tools">
<span <span
class="mdi mdi-close" class="mdi mdi-close"
title="close" title="Fermer les résultats de recherche"
@click.prevent="close" @click.prevent="close"
@keydown.enter.prevent="close" @keydown.enter.prevent="close"
/> />
@@ -109,7 +111,7 @@ export default {
* above. * above.
*/ */
const popper = createPopper(component.$refs.toggle, dropdownList, { const popper = createPopper(component.$refs.toggle, dropdownList, {
placement: 'top', placement: 'bottom',
modifiers: [ modifiers: [
{ {
name: 'offset', name: 'offset',
@@ -122,7 +124,7 @@ export default {
enabled: true, enabled: true,
phase: 'write', phase: 'write',
fn ({ state }) { fn ({ state }) {
component.$el.classList.toggle('drop-up', state.placement === 'top') component.$el.classList.toggle('drop-up', state.placement === 'bottom')
} }
}] }]
}) })
+58 -19
View File
@@ -1,14 +1,14 @@
<template> <template>
<div id="search" class="col-11" :class="{ loading: isloading }"> <div id="search" class="" :class="[isloading ? loading : '', wrapperClass]">
<form class="search-form row"> <form class="search-form row">
<fieldset class="search small-col-10 med-col-2 large-col-2"> <fieldset class="" :class="['search', 'small-col-10', firstFieldsetClass]">
<div> <div>
<label for="keys">Search</label> <label for="keys">Recherche</label>
<input <input
id="keys" id="keys"
v-model="keys" v-model="keys"
type="text" type="text"
placeholder="search" placeholder="Rechercher"
@keydown.enter.prevent="submit" @keydown.enter.prevent="submit"
> >
<v-select <v-select
@@ -37,11 +37,23 @@
title="chargement" title="chargement"
/> />
</fieldset> </fieldset>
<fieldset v-if="filters.persons.length" class="filters filters-nominum small-col-4 med-col-2 large-col-2"> <fieldset v-if="filters.texts.length && searchOpened" class="filters filters-texts small-col-4 med-col-2 large-col-2">
<v-select
id="filters-texts"
type="select"
placeholder="Filtrer par textes"
append-to-body
:calculate-position="dropDownMenuPos"
:options="textsOptions"
:value="activeFilters.texts"
@input="onFiltersTextSelected"
/>
</fieldset>
<fieldset v-if="filters.persons.length && searchOpened" class="filters filters-nominum small-col-4 med-col-2 large-col-2">
<v-select <v-select
id="filters-nominum" id="filters-nominum"
type="select" type="select"
placeholder="filtrer par personne" placeholder="Filtrer par personnes"
append-to-body append-to-body
:calculate-position="dropDownMenuPos" :calculate-position="dropDownMenuPos"
:options="personsOptions" :options="personsOptions"
@@ -50,11 +62,11 @@
@input="onFiltersNominumSelected" @input="onFiltersNominumSelected"
/> />
</fieldset> </fieldset>
<fieldset v-if="filters.places.length" class="filters filters-locorum small-col-4 med-col-2 large-col-2"> <fieldset v-if="filters.places.length && searchOpened" class="filters filters-locorum small-col-4 med-col-2 large-col-2">
<v-select <v-select
id="filters-locorum" id="filters-locorum"
type="select" type="select"
placeholder="filtrer par lieux" placeholder="Filtrer par lieux"
append-to-body append-to-body
:calculate-position="dropDownMenuPos" :calculate-position="dropDownMenuPos"
:options="placesOptions" :options="placesOptions"
@@ -63,11 +75,11 @@
@input="onFiltersLocorumSelected" @input="onFiltersLocorumSelected"
/> />
</fieldset> </fieldset>
<fieldset v-if="filters.objects.length" class="filters filters-operum small-col-4 med-col-2 large-col-2"> <fieldset v-if="filters.objects.length && searchOpened" class="filters filters-operum small-col-4 med-col-2 large-col-2">
<v-select <v-select
id="filters-operum" id="filters-operum"
type="select" type="select"
placeholder="filtrer par objet" placeholder="Filtrer par œuvres"
append-to-body append-to-body
:calculate-position="dropDownMenuPos" :calculate-position="dropDownMenuPos"
:options="objectsOptions" :options="objectsOptions"
@@ -91,19 +103,36 @@ export default {
data: () => ({ data: () => ({
}), }),
computed: { computed: {
// TODO: do not synch keys instantetly (infinite loading will drop) // searchOpened: {
keys: { // get () { return this.$store.state.Search.opened },
get () { return this.$store.state.Search.keys }, // set (value) { this.$store.commit('Search/setOpened', value) }
set (value) { this.$store.commit('Search/setKeys', value) } // },
},
...mapState({ ...mapState({
isloading: state => state.Search.isloading, isloading: state => state.Search.isloading,
searchTypeOptions: state => state.Search.searchTypeOptions, searchTypeOptions: state => state.Search.searchTypeOptions,
searchTypeValue: state => state.Search.searchTypeValue, searchTypeValue: state => state.Search.searchTypeValue,
filters: state => state.Search.filters, filters: state => state.Search.filters,
activeFilters: state => state.Search.activeFilters, activeFilters: state => state.Search.activeFilters,
corpusLoaded: state => state.Corpus.corpusLoaded searchOpened: state => state.Search.opened,
corpusLoaded: state => state.Corpus.corpusLoaded,
results: state => state.Corpus.results
}), }),
// TODO: do not synch keys instantetly (infinite loading will drop)
wrapperClass () {
console.log('this.$route.name', this.$route.name)
if (this.$route.name === 'home' && (!this.results || !this.results.length)) {
return 'small-col-11 med-col-4 large-col-4'
} else {
return 'med-col-11 large-col-11'
}
},
firstFieldsetClass () {
return (this.$route.name === 'home' && (!this.results || !this.results.length)) ? 'med-col-10 large-col-10' : 'med-col-4 large-col-4'
},
keys: {
get () { return this.$store.state.Search.keys },
set (value) { this.$store.commit('Search/setKeys', value) }
},
personsOptions () { personsOptions () {
return this.filters.persons.filter(option => !this.activeFilters.persons.includes(option)) return this.filters.persons.filter(option => !this.activeFilters.persons.includes(option))
}, },
@@ -112,7 +141,11 @@ export default {
}, },
objectsOptions () { objectsOptions () {
return this.filters.objects.filter(option => !this.activeFilters.objects.includes(option)) return this.filters.objects.filter(option => !this.activeFilters.objects.includes(option))
},
textsOptions () {
return this.filters.texts.filter(option => !this.activeFilters.texts.includes(option))
} }
}, },
methods: { methods: {
...mapMutations({ ...mapMutations({
@@ -175,17 +208,23 @@ export default {
}, },
onFiltersNominumSelected (e) { onFiltersNominumSelected (e) {
console.log('onFiltersNominumSelected', e) console.log('onFiltersNominumSelected', e)
this.setActiveFilters({ index: 'persons', value: e }) this.setActiveFilters({ filter: 'persons', value: e })
this.updateSearch() this.updateSearch()
}, },
onFiltersLocorumSelected (e) { onFiltersLocorumSelected (e) {
console.log('onFiltersLocorumSelected', e) console.log('onFiltersLocorumSelected', e)
this.setActiveFilters({ index: 'places', value: e }) this.setActiveFilters({ filter: 'places', value: e })
this.updateSearch() this.updateSearch()
}, },
onFiltersOperumSelected (e) { onFiltersOperumSelected (e) {
console.log('onFiltersOperumSelected', e) console.log('onFiltersOperumSelected', e)
this.setActiveFilters({ index: 'objects', value: e }) this.setActiveFilters({ filter: 'objects', value: e })
this.updateSearch()
},
onFiltersTextSelected (e) {
console.log('onFiltersTextSelected', e)
// as texts is not multiple, convert one object value to array [e]
this.setActiveFilters({ filter: 'texts', value: e ? [e] : [] })
this.updateSearch() this.updateSearch()
} }
} }
+20 -2
View File
@@ -7,12 +7,17 @@ import InfiniteLoading from 'vue-infinite-loading'
import VueScrollTo from 'vue-scrollto' import VueScrollTo from 'vue-scrollto'
import VueSelect from 'vue-select' import VueSelect from 'vue-select'
import Vue2TouchEvents from 'vue2-touch-events' import Vue2TouchEvents from 'vue2-touch-events'
import VueClipboard from 'vue-clipboard2'
import VueSweetalert2 from 'vue-sweetalert2'
import App from './App' import App from './App'
import 'assets/css/mdi/css/materialdesignicons.css' import 'assets/css/mdi/css/materialdesignicons.css'
// import 'mdi/font' // import 'mdi/font'
import 'vue-select/src/scss/vue-select.scss' import 'vue-select/src/scss/vue-select.scss'
import 'sweetalert2/dist/sweetalert2.min.css'
import '@sweetalert2/themes/dark/dark.scss'
import 'assets/css/app.scss' import 'assets/css/app.scss'
Vue.use(Meta) Vue.use(Meta)
@@ -33,9 +38,22 @@ Vue.use(InfiniteLoading, {
Vue.use(VueScrollTo) Vue.use(VueScrollTo)
Vue.component('v-select', VueSelect) Vue.component('v-select', VueSelect)
Vue.use(Vue2TouchEvents) Vue.use(Vue2TouchEvents)
Vue.use(VueClipboard)
Vue.use(VueSweetalert2)
window.apipath = process.env === 'prod' ? `http://${window.location.hostname}/api` : 'http://localhost:8984' // https://apple.stackexchange.com/questions/17077/add-a-hosts-file-entry-without-jailbreaking
// window.apipath = process.env === 'prod' || window.location.hostname === 'dev.gdp.fr' ? `http://${window.location.hostname}/api` : 'http://localhost:8984'
if (process.env === 'prod') {
window.apipath = `https://api.guidesdeparis.fr`
} else if (window.location.hostname === 'dev.gdp.fr') {
window.apipath = `http://${window.location.hostname}/api`
} else {
window.apipath = 'http://localhost:8984'
}
// if (window.location.hostname === 'dev.gdp.fr') {
// window.apipath = `http://${window.location.hostname}/api`
// }
// window.apipath = `http://${window.location.hostname}:8984`
// sync(store, router) // done. Returns an unsync callback fn // sync(store, router) // done. Returns an unsync callback fn
new Vue({ new Vue({
+263 -27
View File
@@ -1,9 +1,9 @@
<template> <template>
<MainContentLayout id="biblio"> <MainContentLayout id="biblio">
<template v-if="!content" #header> <template v-if="!expressions.meta || !manifestations.meta" #header>
<span>Loading ...</span> <span class="loading">Chargement ...</span>
</template> </template>
<template #header> <template v-else #header>
<h1> <h1>
<router-link :to="{ name:'bibliographie'}">Bibliographie</router-link> <router-link :to="{ name:'bibliographie'}">Bibliographie</router-link>
</h1> </h1>
@@ -12,15 +12,17 @@
<li> <li>
<router-link <router-link
:to="{ name:'bibliographie', params: { type: 'expressions'}}" :to="{ name:'bibliographie', params: { type: 'expressions'}}"
title="Consulter la liste des expressions"
> >
Expressions {{ expressions.meta.quantity.quantity }} {{ expressions.meta.quantity.unit }}
</router-link> </router-link>
</li> </li>
<li> <li>
<router-link <router-link
:to="{ name:'bibliographie', params: { type: 'manifestations'}}" :to="{ name:'bibliographie', params: { type: 'manifestations'}}"
title="Consulter toutes les manifestations"
> >
Manifestations {{ manifestations.meta.quantity.quantity }} {{ manifestations.meta.quantity.unit }}
</router-link> </router-link>
</li> </li>
</ul> </ul>
@@ -28,39 +30,131 @@
</template> </template>
<!-- default slot --> <!-- default slot -->
<!-- expressions or manifestations list --> <!-- expressions list -->
<template v-if="!uuid"> <template v-if="!uuid && type === 'expressions'">
<ul class="item-list"> <ul class="item-list">
<li v-for="item in content" :key="item.uuid"> <li v-for="item in expressions.content" :key="item.uuid">
<h2> <h2>
<router-link <router-link
v-if="item.authors"
:to="{ name:'bibliographieItem', params:{ type:type, uuid:item.uuid } }" :to="{ name:'bibliographieItem', params:{ type:type, uuid:item.uuid } }"
title="Consulter la notice de l'expression"
> >
{{ item.authors }} {{ item.authors }}
</router-link> </router-link>
<span v-else>/!\ No authors /!\</span>
</h2> </h2>
<p class="date">{{ item.dates }}</p> <p v-if="item.dates" class="date">{{ item.dates }}</p>
<p class="titles">{{ item.titles }}</p> <em v-if="item.titles" class="titles">{{ item.titles }}</em>
<aside v-if="item.manifestations && item.manifestations.length">
<h5
@click.prevent="onToggleManifs"
@keyup.enter="onToggleManifs"
>Afficher les manifestations</h5>
<ul>
<li v-for="manif in item.manifestations" :key="manif.uuid">
<span class="date">{{ manif.dates }} </span>
<router-link
:to="{ name:'bibliographieItem', params:{ type:'manifestations', uuid:manif.uuid } }"
title="Consulter la notice de la manifestation"
>
<em>{{ manif.titles }}</em>
</router-link>
</li>
</ul>
</aside>
</li> </li>
</ul> </ul>
</template> </template>
<!-- or item --> <!-- manifestations list -->
<template v-else> <template v-if="!uuid && type === 'manifestations'">
<div class="biblio-item"> <ul class="item-list manifestations">
<h2>{{ content.authors }}</h2> <li
<p v-if="content.dates" class="date">{{ content.dates }}</p> v-for="item in manifestations.content" :key="item.uuid"
<p class="titles">{{ content.titles }}</p> :class="isInActiveAuthors(item.authors)"
<ul vi-if="content.manifestations.length" class="item-list"> >
<li v-for="item in content.manifestations" :key="item.uuid"> <div class="wrapper">
<span class="date">{{ item.dates }} </span>
<router-link <router-link
:to="{ name:'bibliographieItem', params:{ type:'manifestations', uuid:item.uuid } }" :to="{ name:'bibliographieItem', params:{ type:'manifestations', uuid:item.uuid } }"
v-html="item.tei" >
<em class="titles">{{ item.titles }}</em>
</router-link>
<!-- <p class="authors">{{ item.authors }}</p> -->
</div>
</li>
</ul>
</template>
<!-- or expression / manifestation item -->
<template v-if="uuid">
<div class="biblio-item">
<h3 v-if="item.type" class="type">{{ item.type }}</h3>
<h2 v-html="item.tei" />
<p class="author"><span class="label">Auteur :</span> {{ item.authors }}</p>
<p v-if="item.dates" class="date"><span class="label">Dates :</span> {{ item.dates }}</p>
<p v-if="item.edition" class="edition"><span class="label">Édition :</span> {{ item.edition }}</p>
<p v-if="item.editeur" class="editeur" v-html="editeur" />
<p v-if="item.lieu" class="lieu"><span class="label">Lieu de publication :</span> {{ item.lieu }}</p>
<p v-if="item.extent" class="extent"><span class="label">Format :</span> {{ item.extent }}</p>
<!-- manifestation -->
<h3 v-if="item.manifestations && item.manifestations.length">Liste des manifestations :</h3>
<ul v-if="item.manifestations && item.manifestations.length" class="item-list">
<li v-for="manif in item.manifestations" :key="manif.uuid">
<router-link
:to="{ name:'bibliographieItem', params:{ type:'manifestations', uuid:manif.uuid } }"
title="Consulter la notice de la manifestation"
v-html="manif.tei"
/> />
</li> </li>
</ul> </ul>
<!-- note -->
<h3 v-if="item.notes && item.notes.length">Note :</h3>
<ul v-if="item.notes && item.notes.length" class="notes-list">
<li v-for="note in item.notes" :key="note.uuid">
<p v-html="note" />
</li>
</ul>
<!-- BNF -->
<h3 v-if="noticesbnf.length">Notices BnF :</h3>
<ul v-if="noticesbnf.length" class="item-list">
<li v-for="id in noticesbnf" :key="id.url">
<a :href="id.url">{{ id.type }}: {{ id.url }}</a>
</li>
</ul>
<!-- GALLICA -->
<h3 v-if="noticesgallica.length">Exemplaires sur Gallica :</h3>
<ul v-if="noticesgallica.length" class="item-list">
<li v-for="id in noticesgallica" :key="id.url">
<a :href="id.url">{{ id.type }}: {{ id.url }}</a>
</li>
</ul>
</div> </div>
</template> </template>
<template #nav />
<template v-if="!uuid && type === 'manifestations'" #nav>
<ul class="authors-filters">
<li
v-for="author in authors" :key="author"
>
<span
:class="isInActiveAuthors(author)"
@click.prevent="onToggleAuthors(author)"
@keyup.enter="onToggleAuthors(author)"
>{{ author }}</span>
</li>
</ul>
</template>
<template v-if="item.url && item.uuid && item.path" #nav>
<aside class="links">
<p>
Permalien:<br><a :href="`${item.url}`">{{ item.url }}</a>
</p>
<p>
JSON:<br><a :href="`${apipath}${item.path}${item.uuid}`">{{ apipath }}{{ item.path }}{{ item.uuid }}</a>
</p>
</aside>
</template>
</MainContentLayout> </MainContentLayout>
</template> </template>
@@ -82,32 +176,174 @@ export default {
uuid: String uuid: String
}, },
data: () => ({ data: () => ({
content: Array content: Array,
manifestations: Array,
expressions: Array,
authors: Array,
activeAuthors: Array,
item: Array
}), }),
computed: {
apipath () {
return window.apipath
},
editeur () {
return '<span class="label">Éditeur : </span>' + this.item.editeur
},
noticesbnf (item) {
let n = []
if (this.item && this.item.idno && this.item.idno.length) {
this.item.idno.forEach(id => {
if (id.type === 'catBnf') {
n.push(id)
}
})
}
return n
},
noticesgallica (item) {
let n = []
if (this.item && this.item.idno && this.item.idno.length) {
this.item.idno.forEach(id => {
if (id.type === 'gallica') {
n.push(id)
}
})
}
return n
}
},
watch: { watch: {
$route (to, from) { $route (to, from) {
this.getContent() console.log('watch $route to', to)
// this.getContent()
if (to.params.uuid) {
this.getItem(to.params.type, to.params.uuid)
}
} }
}, },
created () { created () {
// this.type = this.$route.params.type || 'expressions' // this.type = this.$route.params.type || 'expressions'
// this.uuid = this.$route.params.id || null // this.uuid = this.$route.params.id || null
this.activeAuthors = []
this.getContent() this.getContent()
if (this.$route.params.uuid) {
this.getItem(this.$route.params.type, this.$route.params.uuid)
}
}, },
methods: { methods: {
getContent () { getContent () {
// ?_format=json REST.get(`${window.apipath}/bibliography/expressions`, {})
REST.get(`${window.apipath}/bibliography/${this.type}/${this.uuid || ''}`, {})
.then(({ data }) => { .then(({ data }) => {
console.log('Biblio REST: data', data) console.log('Biblio REST expressions: data', data)
if (data.content) { if (data.content) {
this.content = data.content this.expressions = data
REST.get(`${window.apipath}/bibliography/manifestations`, {})
.then(({ data }) => {
console.log('Biblio REST manifestations: data', data)
if (data.content) {
this.manifestations = data
}
this.parseContents()
})
.catch((error) => {
console.warn('Issue with bibliographie manifestations', error)
Promise.reject(error)
})
} }
}) })
.catch((error) => { .catch((error) => {
console.warn('Issue with bibliographie', error) console.warn('Issue with bibliographie expressions', error)
Promise.reject(error) Promise.reject(error)
}) })
// // ?_format=json
// REST.get(`${window.apipath}/bibliography/${this.type}/${this.uuid || ''}`, {})
// .then(({ data }) => {
// console.log('Biblio REST: data', data)
// if (data.content) {
// this.content = data.content
// }
// })
// .catch((error) => {
// console.warn('Issue with bibliographie', error)
// Promise.reject(error)
// })
},
getItem (type, uuid) {
REST.get(`${window.apipath}/bibliography/${type}/${uuid}`, {})
.then(({ data }) => {
console.log('Biblio REST item: data', data)
if (data.content) {
this.item = data.content
console.log('getItem item', this.item)
}
})
.catch((error) => {
console.warn('Issue with bibliographie get item', error)
Promise.reject(error)
})
},
parseContents () {
this.expressions.content = this.expressions.content.sort((a, b) => {
let Adate = parseInt(a.dates)
let Bdate = parseInt(b.dates)
if (Adate < Bdate) {
return -1
} else if (Adate > Bdate) {
return 1
} else {
return 0
}
})
this.manifestations.content = this.manifestations.content.sort((a, b) => {
let Adate = parseInt(a.dates)
let Bdate = parseInt(b.dates)
if (Adate < Bdate) {
return -1
} else if (Adate > Bdate) {
return 1
} else {
return 0
}
})
this.authors = []
this.manifestations.content.forEach(manif => {
// console.log('manif', manif)
if (this.authors.indexOf(manif.authors) === -1) {
this.authors.push(manif.authors)
this.activeAuthors.push(manif.authors)
}
// console.log('authors', this.authors)
})
this.expressions.content.forEach((expr, i) => {
let manifs = []
this.manifestations.content.forEach((manif, j) => {
if (manif.authors !== '' && manif.authors === expr.authors) {
manifs.push(manif)
}
})
this.expressions.content[i].manifestations = manifs
})
this.content = this.expressions.content
console.log('Biblio content parsed', this.expressions, this.manifestations)
},
onToggleManifs (e) {
console.log('togle manifs', e)
let aside = e.target.parentNode
// console.log('aside', aside)
aside.classList.toggle('opened')
},
isInActiveAuthors (authors) {
return this.activeAuthors.indexOf(authors) !== -1 ? 'active' : null
},
onToggleAuthors (author) {
if (this.activeAuthors.indexOf(author) === -1) {
this.activeAuthors.push(author)
} else {
this.activeAuthors.splice(this.activeAuthors.indexOf(author), 1)
}
} }
} }
} }
+250 -68
View File
@@ -3,17 +3,67 @@
id="edition" id="edition"
:reftoscrollto="reftoscrollto" :reftoscrollto="reftoscrollto"
:navopened="navopened" :navopened="navopened"
:headeropened="headeropened"
@onCenterScrolled="onCenterScrolled" @onCenterScrolled="onCenterScrolled"
> >
<template v-if="!content" #header> <!-- <transition name="fade" mode="out-in"> -->
<span>Loading ...</span> <template v-if="!corpusLoaded" #header>
<span class="loading">Chargement ...</span>
</template> </template>
<template #header>
<template v-else #header>
<span
class="header-title"
@click.prevent="onOpenCloseHeader"
@keyup.enter="onOpenCloseHeader"
>
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="10" role="presentation" class="vs__open-indicator"><path d="M9.211364 7.59931l4.48338-4.867229c.407008-.441854.407008-1.158247 0-1.60046l-.73712-.80023c-.407008-.441854-1.066904-.441854-1.474243 0L7 5.198617 2.51662.33139c-.407008-.441853-1.066904-.441853-1.474243 0l-.737121.80023c-.407008.441854-.407008 1.158248 0 1.600461l4.48338 4.867228L7 10l2.211364-2.40069z" /></svg>
Notice
</span>
<h1> <h1>
<router-link :to="{ name:'edition', params: { id: editionid }}">{{ title }}</router-link> <router-link :to="{ name:'edition', params: { id: editionid }}">{{ title }}</router-link>
</h1> </h1>
<aside class="notice opened">
<div v-if="description">
<p v-html="description" />
</div>
<div v-if="author">
<p>{{ author }}</p>
</div>
<!-- <div v-if="date">
<p>{{ date }}</p>
</div> -->
<div v-if="biblio" class="biblio">
<p>
<a
:href="edition_manifestation_href"
@click.prevent="onClickManifestation"
@keyup.enter="onClickManifestation"
title="Consulter la notice bibliographique"
v-html="biblio.description"
/>
</p>
</div>
</aside>
<p v-if="meta">{{ meta.author }}</p> <nav class="entities-hide-show">
<span
v-if="entities_displayed"
@click.prevent="onCLickEntitiesDisplay"
@keyup.enter="onCLickEntitiesDisplay"
>
<span class="mdi mdi-eye-outline" /> Afficher les marques d'entité
</span>
<span
v-if="!entities_displayed"
@click.prevent="onCLickEntitiesDisplay"
@keyup.enter="onCLickEntitiesDisplay"
>
<span class="mdi mdi-eye-off-outline" /> Masquer les marques d'entité
</span>
</nav>
<!-- displayed on hover entity on texte -->
<aside <aside
v-if="indexitem" v-if="indexitem"
class="index-tooltip" class="index-tooltip"
@@ -23,7 +73,7 @@
@click.prevent="onClickTooltip" @click.prevent="onClickTooltip"
@keyup.enter="onClickTooltip" @keyup.enter="onClickTooltip"
> >
<span v-if="indexitem == 'loading'">Loading ...</span> <span v-if="indexitem == 'loading'" class="loading">Chargement ...</span>
<template v-if="indexitem !== 'loading'"> <template v-if="indexitem !== 'loading'">
<h1 v-html="indexitem.title" /> <h1 v-html="indexitem.title" />
<p v-if="indexitem.birthDate" class="birthdeath"> <p v-if="indexitem.birthDate" class="birthdeath">
@@ -40,9 +90,9 @@
</aside> </aside>
</template> </template>
<!-- </transition> -->
<!-- default slot --> <!-- default slot -->
<div id="text"> <div id="text" :class="{ 'entities-displayed': !entities_displayed, 'entities-hidden': entities_displayed }">
<template v-if="texts.length"> <template v-if="texts.length">
<infinite-loading <infinite-loading
v-if="flattoc && center_scrolled" v-if="flattoc && center_scrolled"
@@ -51,16 +101,20 @@
:distance="inifinite_load_distance" :distance="inifinite_load_distance"
@infinite="prevText" @infinite="prevText"
/> />
<!-- <transition-group name="edition-texts" tag="div"> -->
<EdText <EdText
v-for="text in texts" v-for="text in texts"
:ref="text.content.uuid" :ref="text.content.uuid"
:key="text.content.uuid" :key="text.content.uuid"
:tei="text.content.tei" :tei="text.content.tei"
:uuid="text.content.uuid" :uuid="text.content.uuid"
:url="text.content.url"
:textid="textid" :textid="textid"
:extractid="extractid"
@onHoverLink="onHoverLink" @onHoverLink="onHoverLink"
@onLeaveLink="onLeaveLink" @onLeaveLink="onLeaveLink"
/> />
<!-- </transition-group> -->
<infinite-loading <infinite-loading
v-if="flattoc" v-if="flattoc"
:identifier="inifinite_load_id" :identifier="inifinite_load_id"
@@ -82,8 +136,15 @@
id="toc" id="toc"
:toc="toc" :toc="toc"
:loadedtextsuuids="textsuuids" :loadedtextsuuids="textsuuids"
:selectedindex="selectedindex"
@onClickTocItem="onClickTocItem" @onClickTocItem="onClickTocItem"
/> />
<EdIndexes
v-if="indexes"
id="indexes-filters"
:indexes="indexes"
@onClickIndexItem="onClickIndexItem"
/>
<EdPagination <EdPagination
v-if="pagination" v-if="pagination"
id="page-nav" id="page-nav"
@@ -104,6 +165,7 @@ import { mapState, mapActions } from 'vuex'
import MainContentLayout from '../components/Layouts/MainContentLayout' import MainContentLayout from '../components/Layouts/MainContentLayout'
import EdText from '../components/Content/EdText' import EdText from '../components/Content/EdText'
import EdToc from '../components/Content/EdToc' import EdToc from '../components/Content/EdToc'
import EdIndexes from '../components/Content/EdIndexes'
import EdPagination from '../components/Content/EdPagination' import EdPagination from '../components/Content/EdPagination'
export default { export default {
@@ -111,24 +173,31 @@ export default {
metaInfo () { metaInfo () {
// console.log('metainfo', this.meta) // console.log('metainfo', this.meta)
return { return {
title: this.metainfotitle title: this.metainfotitle,
meta: this.meta
} }
}, },
components: { components: {
MainContentLayout, MainContentLayout,
EdText, EdText,
EdToc, EdToc,
EdIndexes,
EdPagination EdPagination
}, },
data: () => ({ data: () => ({
meta: null, meta: [],
editionid: null, editionid: null,
textid: null, textid: null,
extract: null,
extractid: null,
texts: [], texts: [],
textsuuids: [], textsuuids: [],
metainfotitle: undefined, metainfotitle: undefined,
title: undefined, title: undefined,
biblio: undefined,
author: undefined, author: undefined,
date: undefined,
description: undefined,
texttitle: undefined, texttitle: undefined,
// //
indexitem: null, indexitem: null,
@@ -143,23 +212,43 @@ export default {
toc: null, toc: null,
flattoc: null, flattoc: null,
// //
indexes: null,
selectedindex: null,
//
pagination: null, pagination: null,
// //
navopened: false headeropened: false,
navopened: false,
//
entities_displayed: false
}), }),
computed: { computed: {
...mapState({ ...mapState({
corpusLoaded: state => state.Corpus.corpusLoaded, corpusLoaded: state => state.Corpus.corpusLoaded,
editionslist: state => state.Corpus.editionslist, editionslist: state => state.Corpus.editionslist,
editionsbyuuid: state => state.Corpus.editionsbyuuid editionsbyuuid: state => state.Corpus.editionsbyuuid
}) }),
edition_manifestation_href () {
return `${this.biblio.path}${this.biblio.uuid}`
}
}, },
watch: { watch: {
$route (to, from) { $route (to, from) {
console.log('Edition Watcher $route', from, to) console.log('Edition Watcher $route', from, to)
if (to.params.id !== this.editionid) {
this.setValues()
}
if (to.params.textid) { if (to.params.textid) {
// change textid when route change // change textid when route change
this.textid = to.params.textid this.textid = to.params.textid
// change also extract if exists
this.extractid = null
if (to.params.extract) {
console.log('extract params from route', to.params.extract)
this.extractid = to.params.ocid
// scrolling is not working :(
this.reftoscrollto = '#mark-1'
}
} else if (this.toc) { } else if (this.toc) {
// if no textid in new route (e.g. edition front) // if no textid in new route (e.g. edition front)
// but we have toc // but we have toc
@@ -170,7 +259,11 @@ export default {
this.textid = null this.textid = null
} }
}, },
reftoscrollto (newref, oldref) {
console.log('reftoscrollto changed', oldref, newref)
},
textid (newid, oldid) { textid (newid, oldid) {
// triggered when route change (when TOC item clicked)
console.log('textid watcher', this, oldid, newid) console.log('textid watcher', this, oldid, newid)
this.texts = [] this.texts = []
this.textsuuids = [] this.textsuuids = []
@@ -181,68 +274,110 @@ export default {
this.inifinite_load_id += 1 this.inifinite_load_id += 1
} }
}, },
textdata (newtxtdata, oldtxtdata) { // textdata (newtxtdata, oldtxtdata) {
console.log('textdata watcher', oldtxtdata, newtxtdata) // console.log('textdata watcher', oldtxtdata, newtxtdata)
this.metainfotitle = `${this.title} ${newtxtdata.meta.title}` // this.metainfotitle = `${this.title} ${newtxtdata.meta.title}`
}, // },
page_selected (newp, oldp) { page_selected (newp, oldp) {
console.log('page_selected watcher', oldp, newp) console.log('page_selected watcher', oldp, newp)
this.scrollToPage(newp) this.scrollToPage(newp)
},
flattoc (n, o) {
console.log('flattoc watcher', o, n)
// this.scrollToPage(newp)
} }
}, },
created () { created () {
// console.log('Edition this.$route.params.id', this.$route.params.id) this.setValues()
this.editionid = this.$route.params.id
// get the text if textid available
if (this.$route.params.textid) {
this.textid = this.$route.params.textid
}
// wait for editions list from Corpus Store if not already loaded
if (!this.corpusLoaded) {
// this.getCorpuses()
// subsribe to store to get the editionbyuuid list
// https://dev.to/viniciuskneves/watch-for-vuex-state-changes-2mgj
this.edUuuidsUnsubscribe = this.$store.subscribe((mutation, state) => {
// console.log('Edition store subscribe', mutation.type)
if (mutation.type === 'Corpus/setEditionsByUUID') {
// console.log('Edition state.Coprus.editionsbyuuid', this.editionid, state.Corpus.editionsbyuuid)
this.title = this.metainfotitle = state.Corpus.editionsbyuuid[this.editionid].title
}
if (mutation.type === 'Corpus/setTocs') {
console.log('Edition Corpus/setTocs', this.editionid, state.Corpus.editionsbyuuid)
this.toc = state.Corpus.editionsbyuuid[this.editionid].toc
this.flattoc = state.Corpus.editionsbyuuid[this.editionid].flattoc
this.inifinite_load_id += 1
// if no textid in new route (e.g. edition front)
// but we have toc
// get the first item
// will be replaced by front page of edition
if (!this.textid) { this.textid = this.toc[0].children[0].uuid }
}
if (mutation.type === 'Corpus/setPaginations') {
// console.log('Edition state.Coprus.editionsbyuuid', this.editionid, state.Corpus.editionsbyuuid)
this.pagination = state.Corpus.editionsbyuuid[this.editionid].pagination
}
})
} else {
// console.log('');
this.title = this.metainfotitle = this.editionsbyuuid[this.editionid].title
this.toc = this.editionsbyuuid[this.editionid].toc
this.flattoc = this.editionsbyuuid[this.editionid].flattoc
// if no textid in new route (e.g. edition front)
// but we have toc
// get the first item
// will be replaced by front page of edition
if (!this.textid) { this.textid = this.toc[0].children[0].uuid }
this.pagination = this.editionsbyuuid[this.editionid].pagination
}
}, },
// updated () {
// this.setValues()
// },
methods: { methods: {
...mapActions({ ...mapActions({
getCorpuses: 'Corpus/getCorpuses' getCorpuses: 'Corpus/getCorpuses'
}), }),
setValues () {
// console.log('Edition this.$route.params.id', this.$route.params.id)
this.editionid = this.$route.params.id
// get the text if textid available
if (this.$route.params.textid) {
this.textid = this.$route.params.textid
}
// get the searchkeys from route param (only comming from result item) for text highlighting
if (this.$route.params.ocid) {
this.extractid = this.$route.params.ocid
// scrolling is not working :(
this.reftoscrollto = '#mark-1'
}
// wait for editions list from Corpus Store if not already loaded
if (!this.corpusLoaded) {
// this.getCorpuses()
// subsribe to store to get the editionbyuuid list
// https://dev.to/viniciuskneves/watch-for-vuex-state-changes-2mgj
this.edUuuidsUnsubscribe = this.$store.subscribe((mutation, state) => {
// console.log('Edition store subscribe', mutation.type)
if (mutation.type === 'Corpus/setEditionsByUUID') {
// console.log('Edition state.Coprus.editionsbyuuid', this.editionid, state.Corpus.editionsbyuuid)
this.title = this.metainfotitle = state.Corpus.editionsbyuuid[this.editionid].title
this.meta = [
{ name: 'test', content: 'edition chargé' }
]
this.biblio = state.Corpus.editionsbyuuid[this.editionid].biblio
this.description = state.Corpus.editionsbyuuid[this.editionid].description
this.date = state.Corpus.editionsbyuuid[this.editionid].date
this.author = state.Corpus.editionsbyuuid[this.editionid].author
}
if (mutation.type === 'Corpus/setTocs') {
console.log('Edition Corpus/setTocs', this.editionid, state.Corpus.editionsbyuuid)
this.toc = state.Corpus.editionsbyuuid[this.editionid].toc
}
if (mutation.type === 'Corpus/buildFlatTocsAndFilters') {
console.log('Edition Corpus/buildFlatTocsAndFilters', this.editionid, state.Corpus.editionsbyuuid)
this.flattoc = state.Corpus.editionsbyuuid[this.editionid].flattoc
// launch infinitloading
this.inifinite_load_id += 1
// if no textid in new route (e.g. edition front)
// but we have toc
// get the first item
// will be replaced by front page of edition
if (!this.textid) { this.textid = this.flattoc[1] }
//
this.indexes = state.Corpus.editionsbyuuid[this.editionid].indexes
}
if (mutation.type === 'Corpus/setPaginations') {
// console.log('Edition state.Coprus.editionsbyuuid', this.editionid, state.Corpus.editionsbyuuid)
this.pagination = state.Corpus.editionsbyuuid[this.editionid].pagination
}
})
} else {
// console.log('');
this.title = this.metainfotitle = this.editionsbyuuid[this.editionid].title
this.meta = [
{ name: 'test', content: 'edition deja là' }
]
this.biblio = this.editionsbyuuid[this.editionid].biblio
this.description = this.editionsbyuuid[this.editionid].description
this.date = this.editionsbyuuid[this.editionid].date
this.author = this.editionsbyuuid[this.editionid].author
this.toc = this.editionsbyuuid[this.editionid].toc
this.flattoc = this.editionsbyuuid[this.editionid].flattoc
// if no textid in new route (e.g. edition front)
// but we have toc
// get the first item
// will be replaced by front page of edition
if (!this.textid) { this.textid = this.toc[0].children[0].uuid }
this.indexes = this.editionsbyuuid[this.editionid].indexes
this.pagination = this.editionsbyuuid[this.editionid].pagination
}
},
getTextContent (textid, $state = null, direction = 'next') { getTextContent (textid, $state = null, direction = 'next') {
console.log('getTextContent', textid) console.log('getTextContent', textid)
let params = { let params = {
@@ -260,8 +395,13 @@ export default {
this.textsuuids.unshift(data.content.uuid) this.textsuuids.unshift(data.content.uuid)
} }
if ($state) { if ($state) {
// triggered by infinite scroll
$state.loaded() $state.loaded()
this.next_loaded = true this.next_loaded = true
} else {
// triggered by TOC item click
// UPDATE METATAGS
this.updateMetaData(data.meta.metadata)
} }
}) })
.catch((error) => { .catch((error) => {
@@ -285,10 +425,27 @@ export default {
// }) // })
}) })
}, },
updateMetaData (metadata) {
this.meta = []
metadata.forEach(m => {
let o = {}
o.name = m.name
if (Array.isArray(m.content)) {
o.content = m.content.join(', ')
} else {
o.content = m.content
}
if (typeof m.scheme !== 'undefined') {
o.scheme = m.scheme
}
this.meta.push(o)
})
},
onCenterScrolled (e) { onCenterScrolled (e) {
// console.log('Edition centerScrolled(e)', e.target.scrollTop) console.log('Edition centerScrolled(e)', e.target.scrollTop)
if (!this.center_scrolled && e.target.scrollTop > this.inifinite_load_distance * 1.5) { if (!this.center_scrolled && e.target.scrollTop > this.inifinite_load_distance * 1.5) {
this.center_scrolled = true this.center_scrolled = true
// this.$store.commit('History/setOpened', false)
} }
this.indexitem = null this.indexitem = null
}, },
@@ -351,11 +508,15 @@ export default {
}) })
} }
}, },
onClickIndexItem (o) {
this.selectedindex = o
},
onClickPaginationItem (o) { onClickPaginationItem (o) {
console.log('onClickPaginationItem', o) console.log('onClickPaginationItem', o)
if (this.textsuuids.indexOf(o.uuid) !== -1) { if (this.textsuuids.indexOf(o.uuid) !== -1) {
// if already loaded, scroll to uuid // if already loaded, scroll to uuid
this.scrollToPage(o) // this.scrollToPage(o)
this.reftoscrollto = `span[role="pageBreak"][id="${o.code}"]`
} else { } else {
// if not already loaded, change route // if not already loaded, change route
this.$router.push({ this.$router.push({
@@ -367,13 +528,23 @@ export default {
}) })
} }
}, },
scrollToPage (p) { // scrollToPage (p) {
// console.log('scrollToPage', p) // console.log('scrollToPage', p)
this.reftoscrollto = `span[role="pageBreak"][id="${p.code}"]` //
}, // },
onOpenCloseNav (e) { onOpenCloseNav (e) {
console.log('onOpenCloseNav', e) console.log('onOpenCloseNav', e)
this.navopened = !this.navopened this.navopened = !this.navopened
if (this.navopened) {
this.headeropened = false
}
},
onOpenCloseHeader (e) {
console.log('onOpenCloseHeader', e)
this.headeropened = !this.headeropened
if (this.headeropened) {
this.navopened = false
}
}, },
onClickTooltip (e) { onClickTooltip (e) {
console.log(`onClickTooltip index: ${e.target.dataset.index}, uuid: ${e.target.dataset.uuid}`) console.log(`onClickTooltip index: ${e.target.dataset.index}, uuid: ${e.target.dataset.uuid}`)
@@ -381,6 +552,17 @@ export default {
name: e.target.dataset.index, name: e.target.dataset.index,
params: { id: e.target.dataset.uuid } params: { id: e.target.dataset.uuid }
}) })
},
onClickManifestation (e) {
console.log(`onClickManifestation`)
this.$router.push({
name: 'bibliographieItem',
params: { type: 'manifestations', uuid: this.biblio.uuid }
})
},
onCLickEntitiesDisplay (e) {
console.log('onCLickEntitiesDisplay')
this.entities_displayed = !this.entities_displayed
} }
} }
} }
+71 -18
View File
@@ -8,32 +8,85 @@
<h2>Corpus des XVII et XVIII<sup>E</sup> siècles</h2> <h2>Corpus des XVII et XVIII<sup>E</sup> siècles</h2>
</header> </header>
<section class="row"> <section class="row">
<div class="col-3" /> <div class="col-2" />
<div class="col-6 teasers"> <div class="col-8 teasers">
<article> <div class="wrapper">
<h1>Le projet de recherche</h1> <template v-if="!colophonHome || colophonHome.length <= 0">
<p>Conduit au sein du Labex les Passés dans le Présent, le projet des Guides de Paris consiste à numériser, éditer exposer dans le Linked Open Data un corpus de guides des XVIIeet XVIIIesiècles en vue de leur étude.</p> <span class="loading">Chargement ...</span>
<span>Lire la suite</span> </template>
</article> <template v-else>
<article> <article
<h1>Le projet de recherche</h1> v-for="page in colophonHome"
<p>Conduit au sein du Labex les Passés dans le Présent, le projet des Guides de Paris consiste à numériser, éditer exposer dans le Linked Open Data un corpus de guides des XVIIeet XVIIIesiècles en vue de leur étude.</p> :key="page.uuid"
<span>Lire la suite</span> >
</article> <!-- <h1>{{ page.title }}</h1> -->
<article> <div v-html="trimedTei(page.tei)" />
<h1>Le projet de recherche</h1> <a
<p>Conduit au sein du Labex les Passés dans le Présent, le projet des Guides de Paris consiste à numériser, éditer exposer dans le Linked Open Data un corpus de guides des XVIIeet XVIIIesiècles en vue de leur étude.</p> :href="page.url"
<span>Lire la suite</span> class="readmore"
</article> @click.prevent="onclick(page.uuid)"
@keyup.enter="onclick(page.uuid)"
>
<span>Lire la suite</span>
</a>
</article>
</template>
</div>
</div> </div>
<div class="col-3" /> <div class="col-2" />
</section> </section>
</div> </div>
</template> </template>
<script> <script>
import { mapState, mapActions } from 'vuex'
import truncate from 'truncate-html'
export default { export default {
name: 'Home',
metaInfo: {
title: 'Home'
},
// data: () => ({
// // editionslist: []
// }),
computed: {
...mapState({
colophonHome: state => state.Colophon.colophonHome
})
},
created () {
if (!this.colophonHome.length) {
this.getColophon()
}
},
methods: {
...mapActions({
getColophon: 'Colophon/getColophon'
}),
trimedTei (tei) {
return truncate(tei, 30, {
byWords: true,
stripTags: false,
reserveLastWord: 10
})
},
onclick (uuid) {
console.log('clicked on home teaser', uuid)
this.$router.push({
name: uuid
})
}
}
} }
</script> </script>
<style lang="scss">
// a{
// z-index: 100;
// }
</style>
+111 -15
View File
@@ -2,22 +2,53 @@
<MainContentLayout id="index-locorum" class="index"> <MainContentLayout id="index-locorum" class="index">
<template v-slot:header> <template v-slot:header>
<h1>Lieux</h1> <h1>Lieux</h1>
<span v-if="!items.length">Loading ...</span> <span v-if="!items.length" class="loading">Chargement ...</span>
<span v-else>{{ meta.quantity.quantity }} {{ meta.quantity.unit }}</span>
</template> </template>
<ul v-if="items.length" class="item-list"> <ul v-if="items.length" class="item-list">
<li v-for="item in items" :key="item.uuid"> <li
v-for="item in items"
:key="item.uuid"
:class="{ hidden: activeLetter && item.letter !== activeLetter }"
>
<LocorumItem :item="item" /> <LocorumItem :item="item" />
</li> </li>
</ul> </ul>
<template v-slot:nav /> <template v-slot:nav>
<div v-if="items.length" class="abc">
<ul>
<li :class="{ inactive: activeLetter }">
<span
class="tout"
@click.prevent="onClickLetter(null)"
@keyup.enter="onClickLetter(null)"
>tout</span>
<span class="quantity">[{{ items.length }}]</span>
</li>
<li
v-for="l in letters" :key="l.l"
:class="{ inactive: activeLetter && l.l !== activeLetter }"
>
<span
class="letter"
@click.prevent="onClickLetter(l.l)"
@keyup.enter="onClickLetter(l.l)"
>{{ l.l }}</span>
<span class="quantity">[{{ l.q }}]</span>
</li>
</ul>
</div>
</template>
</MainContentLayout> </MainContentLayout>
</template> </template>
<script> <script>
import { REST } from 'api/rest-axios' import { REST } from 'api/rest-axios'
import qs from 'querystring'
import MainContentLayout from '../components/Layouts/MainContentLayout' import MainContentLayout from '../components/Layouts/MainContentLayout'
import LocorumItem from '../components/Content/LocorumItem' import LocorumItem from '../components/Content/LocorumItem'
@@ -31,20 +62,85 @@ export default {
MainContentLayout MainContentLayout
}, },
data: () => ({ data: () => ({
items: [] items: [],
letters: {},
activeLetter: null,
meta: null,
content: []
}), }),
beforeCreate () { created () {
REST.get(`${window.apipath}/indexLocorum`, {}) this.loadIndex(1, 200)
.then(({ data }) => { },
console.log('index locorum REST: data', data) methods: {
if (data.content.length) { loadIndex (start, count) {
this.items = data.content console.log('loadIndex', start, count)
// construct params
let params = {
start: start,
count: count
}
let q = qs.stringify(params)
REST.get(`${window.apipath}/indexLocorum?` + q, {})
.then(({ data }) => {
console.log('index locorum REST: data', data)
this.meta = data.meta
this.content = this.content.concat(data.content)
if (this.content.length < data.meta.quantity.quantity) {
this.loadIndex(start + count, count)
} else {
this.parseIndex()
}
})
.catch((error) => {
console.warn('Issue with index locorum', error)
Promise.reject(error)
})
},
parseIndex () {
console.log('parseIndex', this.content)
if (this.content.length) {
this.items = this.content.sort((a, b) => {
let Aletter = a.letter.toLowerCase()
let Bletter = b.letter.toLowerCase()
if (Aletter < Bletter) {
return -1
} else if (Aletter > Bletter) {
return 1
} else {
return 0
}
})
}
for (let i = 0; i < this.items.length; i++) {
// console.log(typeof this.items[i].letter)
if (this.items[i].letter !== '') {
let letter = this.items[i].letter.toLowerCase()
console.log(letter)
if (Object.keys(this.letters).indexOf(letter) === -1) {
this.letters[letter] = {
l: letter,
q: 1
}
} else {
this.letters[letter].q += 1
}
} }
}) }
.catch((error) => { // console.log(this.letters)
console.warn('Issue with index locorum', error) // this.letters = this.letters.sort((a, b) => {
Promise.reject(error) // if (a.l < b.l) {
}) // return -1
// } else if (a.l > b.l) {
// return 1
// } else {
// return 0
// }
// })
},
onClickLetter (l) {
this.activeLetter = l
// console.log('activeLetter', this.activeLetter)
}
} }
} }
</script> </script>
+110 -16
View File
@@ -2,22 +2,53 @@
<MainContentLayout id="index-nominum" class="index"> <MainContentLayout id="index-nominum" class="index">
<template v-slot:header> <template v-slot:header>
<h1>Personnes</h1> <h1>Personnes</h1>
<span v-if="!items.length">Loading ...</span> <span v-if="!items.length" class="loading">Chargement ...</span>
<span v-else>{{ meta.quantity.quantity }} {{ meta.quantity.unit }}</span>
</template> </template>
<ul v-if="items.length" class="item-list"> <ul v-if="items.length" class="item-list">
<li v-for="item in items" :key="item.url"> <li
v-for="item in items"
:key="item.url"
:class="{ hidden: activeLetter && item.letter !== activeLetter }"
>
<NominumItem :item="item" /> <NominumItem :item="item" />
</li> </li>
</ul> </ul>
<template v-slot:nav /> <template v-slot:nav>
<div v-if="items.length" class="abc">
<ul>
<li :class="{ inactive: activeLetter }">
<span
class="tout"
@click.prevent="onClickLetter(null)"
@keyup.enter="onClickLetter(null)"
>tout</span>
<span class="quantity">[{{ items.length }}]</span>
</li>
<li
v-for="l in letters" :key="l.l"
:class="{ inactive: activeLetter && l.l !== activeLetter }"
>
<span
class="letter"
@click.prevent="onClickLetter(l.l)"
@keyup.enter="onClickLetter(l.l)"
>{{ l.l }}</span>
<span class="quantity">[{{ l.q }}]</span>
</li>
</ul>
</div>
</template>
</MainContentLayout> </MainContentLayout>
</template> </template>
<script> <script>
import { REST } from 'api/rest-axios' import { REST } from 'api/rest-axios'
import qs from 'querystring'
import MainContentLayout from '../components/Layouts/MainContentLayout' import MainContentLayout from '../components/Layouts/MainContentLayout'
import NominumItem from '../components/Content/NominumItem' import NominumItem from '../components/Content/NominumItem'
@@ -31,23 +62,86 @@ export default {
MainContentLayout MainContentLayout
}, },
data: () => ({ data: () => ({
items: [] items: [],
letters: {},
activeLetter: null,
meta: null,
content: []
}), }),
beforeCreate () { created () {
// items/gdpLeMaire1685T01BodyFr01.003.016 // items/gdpLeMaire1685T01BodyFr01.003.016
// texts/gdpSauval1724 // texts/gdpSauval1724
REST.get(`${window.apipath}/indexNominum`, {}) this.loadIndex(0, 200)
.then(({ data }) => { },
console.log('index nominum REST: data', data) methods: {
if (data.content.length) { loadIndex (start, count) {
this.items = data.content console.log('loadIndex', start, count)// construct params
let params = {
start: start,
count: count
}
let q = qs.stringify(params)
REST.get(`${window.apipath}/indexNominum?` + q, { start: start, count: count })
.then(({ data }) => {
console.log('index nominum REST: data', data)
this.meta = data.meta
this.content = this.content.concat(data.content)
if (this.content.length < data.meta.quantity.quantity) {
this.loadIndex(start + count, count)
} else {
this.parseIndex()
}
})
.catch((error) => {
console.warn('Issue with index nominum', error)
Promise.reject(error)
})
},
parseIndex () {
console.log('parseIndex', this.content)
if (this.content.length) {
this.items = this.content.sort((a, b) => {
let Aletter = a.letter.toLowerCase()
let Bletter = b.letter.toLowerCase()
if (Aletter < Bletter) {
return -1
} else if (Aletter > Bletter) {
return 1
} else {
return 0
}
})
}
for (let i = 0; i < this.items.length; i++) {
// console.log(typeof this.items[i].letter)
if (this.items[i].letter !== '') {
let letter = this.items[i].letter.toLowerCase()
console.log(letter)
if (Object.keys(this.letters).indexOf(letter) === -1) {
this.letters[letter] = {
l: letter,
q: 1
}
} else {
this.letters[letter].q += 1
}
} }
}) }
.catch((error) => { // console.log('this.letters', this.letters)
console.warn('Issue with index nominum', error) // this.letters = this.letters.sort((a, b) => {
Promise.reject(error) // if (a.l < b.l) {
}) // return -1
// } else if (a.l > b.l) {
// return 1
// } else {
// return 0
// }
// })
},
onClickLetter (l) {
this.activeLetter = l
// console.log('activeLetter', this.activeLetter)
}
} }
} }
</script> </script>
+112 -15
View File
@@ -2,22 +2,55 @@
<MainContentLayout id="index-operum" class="index"> <MainContentLayout id="index-operum" class="index">
<template v-slot:header> <template v-slot:header>
<h1>Œuvres</h1> <h1>Œuvres</h1>
<span v-if="!items.length">Loading ...</span> <span v-if="!items.length" class="loading">Chargement ...</span>
<span v-else>{{ meta.quantity.quantity }} {{ meta.quantity.unit }}</span>
</template> </template>
<ul v-if="items.length" class="item-list"> <ul v-if="items.length" class="item-list">
<li v-for="item in items" :key="item.uuid"> <li
v-for="item in items"
:key="item.uuid"
:class="{ hidden: activeLetter && item.letter !== activeLetter }"
>
<OperumItem :item="item" /> <OperumItem :item="item" />
</li> </li>
</ul> </ul>
<template v-slot:nav /> <template v-slot:nav>
<div v-if="items.length" class="abc">
<ul>
<li :class="{ inactive: activeLetter }">
<span
class="tout"
@click.prevent="onClickLetter(null)"
@keyup.enter="onClickLetter(null)"
>tout</span>
<span class="quantity">[{{ items.length }}]</span>
</li>
<li
v-for="l in letters" :key="l.l"
:class="{ inactive: activeLetter && l.l !== activeLetter }"
>
<span
class="letter"
@click.prevent="onClickLetter(l.l)"
@keyup.enter="onClickLetter(l.l)"
>{{ l.l }}</span>
<span class="quantity">[{{ l.q }}]</span>
</li>
</ul>
</div>
</template>
</MainContentLayout> </MainContentLayout>
</template> </template>
<script> <script>
import { REST } from 'api/rest-axios' import { REST } from 'api/rest-axios'
import qs from 'querystring'
import MainContentLayout from '../components/Layouts/MainContentLayout' import MainContentLayout from '../components/Layouts/MainContentLayout'
import OperumItem from '../components/Content/OperumItem' import OperumItem from '../components/Content/OperumItem'
@@ -31,20 +64,84 @@ export default {
MainContentLayout MainContentLayout
}, },
data: () => ({ data: () => ({
items: [] items: [],
letters: {},
activeLetter: null,
meta: null,
content: []
}), }),
beforeCreate () { created () {
REST.get(`${window.apipath}/indexOperum`, {}) this.loadIndex(1, 200)
.then(({ data }) => { },
console.log('index operum REST: data', data) methods: {
if (data.content.length) { loadIndex (start, count) {
this.items = data.content console.log('loadIndex', start, count)
// construct params
let params = {
start: start,
count: count
}
let q = qs.stringify(params)
REST.get(`${window.apipath}/indexOperum?` + q, {})
.then(({ data }) => {
console.log('index operum REST: data', data)
this.meta = data.meta
this.content = this.content.concat(data.content)
if (this.content.length < data.meta.quantity.quantity) {
this.loadIndex(start + count, count)
} else {
this.parseIndex()
}
})
.catch((error) => {
console.warn('Issue with index operum', error)
Promise.reject(error)
})
},
parseIndex () {
if (this.content.length) {
this.items = this.content.sort((a, b) => {
let Aletter = a.letter.toLowerCase()
let Bletter = b.letter.toLowerCase()
if (Aletter < Bletter) {
return -1
} else if (Aletter > Bletter) {
return 1
} else {
return 0
}
})
}
for (let i = 0; i < this.items.length; i++) {
// console.log(typeof this.items[i].letter)
if (this.items[i].letter !== '') {
let letter = this.items[i].letter.toLowerCase()
console.log(letter)
if (Object.keys(this.letters).indexOf(letter) === -1) {
this.letters[letter] = {
l: letter,
q: 1
}
} else {
this.letters[letter].q += 1
}
} }
}) }
.catch((error) => { // console.log(this.letters)
console.warn('Issue with index operum', error) // this.letters = this.letters.sort((a, b) => {
Promise.reject(error) // if (a.l < b.l) {
}) // return -1
// } else if (a.l > b.l) {
// return 1
// } else {
// return 0
// }
// })
},
onClickLetter (l) {
this.activeLetter = l
// console.log('activeLetter', this.activeLetter)
}
} }
} }
</script> </script>
+12 -9
View File
@@ -2,21 +2,18 @@
<MainContentLayout id="list-corpus"> <MainContentLayout id="list-corpus">
<template v-slot:header> <template v-slot:header>
<h1>Corpus</h1> <h1>Corpus</h1>
<span v-if="!editionslist.length">Loading ...</span> <span v-if="!editionslist.length" class="loading">Chargement ...</span>
</template> </template>
<ul v-if="editionslist.length" class="item-list"> <ul v-if="editionslist.length" class="item-list">
<li v-for="(corpus,index) in editionslist" :key="index"> <li v-for="(corpus,index) in editionslist" :key="index">
<header> <header>
<h2>{{ corpus.author.title }}</h2> <h2>{{ corpus.author.author }}</h2>
<h3>{{ corpus.author.date }}</h3> <h3 class="editions-quantity">
Corpus : {{ corpus.author.editionsQuantity.quantity }} {{ corpus.author.editionsQuantity.unit }}, {{ corpus.author.date }}
</h3>
<section v-if="corpus.author.note" class="notice" v-html="corpus.author.note" />
</header> </header>
<section class="editions">
<h4 class="editions-quantity">
{{ corpus.author.editionsQuantity.quantity }} {{ corpus.author.editionsQuantity.unit }}
</h4>
<!-- <div v-if="corpus.author.editions" class="editions" v-html="corpus.author.editions"/> -->
</section>
<section class="texts"> <section class="texts">
<h4 class="texts-quantity"> <h4 class="texts-quantity">
{{ corpus.author.textsQuantity.quantity }} {{ corpus.author.textsQuantity.quantity }}
@@ -26,13 +23,19 @@
<li v-for="text in corpus.editions.content" :key="text.uuid"> <li v-for="text in corpus.editions.content" :key="text.uuid">
<h3> <h3>
<a <a
class="title"
:href="text.url" :href="text.url"
:uuid="text.uuid" :uuid="text.uuid"
@click.prevent="onclick" @click.prevent="onclick"
@keyup.enter="onclick" @keyup.enter="onclick"
v-html="text.title" v-html="text.title"
title="Consulter cette édition"
/> />
</h3> </h3>
<p
class="biblio"
v-html="text.biblio.description"
/>
</li> </li>
</ul> </ul>
</section> </section>
+58 -6
View File
@@ -1,19 +1,47 @@
<template> <template>
<MainContentLayout id="locorum" class="index-item"> <MainContentLayout id="locorum" class="index-item">
<template v-if="!content" v-slot:header> <template v-if="!content" v-slot:header>
<span class="loading">Loading ...</span> <span class="loading">Chargement ...</span>
</template> </template>
<template v-if="content" v-slot:header> <template v-if="content" v-slot:header>
<h1 v-html="content.title" /> <h1 v-html="content.title" />
<p> <h2 v-html="content.rubrique" />
{{ content.type }} <p><em>{{ content.type }}</em></p>
</p> <p v-if="content.country"><span class="label">Pays :</span> {{ content.country }}</p>
<p v-if="content.ville"><span class="label">Ville :</span> {{ content.ville }}</p>
<section v-if="content.notes && content.notes.length" class="notes">
<h3>Notes</h3>
<div v-for="(note, i) in content.note" :key="i" class="note" v-html="note" />
</section>
<section v-if="content.autorities && content.autorities.length" class="autorities">
<h3>Autorities</h3>
<ul>
<li v-for="(aut, i) in content.autorities" :key="i">
<a :href="aut.identifier" target="_blanck">
{{ aut.autority }}
<span class="mdi mdi-open-in-new" />
</a>
</li>
</ul>
</section>
</template> </template>
<!-- default slot --> <!-- default slot -->
<IndexItemOcurrences v-if="content" :content="content" /> <IndexItemOcurrences v-if="content" :content="content" />
<template #nav>
<aside class="links">
<p>
Permalien:<br><a :href="`${content.url}`">{{ content.url }}</a>
</p>
<p>
JSON:<br><a :href="`${apipath}${content.path}${content.uuid}`">{{ apipath }}{{ content.path }}{{ content.uuid }}</a>
</p>
</aside>
</template>
</MainContentLayout> </MainContentLayout>
</template> </template>
@@ -30,11 +58,15 @@ export default {
IndexItemOcurrences IndexItemOcurrences
}, },
data: () => ({ data: () => ({
content: null content: null,
meta: [],
metainfotitle: undefined
}), }),
metaInfo () { metaInfo () {
// console.log('metainfo', this.meta)
return { return {
title: `Locorum ${this.$route.params.id}` title: this.metainfotitle,
meta: this.meta
} }
}, },
computed: { computed: {
@@ -46,7 +78,9 @@ export default {
console.log('locorum REST: data', data) console.log('locorum REST: data', data)
if (data.content) { if (data.content) {
this.content = data.content this.content = data.content
this.metainfotitle = data.content.title
} }
this.updateMetaData(data.meta.metadata)
}) })
.catch((error) => { .catch((error) => {
console.warn('Issue with locorum', error) console.warn('Issue with locorum', error)
@@ -56,6 +90,24 @@ export default {
query: { fullpath: this.$route.path } query: { fullpath: this.$route.path }
}) })
}) })
},
methods: {
updateMetaData (metadata) {
this.meta = []
metadata.forEach(m => {
let o = {}
o.name = m.name
if (Array.isArray(m.content)) {
o.content = m.content.join(', ')
} else {
o.content = m.content
}
if (typeof m.scheme !== 'undefined') {
o.scheme = m.scheme
}
this.meta.push(o)
})
}
} }
} }
</script> </script>
+144 -12
View File
@@ -1,25 +1,54 @@
<template> <template>
<MainContentLayout id="nominum" class="index-item"> <MainContentLayout id="nominum" class="index-item">
<template v-if="!content" v-slot:header> <template v-if="!content" v-slot:header>
<span class="loading">Loading ...</span> <span class="loading">Chargement ...</span>
</template> </template>
<template v-if="content" v-slot:header> <template v-if="content" v-slot:header>
<h1 v-html="content.title" /> <h1 v-html="content.title" />
<p> <h2 v-html="content.rubrique" />
{{ content.birthDate }}, {{ content.birthPlace }}<br> <p v-if="content.occupation"><em>{{ content.occupation }}</em></p>
{{ content.deathDate }}, {{ content.deathPlace }} <p v-if="content.surname"><span class="label">Nom : </span>{{ content.surname }}, {{ content.surname }}</p>
<p v-if="content.forename"><span class="label">Prénom : </span>{{ content.forename }}, {{ content.forename }}</p>
<p v-if="content.sexe === 1 || content.sexe === 0"><span class="label">Sexe : </span>
<span v-if="content.sexe === 1">Masculin</span>
<span v-if="content.sexe === 0">Feminin</span>
</p> </p>
<!-- <ul v-if="content.attestedForms.lenght" class="attestedForms"> <p v-if="content.birthPlace || content.birthDate" v-html="birth_str" />
<li v-for="(item, index) in content.attestedForms" :key="index"> <p v-if="content.deathPlace || content.deathDate" v-html="death_str" />
<section v-if="content.note && content.note.length > 0" class="notes">
<h3>Notes</h3>
<div v-for="(note, i) in content.note" :key="i" class="note" v-html="note" />
</section>
<section v-if="content.autorities && content.autorities.length > 0" class="autorities">
<h3>Autorités</h3>
<ul>
<li v-for="(aut, i) in content.autorities" :key="i">
<a :href="aut.identifier" target="_blanck">
{{ aut.autority }}
<span class="mdi mdi-open-in-new" />
</a>
</li>
</ul>
</section>
</li>
</ul> -->
</template> </template>
<!-- default slot --> <!-- default slot -->
<IndexItemOcurrences v-if="content" :content="content" /> <IndexItemOcurrences v-if="content" :content="content" />
<template #nav>
<aside class="links">
<p>
Permalien:<br><a :href="`${content.url}`">{{ content.url }}</a>
</p>
<p>
JSON:<br><a :href="`${apipath}${content.path}${content.uuid}`">{{ apipath }}{{ content.path }}{{ content.uuid }}</a>
</p>
</aside>
</template>
</MainContentLayout> </MainContentLayout>
</template> </template>
@@ -36,21 +65,57 @@ export default {
IndexItemOcurrences IndexItemOcurrences
}, },
data: () => ({ data: () => ({
content: null content: null,
meta: [],
metainfotitle: undefined
}), }),
metaInfo () { metaInfo () {
// console.log('metainfo', this.meta)
return { return {
title: `Nominum ${this.$route.params.id}` title: this.metainfotitle,
meta: this.meta
} }
}, },
beforeCreate () { computed: {
birth_str () {
let str = '<span class="label">Naissance :</span>'
if (this.content.birthPlace) {
str += ' ' + this.content.birthPlace
}
if (this.content.birthPlace && this.content.birthDate) {
str += ','
}
if (this.content.birthDate) {
str += ' ' + this.content.birthDate
}
return str
},
death_str () {
let str = '<span class="label">Mort :</span>'
if (this.content.deathPlace) {
str += ' ' + this.content.deathPlace
}
if (this.content.deathPlace && this.content.deathDate) {
str += ','
}
if (this.content.deathDate) {
str += ' ' + this.content.deathDate
}
return str
}
},
created () {
console.log('nominum this.$route', this.$route) console.log('nominum this.$route', this.$route)
REST.get(`${window.apipath}/indexNominum/` + this.$route.params.id, {}) REST.get(`${window.apipath}/indexNominum/` + this.$route.params.id, {})
.then(({ data }) => { .then(({ data }) => {
console.log('nominum REST: data', data) console.log('nominum REST: data', data)
if (data.content) { if (data.content) {
this.content = data.content this.parseOccurences(data.content)
this.metainfotitle = data.content.title
} }
this.updateMetaData(data.meta.metadata)
}) })
.catch((error) => { .catch((error) => {
console.warn('Issue with nominum', error) console.warn('Issue with nominum', error)
@@ -60,6 +125,73 @@ export default {
query: { fullpath: this.$route.path } query: { fullpath: this.$route.path }
}) })
}) })
},
methods: {
updateMetaData (metadata) {
this.meta = []
metadata.forEach(m => {
let o = {}
o.name = m.name
if (Array.isArray(m.content)) {
o.content = m.content.join(', ')
} else {
o.content = m.content
}
if (typeof m.scheme !== 'undefined') {
o.scheme = m.scheme
}
this.meta.push(o)
})
},
parseOccurences (content) {
console.log('parseOccurences', content)
// ! parsing occurences
for (let i = 0; i < content.occurences.length; i++) {
let ed = content.occurences[i]
for (let j = 0; j < ed.occurences.length; j++) {
let o = ed.occurences[j]
const uuid = o.uuid
for (let k = 0; k < content.attestedForms.length; k++) {
const form = content.attestedForms[k]
if (form.uuid.indexOf(uuid) >= 0) {
content.occurences[i].occurences[j].form = form.title
break
}
console.warn('no form for occurence', o.uuid, o.title)
content.occurences[i].occurences[j].form = ''
}
}
}
// ! parsing attested-forms
for (let f = 0; f < content.attestedForms.length; f++) {
let form = content.attestedForms[f]
content.attestedForms[f].occurences = []
for (let u = 0; u < form.uuid.length; u++) {
// ? some UUID are duplicate
let oc = {
uuid: form.uuid[u]
}
for (let e = 0; e < content.occurences.length; e++) {
let ed = content.occurences[e]
for (let o = 0; o < ed.occurences.length; o++) {
let occ = ed.occurences[o]
if (oc.uuid === occ.uuid && occ.title) {
oc.title = occ.title
oc.ed = {
uuid: ed.item,
title: ed.biblio
}
content.attestedForms[f].occurences.push(oc)
// content.attestedForms[f].uuid[u] = oc
break
}
}
if (oc.title) break
}
}
}
this.content = content
}
} }
} }
</script> </script>
+58 -3
View File
@@ -1,16 +1,47 @@
<template> <template>
<MainContentLayout id="operum" class="index-item"> <MainContentLayout id="operum" class="index-item">
<template v-if="!content" v-slot:header> <template v-if="!content" v-slot:header>
<span class="loading">Loading ...</span> <span class="loading">Chargement ...</span>
</template> </template>
<template v-if="content" v-slot:header> <template v-if="content" v-slot:header>
<h1 v-html="content.title" /> <h1 v-html="content.title" />
<h2 v-html="content.rubrique" />
<p><em>{{ content.type }}</em></p>
<p v-if="content.location"><span class="label">Adresse :</span> {{ content.location }}</p>
<p v-if="content.description">{{ content.description }}</p>
<section v-if="content.notes && content.notes.length" class="notes">
<h3>Notes</h3>
<div v-for="(note, i) in content.note" :key="i" class="note" v-html="note" />
</section>
<section v-if="content.autorities && content.autorities.length" class="autorities">
<h3>Autorities</h3>
<ul>
<li v-for="(aut, i) in content.autorities" :key="i">
<a :href="aut.identifier" target="_blanck">
{{ aut.autority }}
<span class="mdi mdi-open-in-new" />
</a>
</li>
</ul>
</section>
</template> </template>
<!-- default slot --> <!-- default slot -->
<IndexItemOcurrences v-if="content" :content="content" /> <IndexItemOcurrences v-if="content" :content="content" />
<template #nav>
<aside class="links">
<p>
Permalien:<br><a :href="`${content.url}`">{{ content.url }}</a>
</p>
<p>
JSON:<br><a :href="`${apipath}${content.path}${content.uuid}`">{{ apipath }}{{ content.path }}{{ content.uuid }}</a>
</p>
</aside>
</template>
</MainContentLayout> </MainContentLayout>
</template> </template>
@@ -27,11 +58,15 @@ export default {
IndexItemOcurrences IndexItemOcurrences
}, },
data: () => ({ data: () => ({
content: null content: null,
meta: [],
metainfotitle: undefined
}), }),
metaInfo () { metaInfo () {
// console.log('metainfo', this.meta)
return { return {
title: `Operum ${this.$route.params.id}` title: this.metainfotitle,
meta: this.meta
} }
}, },
beforeCreate () { beforeCreate () {
@@ -41,7 +76,9 @@ export default {
console.log('operum REST: data', data) console.log('operum REST: data', data)
if (data.content) { if (data.content) {
this.content = data.content this.content = data.content
this.metainfotitle = data.content.title
} }
this.updateMetaData(data.meta.metadata)
}) })
.catch((error) => { .catch((error) => {
console.warn('Issue with operum', error) console.warn('Issue with operum', error)
@@ -51,6 +88,24 @@ export default {
query: { fullpath: this.$route.path } query: { fullpath: this.$route.path }
}) })
}) })
},
methods: {
updateMetaData (metadata) {
this.meta = []
metadata.forEach(m => {
let o = {}
o.name = m.name
if (Array.isArray(m.content)) {
o.content = m.content.join(', ')
} else {
o.content = m.content
}
if (typeof m.scheme !== 'undefined') {
o.scheme = m.scheme
}
this.meta.push(o)
})
}
} }
} }
</script> </script>
+144
View File
@@ -0,0 +1,144 @@
<template>
<MainContentLayout
id="static"
:reftoscrollto="reftoscrollto"
>
<template v-slot:header>
<span v-if="!page" class="loading">Chargement ...</span>
<template v-else>
<h1>{{ page.title }}</h1>
<nav v-if="toc" class="toc" :class="{ opened: sommaireopened }">
<span
class="sommaire-title"
@click.prevent="onOpenCloseSommaire"
@keyup.enter="onOpenCloseSommaire"
>
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="10" role="presentation" class="vs__open-indicator"><path d="M9.211364 7.59931l4.48338-4.867229c.407008-.441854.407008-1.158247 0-1.60046l-.73712-.80023c-.407008-.441854-1.066904-.441854-1.474243 0L7 5.198617 2.51662.33139c-.407008-.441853-1.066904-.441853-1.474243 0l-.737121.80023c-.407008.441854-.407008 1.158248 0 1.600461l4.48338 4.867228L7 10l2.211364-2.40069z" /></svg>
Sommaire
</span>
<div class="wrapper">
<ul>
<li
v-for="(item,index) in toc"
:key="index"
>
<a
:href="'#' + item.hash"
@click.prevent="onclickTOC"
@keyup.enter="onclickTOC"
>
{{ item.title }}
</a>
</li>
</ul>
</div>
</nav>
</template>
</template>
<div v-if="page" v-html="page.tei_parsed" />
</MainContentLayout>
</template>
<script>
import { mapState, mapActions } from 'vuex'
import MainContentLayout from '../components/Layouts/MainContentLayout'
export default {
name: 'Static',
components: {
MainContentLayout
},
data: () => ({
uuid: null,
page: null,
toc: [],
reftoscrollto: null,
sommaireopened: false
}),
computed: {
...mapState({
colophon: state => state.Colophon.colophon
})
// page () {
// }
},
watch: {
$route (n, o) {
console.log('static route changed', n, o)
this.uuid = n.name
if (this.colophon && this.colophon.length > 0) {
this.setPage()
}
},
colophon (n, o) {
this.setPage()
}
},
beforeCreate () {
},
created () {
if (!this.colophon.length) {
this.getColophon()
}
console.log('Static created', this.$route)
this.uuid = this.$route.name
if (this.colophon && this.colophon.length > 0) {
this.setPage()
}
},
methods: {
...mapActions({
getColophon: 'Colophon/getColophon'
}),
setPage () {
for (let i = 0; i < this.colophon.length; i++) {
if (this.colophon[i].uuid === this.uuid) {
this.page = this.colophon[i]
}
}
this.parseContentImages()
this.parseContentTOC()
},
parseContentImages () {
console.log('parseContentImages')
this.page.tei_parsed = this.page.tei.replace(/src="\/gdp\/static\/images\/(\w+)\.jpg"/g, `src="${window.apipath}/gdp/static/images/$1.jpg"`)
// console.log(this.page.tei_parsed)
},
parseContentTOC () {
let match = this.page.tei_parsed.match(/<h1[^>]*>[^<]+<\/h1>/g)
console.log('match', match)
match.forEach((element, index) => {
console.log(element, index)
// let elmt = element.replace(/<h1([^>]*)>([^<]+)<\/h1>/, `<h1 id="toc-${index}"$1>$2</h1>`)
let elmtmatch = element.match(/(<h1([^>]*)>)([^<]+)<\/h1>/)
let elmt = element.replace(elmtmatch[1], `<h1 id="toc-${index}"${elmtmatch[2]}>`)
this.page.tei_parsed = this.page.tei_parsed.replace(element, elmt)
this.toc.push({
title: elmtmatch[3],
hash: `toc-${index}`
})
})
},
onOpenCloseSommaire (e) {
console.log('onOpenCloseSommaire', e)
this.sommaireopened = !this.sommaireopened
},
onclickTOC (e) {
console.log('onClickTOC', e, e.target.hash)
this.reftoscrollto = e.target.hash
}
},
metaInfo () {
return {
title: `Static`
}
}
}
</script>
<style lang="scss" scoped>
</style>
+64 -18
View File
@@ -1,6 +1,8 @@
import Vue from 'vue' import Vue from 'vue'
import Router from 'vue-router' import Router from 'vue-router'
import { REST } from 'api/rest-axios'
import Home from 'pages/Home' import Home from 'pages/Home'
// import Item from 'pages/Item' // import Item from 'pages/Item'
import ListCorpus from 'pages/ListCorpus' import ListCorpus from 'pages/ListCorpus'
@@ -14,6 +16,7 @@ import Locorum from 'pages/Locorum'
import Operum from 'pages/Operum' import Operum from 'pages/Operum'
import Bibliographie from 'pages/Bibliographie' import Bibliographie from 'pages/Bibliographie'
import NotFound from 'pages/NotFound' import NotFound from 'pages/NotFound'
import Static from 'pages/Static'
Vue.use(Router) Vue.use(Router)
@@ -23,12 +26,26 @@ const routes = [
path: '/', path: '/',
component: Home component: Home
}, },
// { {
// name: 'item', name: 'credits',
// path: '/babar/:uuid', path: '/credits',
// component: Item, component: Static
// props: true },
// }, {
name: 'guide',
path: '/guide',
component: Static
},
{
name: 'schema',
path: '/schema',
component: Static
},
{
name: 'api',
path: '/api',
component: Static
},
{ {
name: 'listcorpus', name: 'listcorpus',
path: '/corpus', path: '/corpus',
@@ -41,60 +58,89 @@ const routes = [
// }, // },
{ {
name: 'edition', name: 'edition',
path: '/edition/:id', path: '/texts/:id',
component: Edition component: Edition
}, },
{ {
name: 'editiontext', name: 'editiontext',
path: '/edition/:id/:textid', path: '/texts/:id/:textid',
component: Edition
},
{
name: 'editiontextextract',
path: '/texts/:id/:textid/:ocid',
component: Edition component: Edition
}, },
{ {
name: 'indexNominum', name: 'indexNominum',
path: '/nominum', path: '/indexNominum',
component: IndexNominum component: IndexNominum
}, },
{ {
name: 'nominum', name: 'nominum',
path: '/nominum/:id', path: '/indexNominum/:id',
component: Nominum component: Nominum
}, },
{ {
name: 'indexLocorum', name: 'indexLocorum',
path: '/locorum', path: '/indexLocorum',
component: IndexLocorum component: IndexLocorum
}, },
{ {
name: 'locorum', name: 'locorum',
path: '/locorum/:id', path: '/indexLocorum/:id',
component: Locorum component: Locorum
}, },
{ {
name: 'indexOperum', name: 'indexOperum',
path: '/operum', path: '/indexOperum',
component: IndexOperum component: IndexOperum
}, },
{ {
name: 'operum', name: 'operum',
path: '/operum/:id', path: '/indexOperum/:id',
component: Operum component: Operum
}, },
{ {
path: '/bibliographie', path: '/bibliography',
redirect: '/bibliographie/expressions' redirect: '/bibliography/expressions'
}, },
{ {
name: 'bibliographie', name: 'bibliographie',
path: '/bibliographie/:type', path: '/bibliography/:type',
component: Bibliographie, component: Bibliographie,
props: true props: true
}, },
{ {
name: 'bibliographieItem', name: 'bibliographieItem',
path: '/bibliographie/:type/:uuid', path: '/bibliography/:type/:uuid',
component: Bibliographie, component: Bibliographie,
props: true props: true
}, },
// redirects /items/uuid to /texts/[edid]/[textid]
{
name: 'items',
path: '/items/:uuid',
beforeEnter: async (to, from, next) => {
console.log('items before enter', from, to, next)
let item = await REST.get(`${window.apipath}/items/` + to.params.uuid, {})
.then(({ data }) => {
// console.log('corpus getEditionsList REST: author, data', author, data)
return data.content
})
.catch((error) => {
console.warn('Issue with getEditionsList', error)
// Promise.reject(error)
})
console.log('items : item', item)
// item.textid = 'gdpSauval1724'
// this named route does not replace the url
// next({ name: 'editiontext', params: { id: item.textid, textid: item.uuid }, replace: true })
next({ path: `/texts/${item.textId}/${item.uuid}`, replace: true })
},
component: { render: () => null }
},
{ {
name: 'notfound', name: 'notfound',
path: '/404', path: '/404',
+3 -1
View File
@@ -4,12 +4,14 @@ import Vuex from 'vuex'
import Corpus from './modules/corpus' import Corpus from './modules/corpus'
import Search from './modules/search' import Search from './modules/search'
import History from './modules/history' import History from './modules/history'
import Colophon from './modules/colophon'
Vue.use(Vuex) Vue.use(Vuex)
export default new Vuex.Store({ export default new Vuex.Store({
modules: { modules: {
Corpus, Corpus,
Search, Search,
History History,
Colophon
} }
}) })
+65
View File
@@ -0,0 +1,65 @@
import { REST } from 'api/rest-axios'
import router from '../../router'
export default {
namespaced: true,
router,
// initial state
state: {
colophon: [],
colophonHome: []
},
// getters
getters: {},
// mutations
mutations: {
setColophon (state, colophon) {
state.colophon = colophon
for (let i = 0; i < colophon.length; i++) {
if (colophon[i].uuid !== 'schema') {
state.colophonHome.push(colophon[i])
}
}
}
},
// actions
actions: {
getColophon ({ dispatch, commit, state }) {
REST.get(`${window.apipath}/colophon`, {})
.then(({ data }) => {
console.log('colophon getColophon REST: data', data)
// commit('setColophon', data.content)
dispatch('getPages', data.content.pages)
.then((pages) => {
console.log('all pages returned: pages', pages)
commit('setColophon', pages)
})
})
.catch((error) => {
console.warn('Issue with getColophon', error)
Promise.reject(error)
})
},
// async get pages
getPages ({ dispatch, commit, state }, pages) {
return Promise.all(pages.map(function (page) {
return REST.get(`${window.apipath}/colophon/` + page.uuid, {})
.then(({ data }) => {
console.log('colophon getPages REST: page, data', page, data)
// // work arround
// if (!Array.isArray(data.content)) {
// data.content = [data.content]
// }
return data.content
})
.catch((error) => {
console.warn('colophon Issue with getPages', error)
Promise.reject(error)
})
}))
}
}
}
+45 -51
View File
@@ -10,7 +10,8 @@ export default {
editionslist: [], editionslist: [],
editionsbyuuid: {}, editionsbyuuid: {},
editionsuuids: [], editionsuuids: [],
corpusLoaded: false corpusLoaded: false,
numTocsItem: 0
}, },
// getters // getters
@@ -40,22 +41,53 @@ export default {
}) })
// console.log('corpus editionsbyuuid', state.editionsbyuuid) // console.log('corpus editionsbyuuid', state.editionsbyuuid)
}, },
buildFlatTocs (state, eeuid) { buildFlatTocsAndFilters (state) {
let recurseFlatToc = (state, eduuid, a) => { let recurseToc = (state, eduuid, a) => {
// console.log('recurseFlatToc', a) // console.log('recurseToc', a)
a.forEach((item, i) => { a.forEach((item, i) => {
state.editionsbyuuid[eduuid].flattoc.push(item.uuid) if (item) {
if (item.children && item.children.length) { // flatToc
recurseFlatToc(state, eduuid, item.children) state.editionsbyuuid[eduuid].flattoc.push(item.uuid)
state.numTocsItem++
// filters
let indexes = item.indexes[0]
for (const key in indexes) {
// loop through indexes (objects, persons, places)
if (Object.hasOwnProperty.call(indexes, key)) {
indexes[key].forEach(element => {
// loop through index elements
if (!(element.uuid in state.editionsbyuuid[eduuid].indexes[key])) {
state.editionsbyuuid[eduuid].indexes[key][element.uuid] = element
}
})
}
}
// recursive loop
if (item.children && item.children.length) {
recurseToc(state, eduuid, item.children)
}
} }
}) })
} }
state.editionsuuids.forEach((eduuid, i) => { state.editionsuuids.forEach((eduuid, i) => {
// console.log('buildFlatTocs', i, eduuid) // console.log('buildFlatTocsAndFilters', i, eduuid)
state.editionsbyuuid[eduuid].flattoc = [] state.editionsbyuuid[eduuid].flattoc = []
recurseFlatToc(state, eduuid, state.editionsbyuuid[eduuid].toc) state.editionsbyuuid[eduuid].indexes = {
// console.log('buildFlatTocs DONE', eduuid, state.editionsbyuuid[eduuid].flattoc) objects: {},
persons: {},
places: {}
}
recurseToc(state, eduuid, state.editionsbyuuid[eduuid].toc)
console.log('buildFlatTocsAndFilters DONE',
eduuid,
`places: ${Object.keys(state.editionsbyuuid[eduuid].indexes['places']).length}`,
`objects: ${Object.keys(state.editionsbyuuid[eduuid].indexes['objects']).length}`,
`persons: ${Object.keys(state.editionsbyuuid[eduuid].indexes['persons']).length}`,
state.editionsbyuuid[eduuid].indexes)
}) })
console.log('numTocsItem', state.numTocsItem)
}, },
setPaginations (state, paginationslist) { setPaginations (state, paginationslist) {
// console.log('setPaginations', paginationslist) // console.log('setPaginations', paginationslist)
@@ -68,6 +100,7 @@ export default {
console.info('corpusLoaded') console.info('corpusLoaded')
state.corpusLoaded = true state.corpusLoaded = true
} }
}, },
// actions // actions
@@ -79,11 +112,6 @@ export default {
.then(({ data }) => { .then(({ data }) => {
// console.log('getCorpuses authors data', data) // console.log('getCorpuses authors data', data)
commit('setAuthors', data.content) commit('setAuthors', data.content)
// get the texts list for each corpus (aka author)
// let authorsUuids = []
// for (let author of data.content) {
// authorsUuids.push(author.uuid)
// }
dispatch('getEditionsList', data.content) dispatch('getEditionsList', data.content)
.then((editionslist) => { .then((editionslist) => {
console.log('all texts returned: editionslist', editionslist) console.log('all texts returned: editionslist', editionslist)
@@ -94,9 +122,7 @@ export default {
.then((tocslist) => { .then((tocslist) => {
console.log('all tocs returned: tocslist', tocslist) console.log('all tocs returned: tocslist', tocslist)
commit('setTocs', tocslist) commit('setTocs', tocslist)
// this.methods.testMethod() commit('buildFlatTocsAndFilters')
// dispatch('buildFlatTocs')
commit('buildFlatTocs')
dispatch('getEditionsPaginations') dispatch('getEditionsPaginations')
.then((paginationslist) => { .then((paginationslist) => {
console.log('all paginations returned: paginationslist', paginationslist) console.log('all paginations returned: paginationslist', paginationslist)
@@ -146,7 +172,7 @@ export default {
return Promise.all(state.editionsuuids.map(function (uuid) { return Promise.all(state.editionsuuids.map(function (uuid) {
return REST.get(`${window.apipath}/texts/${uuid}/toc`, {}) return REST.get(`${window.apipath}/texts/${uuid}/toc`, {})
.then(({ data }) => { .then(({ data }) => {
// console.log('corpus getEditionsTocs REST: uuid, data', uuid, data) console.log('corpus getEditionsTocs REST: uuid, data', uuid, data)
// work arround // work arround
// if (!Array.isArray(data.content)) { // if (!Array.isArray(data.content)) {
// data.content = [data.content] // data.content = [data.content]
@@ -183,38 +209,6 @@ export default {
}) })
})) }))
} }
// ,
// buildFlatTocs ({ dispatch, commit, state }) {
// state.editionsuuids.forEach((eduuid, i) => {
// // console.log('buildFlatTocs', i, eduuid)
// dispatch('recurseFlatToc', state.editionsbyuuid[eduuid].toc)
// .then((ft) => {
// console.log('buildFlatTocs DONE', eduuid, ft)
// state.editionsbyuuid[eduuid].flattoc = ft
// })
// })
// },
// recurseFlatToc ({ dispatch, commit, state }, a) {
// // console.log('recurseFlatToc', a)
// let na = []
// // a.forEach((item, i) => {
// return Promise.all(a.map(function (item) {
// console.log('item', item)
// na.push(item.uuid)
// if (item.children && item.children.length) {
// return dispatch('recurseFlatToc', item.children)
// .then((nna) => {
// console.log('recurseFlatToc: na, nna', na, nna)
// na.concat(nna)
// })
// }
// // else {
// // return na
// // }
// }))
// // })
// // return na
// }
}, },
methods: { methods: {
testMethod () { testMethod () {
+1 -1
View File
@@ -16,7 +16,7 @@ export default {
// mutations // mutations
mutations: { mutations: {
addItem (state, item) { addItem (state, item) {
state.items.push(item) state.items.unshift(item)
}, },
setOpened (state, opened) { setOpened (state, opened) {
state.opened = opened state.opened = opened
+28 -27
View File
@@ -3,7 +3,7 @@ import axios from 'axios'
import { REST } from 'api/rest-axios' import { REST } from 'api/rest-axios'
import qs from 'querystring' import qs from 'querystring'
const _filterskeys = ['persons', 'places', 'objects'] const _filterskeys = ['persons', 'places', 'objects', 'texts']
const _CancelToken = axios.CancelToken const _CancelToken = axios.CancelToken
// const _cancelTokenSource = _CancelToken.source() // const _cancelTokenSource = _CancelToken.source()
let _cancelTokens = [] let _cancelTokens = []
@@ -20,11 +20,11 @@ export default {
{ 'code': 'text', 'label': 'Dans les textes' }, { 'code': 'text', 'label': 'Dans les textes' },
{ 'code': 'persons', 'label': 'Dans les personnes' }, { 'code': 'persons', 'label': 'Dans les personnes' },
{ 'code': 'places', 'label': 'Dans les lieux' }, { 'code': 'places', 'label': 'Dans les lieux' },
{ 'code': 'objects', 'label': 'Dans les objets' } { 'code': 'objects', 'label': 'Dans les œuvres' }
], ],
searchTypeValue: { 'code': 'text', 'label': 'Dans les textes' }, searchTypeValue: { 'code': 'text', 'label': 'Dans les textes' },
filters: { persons: [], places: [], objects: [] }, filters: { persons: [], places: [], objects: [], texts: [] },
activeFilters: { persons: [], places: [], objects: [] }, activeFilters: { persons: [], places: [], objects: [], texts: [] },
sortOptions: [ sortOptions: [
{ code: 'date', label: 'date' }, { code: 'date', label: 'date' },
{ code: 'score', label: 'pertinence' }, { code: 'score', label: 'pertinence' },
@@ -77,30 +77,30 @@ export default {
state.searchTypeValue = value state.searchTypeValue = value
}, },
setFilters (state, filters) { setFilters (state, filters) {
for (let index in filters) { for (let filter in filters) {
if (filters.hasOwnProperty(index)) { if (filters.hasOwnProperty(filter)) {
console.log('index', index) console.log('filter', filter)
if (filters[index]) { if (filters[filter]) {
if (Array.isArray(filters[index])) { if (Array.isArray(filters[filter])) {
state.filters[index] = [] state.filters[filter] = []
for (var i = 0; i < filters[index].length; i++) { for (var i = 0; i < filters[filter].length; i++) {
if (filters[index][i].uuid && filters[index][i].title) { if (filters[filter][i].uuid && filters[filter][i].title) {
state.filters[index].push({ state.filters[filter].push({
code: filters[index][i].uuid, code: filters[filter][i].uuid,
label: filters[index][i].title label: `${filters[filter][i].title} [${filters[filter][i].quantity}]`
}) })
} }
} }
} else { } else {
if (filters[index].uuid && filters[index].title) { if (filters[filter].uuid && filters[filter].title) {
state.filters[index] = [{ state.filters[filter] = [{
code: filters[index].uuid, code: filters[filter].uuid,
label: filters[index].title label: filters[filter].title
}] }]
} }
} }
} else { } else {
state.filters[index] = [] state.filters[filter] = []
} }
} }
} }
@@ -108,7 +108,7 @@ export default {
}, },
setActiveFilters (state, filters) { setActiveFilters (state, filters) {
// console.log('setActiveFilters', filters) // console.log('setActiveFilters', filters)
state.activeFilters[filters.index] = filters.value state.activeFilters[filters.filter] = filters.value
// console.log('state.activeFilters', state.activeFilters) // console.log('state.activeFilters', state.activeFilters)
}, },
resetActiveFilters (state) { resetActiveFilters (state) {
@@ -148,19 +148,20 @@ export default {
params.type = state.searchTypeValue.code params.type = state.searchTypeValue.code
} }
let f let f
for (var index of _filterskeys) { for (var filter of _filterskeys) {
if (state.activeFilters[index].length) { // console.log(`state.activeFilters[${filter}]`, state.activeFilters[filter])
f = `filter${index.charAt(0).toUpperCase()}${index.slice(1)}` if (state.activeFilters[filter].length) {
f = filter === 'texts' ? 'text' : `filter${filter.charAt(0).toUpperCase()}${filter.slice(1)}`
params[f] = [] params[f] = []
for (var i = 0; i < state.activeFilters[index].length; i++) { for (var i = 0; i < state.activeFilters[filter].length; i++) {
params[f].push(state.activeFilters[index][i].code) params[f].push(state.activeFilters[filter][i].code)
} }
} }
} }
if (state.sorting) { if (state.sorting) {
params.sort = state.sorting.code params.sort = state.sorting.code
} }
// console.log('Search getResults params', params); console.log('Search getResults params', params)
let q = qs.stringify(params) let q = qs.stringify(params)
// construct options // construct options
+11
View File
@@ -0,0 +1,11 @@
<IfModule mod_negotiation.c>
Options -MultiViews
</IfModule>
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</IfModule>
Binary file not shown.

After

Width:  |  Height:  |  Size: 135 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB