Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • websites/monnaie-libre-fr
  • midiland/monnaie-libre-fr
  • websites/moneda-libre-org
  • atlasan/g1-monetalibera-it
  • Processus42/monnaie-libre-fr
  • diablade/monnaie-libre-fr
  • Spiranne/monnaie-libre-fr
7 results
Show changes
Commits on Source (1280)
Showing
with 638 additions and 178 deletions
File moved
v16.15.1
...@@ -33,7 +33,7 @@ For detailed explanation on how things work, check out [Nuxt.js docs](https://nu ...@@ -33,7 +33,7 @@ For detailed explanation on how things work, check out [Nuxt.js docs](https://nu
# Administration : le back office # Administration : le back office
Vous pouvez accéder à l'administration ici : https://monnaie-libre.fr/admin/ Vous pouvez accéder à l'administration ici : https://monnaie-libre.fr/admin/
Le back office est conçu avec [netlify cms](https://www.netlifycms.org/) qui est lui même couplé à ce dépôt. Tout changement effectué en back office créera une demande de fusion dans ce dépôt. Le back office est conçu avec [netlify cms](https://www.netlifycms.org/) qui est lui même couplé à ce dépôt gitlab. Tout changement effectué en back office créera une demande de fusion dans ce dépôt.
Vous devez avoir un compte sur ce gitlab (git.duniter.org) pour pouvoir accéder au back office. Vous devez avoir un compte sur ce gitlab (git.duniter.org) pour pouvoir accéder au back office.
## Lancer le back office (netlify) ## Lancer le back office (netlify)
...@@ -51,9 +51,13 @@ Puis aller sur http://localhost:3000/admin/ ...@@ -51,9 +51,13 @@ Puis aller sur http://localhost:3000/admin/
# Design # Design
## Storybook ## Illustration
Idée abandonnée. J'ai installé, configuré et testé. Mais c'est compliqué, et finalement pas super intégré pour vue.js... Toutes les images utilisées sur le site :
https://www.figma.com/file/Gof5rulCCUMvwk3WDKlgVY/monnaie-libre.fr
Ressources :
https://www.pixeltrue.com/free-packs/minimalistic-illustrations#preview
## Afficher toutes les `class` de tailwindcss ## Afficher toutes les `class` de tailwindcss
...@@ -120,6 +124,19 @@ Go to http://localhost/ ! ...@@ -120,6 +124,19 @@ Go to http://localhost/ !
You can change the port. In the command above, replace `80:80` by `4000:80` and go to http://localhost:4000/ You can change the port. In the command above, replace `80:80` by `4000:80` and go to http://localhost:4000/
# CI Gitlab # Gitlab
## Graphql
Graphql Endpoint : https://git.duniter.org/api/graphql
Graphql Explorer : https://git.duniter.org/-/graphql-explorer
## About CI
https://blog.logrocket.com/how-to-auto-deploy-a-vue-application-using-gitlab-ci-cd-on-ubuntu/ https://blog.logrocket.com/how-to-auto-deploy-a-vue-application-using-gitlab-ci-cd-on-ubuntu/
# Discourse
## API Docs
https://docs.discourse.org/
...@@ -29,6 +29,14 @@ html { ...@@ -29,6 +29,14 @@ html {
@apply text-white; @apply text-white;
} }
/* For emojis from discourse */
img.emoji {
width: 20px;
height: 20px;
vertical-align: middle;
display: inline;
}
/* Loader */ /* Loader */
@keyframes spinner { @keyframes spinner {
to { to {
......
<template> <template>
<t-toggle v-model="mode" value="dark" unchecked-value="light" variant="dark"> <t-toggle
v-model="mode"
value="dark"
unchecked-value="light"
variant="dark"
:aria-checked="mode === 'light' ? 'false' : 'true'"
aria-label="Toggle dark mode"
>
<fa <fa
slot="unchecked" slot="unchecked"
icon="sun" icon="sun"
......
<template> <template>
<div class="flex items-center mb-8"> <div class="flex items-center mb-8 text-gray-500">
<fa :icon="['far', 'clock']" class="text-gray-400 text-lg mr-2" /> <fa :icon="['far', 'clock']" class="text-xl mr-2" />
<div> <div>
<span>{{ readingTimeToStr }}</span> <span>{{ readingTimeToStr }}</span>
<span class="text-gray-400 text-sm pl-1"> <span
class="text-sm text-gray-400 dark:text-gray-600 pl-1 hidden xl:inline"
>
{{ `(${readingTime.words} mots)` }} {{ `(${readingTime.words} mots)` }}
</span> </span>
</div> </div>
......
<template>
<div class="relative">
<t-dropdown
:show.sync="show"
toggle-on-focus
toggle-on-hover
:hide-on-leave-timeout="0"
:classes="{
dropdown:
'absolute rounded-md shadow-lg dark:border-gray-500 border -top-3 -left-3 z-10 overflow-hidden w-40 bg-white dark:bg-gray-600 transition duration-150 ease-in-out',
}"
>
<button
slot="button"
class="relative flex items-center text-gray-500"
:class="show && 'z-20 text-gray-800 dark:text-gray-200'"
aria-label="Partager"
aria-haspopup="true"
>
<fa icon="share-alt" class="text-xl mr-2.5" />
<div>Partager</div>
</button>
<div class="mt-11 pt-0.5 pb-1">
<div class="border-t dark:border-gray-500 pt-1 mx-2"></div>
<ShareNetwork
v-for="network in networks"
:key="network.name"
:network="network.network"
:url="$config.site_url + document.path.replace(/^\/pages\//, '/')"
:title="document.title"
:description="document.description"
:quote="document.description"
:hashtags="$config.social_networks_hashtags"
:twitter-user="$config.twitter_user"
:media="media"
class="
flex
items-center
pl-4
pr-2
py-1
text-gray-600
hover:text-gray-700 hover:bg-hover-light
dark:text-gray-200
"
>
<fa :icon="network.icon" :class="network.class" />
<span class="pl-2">
{{ network.name }}
</span>
</ShareNetwork>
</div>
</t-dropdown>
</div>
</template>
<script>
import { defineComponent, ref } from '@nuxtjs/composition-api'
export default defineComponent({
props: {
document: {
type: Object,
required: true,
},
media: {
type: String,
default: null,
},
},
setup() {
const show = ref(false)
return {
show,
networks: [
{ network: 'email', name: 'Email', icon: 'envelope', class: 'email' },
{
network: 'facebook',
name: 'Facebook',
icon: ['fab', 'facebook'],
class: 'facebook',
},
{
network: 'twitter',
name: 'Twitter',
icon: ['fab', 'twitter'],
class: 'twitter',
},
{
network: 'linkedin',
name: 'Linkedin',
icon: ['fab', 'linkedin'],
class: 'linkedin',
},
{
network: 'reddit',
name: 'Reddit',
icon: ['fab', 'reddit'],
class: 'reddit',
},
{
network: 'skype',
name: 'Skype',
icon: ['fab', 'skype'],
class: 'skype',
},
{ network: 'sms', name: 'SMS', icon: 'comment', class: 'sms' },
{
network: 'telegram',
name: 'Telegram',
icon: ['fab', 'telegram'],
class: 'telegram',
},
{
network: 'whatsapp',
name: 'Whatsapp',
icon: ['fab', 'whatsapp'],
class: 'whatsapp',
},
],
}
},
})
</script>
<style scoped>
.email,
.sms {
color: #444;
}
.twitter {
color: #1da1f2;
}
.facebook {
color: #3b5998;
}
.linkedin {
color: #0077b5;
}
.skype {
color: #00aff0;
}
.reddit {
color: #ff4500;
}
.telegram {
color: #0088cc;
}
.whatsapp {
color: #43d854;
}
</style>
...@@ -4,7 +4,17 @@ ...@@ -4,7 +4,17 @@
<span <span
v-show="hovered" v-show="hovered"
id="tooltip-mini-map" id="tooltip-mini-map"
class="absolute whitespace-nowrap pointer-events-none p-1 shadow-lg rounded text-xs bg-opacity-90 bg-white dark:bg-gray-700" class="
absolute
whitespace-nowrap
pointer-events-none
p-1
shadow-lg
rounded
text-xs
bg-opacity-90 bg-white
dark:bg-gray-700
"
> >
{{ hovered && hovered.name }} {{ hovered && hovered.name }}
</span> </span>
...@@ -223,7 +233,7 @@ export default { ...@@ -223,7 +233,7 @@ export default {
region.addEventListener('click', (evt) => { region.addEventListener('click', (evt) => {
window.open( window.open(
`https://forum.monnaie-libre.fr/c/${regions[evt.target.id].id}`, `${this.$config.forum_url}/c/${regions[evt.target.id].id}`,
'_blank' '_blank'
) )
}) })
......
...@@ -8,7 +8,10 @@ ...@@ -8,7 +8,10 @@
v-bind="$attrs" v-bind="$attrs"
v-on="$listeners" v-on="$listeners"
/> />
<div class="absolute flex items-center ml-3 bottom-0 top-0"> <div
class="absolute flex items-center bottom-0 top-0 ml-4"
:class="iconWrapperClass"
>
<fa slot="icon" :icon="icon" :class="iconClass" /> <fa slot="icon" :icon="icon" :class="iconClass" />
</div> </div>
</div> </div>
...@@ -26,6 +29,10 @@ export default { ...@@ -26,6 +29,10 @@ export default {
type: String, type: String,
default: null, default: null,
}, },
iconWrapperClass: {
type: String,
default: null,
},
iconClass: { iconClass: {
type: String, type: String,
default: null, default: null,
...@@ -40,7 +47,7 @@ export default { ...@@ -40,7 +47,7 @@ export default {
}, },
}, },
mounted() { mounted() {
if (this.focus) this.focus() if (this.hasFocus) this.focus()
}, },
methods: { methods: {
focus() { focus() {
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
:to="next.path" :to="next.path"
class="group next-blog flex-1 py-8 text-right" class="group next-blog flex-1 py-8 text-right"
> >
<span class="group-hover:text-hover"> <span v-prevent-last-char-break class="group-hover:text-hover">
{{ next.title }} {{ next.title }}
</span> </span>
<fa icon="chevron-right" class="text-gray-300 ml-3 transition" /> <fa icon="chevron-right" class="text-gray-300 ml-3 transition" />
......
...@@ -45,13 +45,12 @@ export default { ...@@ -45,13 +45,12 @@ export default {
@apply m-0 !important; @apply m-0 !important;
} }
.alert a { .alert a {
@apply text-gray-700 !important; @apply text-current !important;
} filter: brightness(1.25);
.dark-mode .alert a {
@apply text-gray-300 !important;
} }
.alert strong { .alert strong {
@apply text-current; @apply text-current !important;
filter: brightness(1.25);
} }
.alert-content pre code { .alert-content pre code {
background-color: inherit !important; background-color: inherit !important;
...@@ -69,13 +68,13 @@ export default { ...@@ -69,13 +68,13 @@ export default {
.alert-info .alert-content { .alert-info .alert-content {
@apply text-blue-700; @apply text-blue-700;
} }
.dark-mode .alert-info { .dark .alert-info {
@apply bg-blue-900 border-blue-700; @apply bg-blue-900 border-blue-700;
} }
.dark-mode .alert-info code { .dark .alert-info code {
@apply bg-blue-800; @apply bg-blue-800;
} }
.dark-mode .alert-info .alert-content { .dark .alert-info .alert-content {
@apply text-blue-300; @apply text-blue-300;
} }
/* Success */ /* Success */
...@@ -91,13 +90,13 @@ export default { ...@@ -91,13 +90,13 @@ export default {
.alert-success .alert-content { .alert-success .alert-content {
@apply text-green-700; @apply text-green-700;
} }
.dark-mode .alert-success { .dark .alert-success {
@apply bg-green-900 border-green-700; @apply bg-green-900 border-green-700;
} }
.dark-mode .alert-success code { .dark .alert-success code {
@apply bg-green-800; @apply bg-green-800;
} }
.dark-mode .alert-success .alert-content { .dark .alert-success .alert-content {
@apply text-green-300; @apply text-green-300;
} }
/* Warning */ /* Warning */
...@@ -113,13 +112,13 @@ export default { ...@@ -113,13 +112,13 @@ export default {
.alert-warning .alert-content { .alert-warning .alert-content {
@apply text-yellow-700; @apply text-yellow-700;
} }
.dark-mode .alert-warning { .dark .alert-warning {
@apply bg-yellow-900 border-yellow-700; @apply bg-yellow-800 border-yellow-600;
} }
.dark-mode .alert-warning code { .dark .alert-warning code {
@apply bg-yellow-800; @apply bg-yellow-800;
} }
.dark-mode .alert-warning .alert-content { .dark .alert-warning .alert-content {
@apply text-yellow-300; @apply text-yellow-300;
} }
/* Danger */ /* Danger */
...@@ -135,13 +134,13 @@ export default { ...@@ -135,13 +134,13 @@ export default {
.alert-danger .alert-content { .alert-danger .alert-content {
@apply text-red-700; @apply text-red-700;
} }
.dark-mode .alert-danger { .dark .alert-danger {
@apply bg-red-900 border-red-700; @apply bg-red-900 border-red-700;
} }
.dark-mode .alert-danger code { .dark .alert-danger code {
@apply bg-red-800; @apply bg-red-800;
} }
.dark-mode .alert-danger .alert-content { .dark .alert-danger .alert-content {
@apply text-red-300; @apply text-red-300;
} }
</style> </style>
<template>
<component
:is="to ? 'nuxt-link' : 'div'"
:to="to"
class="block rounded p-4"
:class="computedClass"
>
<slot />
</component>
</template>
<script>
export default {
name: 'Box',
props: {
to: {
type: [String, Object],
default: null,
},
color: {
type: String,
default: null,
},
},
computed: {
computedClass() {
let classes = ''
if (this.color) {
classes += `bg-${this.color}-100 dark:bg-${this.color}-900`
} else {
classes = `border dark:border-gray-700`
}
if (this.to)
classes +=
' transition transform hover:shadow-xl hover:-translate-y-0.5 is-box-with-link'
return classes
},
},
}
</script>
<style lang="postcss" scoped>
.is-box-with-link {
text-decoration: none !important;
color: currentColor !important;
font-weight: normal !important;
}
</style>
...@@ -40,7 +40,17 @@ ...@@ -40,7 +40,17 @@
</slot> </slot>
<div <div
class="flex items-center w-full lg:w-max justify-center px-2 lg:px-0 pt-2 lg:pt-0" class="
flex
items-center
w-full
lg:w-max
justify-center
px-2
lg:px-0
pt-2
lg:pt-0
"
> >
<slot <slot
v-if="!isKeyCopied" v-if="!isKeyCopied"
...@@ -140,9 +150,8 @@ export default { ...@@ -140,9 +150,8 @@ export default {
computed: { computed: {
endpoint() { endpoint() {
// Build url from props. Prevent missing protocol. // Build url from props. Prevent missing protocol.
return (/^https:\/\//.test(this.node) return (
? this.node /^https:\/\//.test(this.node) ? this.node : `https://${this.node}`
: `https://${this.node}`
).replace(/\/$/, '') ).replace(/\/$/, '')
}, },
startDateTimestamp() { startDateTimestamp() {
......
<template> <template>
<span <span
class="tooltip-box relative" class="tooltip-box relative"
:class="page && 'cursor-pointer'" :class="document && 'cursor-pointer'"
v-on="page ? { click: onClick } : {}" v-on="document ? { click: onClick } : {}"
> >
<abbr :aria-label="page ? page.title : title" :title="page ? '' : null"> <abbr
:aria-label="document ? document.title : title"
:title="document ? '' : null"
>
<slot /> <slot />
</abbr> </abbr>
<client-only> <client-only>
<div <div
v-if="page" v-if="document"
class="tooltip absolute bg-gray-200 invisible opacity-0 left-1/2 px-4 py-2 rounded-xl shadow-lg text-gray-600 text-sm z-50" class="
tooltip
absolute
bg-blue-100
border-blue-200 border
invisible
opacity-0
left-1/2
px-4
py-3
rounded-xl
shadow-2xl
text-gray-600 text-sm
z-50
dark:bg-blue-900 dark:text-gray-100 dark:border-blue-800
"
> >
<span class="triangle absolute"></span> <span class="triangle absolute"></span>
<span v-if="title" class="block mb-2 uppercase"> <span class="block font-bold text-lg uppercase leading-6 pb-2">
{{ title }} {{ document.title }} :
</span> </span>
<span>{{ page.description }}</span> <span>{{ document.description }}</span>
<span class="block font-extralight mt-2 text-xs"> <span
class="
block
font-light
mt-3
text-xs text-purple-800
dark:text-purple-500
"
>
{{ $t('lexique.tooltipReadmore') }} {{ $t('lexique.tooltipReadmore') }}
</span> </span>
</div> </div>
...@@ -40,23 +66,24 @@ export default { ...@@ -40,23 +66,24 @@ export default {
}, },
data() { data() {
return { return {
page: null, document: null,
} }
}, },
async fetch() { async fetch() {
if (this.computedTitle) { if (this.computedTitle) {
try { const term = this.computedTitle.toLowerCase()
this.page = await this.$content( const results = await this.$content('lexique')
'lexique', .where({
this.computedTitle.toLowerCase() $or: [
) { title: { $regex: [`^${term}$`, 'i'] } }, // case insensitive
.only(['title', 'description']) { synonyms: { $contains: term } }, // search in synonyms
.fetch() ],
} catch (e) { })
// eslint-disable-next-line no-console .limit(1)
console.warn( .fetch()
`lexique term '${this.computedTitle}' not found in /content/lexique/ from file ${this.$parent.fileUrl}`
) if (results.length) {
this.document = results[0]
} }
} }
}, },
...@@ -68,7 +95,7 @@ export default { ...@@ -68,7 +95,7 @@ export default {
}, },
methods: { methods: {
onClick() { onClick() {
this.$router.push(`/lexique/${this.computedTitle.toLowerCase()}`) this.$router.push(this.document.path)
}, },
}, },
} }
...@@ -92,11 +119,26 @@ abbr { ...@@ -92,11 +119,26 @@ abbr {
opacity: 1; opacity: 1;
} }
.triangle { .triangle {
border-width: 0 6px 6px; border-width: 0 10px 10px;
border-color: transparent; border-color: transparent;
border-bottom-color: rgba(229, 231, 235, var(--tw-bg-opacity)); border-bottom-color: #bfdbfe;
top: -6px; top: -10px;
left: 50%; left: 50%;
transform: translateX(-50%); transform: translateX(-50%);
} }
.triangle:before {
content: '';
position: absolute;
border-width: 0 10px 10px;
border-color: transparent;
border-bottom-color: #dbeafe;
top: 2px;
left: -10px;
}
.dark .triangle {
border-bottom-color: #1e40af;
}
.dark .triangle:before {
border-bottom-color: #1e3a8a;
}
</style> </style>
<template>
<div class="prose dark:prose-dark">
<slot />
<slot v-if="Array.isArray(data)" name="items" :items="data">
<ul class="list">
<li v-for="(item, i) in data" :key="i">
<nuxt-link :to="item.path.replace(/^\/pages\//, '/')">
<div v-if="title">{{ item.title }}</div>
</nuxt-link>
<span v-if="description">{{ item.description }}</span>
</li>
</ul>
</slot>
<slot v-else-if="data" name="item">
<h2 v-if="title">{{ data.title }}</h2>
<p v-if="description">{{ data.description }}</p>
</slot>
</div>
</template>
<script>
export default {
name: 'List',
props: {
content: {
type: String,
default: null,
},
only: {
type: [String, Array],
default: null,
},
where: {
type: Object,
default: null,
},
sortBy: {
type: String,
default: null,
},
direction: {
type: String,
default: 'asc',
validator(value) {
return ['asc', 'desc'].includes(value)
},
},
skip: {
type: [Number, String],
default: null,
},
search: {
type: String,
default: null,
},
searchField: {
type: String,
default: null,
},
limit: {
type: [Number, String],
default: null,
},
title: {
type: Boolean,
default: true,
},
description: {
type: Boolean,
default: false,
},
readingTime: {
type: Boolean,
default: false,
},
},
data() {
return {
data: null,
}
},
async fetch() {
if (this.content) {
const content = this.$content(this.content)
if (this.only) content.only(this.only)
if (this.where) content.where(this.where)
if (this.sortBy) content.sortBy(this.sortBy, this.direction)
if (this.skip) content.skip(+this.skip)
if (this.search) {
this.searchField
? content.search(this.searchField, this.search)
: content.search(this.search)
}
if (this.limit) content.limit(+this.limit)
this.data = await content.fetch()
}
},
}
</script>
<style lang="postcss" scoped></style>
<template> <template>
<div id="container-cta" class="container mb-12"> <div class="pt-8">
<nuxt-content :document="document" /> <t-button
class="flex items-center rounded-2xl"
variant="success"
@click="$modal.show('videoIntro')"
>
<fa :icon="['fab', 'youtube']" class="text-4xl mr-4" />
<div class="text-left pr-1">
<div class="text-xl font-bold">Introduction</div>
<div class="-mt-1">3 min en vidéo</div>
</div>
</t-button>
<t-modal name="videoIntro" variant="video">
<div style="padding: 56.25% 0 0 0; position: relative">
<iframe
src="https://player.vimeo.com/video/514975135?h=7f6183d68c&portrait=0&autoplay=1"
style="position: absolute; top: 0; left: 0; width: 100%; height: 100%"
frameborder="0"
allow="autoplay; fullscreen; picture-in-picture"
allowfullscreen
></iframe>
</div>
</t-modal>
</div> </div>
</template> </template>
<script> <script>
export default { export default {}
props: {
document: {
type: Object,
required: true,
},
},
}
</script> </script>
<style lang="postcss"> <style lang="postcss"></style>
.list-cta > li {
position: relative;
padding-left: 1.75em;
margin: 0.5em 0;
line-height: 1.2em;
}
.list-cta > li::before {
content: '';
position: absolute;
background-color: #3b82f6;
border-radius: 50%;
width: 0.375em;
height: 0.375em;
top: 0.375em;
left: 0.25em;
}
#container-cta .svg-inline--fa {
animation: shake 10s cubic-bezier(0.36, 0.07, 0.19, 0.97) infinite;
animation-delay: 5s;
}
#container-cta .grid > a:nth-child(2) .svg-inline--fa {
animation-delay: 5.5s;
}
#container-cta .grid > a:nth-child(3) .svg-inline--fa {
animation-delay: 6s;
}
#container-cta .grid > a:nth-child(4) .svg-inline--fa {
animation-delay: 6.5s;
}
@keyframes shake {
0% {
-webkit-transform: translate(2px, 1px) rotate(0deg);
}
1% {
-webkit-transform: translate(-1px, -2px) rotate(-3deg);
}
2% {
-webkit-transform: translate(-3px, 0px) rotate(3deg);
}
3% {
-webkit-transform: translate(0px, 2px) rotate(0deg);
}
4% {
-webkit-transform: translate(1px, -1px) rotate(3deg);
}
5% {
-webkit-transform: translate(-1px, 2px) rotate(-3deg);
}
6% {
-webkit-transform: translate(-3px, 1px) rotate(0deg);
}
7% {
-webkit-transform: translate(2px, 1px) rotate(-3deg);
}
8% {
-webkit-transform: translate(-1px, -1px) rotate(3deg);
}
9% {
-webkit-transform: translate(2px, 2px) rotate(0deg);
}
10% {
-webkit-transform: translate(1px, -2px) rotate(-3deg);
}
11% {
transform: translate(0, 0) rotate(0deg);
}
}
</style>
<template> <template>
<div class="hero container flex"> <div class="hero container flex lg:items-center">
<div class="lg:items-start max-w-2xl 2xl:max-w-3xl w-full z-10"> <div class="max-w-2xl 2xl:max-w-3xl w-full">
<nuxt-content :document="document" /> <nuxt-content :document="document" />
<HomeCTA />
</div> </div>
<SuperHero class="superhero w-full h-full" /> <SuperHero
class="
superhero
absolute
h-40
hidden
lg:h-full lg:relative lg:right-0 lg:w-full
md:block
right-6
w-1/3
"
/>
</div> </div>
</template> </template>
...@@ -26,7 +39,7 @@ export default { ...@@ -26,7 +39,7 @@ export default {
<style lang="postcss" scoped> <style lang="postcss" scoped>
.hero { .hero {
padding: max(8vh, 8rem) 0; padding: max(8vh, 4rem) 1.5rem;
} }
@keyframes floatHero { @keyframes floatHero {
......
<template>
<section id="map">
<div class="container flex items-end mb-3 pl-8">
<FaviconMap class="w-12 h-12 mr-3 fill-current dark:text-gray-100" />
<a
href="https://carte.monnaie-libre.fr"
target="_blank"
class="
group
bg-clip-text bg-gradient-to-r
font-extrabold
from-purple-800
hover:underline
text-4xl text-transparent
to-blue-600
uppercase
"
rel="noopener noreferrer"
>
Carte
<fa
icon="external-link-alt"
class="w-3 ml-1.5 text-gray-500 opacity-0 group-hover:opacity-75"
/>
</a>
</div>
<iframe
:src="intersected ? $config.map_url : null"
class="w-full bg-gray-200"
style="height: 50vh; min-height: 600px"
title="Carte monnaie-libre"
/>
</section>
</template>
<script>
import FaviconMap from '~/static/img/favicon-map-g1.svg?inline'
export default {
components: {
FaviconMap,
},
data() {
return {
observer: null,
intersected: false,
}
},
mounted() {
this.observer = new IntersectionObserver(
(entries) => {
const item = entries[0]
if (item.isIntersecting) {
this.intersected = true
this.observer.disconnect()
}
},
{
rootMargin: '500px',
}
)
this.observer.observe(this.$el)
},
destroyed() {
this.observer.disconnect()
},
}
</script>
<template> <template>
<section id="agenda" class="container py-12"> <section id="agenda" class="container py-12">
<div class="border-b-2 container flex items-end mb-3 pb-2"> <div class="border-b-2 container flex items-end mb-3 pb-2 pl-1">
<JuneCalendar class="w-12 mr-3 fill-current dark:text-gray-100" /> <JuneCalendar class="w-12 mr-3 fill-current dark:text-gray-100" />
<a <a
href="https://forum.monnaie-libre.fr/calendar" :href="`${$config.forum_url}/calendar`"
target="_blank" target="_blank"
class="group bg-clip-text bg-gradient-to-r font-extrabold from-purple-800 hover:underline text-4xl text-transparent to-blue-600 uppercase" class="
group
bg-clip-text bg-gradient-to-r
font-extrabold
from-purple-800
hover:underline
text-4xl text-transparent
to-blue-600
uppercase
"
rel="noopener noreferrer"
> >
Agenda Agenda
<fa <fa
...@@ -25,15 +35,25 @@ ...@@ -25,15 +35,25 @@
<a <a
v-for="(event, index) in column" v-for="(event, index) in column"
:key="index" :key="index"
:href="`https://forum.monnaie-libre.fr/t/${event.slug}/${event.id}`" :href="`${$config.forum_url}${event.post.url}`"
targe="_blank" target="_blank"
class="block hover:bg-hover-light dark-hover:text-gray-800 p-2 mt-1 rounded-lg transition-colors" class="
block
hover:bg-hover-light
dark-hover:text-gray-800
p-2
mt-1
rounded-lg
transition-colors
"
rel="noopener noreferrer"
> >
<div class="event-date text-sm text-gray-500"> <div class="event-date text-sm text-gray-500">
{{ prettyDate(event.event.start) }} {{ prettyDate(event.starts_at) }}
<!-- poka: I don't find tags anymore with new api, so this line is actually unused -->
<div v-for="(tag, i) in event.tag" :key="i">{{ tag }}</div> <div v-for="(tag, i) in event.tag" :key="i">{{ tag }}</div>
</div> </div>
<div>{{ event.title }}</div> <div v-html="emojify(event.post.topic.title)" />
</a> </a>
</div> </div>
</aside> </aside>
...@@ -47,6 +67,7 @@ ...@@ -47,6 +67,7 @@
<script> <script>
import JuneCalendar from '~/static/img/june-calendar.svg?inline' import JuneCalendar from '~/static/img/june-calendar.svg?inline'
import { fetchNextEvents } from '~/libs/api-forum' import { fetchNextEvents } from '~/libs/api-forum'
import { performEmojiUnescape } from '~/libs/emoji'
export default { export default {
name: 'HomeNextEvents', name: 'HomeNextEvents',
...@@ -99,6 +120,13 @@ export default { ...@@ -99,6 +120,13 @@ export default {
}) })
.reduce((string, part) => string + part) .reduce((string, part) => string + part)
}, },
emojify(text) {
return performEmojiUnescape(text, {
emojiSet: 'images/emoji/twitter',
emojiCDNUrl: 'https://forum.monnaie-libre.fr',
getURL: (url) => url,
})
},
}, },
} }
</script> </script>
......
<template> <template>
<div class="flex justify-evenly"> <section class="bg-gray-100 dark:bg-gray-800">
<TInputIcon <div class="container py-12 relative prose">
ref="search" <div class="flex justify-evenly">
v-model="query" <TInputIcon
type="search" ref="search"
:placeholder="placeholder" v-model="query"
class="w-full" type="search"
:input-class="inputClass" :placeholder="placeholder"
icon="search" class="w-full"
:icon-class="iconClass" :input-class="inputClass"
@keyup.enter="search()" icon="search"
/> :icon-class="iconClass"
icon-wrapper-class="top-0.5"
@keyup.enter="search()"
/>
<t-button :class="buttonClass" :text="$t('search')" @click="search()" /> <t-button :class="buttonClass" :text="$t('search')" @click="search()" />
</div> </div>
</div>
</section>
</template> </template>
<script> <script>
......