Merge branch 'master' into dev

This commit is contained in:
lesion 2023-11-05 22:23:14 +01:00
commit 19eab92d39
No known key found for this signature in database
GPG key ID: 352918250B012177
86 changed files with 5538 additions and 3842 deletions

2
.gitmodules vendored
View file

@ -1,3 +1,3 @@
[submodule "gancio_plugins/gancio-plugin-telegram-bridge"]
path = gancio_plugins/gancio-plugin-telegram-bridge
url = https://framagit.org/bcn.convocala/gancio-plugin-telegram-bridge.git
url = https://framagit.org/bcn.convocala/gancio-plugin-telegram-bridge

View file

@ -1,4 +1,56 @@
All notable changes to this project will be documented in this file.
# Changelog
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
### [1.6.19](https://framagit.org/les/gancio/compare/v1.6.18...v1.6.19) (2023-11-04)
### Bug Fixes
* issue displaying recurrent event string ([a94ccda](https://framagit.org/les/gancio/commit/a94ccda049f7571a9caa90507141a0aac30331a9))
### 1.6.18 - 3 Nov '23
- [feat] allow to specify password while create new user via CLI to [support yunohost](https://github.com/YunoHost-Apps/gancio_ynh/pull/2#discussion_r1364285417)
- [feat] check if I'm reachable to myself to help in [#298](https://framagit.org/les/gancio/-/issues/298)
- [feat] improve recover and user_confirm error messages
- [feat] improve export and allow to export `collections` in rss/ics/widget
- [fix] fix postgres image version in docker-compose [#303](https://framagit.org/les/gancio/-/issues/303)
- [fix] Improve json-ld representation of events [#33](https://framagit.org/les/gancio/-/merge_requests/33)
- [fix] Add description field to admin's new user form, closes [#307](https://framagit.org/les/gancio/-/issues/307)
- [fix] use tls SSLv3 to send email, fix [#192](https://framagit.org/les/gancio/-/issues/192)
- [fix] notify user when accepted, fix [#308](https://framagit.org/les/gancio/-/issues/308)
- [fix] forgot password on active user only
- [fix] make search case insensitive, fix [#301](https://framagit.org/les/gancio/-/issues/301)
### 1.6.17 - 4 Oct '23
- [fix] typo
### 1.6.16 - 4 Oct '23
- [feat] add Czech locale
- [fix] improve datetime validation
### 1.6.15 - 3 Oct '23
- [feat] clone event
- [feat] am/pm / 24hr support, fix [#294](https://framagit.org/les/gancio/-/issues/294) [#264](https://framagit.org/les/gancio/-/issues/264)
- [feat] update telegram plugin bridge to v1.0.3, [#299](https://framagit.org/les/gancio/-/issues/299)
- [feat] include Brazilian Portuguese (pt-br) and Portugual Portuguese (pt-pt) [#292](https://framagit.org/les/gancio/-/issues/292)
- [fix] MariaDB JSON fields manual fix
- [fix] improve some corner case with SMTP From field [#297](https://framagit.org/les/gancio/-/issues/297)
- [fix] CLI has to fail when configuration not present [#284](https://framagit.org/les/gancio/-/issues/284)
- [minor] remove html2text dep from client
- [minor] RSS item's title format is now YYYY-MM-DD, [#300](https://framagit.org/les/gancio/-/issues/300)
### 1.6.14 - 30 June '23
- improve CLI accounts operations ([documentation](https://gancio.org/usage/cli))
- allow plugins to expose API ([documentation](http://gancio.org/dev/plugins))
- allow plugins to access DB ([documentation](http://gancio.org/dev/plugins))
- show map on the places page, #276 #30
- add node v18 support, #278
- fix media update, #285
- fix nodejs v14 compatibility in export
- fix invalid event microdata, #277
- fix recurrent event, #280
- update deps and locales
### 1.6.13 - 16 may '23
- fix feed, ics, json exports

View file

@ -25,10 +25,10 @@ function ye(t) {
function u(t, e) {
t.appendChild(e);
}
function p(t, e, i) {
function k(t, e, i) {
t.insertBefore(e, i || null);
}
function k(t) {
function x(t) {
t.parentNode.removeChild(t);
}
function be(t, e) {
@ -38,14 +38,14 @@ function be(t, e) {
function m(t) {
return document.createElement(t);
}
function $(t) {
function z(t) {
return document.createTextNode(t);
}
function M() {
return $(" ");
function C() {
return z(" ");
}
function pe() {
return $("");
return z("");
}
function a(t, e, i) {
i == null ? t.removeAttribute(e) : t.getAttribute(e) !== i && t.setAttribute(e, i);
@ -69,25 +69,25 @@ let O;
function I(t) {
O = t;
}
function $e() {
function Ee() {
if (!O)
throw new Error("Function called outside component initialization");
return O;
}
function ke(t) {
$e().$$.on_mount.push(t);
Ee().$$.on_mount.push(t);
}
const R = [], Z = [], P = [], ee = [], Ee = Promise.resolve();
const R = [], Z = [], P = [], ee = [], $e = Promise.resolve();
let K = !1;
function je() {
K || (K = !0, Ee.then(x));
K || (K = !0, $e.then(y));
}
function Q(t) {
P.push(t);
}
const J = /* @__PURE__ */ new Set();
let D = 0;
function x() {
function y() {
const t = O;
do {
for (; D < R.length; ) {
@ -120,8 +120,8 @@ function Ce(t, e) {
function Ae(t, e, i, l) {
const { fragment: n, on_mount: r, on_destroy: o, after_update: f } = t.$$;
n && n.m(e, i), l || Q(() => {
const c = r.map(W).filter(ge);
o ? o.push(...c) : U(c), t.$$.on_mount = [];
const s = r.map(W).filter(ge);
o ? o.push(...s) : U(s), t.$$.on_mount = [];
}), f.forEach(Q);
}
function Me(t, e) {
@ -132,9 +132,9 @@ function Ne(t, e) {
t.$$.dirty[0] === -1 && (R.push(t), je(), t.$$.dirty.fill(0)), t.$$.dirty[e / 31 | 0] |= 1 << e % 31;
}
function we(t, e, i, l, n, r, o, f = [-1]) {
const c = O;
const s = O;
I(t);
const s = t.$$ = {
const c = t.$$ = {
fragment: null,
ctx: null,
props: r,
@ -146,26 +146,26 @@ function we(t, e, i, l, n, r, o, f = [-1]) {
on_disconnect: [],
before_update: [],
after_update: [],
context: new Map(e.context || (c ? c.$$.context : [])),
context: new Map(e.context || (s ? s.$$.context : [])),
callbacks: Y(),
dirty: f,
skip_bound: !1,
root: e.target || c.$$.root
root: e.target || s.$$.root
};
o && o(s.root);
o && o(c.root);
let w = !1;
if (s.ctx = i ? i(t, e.props || {}, (g, _, ...A) => {
const y = A.length ? A[0] : _;
return s.ctx && n(s.ctx[g], s.ctx[g] = y) && (!s.skip_bound && s.bound[g] && s.bound[g](y), w && Ne(t, g)), _;
}) : [], s.update(), w = !0, U(s.before_update), s.fragment = l ? l(s.ctx) : !1, e.target) {
if (c.ctx = i ? i(t, e.props || {}, (g, _, ...A) => {
const E = A.length ? A[0] : _;
return c.ctx && n(c.ctx[g], c.ctx[g] = E) && (!c.skip_bound && c.bound[g] && c.bound[g](E), w && Ne(t, g)), _;
}) : [], c.update(), w = !0, U(c.before_update), c.fragment = l ? l(c.ctx) : !1, e.target) {
if (e.hydrate) {
const g = xe(e.target);
s.fragment && s.fragment.l(g), g.forEach(k);
c.fragment && c.fragment.l(g), g.forEach(x);
} else
s.fragment && s.fragment.c();
e.intro && Ce(t.$$.fragment), Ae(t, e.target, e.anchor, e.customElement), x();
c.fragment && c.fragment.c();
e.intro && Ce(t.$$.fragment), Ae(t, e.target, e.anchor, e.customElement), y();
}
I(c);
I(s);
}
let X;
typeof HTMLElement == "function" && (X = class extends HTMLElement {
@ -213,11 +213,11 @@ function V(t) {
}
function te(t, e, i) {
const l = t.slice();
return l[12] = e[i], l;
return l[13] = e[i], l;
}
function ie(t, e, i) {
const l = t.slice();
return l[15] = e[i], l;
return l[16] = e[i], l;
}
function le(t) {
let e;
@ -226,13 +226,13 @@ function le(t) {
e = m("link"), a(e, "rel", "stylesheet"), a(e, "href", t[4]);
},
m(i, l) {
p(i, e, l);
k(i, e, l);
},
p(i, l) {
l & 16 && a(e, "href", i[4]);
},
d(i) {
i && k(e);
i && x(e);
}
};
}
@ -242,32 +242,32 @@ function ne(t) {
r[o] = fe(te(t, n, o));
return {
c() {
e = m("div"), l && l.c(), i = M();
e = m("div"), l && l.c(), i = C();
for (let o = 0; o < r.length; o += 1)
r[o].c();
a(e, "id", "gancioEvents"), L(e, "dark", t[2] === "dark"), L(e, "light", t[2] === "light"), L(e, "sidebar", t[3] === "true"), L(e, "nosidebar", t[3] !== "true");
},
m(o, f) {
p(o, e, f), l && l.m(e, null), u(e, i);
for (let c = 0; c < r.length; c += 1)
r[c].m(e, null);
k(o, e, f), l && l.m(e, null), u(e, i);
for (let s = 0; s < r.length; s += 1)
r[s].m(e, null);
},
p(o, f) {
if (o[1] && o[3] === "true" ? l ? l.p(o, f) : (l = re(o), l.c(), l.m(e, i)) : l && (l.d(1), l = null), f & 41) {
n = o[5];
let c;
for (c = 0; c < n.length; c += 1) {
const s = te(o, n, c);
r[c] ? r[c].p(s, f) : (r[c] = fe(s), r[c].c(), r[c].m(e, null));
let s;
for (s = 0; s < n.length; s += 1) {
const c = te(o, n, s);
r[s] ? r[s].p(c, f) : (r[s] = fe(c), r[s].c(), r[s].m(e, null));
}
for (; c < r.length; c += 1)
r[c].d(1);
for (; s < r.length; s += 1)
r[s].d(1);
r.length = n.length;
}
f & 4 && L(e, "dark", o[2] === "dark"), f & 4 && L(e, "light", o[2] === "light"), f & 8 && L(e, "sidebar", o[3] === "true"), f & 8 && L(e, "nosidebar", o[3] !== "true");
},
d(o) {
o && k(e), l && l.d(), be(r, o);
o && x(e), l && l.d(), be(r, o);
}
};
}
@ -275,23 +275,23 @@ function re(t) {
let e, i, l, n, r, o, f;
return {
c() {
e = m("a"), i = m("div"), l = m("div"), n = $(t[1]), r = M(), o = m("img"), a(l, "class", "title"), a(o, "id", "logo"), a(o, "alt", "logo"), H(o.src, f = t[0] + "/logo.png") || a(o, "src", f), a(i, "class", "content"), a(e, "href", t[0]), a(e, "target", "_blank"), a(e, "id", "header");
e = m("a"), i = m("div"), l = m("div"), n = z(t[1]), r = C(), o = m("img"), a(l, "class", "title"), a(o, "id", "logo"), a(o, "alt", "logo"), H(o.src, f = t[0] + "/logo.png") || a(o, "src", f), a(i, "class", "content"), a(e, "href", t[0]), a(e, "target", "_blank"), a(e, "id", "header");
},
m(c, s) {
p(c, e, s), u(e, i), u(i, l), u(l, n), u(i, r), u(i, o);
m(s, c) {
k(s, e, c), u(e, i), u(i, l), u(l, n), u(i, r), u(i, o);
},
p(c, s) {
s & 2 && T(n, c[1]), s & 1 && !H(o.src, f = c[0] + "/logo.png") && a(o, "src", f), s & 1 && a(e, "href", c[0]);
p(s, c) {
c & 2 && T(n, s[1]), c & 1 && !H(o.src, f = s[0] + "/logo.png") && a(o, "src", f), c & 1 && a(e, "href", s[0]);
},
d(c) {
c && k(e);
d(s) {
s && x(e);
}
};
}
function oe(t) {
let e;
function i(r, o) {
return r[12].media.length ? Le : Te;
return r[13].media.length ? Le : Te;
}
let l = i(t), n = l(t);
return {
@ -299,13 +299,13 @@ function oe(t) {
e = m("div"), n.c(), a(e, "class", "img");
},
m(r, o) {
p(r, e, o), n.m(e, null);
k(r, e, o), n.m(e, null);
},
p(r, o) {
l === (l = i(r)) && n ? n.p(r, o) : (n.d(1), n = l(r), n && (n.c(), n.m(e, null)));
},
d(r) {
r && k(e), n.d();
r && x(e), n.d();
}
};
}
@ -313,16 +313,16 @@ function Te(t) {
let e, i, l;
return {
c() {
e = m("img"), a(e, "style", "aspect-ratio=1.7778;"), a(e, "alt", i = t[12].title), H(e.src, l = t[0] + "/fallbackimage.png") || a(e, "src", l), a(e, "loading", "lazy");
e = m("img"), a(e, "style", "aspect-ratio=1.7778;"), a(e, "alt", i = t[13].title), H(e.src, l = t[0] + "/fallbackimage.png") || a(e, "src", l), a(e, "loading", "lazy");
},
m(n, r) {
p(n, e, r);
k(n, e, r);
},
p(n, r) {
r & 32 && i !== (i = n[12].title) && a(e, "alt", i), r & 1 && !H(e.src, l = n[0] + "/fallbackimage.png") && a(e, "src", l);
r & 32 && i !== (i = n[13].title) && a(e, "alt", i), r & 1 && !H(e.src, l = n[0] + "/fallbackimage.png") && a(e, "src", l);
},
d(n) {
n && k(e);
n && x(e);
}
};
}
@ -330,38 +330,38 @@ function Le(t) {
let e, i, l, n;
return {
c() {
e = m("img"), a(e, "style", i = "object-position: " + ue(t[12]) + "; aspect-ratio=1.7778;"), a(e, "alt", l = t[12].media[0].name), H(e.src, n = t[0] + "/media/thumb/" + t[12].media[0].url) || a(e, "src", n), a(e, "loading", "lazy");
e = m("img"), a(e, "style", i = "object-position: " + ue(t[13]) + "; aspect-ratio=1.7778;"), a(e, "alt", l = t[13].media[0].name), H(e.src, n = t[0] + "/media/thumb/" + t[13].media[0].url) || a(e, "src", n), a(e, "loading", "lazy");
},
m(r, o) {
p(r, e, o);
k(r, e, o);
},
p(r, o) {
o & 32 && i !== (i = "object-position: " + ue(r[12]) + "; aspect-ratio=1.7778;") && a(e, "style", i), o & 32 && l !== (l = r[12].media[0].name) && a(e, "alt", l), o & 33 && !H(e.src, n = r[0] + "/media/thumb/" + r[12].media[0].url) && a(e, "src", n);
o & 32 && i !== (i = "object-position: " + ue(r[13]) + "; aspect-ratio=1.7778;") && a(e, "style", i), o & 32 && l !== (l = r[13].media[0].name) && a(e, "alt", l), o & 33 && !H(e.src, n = r[0] + "/media/thumb/" + r[13].media[0].url) && a(e, "src", n);
},
d(r) {
r && k(e);
r && x(e);
}
};
}
function ae(t) {
let e, i = t[12].place.address + "", l;
let e, i = t[13].place.address + "", l;
return {
c() {
e = m("span"), l = $(i), a(e, "class", "subtitle");
e = m("span"), l = z(i), a(e, "class", "subtitle");
},
m(n, r) {
p(n, e, r), u(e, l);
k(n, e, r), u(e, l);
},
p(n, r) {
r & 32 && i !== (i = n[12].place.address + "") && T(l, i);
r & 32 && i !== (i = n[13].place.address + "") && T(l, i);
},
d(n) {
n && k(e);
n && x(e);
}
};
}
function se(t) {
let e, i = t[12].tags, l = [];
let e, i = t[13].tags, l = [];
for (let n = 0; n < i.length; n += 1)
l[n] = ce(ie(t, i, n));
return {
@ -372,13 +372,13 @@ function se(t) {
a(e, "class", "tags");
},
m(n, r) {
p(n, e, r);
k(n, e, r);
for (let o = 0; o < l.length; o += 1)
l[o].m(e, null);
},
p(n, r) {
if (r & 32) {
i = n[12].tags;
i = n[13].tags;
let o;
for (o = 0; o < i.length; o += 1) {
const f = ie(n, i, o);
@ -390,42 +390,41 @@ function se(t) {
}
},
d(n) {
n && k(e), be(l, n);
n && x(e), be(l, n);
}
};
}
function ce(t) {
let e, i, l = t[15] + "", n;
let e, i, l = t[16] + "", n;
return {
c() {
e = m("span"), i = $("#"), n = $(l), a(e, "class", "tag");
e = m("span"), i = z("#"), n = z(l), a(e, "class", "tag");
},
m(r, o) {
p(r, e, o), u(e, i), u(e, n);
k(r, e, o), u(e, i), u(e, n);
},
p(r, o) {
o & 32 && l !== (l = r[15] + "") && T(n, l);
o & 32 && l !== (l = r[16] + "") && T(n, l);
},
d(r) {
r && k(e);
r && x(e);
}
};
}
function fe(t) {
let e, i, l, n, r = V(t[12]) + "", o, f, c, s = t[12].title + "", w, g, _, A, y = t[12].place.name + "", d, z, h, v, C, q, E = t[3] !== "true" && oe(t), j = t[12].place.name !== "online" && ae(t), S = t[12].tags.length && se(t);
let e, i, l, n, r = V(t[13]) + "", o, f, s, c = t[13].title + "", w, g, _, A, E = t[13].place.name + "", M, d, h, p, v, q, $ = t[3] !== "true" && oe(t), j = t[13].place.name !== "online" && ae(t), S = t[13].tags.length && se(t);
return {
c() {
e = m("a"), E && E.c(), i = M(), l = m("div"), n = m("div"), o = $(r), f = M(), c = m("div"), w = $(s), g = M(), _ = m("span"), A = $('@"'), d = $(y), z = $(`"
`), j && j.c(), h = M(), S && S.c(), v = M(), a(n, "class", "subtitle"), a(c, "class", "title"), a(_, "class", "place"), a(l, "class", "content"), a(e, "href", C = t[0] + "/event/" + (t[12].slug || t[12].id)), a(e, "class", "event"), a(e, "title", q = t[12].title), a(e, "target", "_blank");
e = m("a"), $ && $.c(), i = C(), l = m("div"), n = m("div"), o = z(r), f = C(), s = m("div"), w = z(c), g = C(), _ = m("span"), A = z("@"), M = z(E), d = C(), j && j.c(), h = C(), S && S.c(), p = C(), a(n, "class", "subtitle"), a(s, "class", "title"), a(_, "class", "place"), a(l, "class", "content"), a(e, "href", v = t[0] + "/event/" + (t[13].slug || t[13].id)), a(e, "class", "event"), a(e, "title", q = t[13].title), a(e, "target", "_blank");
},
m(b, N) {
p(b, e, N), E && E.m(e, null), u(e, i), u(e, l), u(l, n), u(n, o), u(l, f), u(l, c), u(c, w), u(l, g), u(l, _), u(_, A), u(_, d), u(_, z), j && j.m(_, null), u(l, h), S && S.m(l, null), u(e, v);
k(b, e, N), $ && $.m(e, null), u(e, i), u(e, l), u(l, n), u(n, o), u(l, f), u(l, s), u(s, w), u(l, g), u(l, _), u(_, A), u(_, M), u(_, d), j && j.m(_, null), u(l, h), S && S.m(l, null), u(e, p);
},
p(b, N) {
b[3] !== "true" ? E ? E.p(b, N) : (E = oe(b), E.c(), E.m(e, i)) : E && (E.d(1), E = null), N & 32 && r !== (r = V(b[12]) + "") && T(o, r), N & 32 && s !== (s = b[12].title + "") && T(w, s), N & 32 && y !== (y = b[12].place.name + "") && T(d, y), b[12].place.name !== "online" ? j ? j.p(b, N) : (j = ae(b), j.c(), j.m(_, null)) : j && (j.d(1), j = null), b[12].tags.length ? S ? S.p(b, N) : (S = se(b), S.c(), S.m(l, null)) : S && (S.d(1), S = null), N & 33 && C !== (C = b[0] + "/event/" + (b[12].slug || b[12].id)) && a(e, "href", C), N & 32 && q !== (q = b[12].title) && a(e, "title", q);
b[3] !== "true" ? $ ? $.p(b, N) : ($ = oe(b), $.c(), $.m(e, i)) : $ && ($.d(1), $ = null), N & 32 && r !== (r = V(b[13]) + "") && T(o, r), N & 32 && c !== (c = b[13].title + "") && T(w, c), N & 32 && E !== (E = b[13].place.name + "") && T(M, E), b[13].place.name !== "online" ? j ? j.p(b, N) : (j = ae(b), j.c(), j.m(_, null)) : j && (j.d(1), j = null), b[13].tags.length ? S ? S.p(b, N) : (S = se(b), S.c(), S.m(l, null)) : S && (S.d(1), S = null), N & 33 && v !== (v = b[0] + "/event/" + (b[13].slug || b[13].id)) && a(e, "href", v), N & 32 && q !== (q = b[13].title) && a(e, "title", q);
},
d(b) {
b && k(e), E && E.d(), j && j.d(), S && S.d();
b && x(e), $ && $.d(), j && j.d(), S && S.d();
}
};
}
@ -433,10 +432,10 @@ function Ge(t) {
let e, i, l = t[4] && le(t), n = t[5].length && ne(t);
return {
c() {
l && l.c(), e = M(), n && n.c(), i = pe(), this.c = G;
l && l.c(), e = C(), n && n.c(), i = pe(), this.c = G;
},
m(r, o) {
l && l.m(r, o), p(r, e, o), n && n.m(r, o), p(r, i, o);
l && l.m(r, o), k(r, e, o), n && n.m(r, o), k(r, i, o);
},
p(r, [o]) {
r[4] ? l ? l.p(r, o) : (l = le(r), l.c(), l.m(e.parentNode, e)) : l && (l.d(1), l = null), r[5].length ? n ? n.p(r, o) : (n = ne(r), n.c(), n.m(i.parentNode, i)) : n && (n.d(1), n = null);
@ -444,7 +443,7 @@ function Ge(t) {
i: G,
o: G,
d(r) {
l && l.d(r), r && k(e), n && n.d(r), r && k(i);
l && l.d(r), r && x(e), n && n.d(r), r && x(i);
}
};
}
@ -456,34 +455,37 @@ function ue(t) {
return "center center";
}
function He(t, e, i) {
let { baseurl: l = "" } = e, { title: n = "" } = e, { maxlength: r = !1 } = e, { tags: o = "" } = e, { places: f = "" } = e, { theme: c = "light" } = e, { show_recurrent: s = !1 } = e, { sidebar: w = "true" } = e, { external_style: g = "" } = e, _ = !1, A = [];
function y(d) {
if (!_)
let { baseurl: l = "" } = e, { title: n = "" } = e, { maxlength: r = !1 } = e, { collection: o = "" } = e, { tags: f = "" } = e, { places: s = "" } = e, { theme: c = "light" } = e, { show_recurrent: w = !1 } = e, { sidebar: g = "true" } = e, { external_style: _ = "" } = e, A = !1, E = [];
function M(d) {
if (!A)
return;
const z = [];
r && z.push(`max=${r}`), o && z.push(`tags=${o}`), f && z.push(`places=${f}`), z.push(`show_recurrent=${s ? "true" : "false"}`), fetch(`${l}/api/events?${z.join("&")}`).then((h) => h.json()).then((h) => {
i(5, A = h);
}).catch((h) => {
console.error("Error loading Gancio API -> ", h);
const h = [];
r && h.push(`max=${r}`);
let p = "/api/events";
o ? p = `/api/collections/${o}` : (f && h.push(`tags=${f}`), s && h.push(`places=${s}`)), h.push(`show_recurrent=${w ? "true" : "false"}`), fetch(`${l}${p}?${h.join("&")}`).then((v) => v.json()).then((v) => {
i(5, E = v.events || v);
}).catch((v) => {
console.error("Error loading Gancio API -> ", v);
});
}
return ke(() => {
_ = !0, y();
A = !0, M();
}), t.$$set = (d) => {
"baseurl" in d && i(0, l = d.baseurl), "title" in d && i(1, n = d.title), "maxlength" in d && i(6, r = d.maxlength), "tags" in d && i(7, o = d.tags), "places" in d && i(8, f = d.places), "theme" in d && i(2, c = d.theme), "show_recurrent" in d && i(9, s = d.show_recurrent), "sidebar" in d && i(3, w = d.sidebar), "external_style" in d && i(4, g = d.external_style);
"baseurl" in d && i(0, l = d.baseurl), "title" in d && i(1, n = d.title), "maxlength" in d && i(6, r = d.maxlength), "collection" in d && i(7, o = d.collection), "tags" in d && i(8, f = d.tags), "places" in d && i(9, s = d.places), "theme" in d && i(2, c = d.theme), "show_recurrent" in d && i(10, w = d.show_recurrent), "sidebar" in d && i(3, g = d.sidebar), "external_style" in d && i(4, _ = d.external_style);
}, t.$$.update = () => {
t.$$.dirty & 975 && y();
t.$$.dirty & 1999 && M();
}, [
l,
n,
c,
w,
g,
A,
_,
E,
r,
o,
f,
s
s,
w
];
}
class Re extends X {
@ -508,21 +510,23 @@ class Re extends X {
baseurl: 0,
title: 1,
maxlength: 6,
tags: 7,
places: 8,
collection: 7,
tags: 8,
places: 9,
theme: 2,
show_recurrent: 9,
show_recurrent: 10,
sidebar: 3,
external_style: 4
},
null
), e && (e.target && p(e.target, this, e.anchor), e.props && (this.$set(e.props), x()));
), e && (e.target && k(e.target, this, e.anchor), e.props && (this.$set(e.props), y()));
}
static get observedAttributes() {
return [
"baseurl",
"title",
"maxlength",
"collection",
"tags",
"places",
"theme",
@ -535,72 +539,78 @@ class Re extends X {
return this.$$.ctx[0];
}
set baseurl(e) {
this.$$set({ baseurl: e }), x();
this.$$set({ baseurl: e }), y();
}
get title() {
return this.$$.ctx[1];
}
set title(e) {
this.$$set({ title: e }), x();
this.$$set({ title: e }), y();
}
get maxlength() {
return this.$$.ctx[6];
}
set maxlength(e) {
this.$$set({ maxlength: e }), x();
this.$$set({ maxlength: e }), y();
}
get tags() {
get collection() {
return this.$$.ctx[7];
}
set tags(e) {
this.$$set({ tags: e }), x();
set collection(e) {
this.$$set({ collection: e }), y();
}
get places() {
get tags() {
return this.$$.ctx[8];
}
set tags(e) {
this.$$set({ tags: e }), y();
}
get places() {
return this.$$.ctx[9];
}
set places(e) {
this.$$set({ places: e }), x();
this.$$set({ places: e }), y();
}
get theme() {
return this.$$.ctx[2];
}
set theme(e) {
this.$$set({ theme: e }), x();
this.$$set({ theme: e }), y();
}
get show_recurrent() {
return this.$$.ctx[9];
return this.$$.ctx[10];
}
set show_recurrent(e) {
this.$$set({ show_recurrent: e }), x();
this.$$set({ show_recurrent: e }), y();
}
get sidebar() {
return this.$$.ctx[3];
}
set sidebar(e) {
this.$$set({ sidebar: e }), x();
this.$$set({ sidebar: e }), y();
}
get external_style() {
return this.$$.ctx[4];
}
set external_style(e) {
this.$$set({ external_style: e }), x();
this.$$set({ external_style: e }), y();
}
}
customElements.define("gancio-events", Re);
function de(t) {
let e, i, l, n, r = t[1].title + "", o, f, c, s = V(t[1]) + "", w, g, _, A, y = t[1].place.name + "", d, z, h = t[1].media.length && he(t);
let e, i, l, n, r = t[1].title + "", o, f, s, c = V(t[1]) + "", w, g, _, A, E = t[1].place.name + "", M, d, h = t[1].media.length && he(t);
return {
c() {
e = m("a"), h && h.c(), i = M(), l = m("div"), n = m("strong"), o = $(r), f = M(), c = m("div"), w = $(s), g = M(), _ = m("div"), A = $("@"), d = $(y), a(_, "class", "place"), a(l, "class", "container"), a(e, "href", z = t[0] + "/event/" + (t[1].slug || t[1].id)), a(e, "class", "card"), a(e, "target", "_blank");
e = m("a"), h && h.c(), i = C(), l = m("div"), n = m("strong"), o = z(r), f = C(), s = m("div"), w = z(c), g = C(), _ = m("div"), A = z("@"), M = z(E), a(_, "class", "place"), a(l, "class", "container"), a(e, "href", d = t[0] + "/event/" + (t[1].slug || t[1].id)), a(e, "class", "card"), a(e, "target", "_blank");
},
m(v, C) {
p(v, e, C), h && h.m(e, null), u(e, i), u(e, l), u(l, n), u(n, o), u(l, f), u(l, c), u(c, w), u(l, g), u(l, _), u(_, A), u(_, d);
m(p, v) {
k(p, e, v), h && h.m(e, null), u(e, i), u(e, l), u(l, n), u(n, o), u(l, f), u(l, s), u(s, w), u(l, g), u(l, _), u(_, A), u(_, M);
},
p(v, C) {
v[1].media.length ? h ? h.p(v, C) : (h = he(v), h.c(), h.m(e, i)) : h && (h.d(1), h = null), C & 2 && r !== (r = v[1].title + "") && T(o, r), C & 2 && s !== (s = V(v[1]) + "") && T(w, s), C & 2 && y !== (y = v[1].place.name + "") && T(d, y), C & 3 && z !== (z = v[0] + "/event/" + (v[1].slug || v[1].id)) && a(e, "href", z);
p(p, v) {
p[1].media.length ? h ? h.p(p, v) : (h = he(p), h.c(), h.m(e, i)) : h && (h.d(1), h = null), v & 2 && r !== (r = p[1].title + "") && T(o, r), v & 2 && c !== (c = V(p[1]) + "") && T(w, c), v & 2 && E !== (E = p[1].place.name + "") && T(M, E), v & 3 && d !== (d = p[0] + "/event/" + (p[1].slug || p[1].id)) && a(e, "href", d);
},
d(v) {
v && k(e), h && h.d();
d(p) {
p && x(e), h && h.d();
}
};
}
@ -611,13 +621,13 @@ function he(t) {
e = m("img"), H(e.src, i = t[2](t[1])) || a(e, "src", i), a(e, "alt", l = t[1].media[0].name), a(e, "style", n = "object-position: " + me(t[1]) + "; aspect-ratio=1.7778;");
},
m(r, o) {
p(r, e, o);
k(r, e, o);
},
p(r, o) {
o & 2 && !H(e.src, i = r[2](r[1])) && a(e, "src", i), o & 2 && l !== (l = r[1].media[0].name) && a(e, "alt", l), o & 2 && n !== (n = "object-position: " + me(r[1]) + "; aspect-ratio=1.7778;") && a(e, "style", n);
},
d(r) {
r && k(e);
r && x(e);
}
};
}
@ -628,7 +638,7 @@ function Ie(t) {
i && i.c(), e = pe(), this.c = G;
},
m(l, n) {
i && i.m(l, n), p(l, e, n);
i && i.m(l, n), k(l, e, n);
},
p(l, [n]) {
l[1] ? i ? i.p(l, n) : (i = de(l), i.c(), i.m(e.parentNode, e)) : i && (i.d(1), i = null);
@ -636,7 +646,7 @@ function Ie(t) {
i: G,
o: G,
d(l) {
i && i.d(l), l && k(e);
i && i.d(l), l && x(e);
}
};
}
@ -649,20 +659,20 @@ function me(t) {
}
function Oe(t, e, i) {
let { baseurl: l = "https://demo.gancio.org" } = e, { id: n } = e, r = !1, o;
function f(s, w) {
r && fetch(`${w}/api/event/detail/${s}`).then((g) => g.json()).then((g) => i(1, o = g));
function f(c, w) {
r && fetch(`${w}/api/event/detail/${c}`).then((g) => g.json()).then((g) => i(1, o = g));
}
ke(() => {
r = !0, f(n, l);
});
function c(s) {
return `${l}/media/thumb/${s.media[0].url}`;
function s(c) {
return `${l}/media/thumb/${c.media[0].url}`;
}
return t.$$set = (s) => {
"baseurl" in s && i(0, l = s.baseurl), "id" in s && i(3, n = s.id);
return t.$$set = (c) => {
"baseurl" in c && i(0, l = c.baseurl), "id" in c && i(3, n = c.id);
}, t.$$.update = () => {
t.$$.dirty & 9 && f(n, l);
}, [l, o, c, n];
}, [l, o, s, n];
}
class Ue extends X {
constructor(e) {
@ -679,7 +689,7 @@ class Ue extends X {
_e,
{ baseurl: 0, id: 3 },
null
), e && (e.target && p(e.target, this, e.anchor), e.props && (this.$set(e.props), x()));
), e && (e.target && k(e.target, this, e.anchor), e.props && (this.$set(e.props), y()));
}
static get observedAttributes() {
return ["baseurl", "id"];
@ -688,13 +698,13 @@ class Ue extends X {
return this.$$.ctx[0];
}
set baseurl(e) {
this.$$set({ baseurl: e }), x();
this.$$set({ baseurl: e }), y();
}
get id() {
return this.$$.ctx[3];
}
set id(e) {
this.$$set({ id: e }), x();
this.$$set({ id: e }), y();
}
}
customElements.define("gancio-event", Ue);

View file

@ -1,6 +1,7 @@
html, body {
scrollbar-width: thin;
overflow: auto !important;
overflow-y: auto !important;
overflow-x: hidden;
scrollbar-color: #FF4511 #111;
font-family: sans-serif;
}

View file

@ -47,7 +47,7 @@ v-col(cols=12)
:clear-icon='mdiClose'
@click:clear='() => change("fromHour")'
:label="$t('event.from')"
:value="value.fromHour"
:value="$time.formatHour(value.fromHour)"
:disabled='!value.from'
readonly
:prepend-icon="mdiClockTimeFourOutline"
@ -59,7 +59,7 @@ v-col(cols=12)
:value="value.fromHour"
:allowedMinutes='allowedMinutes'
full-width
format='24hr'
:format='$time.timeFormat()'
@click:minute='menuFromHour = false'
@input='hr => change("fromHour", hr)')
@ -79,7 +79,7 @@ v-col(cols=12)
:clear-icon='mdiClose'
@click:clear='() => change("dueHour")'
:label="$t('event.due')"
:value="value.dueHour"
:value="$time.formatHour(value.dueHour)"
:disabled='!value.fromHour'
readonly
:prepend-icon="mdiClockTimeEightOutline"
@ -90,7 +90,7 @@ v-col(cols=12)
:value="value.dueHour"
full-width
:allowedMinutes='allowedMinutes'
format='24hr'
:format='$time.timeFormat()'
@click:minute='menuDueHour = false'
@input='hr => change("dueHour", hr)')

View file

@ -16,7 +16,7 @@
<template v-slot:activator="{ on, attrs }">
<v-btn icon large v-bind='attrs' v-on='on' aria-label='Language' v-text="$i18n.locale" />
</template>
<v-list>
<v-list dense>
<v-list-item v-for='locale in $i18n.locales' @click.prevent.stop="$i18n.setLocale(locale.code)" :key='locale.code'>
<v-list-item-content>
<v-list-item-title v-text='locale.name' />

View file

@ -1,6 +1,6 @@
<template lang="pug">
v-row
v-col(cols=12)
v-col(sm=3 cols=12)
v-switch(
v-if='settings.allow_recurrent_event'
v-model='show_recurrent'
@ -8,12 +8,12 @@ v-row
inset color='primary'
hide-details
:label="$t('event.show_recurrent')")
v-col.mb-4(cols=12)
v-col(sm="5" cols=12)
v-autocomplete.p-0(
v-model='meta'
:label='$t("common.search")'
:filter='filter'
cache-items
:disabled='!!collection'
v-model="filters"
outlined
:label='$t("common.filter")'
hide-details
color='primary'
hide-selected
@ -35,35 +35,65 @@ v-row
@click:close='remove(item)'
:close-icon='mdiCloseCircle')
v-avatar(left)
v-icon(small v-text="item.type === 'place' ? mdiMapMarker : mdiTag")
v-icon(small v-text="item.type === 'place' ? mdiMapMarker : item.type === 'tag' ? mdiTag : mdiCollage")
span {{ item.label }}
template(v-slot:item='{ item }')
v-list-item-avatar
v-icon(v-text="item.type === 'place' ? mdiMapMarker : mdiTag")
v-icon(v-text="item.type === 'place' ? mdiMapMarker : item.type === 'tag' ? mdiTag : mdiCollage")
v-list-item-content
v-list-item-title(v-text='item.label')
v-list-item-subtitle(v-if='item.type ==="place"' v-text='item.address')
v-list-item-subtitle(v-if='item.type ==="place"' v-text='item.label !== "online" && item.address')
v-col(sm=4 cols=12)
v-autocomplete.p-0(
:disabled='!!filters.length'
v-model="collection"
outlined
:label='$t("common.collections")'
hide-details
color='primary'
hide-selected
:menu-props="{ maxWidth: '400' }"
:items='collections'
@change='change'
hide-no-data
clearable
:clear-icon='mdiCloseCircle'
item-text='name')
template(v-slot:itsdfems='{ item }')
v-list-item-avatar
v-icon(v-text="item.type === 'place' ? mdiMapMarker : item.type === 'tag' ? mdiTag : mdiCollage")
v-list-item-content
v-list-item-title(v-text='item.label')
v-list-item-subtitle(v-if='item.type ==="place"' v-text='item.label !== "online" && item.address')
</template>
<script>
import { mapState } from 'vuex'
import { mdiMapMarker, mdiTag, mdiCloseCircle } from '@mdi/js'
import { mdiMapMarker, mdiTag, mdiCloseCircle, mdiCollage } from '@mdi/js'
import debounce from 'lodash/debounce'
export default {
name: 'Search',
props: {
filters: { type: Object, default: () => ({ }) }
value: { type: Object, default: () => ({ }) }
},
data () {
return {
mdiTag, mdiMapMarker, mdiCloseCircle,
meta: [],
mdiTag, mdiMapMarker, mdiCloseCircle, mdiCollage,
items: [],
show_recurrent: this.filters.show_recurrent || false
filters: [],
collection: null,
collections: [],
show_recurrent: this.value.show_recurrent || false
}
},
computed: mapState(['settings']),
async fetch () {
this.collections = await this.$axios.$get('/collections')
},
computed: {
...mapState(['settings']),
},
methods: {
filter (item, queryText, itemText) {
return itemText.toLocaleLowerCase().indexOf(queryText.toLocaleLowerCase()) > -1 ||
@ -71,18 +101,31 @@ export default {
},
search: debounce(async function(search) {
this.items = await this.$axios.$get(`/event/meta?search=${search.target.value}`)
console.error('items ', this.items.length)
}, 100),
remove (item) {
this.meta = this.meta.filter(m => m.type !== item.type || m.type === 'place' ? m.id !== item.id : m.label !== item.label)
// const filters = {
// tags: this.filters.filter(t => t.type === 'tag' && t.label !== item.label).map(t => t.label),
// places: this.filters.filter(p => p.type === 'place' && p.id !== item.id).map(p => p.id),
// show_recurrent: this.show_recurrent
// }
this.filters = this.filters.filter(m => m.type !== item.type || m.type === 'place' ? m.id !== item.id : m.label !== item.label)
// this.$emit('input', filters)
this.change()
},
change () {
if (this.collection) {
this.filters = []
this.$emit('input', { collection: this.collection, places: [], tags: [], show_recurrent: this.show_recurrent })
} else {
const filters = {
tags: this.meta.filter(t => t.type === 'tag').map(t => t.label),
places: this.meta.filter(p => p.type === 'place').map(p => p.id),
tags: this.filters.filter(t => t.type === 'tag').map(t => t.label),
places: this.filters.filter(p => p.type === 'place').map(p => p.id),
show_recurrent: this.show_recurrent
}
this.$emit('update', filters)
this.$emit('input', filters)
}
}
}
}

View file

@ -79,7 +79,6 @@ v-container
<script>
import { mapActions, mapState } from 'vuex'
import get from 'lodash/get'
import axios from 'axios'
import { mdiDeleteForever, mdiPlus, mdiChevronLeft, mdiChevronRight, mdiChevronDown } from '@mdi/js'
export default {
@ -140,21 +139,15 @@ export default {
this.instance_url = `https://${this.instance_url}`
}
this.instance_url = this.instance_url.replace(/\/$/, '')
// const instance = await axios.get(`${this.instance_url}/.well-known/nodeinfo/2.1`)
// // this.setSetting({
// // key: 'trusted_instances',
// // value: this.settings.trusted_instances.concat({
// const instance = {
// url: this.instance_url,
// name: get(instance, 'data.metadata.nodeName', ''),
// label: get(instance, 'data.metadata.nodeLabel', ''),
// actor: get(instance, 'data.medatada.nodeActor', ''),
// timezone: get(instance, 'data.metadata.nodeTimezone', '')
// }
const ret = await this.$axios.$post('/instances/add_friendly', { instance_url: this.instance_url })
console.error(ret)
const instance = await this.$axios.$get(`${this.instance_url}/.well-known/nodeinfo/2.1`)
this.setSetting({
key: 'trusted_instances',
value: this.settings.trusted_instances.concat({
url: this.instance_url,
name: get(instance, 'metadata.nodeName', ''),
label: get(instance, 'metadata.nodeLabel', '')
})
})
this.$refs.form.reset()
this.dialogAddInstance = false
} catch (e) {

View file

@ -18,7 +18,7 @@ v-container
:rules="[setting.required ? $validators.required(setting.description) : false]")
v-text-field(v-if='setting.type === "NUMBER"' v-model='selectedPlugin.settingsValue[name]' type='number' :label='setting.description')
v-switch(v-if='setting.type === "CHECK"' v-model='selectedPlugin.settingsValue[name]' :label='setting.description')
v-switch(v-if='setting.type === "CHECK"' v-model='selectedPlugin.settingsValue[name]' :label='setting.description' inset)
v-select(v-if='setting.type === "LIST"' v-model='selectedPlugin.settingsValue[name]' :items='setting.items' :label='setting.description')
v-switch(:label="$t('common.enable')" inset color='primary' v-model='selectedPlugin.settingsValue["enable"]')
v-card-actions

View file

@ -73,7 +73,7 @@ export default {
computed: mapState(['settings']),
watch: {
'smtp.secure' (value) {
this.smtp.port = value ? 465 : 25
this.smtp.port = value ? 465 : 587
}
},
methods: {

View file

@ -19,6 +19,7 @@ v-container
v-text-field(v-model='new_user.email'
:label="$t('common.email')"
:rules="$validators.email")
v-text-field(v-model='new_user.description' :label="$t('common.description')")
v-switch(v-model='new_user.is_admin' :label="$t('common.admin')" inset)
v-alert(type='info' :closable='false' :icon='mdiInformation') {{$t('admin.user_add_help')}}
v-card-actions

View file

@ -20,6 +20,13 @@ span
v-list-item-content
v-list-item-title(v-text="$t('common.edit')")
//- Clone
v-list-item(v-if='!event.parentId' :to='`/add/${event.id}?clone=true`')
v-list-item-icon
v-icon(v-text='mdiScanner')
v-list-item-content
v-list-item-title(v-text="$t('common.clone')")
//- Remove
v-list-item(v-if='!event.parentId' @click='remove(false)')
v-list-item-icon
@ -53,26 +60,13 @@ span
v-list-item-content
v-list-item-title(v-text="$t('common.remove')")
//- v-btn(text color='primary' v-if='event.is_visible' @click='toggle(false)') {{$t(`common.${event.parentId?'skip':'hide'}`)}}
//- v-btn(text color='success' v-else @click='toggle(false)') <v-icon color='yellow' v-text='mdiAlert'></v-icon> {{$t('common.confirm')}}
//- v-btn(text color='primary' @click='$router.push(`/add/${event.id}`)') {{$t('common.edit')}}
//- v-btn(text color='primary' v-if='!event.parentId' @click='remove(false)') {{$t('common.remove')}}
//- template(v-if='event.parentId')
//- v-divider
//- span.mr-1 <v-icon v-text='mdiRepeat'></v-icon> {{$t('event.edit_recurrent')}}
//- v-btn(text color='primary' v-if='event.parent.is_visible' @click='toggle(true)') {{$t('common.pause')}}
//- v-btn(text color='primary' v-else @click='toggle(true)') {{$t('common.start')}}
//- v-btn(text color='primary' @click='$router.push(`/add/${event.parentId}`)') {{$t('common.edit')}}
//- v-btn(text color='primary' @click='remove(true)') {{$t('common.remove')}}
</template>
<script>
import { mdiChevronUp, mdiRepeat, mdiDelete, mdiCalendarEdit, mdiEyeOff, mdiEye, mdiPause, mdiPlay, mdiDeleteForever } from '@mdi/js'
import { mdiChevronUp, mdiRepeat, mdiDelete, mdiCalendarEdit, mdiEyeOff, mdiEye, mdiPause, mdiPlay, mdiDeleteForever, mdiScanner } from '@mdi/js'
export default {
name: 'EventAdmin',
data () {
return { mdiChevronUp, mdiRepeat, mdiDelete, mdiCalendarEdit, mdiEyeOff, mdiEye, mdiPause, mdiPlay, mdiDeleteForever }
return { mdiChevronUp, mdiRepeat, mdiDelete, mdiCalendarEdit, mdiEyeOff, mdiEye, mdiPause, mdiPlay, mdiDeleteForever, mdiScanner }
},
props: {
event: {

View file

@ -25,10 +25,10 @@ function ye(t) {
function u(t, e) {
t.appendChild(e);
}
function p(t, e, i) {
function k(t, e, i) {
t.insertBefore(e, i || null);
}
function k(t) {
function x(t) {
t.parentNode.removeChild(t);
}
function be(t, e) {
@ -38,14 +38,14 @@ function be(t, e) {
function m(t) {
return document.createElement(t);
}
function $(t) {
function z(t) {
return document.createTextNode(t);
}
function M() {
return $(" ");
function C() {
return z(" ");
}
function pe() {
return $("");
return z("");
}
function a(t, e, i) {
i == null ? t.removeAttribute(e) : t.getAttribute(e) !== i && t.setAttribute(e, i);
@ -69,25 +69,25 @@ let O;
function I(t) {
O = t;
}
function $e() {
function Ee() {
if (!O)
throw new Error("Function called outside component initialization");
return O;
}
function ke(t) {
$e().$$.on_mount.push(t);
Ee().$$.on_mount.push(t);
}
const R = [], Z = [], P = [], ee = [], Ee = Promise.resolve();
const R = [], Z = [], P = [], ee = [], $e = Promise.resolve();
let K = !1;
function je() {
K || (K = !0, Ee.then(x));
K || (K = !0, $e.then(y));
}
function Q(t) {
P.push(t);
}
const J = /* @__PURE__ */ new Set();
let D = 0;
function x() {
function y() {
const t = O;
do {
for (; D < R.length; ) {
@ -120,8 +120,8 @@ function Ce(t, e) {
function Ae(t, e, i, l) {
const { fragment: n, on_mount: r, on_destroy: o, after_update: f } = t.$$;
n && n.m(e, i), l || Q(() => {
const c = r.map(W).filter(ge);
o ? o.push(...c) : U(c), t.$$.on_mount = [];
const s = r.map(W).filter(ge);
o ? o.push(...s) : U(s), t.$$.on_mount = [];
}), f.forEach(Q);
}
function Me(t, e) {
@ -132,9 +132,9 @@ function Ne(t, e) {
t.$$.dirty[0] === -1 && (R.push(t), je(), t.$$.dirty.fill(0)), t.$$.dirty[e / 31 | 0] |= 1 << e % 31;
}
function we(t, e, i, l, n, r, o, f = [-1]) {
const c = O;
const s = O;
I(t);
const s = t.$$ = {
const c = t.$$ = {
fragment: null,
ctx: null,
props: r,
@ -146,26 +146,26 @@ function we(t, e, i, l, n, r, o, f = [-1]) {
on_disconnect: [],
before_update: [],
after_update: [],
context: new Map(e.context || (c ? c.$$.context : [])),
context: new Map(e.context || (s ? s.$$.context : [])),
callbacks: Y(),
dirty: f,
skip_bound: !1,
root: e.target || c.$$.root
root: e.target || s.$$.root
};
o && o(s.root);
o && o(c.root);
let w = !1;
if (s.ctx = i ? i(t, e.props || {}, (g, _, ...A) => {
const y = A.length ? A[0] : _;
return s.ctx && n(s.ctx[g], s.ctx[g] = y) && (!s.skip_bound && s.bound[g] && s.bound[g](y), w && Ne(t, g)), _;
}) : [], s.update(), w = !0, U(s.before_update), s.fragment = l ? l(s.ctx) : !1, e.target) {
if (c.ctx = i ? i(t, e.props || {}, (g, _, ...A) => {
const E = A.length ? A[0] : _;
return c.ctx && n(c.ctx[g], c.ctx[g] = E) && (!c.skip_bound && c.bound[g] && c.bound[g](E), w && Ne(t, g)), _;
}) : [], c.update(), w = !0, U(c.before_update), c.fragment = l ? l(c.ctx) : !1, e.target) {
if (e.hydrate) {
const g = xe(e.target);
s.fragment && s.fragment.l(g), g.forEach(k);
c.fragment && c.fragment.l(g), g.forEach(x);
} else
s.fragment && s.fragment.c();
e.intro && Ce(t.$$.fragment), Ae(t, e.target, e.anchor, e.customElement), x();
c.fragment && c.fragment.c();
e.intro && Ce(t.$$.fragment), Ae(t, e.target, e.anchor, e.customElement), y();
}
I(c);
I(s);
}
let X;
typeof HTMLElement == "function" && (X = class extends HTMLElement {
@ -213,11 +213,11 @@ function V(t) {
}
function te(t, e, i) {
const l = t.slice();
return l[12] = e[i], l;
return l[13] = e[i], l;
}
function ie(t, e, i) {
const l = t.slice();
return l[15] = e[i], l;
return l[16] = e[i], l;
}
function le(t) {
let e;
@ -226,13 +226,13 @@ function le(t) {
e = m("link"), a(e, "rel", "stylesheet"), a(e, "href", t[4]);
},
m(i, l) {
p(i, e, l);
k(i, e, l);
},
p(i, l) {
l & 16 && a(e, "href", i[4]);
},
d(i) {
i && k(e);
i && x(e);
}
};
}
@ -242,32 +242,32 @@ function ne(t) {
r[o] = fe(te(t, n, o));
return {
c() {
e = m("div"), l && l.c(), i = M();
e = m("div"), l && l.c(), i = C();
for (let o = 0; o < r.length; o += 1)
r[o].c();
a(e, "id", "gancioEvents"), L(e, "dark", t[2] === "dark"), L(e, "light", t[2] === "light"), L(e, "sidebar", t[3] === "true"), L(e, "nosidebar", t[3] !== "true");
},
m(o, f) {
p(o, e, f), l && l.m(e, null), u(e, i);
for (let c = 0; c < r.length; c += 1)
r[c].m(e, null);
k(o, e, f), l && l.m(e, null), u(e, i);
for (let s = 0; s < r.length; s += 1)
r[s].m(e, null);
},
p(o, f) {
if (o[1] && o[3] === "true" ? l ? l.p(o, f) : (l = re(o), l.c(), l.m(e, i)) : l && (l.d(1), l = null), f & 41) {
n = o[5];
let c;
for (c = 0; c < n.length; c += 1) {
const s = te(o, n, c);
r[c] ? r[c].p(s, f) : (r[c] = fe(s), r[c].c(), r[c].m(e, null));
let s;
for (s = 0; s < n.length; s += 1) {
const c = te(o, n, s);
r[s] ? r[s].p(c, f) : (r[s] = fe(c), r[s].c(), r[s].m(e, null));
}
for (; c < r.length; c += 1)
r[c].d(1);
for (; s < r.length; s += 1)
r[s].d(1);
r.length = n.length;
}
f & 4 && L(e, "dark", o[2] === "dark"), f & 4 && L(e, "light", o[2] === "light"), f & 8 && L(e, "sidebar", o[3] === "true"), f & 8 && L(e, "nosidebar", o[3] !== "true");
},
d(o) {
o && k(e), l && l.d(), be(r, o);
o && x(e), l && l.d(), be(r, o);
}
};
}
@ -275,23 +275,23 @@ function re(t) {
let e, i, l, n, r, o, f;
return {
c() {
e = m("a"), i = m("div"), l = m("div"), n = $(t[1]), r = M(), o = m("img"), a(l, "class", "title"), a(o, "id", "logo"), a(o, "alt", "logo"), H(o.src, f = t[0] + "/logo.png") || a(o, "src", f), a(i, "class", "content"), a(e, "href", t[0]), a(e, "target", "_blank"), a(e, "id", "header");
e = m("a"), i = m("div"), l = m("div"), n = z(t[1]), r = C(), o = m("img"), a(l, "class", "title"), a(o, "id", "logo"), a(o, "alt", "logo"), H(o.src, f = t[0] + "/logo.png") || a(o, "src", f), a(i, "class", "content"), a(e, "href", t[0]), a(e, "target", "_blank"), a(e, "id", "header");
},
m(c, s) {
p(c, e, s), u(e, i), u(i, l), u(l, n), u(i, r), u(i, o);
m(s, c) {
k(s, e, c), u(e, i), u(i, l), u(l, n), u(i, r), u(i, o);
},
p(c, s) {
s & 2 && T(n, c[1]), s & 1 && !H(o.src, f = c[0] + "/logo.png") && a(o, "src", f), s & 1 && a(e, "href", c[0]);
p(s, c) {
c & 2 && T(n, s[1]), c & 1 && !H(o.src, f = s[0] + "/logo.png") && a(o, "src", f), c & 1 && a(e, "href", s[0]);
},
d(c) {
c && k(e);
d(s) {
s && x(e);
}
};
}
function oe(t) {
let e;
function i(r, o) {
return r[12].media.length ? Le : Te;
return r[13].media.length ? Le : Te;
}
let l = i(t), n = l(t);
return {
@ -299,13 +299,13 @@ function oe(t) {
e = m("div"), n.c(), a(e, "class", "img");
},
m(r, o) {
p(r, e, o), n.m(e, null);
k(r, e, o), n.m(e, null);
},
p(r, o) {
l === (l = i(r)) && n ? n.p(r, o) : (n.d(1), n = l(r), n && (n.c(), n.m(e, null)));
},
d(r) {
r && k(e), n.d();
r && x(e), n.d();
}
};
}
@ -313,16 +313,16 @@ function Te(t) {
let e, i, l;
return {
c() {
e = m("img"), a(e, "style", "aspect-ratio=1.7778;"), a(e, "alt", i = t[12].title), H(e.src, l = t[0] + "/fallbackimage.png") || a(e, "src", l), a(e, "loading", "lazy");
e = m("img"), a(e, "style", "aspect-ratio=1.7778;"), a(e, "alt", i = t[13].title), H(e.src, l = t[0] + "/fallbackimage.png") || a(e, "src", l), a(e, "loading", "lazy");
},
m(n, r) {
p(n, e, r);
k(n, e, r);
},
p(n, r) {
r & 32 && i !== (i = n[12].title) && a(e, "alt", i), r & 1 && !H(e.src, l = n[0] + "/fallbackimage.png") && a(e, "src", l);
r & 32 && i !== (i = n[13].title) && a(e, "alt", i), r & 1 && !H(e.src, l = n[0] + "/fallbackimage.png") && a(e, "src", l);
},
d(n) {
n && k(e);
n && x(e);
}
};
}
@ -330,38 +330,38 @@ function Le(t) {
let e, i, l, n;
return {
c() {
e = m("img"), a(e, "style", i = "object-position: " + ue(t[12]) + "; aspect-ratio=1.7778;"), a(e, "alt", l = t[12].media[0].name), H(e.src, n = t[0] + "/media/thumb/" + t[12].media[0].url) || a(e, "src", n), a(e, "loading", "lazy");
e = m("img"), a(e, "style", i = "object-position: " + ue(t[13]) + "; aspect-ratio=1.7778;"), a(e, "alt", l = t[13].media[0].name), H(e.src, n = t[0] + "/media/thumb/" + t[13].media[0].url) || a(e, "src", n), a(e, "loading", "lazy");
},
m(r, o) {
p(r, e, o);
k(r, e, o);
},
p(r, o) {
o & 32 && i !== (i = "object-position: " + ue(r[12]) + "; aspect-ratio=1.7778;") && a(e, "style", i), o & 32 && l !== (l = r[12].media[0].name) && a(e, "alt", l), o & 33 && !H(e.src, n = r[0] + "/media/thumb/" + r[12].media[0].url) && a(e, "src", n);
o & 32 && i !== (i = "object-position: " + ue(r[13]) + "; aspect-ratio=1.7778;") && a(e, "style", i), o & 32 && l !== (l = r[13].media[0].name) && a(e, "alt", l), o & 33 && !H(e.src, n = r[0] + "/media/thumb/" + r[13].media[0].url) && a(e, "src", n);
},
d(r) {
r && k(e);
r && x(e);
}
};
}
function ae(t) {
let e, i = t[12].place.address + "", l;
let e, i = t[13].place.address + "", l;
return {
c() {
e = m("span"), l = $(i), a(e, "class", "subtitle");
e = m("span"), l = z(i), a(e, "class", "subtitle");
},
m(n, r) {
p(n, e, r), u(e, l);
k(n, e, r), u(e, l);
},
p(n, r) {
r & 32 && i !== (i = n[12].place.address + "") && T(l, i);
r & 32 && i !== (i = n[13].place.address + "") && T(l, i);
},
d(n) {
n && k(e);
n && x(e);
}
};
}
function se(t) {
let e, i = t[12].tags, l = [];
let e, i = t[13].tags, l = [];
for (let n = 0; n < i.length; n += 1)
l[n] = ce(ie(t, i, n));
return {
@ -372,13 +372,13 @@ function se(t) {
a(e, "class", "tags");
},
m(n, r) {
p(n, e, r);
k(n, e, r);
for (let o = 0; o < l.length; o += 1)
l[o].m(e, null);
},
p(n, r) {
if (r & 32) {
i = n[12].tags;
i = n[13].tags;
let o;
for (o = 0; o < i.length; o += 1) {
const f = ie(n, i, o);
@ -390,42 +390,41 @@ function se(t) {
}
},
d(n) {
n && k(e), be(l, n);
n && x(e), be(l, n);
}
};
}
function ce(t) {
let e, i, l = t[15] + "", n;
let e, i, l = t[16] + "", n;
return {
c() {
e = m("span"), i = $("#"), n = $(l), a(e, "class", "tag");
e = m("span"), i = z("#"), n = z(l), a(e, "class", "tag");
},
m(r, o) {
p(r, e, o), u(e, i), u(e, n);
k(r, e, o), u(e, i), u(e, n);
},
p(r, o) {
o & 32 && l !== (l = r[15] + "") && T(n, l);
o & 32 && l !== (l = r[16] + "") && T(n, l);
},
d(r) {
r && k(e);
r && x(e);
}
};
}
function fe(t) {
let e, i, l, n, r = V(t[12]) + "", o, f, c, s = t[12].title + "", w, g, _, A, y = t[12].place.name + "", d, z, h, v, C, q, E = t[3] !== "true" && oe(t), j = t[12].place.name !== "online" && ae(t), S = t[12].tags.length && se(t);
let e, i, l, n, r = V(t[13]) + "", o, f, s, c = t[13].title + "", w, g, _, A, E = t[13].place.name + "", M, d, h, p, v, q, $ = t[3] !== "true" && oe(t), j = t[13].place.name !== "online" && ae(t), S = t[13].tags.length && se(t);
return {
c() {
e = m("a"), E && E.c(), i = M(), l = m("div"), n = m("div"), o = $(r), f = M(), c = m("div"), w = $(s), g = M(), _ = m("span"), A = $('@"'), d = $(y), z = $(`"
`), j && j.c(), h = M(), S && S.c(), v = M(), a(n, "class", "subtitle"), a(c, "class", "title"), a(_, "class", "place"), a(l, "class", "content"), a(e, "href", C = t[0] + "/event/" + (t[12].slug || t[12].id)), a(e, "class", "event"), a(e, "title", q = t[12].title), a(e, "target", "_blank");
e = m("a"), $ && $.c(), i = C(), l = m("div"), n = m("div"), o = z(r), f = C(), s = m("div"), w = z(c), g = C(), _ = m("span"), A = z("@"), M = z(E), d = C(), j && j.c(), h = C(), S && S.c(), p = C(), a(n, "class", "subtitle"), a(s, "class", "title"), a(_, "class", "place"), a(l, "class", "content"), a(e, "href", v = t[0] + "/event/" + (t[13].slug || t[13].id)), a(e, "class", "event"), a(e, "title", q = t[13].title), a(e, "target", "_blank");
},
m(b, N) {
p(b, e, N), E && E.m(e, null), u(e, i), u(e, l), u(l, n), u(n, o), u(l, f), u(l, c), u(c, w), u(l, g), u(l, _), u(_, A), u(_, d), u(_, z), j && j.m(_, null), u(l, h), S && S.m(l, null), u(e, v);
k(b, e, N), $ && $.m(e, null), u(e, i), u(e, l), u(l, n), u(n, o), u(l, f), u(l, s), u(s, w), u(l, g), u(l, _), u(_, A), u(_, M), u(_, d), j && j.m(_, null), u(l, h), S && S.m(l, null), u(e, p);
},
p(b, N) {
b[3] !== "true" ? E ? E.p(b, N) : (E = oe(b), E.c(), E.m(e, i)) : E && (E.d(1), E = null), N & 32 && r !== (r = V(b[12]) + "") && T(o, r), N & 32 && s !== (s = b[12].title + "") && T(w, s), N & 32 && y !== (y = b[12].place.name + "") && T(d, y), b[12].place.name !== "online" ? j ? j.p(b, N) : (j = ae(b), j.c(), j.m(_, null)) : j && (j.d(1), j = null), b[12].tags.length ? S ? S.p(b, N) : (S = se(b), S.c(), S.m(l, null)) : S && (S.d(1), S = null), N & 33 && C !== (C = b[0] + "/event/" + (b[12].slug || b[12].id)) && a(e, "href", C), N & 32 && q !== (q = b[12].title) && a(e, "title", q);
b[3] !== "true" ? $ ? $.p(b, N) : ($ = oe(b), $.c(), $.m(e, i)) : $ && ($.d(1), $ = null), N & 32 && r !== (r = V(b[13]) + "") && T(o, r), N & 32 && c !== (c = b[13].title + "") && T(w, c), N & 32 && E !== (E = b[13].place.name + "") && T(M, E), b[13].place.name !== "online" ? j ? j.p(b, N) : (j = ae(b), j.c(), j.m(_, null)) : j && (j.d(1), j = null), b[13].tags.length ? S ? S.p(b, N) : (S = se(b), S.c(), S.m(l, null)) : S && (S.d(1), S = null), N & 33 && v !== (v = b[0] + "/event/" + (b[13].slug || b[13].id)) && a(e, "href", v), N & 32 && q !== (q = b[13].title) && a(e, "title", q);
},
d(b) {
b && k(e), E && E.d(), j && j.d(), S && S.d();
b && x(e), $ && $.d(), j && j.d(), S && S.d();
}
};
}
@ -433,10 +432,10 @@ function Ge(t) {
let e, i, l = t[4] && le(t), n = t[5].length && ne(t);
return {
c() {
l && l.c(), e = M(), n && n.c(), i = pe(), this.c = G;
l && l.c(), e = C(), n && n.c(), i = pe(), this.c = G;
},
m(r, o) {
l && l.m(r, o), p(r, e, o), n && n.m(r, o), p(r, i, o);
l && l.m(r, o), k(r, e, o), n && n.m(r, o), k(r, i, o);
},
p(r, [o]) {
r[4] ? l ? l.p(r, o) : (l = le(r), l.c(), l.m(e.parentNode, e)) : l && (l.d(1), l = null), r[5].length ? n ? n.p(r, o) : (n = ne(r), n.c(), n.m(i.parentNode, i)) : n && (n.d(1), n = null);
@ -444,7 +443,7 @@ function Ge(t) {
i: G,
o: G,
d(r) {
l && l.d(r), r && k(e), n && n.d(r), r && k(i);
l && l.d(r), r && x(e), n && n.d(r), r && x(i);
}
};
}
@ -456,34 +455,37 @@ function ue(t) {
return "center center";
}
function He(t, e, i) {
let { baseurl: l = "" } = e, { title: n = "" } = e, { maxlength: r = !1 } = e, { tags: o = "" } = e, { places: f = "" } = e, { theme: c = "light" } = e, { show_recurrent: s = !1 } = e, { sidebar: w = "true" } = e, { external_style: g = "" } = e, _ = !1, A = [];
function y(d) {
if (!_)
let { baseurl: l = "" } = e, { title: n = "" } = e, { maxlength: r = !1 } = e, { collection: o = "" } = e, { tags: f = "" } = e, { places: s = "" } = e, { theme: c = "light" } = e, { show_recurrent: w = !1 } = e, { sidebar: g = "true" } = e, { external_style: _ = "" } = e, A = !1, E = [];
function M(d) {
if (!A)
return;
const z = [];
r && z.push(`max=${r}`), o && z.push(`tags=${o}`), f && z.push(`places=${f}`), z.push(`show_recurrent=${s ? "true" : "false"}`), fetch(`${l}/api/events?${z.join("&")}`).then((h) => h.json()).then((h) => {
i(5, A = h);
}).catch((h) => {
console.error("Error loading Gancio API -> ", h);
const h = [];
r && h.push(`max=${r}`);
let p = "/api/events";
o ? p = `/api/collections/${o}` : (f && h.push(`tags=${f}`), s && h.push(`places=${s}`)), h.push(`show_recurrent=${w ? "true" : "false"}`), fetch(`${l}${p}?${h.join("&")}`).then((v) => v.json()).then((v) => {
i(5, E = v.events || v);
}).catch((v) => {
console.error("Error loading Gancio API -> ", v);
});
}
return ke(() => {
_ = !0, y();
A = !0, M();
}), t.$$set = (d) => {
"baseurl" in d && i(0, l = d.baseurl), "title" in d && i(1, n = d.title), "maxlength" in d && i(6, r = d.maxlength), "tags" in d && i(7, o = d.tags), "places" in d && i(8, f = d.places), "theme" in d && i(2, c = d.theme), "show_recurrent" in d && i(9, s = d.show_recurrent), "sidebar" in d && i(3, w = d.sidebar), "external_style" in d && i(4, g = d.external_style);
"baseurl" in d && i(0, l = d.baseurl), "title" in d && i(1, n = d.title), "maxlength" in d && i(6, r = d.maxlength), "collection" in d && i(7, o = d.collection), "tags" in d && i(8, f = d.tags), "places" in d && i(9, s = d.places), "theme" in d && i(2, c = d.theme), "show_recurrent" in d && i(10, w = d.show_recurrent), "sidebar" in d && i(3, g = d.sidebar), "external_style" in d && i(4, _ = d.external_style);
}, t.$$.update = () => {
t.$$.dirty & 975 && y();
t.$$.dirty & 1999 && M();
}, [
l,
n,
c,
w,
g,
A,
_,
E,
r,
o,
f,
s
s,
w
];
}
class Re extends X {
@ -508,21 +510,23 @@ class Re extends X {
baseurl: 0,
title: 1,
maxlength: 6,
tags: 7,
places: 8,
collection: 7,
tags: 8,
places: 9,
theme: 2,
show_recurrent: 9,
show_recurrent: 10,
sidebar: 3,
external_style: 4
},
null
), e && (e.target && p(e.target, this, e.anchor), e.props && (this.$set(e.props), x()));
), e && (e.target && k(e.target, this, e.anchor), e.props && (this.$set(e.props), y()));
}
static get observedAttributes() {
return [
"baseurl",
"title",
"maxlength",
"collection",
"tags",
"places",
"theme",
@ -535,72 +539,78 @@ class Re extends X {
return this.$$.ctx[0];
}
set baseurl(e) {
this.$$set({ baseurl: e }), x();
this.$$set({ baseurl: e }), y();
}
get title() {
return this.$$.ctx[1];
}
set title(e) {
this.$$set({ title: e }), x();
this.$$set({ title: e }), y();
}
get maxlength() {
return this.$$.ctx[6];
}
set maxlength(e) {
this.$$set({ maxlength: e }), x();
this.$$set({ maxlength: e }), y();
}
get tags() {
get collection() {
return this.$$.ctx[7];
}
set tags(e) {
this.$$set({ tags: e }), x();
set collection(e) {
this.$$set({ collection: e }), y();
}
get places() {
get tags() {
return this.$$.ctx[8];
}
set tags(e) {
this.$$set({ tags: e }), y();
}
get places() {
return this.$$.ctx[9];
}
set places(e) {
this.$$set({ places: e }), x();
this.$$set({ places: e }), y();
}
get theme() {
return this.$$.ctx[2];
}
set theme(e) {
this.$$set({ theme: e }), x();
this.$$set({ theme: e }), y();
}
get show_recurrent() {
return this.$$.ctx[9];
return this.$$.ctx[10];
}
set show_recurrent(e) {
this.$$set({ show_recurrent: e }), x();
this.$$set({ show_recurrent: e }), y();
}
get sidebar() {
return this.$$.ctx[3];
}
set sidebar(e) {
this.$$set({ sidebar: e }), x();
this.$$set({ sidebar: e }), y();
}
get external_style() {
return this.$$.ctx[4];
}
set external_style(e) {
this.$$set({ external_style: e }), x();
this.$$set({ external_style: e }), y();
}
}
customElements.define("gancio-events", Re);
function de(t) {
let e, i, l, n, r = t[1].title + "", o, f, c, s = V(t[1]) + "", w, g, _, A, y = t[1].place.name + "", d, z, h = t[1].media.length && he(t);
let e, i, l, n, r = t[1].title + "", o, f, s, c = V(t[1]) + "", w, g, _, A, E = t[1].place.name + "", M, d, h = t[1].media.length && he(t);
return {
c() {
e = m("a"), h && h.c(), i = M(), l = m("div"), n = m("strong"), o = $(r), f = M(), c = m("div"), w = $(s), g = M(), _ = m("div"), A = $("@"), d = $(y), a(_, "class", "place"), a(l, "class", "container"), a(e, "href", z = t[0] + "/event/" + (t[1].slug || t[1].id)), a(e, "class", "card"), a(e, "target", "_blank");
e = m("a"), h && h.c(), i = C(), l = m("div"), n = m("strong"), o = z(r), f = C(), s = m("div"), w = z(c), g = C(), _ = m("div"), A = z("@"), M = z(E), a(_, "class", "place"), a(l, "class", "container"), a(e, "href", d = t[0] + "/event/" + (t[1].slug || t[1].id)), a(e, "class", "card"), a(e, "target", "_blank");
},
m(v, C) {
p(v, e, C), h && h.m(e, null), u(e, i), u(e, l), u(l, n), u(n, o), u(l, f), u(l, c), u(c, w), u(l, g), u(l, _), u(_, A), u(_, d);
m(p, v) {
k(p, e, v), h && h.m(e, null), u(e, i), u(e, l), u(l, n), u(n, o), u(l, f), u(l, s), u(s, w), u(l, g), u(l, _), u(_, A), u(_, M);
},
p(v, C) {
v[1].media.length ? h ? h.p(v, C) : (h = he(v), h.c(), h.m(e, i)) : h && (h.d(1), h = null), C & 2 && r !== (r = v[1].title + "") && T(o, r), C & 2 && s !== (s = V(v[1]) + "") && T(w, s), C & 2 && y !== (y = v[1].place.name + "") && T(d, y), C & 3 && z !== (z = v[0] + "/event/" + (v[1].slug || v[1].id)) && a(e, "href", z);
p(p, v) {
p[1].media.length ? h ? h.p(p, v) : (h = he(p), h.c(), h.m(e, i)) : h && (h.d(1), h = null), v & 2 && r !== (r = p[1].title + "") && T(o, r), v & 2 && c !== (c = V(p[1]) + "") && T(w, c), v & 2 && E !== (E = p[1].place.name + "") && T(M, E), v & 3 && d !== (d = p[0] + "/event/" + (p[1].slug || p[1].id)) && a(e, "href", d);
},
d(v) {
v && k(e), h && h.d();
d(p) {
p && x(e), h && h.d();
}
};
}
@ -611,13 +621,13 @@ function he(t) {
e = m("img"), H(e.src, i = t[2](t[1])) || a(e, "src", i), a(e, "alt", l = t[1].media[0].name), a(e, "style", n = "object-position: " + me(t[1]) + "; aspect-ratio=1.7778;");
},
m(r, o) {
p(r, e, o);
k(r, e, o);
},
p(r, o) {
o & 2 && !H(e.src, i = r[2](r[1])) && a(e, "src", i), o & 2 && l !== (l = r[1].media[0].name) && a(e, "alt", l), o & 2 && n !== (n = "object-position: " + me(r[1]) + "; aspect-ratio=1.7778;") && a(e, "style", n);
},
d(r) {
r && k(e);
r && x(e);
}
};
}
@ -628,7 +638,7 @@ function Ie(t) {
i && i.c(), e = pe(), this.c = G;
},
m(l, n) {
i && i.m(l, n), p(l, e, n);
i && i.m(l, n), k(l, e, n);
},
p(l, [n]) {
l[1] ? i ? i.p(l, n) : (i = de(l), i.c(), i.m(e.parentNode, e)) : i && (i.d(1), i = null);
@ -636,7 +646,7 @@ function Ie(t) {
i: G,
o: G,
d(l) {
i && i.d(l), l && k(e);
i && i.d(l), l && x(e);
}
};
}
@ -649,20 +659,20 @@ function me(t) {
}
function Oe(t, e, i) {
let { baseurl: l = "https://demo.gancio.org" } = e, { id: n } = e, r = !1, o;
function f(s, w) {
r && fetch(`${w}/api/event/detail/${s}`).then((g) => g.json()).then((g) => i(1, o = g));
function f(c, w) {
r && fetch(`${w}/api/event/detail/${c}`).then((g) => g.json()).then((g) => i(1, o = g));
}
ke(() => {
r = !0, f(n, l);
});
function c(s) {
return `${l}/media/thumb/${s.media[0].url}`;
function s(c) {
return `${l}/media/thumb/${c.media[0].url}`;
}
return t.$$set = (s) => {
"baseurl" in s && i(0, l = s.baseurl), "id" in s && i(3, n = s.id);
return t.$$set = (c) => {
"baseurl" in c && i(0, l = c.baseurl), "id" in c && i(3, n = c.id);
}, t.$$.update = () => {
t.$$.dirty & 9 && f(n, l);
}, [l, o, c, n];
}, [l, o, s, n];
}
class Ue extends X {
constructor(e) {
@ -679,7 +689,7 @@ class Ue extends X {
_e,
{ baseurl: 0, id: 3 },
null
), e && (e.target && p(e.target, this, e.anchor), e.props && (this.$set(e.props), x()));
), e && (e.target && k(e.target, this, e.anchor), e.props && (this.$set(e.props), y()));
}
static get observedAttributes() {
return ["baseurl", "id"];
@ -688,13 +698,13 @@ class Ue extends X {
return this.$$.ctx[0];
}
set baseurl(e) {
this.$$set({ baseurl: e }), x();
this.$$set({ baseurl: e }), y();
}
get id() {
return this.$$.ctx[3];
}
set id(e) {
this.$$set({ id: e }), x();
this.$$set({ id: e }), y();
}
}
customElements.define("gancio-event", Ue);

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View file

@ -5,9 +5,59 @@ permalink: /changelog
nav_order: 10
---
All notable changes to this project will be documented in this file.
### [1.6.19](https://framagit.org/les/gancio/compare/v1.6.18...v1.6.19) (2023-11-04)
### Bug Fixes
* issue displaying recurrent event string ([a94ccda](https://framagit.org/les/gancio/commit/a94ccda049f7571a9caa90507141a0aac30331a9))
### 1.6.18 - 3 Nov '23
- [feat] allow to specify password while create new user via CLI to [support yunohost](https://github.com/YunoHost-Apps/gancio_ynh/pull/2#discussion_r1364285417)
- [feat] check if I'm reachable to myself to help in [#298](https://framagit.org/les/gancio/-/issues/298)
- [feat] improve recover and user_confirm error messages
- [feat] improve export and allow to export `collections` in rss/ics/widget
- [fix] fix postgres image version in docker-compose [#303](https://framagit.org/les/gancio/-/issues/303)
- [fix] Improve json-ld representation of events [#33](https://framagit.org/les/gancio/-/merge_requests/33)
- [fix] Add description field to admin's new user form, closes [#307](https://framagit.org/les/gancio/-/issues/307)
- [fix] use tls SSLv3 to send email, fix [#192](https://framagit.org/les/gancio/-/issues/192)
- [fix] notify user when accepted, fix [#308](https://framagit.org/les/gancio/-/issues/308)
- [fix] forgot password on active user only
- [fix] make search case insensitive, fix [#301](https://framagit.org/les/gancio/-/issues/301)
### 1.6.17 - 4 Oct '23
- [fix] typo
### 1.6.16 - 4 Oct '23
- [feat] add Czech locale
- [fix] improve datetime validation
### 1.6.15 - 3 Oct '23
- [feat] clone event
- [feat] am/pm / 24hr support, fix [#294](https://framagit.org/les/gancio/-/issues/294) [#264](https://framagit.org/les/gancio/-/issues/264)
- [feat] update telegram plugin bridge to v1.0.3, [#299](https://framagit.org/les/gancio/-/issues/299)
- [feat] include Brazilian Portuguese (pt-br) and Portugual Portuguese (pt-pt) [#292](https://framagit.org/les/gancio/-/issues/292)
- [fix] MariaDB JSON fields manual fix
- [fix] improve some corner case with SMTP From field [#297](https://framagit.org/les/gancio/-/issues/297)
- [fix] CLI has to fail when configuration not present [#284](https://framagit.org/les/gancio/-/issues/284)
- [minor] remove html2text dep from client
- [minor] RSS item's title format is now YYYY-MM-DD, [#300](https://framagit.org/les/gancio/-/issues/300)
### 1.6.14 - 30 June '23
- improve CLI accounts operations ([documentation](https://gancio.org/usage/cli))
- allow plugins to expose API ([documentation](http://gancio.org/dev/plugins))
- allow plugins to access DB ([documentation](http://gancio.org/dev/plugins))
- show map on the places page, [#276]((https://framagit.org/les/gancio/-/issues/276)) #30
- add node v18 support, [#278]((https://framagit.org/les/gancio/-/issues/278))
- fix media update, [#285]((https://framagit.org/les/gancio/-/issues/285))
- fix nodejs v14 compatibility in export
- fix invalid event microdata, [#277]((https://framagit.org/les/gancio/-/issues/277))
- fix recurrent event, [#280]((https://framagit.org/les/gancio/-/issues/280))
- update deps and locales
### 1.6.13 - 16 may '23
- fix feed, ics, json exports

View file

@ -52,6 +52,9 @@ POST
| description | `string` | event's description (html accepted and sanitized) |
| place_name | `string` | the name of the place |
| place_address | `string` | the address of the place |
| place_latitude | `float` | the latitude of the place |
| place_longitude | `float` | the longitude of the place |
| online_locations | `array` | List of online locations |
| start_datetime | `integer` | start timestamp |
| multidate | `integer` | is a multidate event? |
| tags | `array` | List of tags |

View file

@ -16,16 +16,110 @@ Since **v.1.2.2** you can write your own plugin that react to event related acti
>
> [**<u>Please share your plugins or your needs</u>**](/contacts)
Plugins should be inside `./plugins` directory, this is an example:
## Example
Here is a complete example of plugins feature: [https://framagit.org/les/gancio/-/blob/master/plugins/gancioPluginExample.js](https://framagit.org/les/gancio/-/blob/master/plugins/gancioPluginExample.js) .
## Basic plugin syntax
A plugin is essentially an `index.js` file inside its own path in `./plugins`, e.g. `./plugins/my-example-plugin/index.js`
```javascript
module.exports = {
}
```
Plugins should be inside `./plugins` directory but you can specify another location using [`plugins_path`](https://gancio.org/install/config#plugins-path) configuration.
## Plugin details
A plugins **MUST** expose a `configuration` key where to specify its details:
```js
const plugin = {
gancio: null,
load (gancio) {
console.error('Plugin GancioPluginExample loaded!')
plugin.gancio = gancio
module.exports = {
configuration: {
name: 'Example',
author: 'lesion',
url: 'https://framagit.org/les/gancio/plugins/gancioPluginExample.js',
description: 'Example plugin',
settings: {
my_plugin_string_setting: {
type: 'TEXT',
description: 'My plugin string setting',
required: true,
hint: 'My plugin setting support <strong>html too</strong>'
},
enable_this_feature_in_my_plugin: {
type: 'CHECK',
description: 'My plugin best feature',
required: true,
hint: 'This feature is super dupe, enable it!'
},
min_post: {
type: 'NUMBER',
description: 'it supports number too'
},
my_default_language: {
description: 'My default language',
type: 'LIST',
items: ['it', 'en', 'fr']
}
}
}
}
```
[![/assets/plugins/settings.png](/assets/plugins/settings.png)](/assets/plugins/settings.png){: data-fancybox="group" data-caption="Home"}
## Load a plugin
When a plugin is enabled by an administrator, Gancio will call the `load` method if specified:
```js
load ({ settings: gancio_settings, db, helpers, log}, settings) {
// access to your plugin local settings
console.info('Your local settings are in ', settings)
console.info(`For example, you can access to your default language setting by using ${settings.my_default_language}`)
// access to gancio settings
console.info(`Gancio settings are in ${gancio_settings}, e.g. ${gancio.settings.baseurl}`)
// log something
log.warn('This is a log entry from my example plugin')
// use the DB (since 1.6.14)
console.info(db.models.findAll())
console.info(db.query('CREATE TABLE IF NOT EXISTS myPluginTable'))
}
```
## Expose an API <span class='label label-yellow'>since 1.6.4</span>
Plugins could have public HTTP endpoints by exposing an express Router in routeAPI object.
```js
const express = require('express')
const routeAPI = express.Router()
routeAPI.get('/test', (req, res) => {
res.json('WOW!')
})
```
This endpoint will be exposed at <your_instance>/api/plugin/<your_plugin_name>/test
## Access to DB <span class='label label-yellow'>since 1.6.4</span>
TODO
## Helpers <span class='label label-red'>DOCUMENTATION NEEDED</span>
- randomString
- sanitizeHTML
- queryParamToBool
## React to events
```js
onEventCreate (event) {
const eventLink = `${plugin.gancio.settings.baseurl}/event/${event.slug}`
if (!event.is_visible) {
@ -42,10 +136,6 @@ const plugin = {
onEventDelete (event) {
console.error(`Event "${event.title}" deleted`)
}
}
module.exports = plugin
```

View file

@ -2,7 +2,7 @@ version: '3'
services:
db:
image: postgres
image: postgres:15
container_name: postgres
volumes:
- ./postgres:/var/lib/postgresql/data

View file

@ -10,7 +10,7 @@ permalink: /
A shared agenda for local communities.
{: .fs-6 }
Last release **[1.6.13 - 16 May 2023](/changelog#1613---16-may-23)**
Last release **[1.6.19 - 4 November 2023](/changelog#1619-2023-11-04)**
[Install]({% link install/install.md %}){: .btn .btn-primary .fs-5 .mb-4 .mb-md-0 .mr-2 }
[Demo](https://demo.gancio.org){: .btn .btn-green .fs-5 .mb-4 .mb-md-0 .mr-2 }

View file

@ -53,7 +53,7 @@ put something like this in `/opt/gancio/user_locale/en.json` to override the reg
english:
```json
{
"registrer": {
"register": {
"description": "My new registration page description"
}
}

View file

@ -55,5 +55,5 @@ You'll need to [setup nginx as a proxy]({% link install/nginx.md %}) then you ca
```bash
cd /opt/gancio # or where your installation is
docker-compose pull && docker-compose restart
docker-compose pull && docker-compose up -d
```

View file

@ -15,7 +15,7 @@ nav_order: 7
---
## Testing
For testing purposes you could skip the nominatim installation and use one of this geocoding providers that run a server for free:
For testing purposes you could skip the nominatim installation and use one of these geocoding providers that run a server for free:
- [https://photon.komoot.io/](https://photon.komoot.io/) [Terms of service](https://photon.komoot.io/)
- [https://nominatim.openstreetmap.org/](https://nominatim.openstreetmap.org/) [Terms of service](https://operations.osmfoundation.org/policies/nominatim/)
@ -28,25 +28,25 @@ From [https://nominatim.org/release-docs/latest/admin/Installation/](https://nom
"A minimum of 2GB of RAM is required or installation will fail. For a full planet import 128GB of RAM or more are strongly recommended. Do not report out of memory problems if you have less than 64GB RAM."
### Planet mirrors
There is a list of planet mirror at [https://wiki.openstreetmap.org/wiki/Planet.osm#Planet.osm_mirrors](https://wiki.openstreetmap.org/wiki/Planet.osm#Planet.osm_mirrors)
There is a list of planet mirrors at [https://wiki.openstreetmap.org/wiki/Planet.osm#Planet.osm_mirrors](https://wiki.openstreetmap.org/wiki/Planet.osm#Planet.osm_mirrors)
There you can also find `Country and area extracts`, divided by `Worldwide extract sources` and `Regional extract sources`
### Download an extract
For Nominatim to work, you will needs to import files in [PBF Format](https://wiki.openstreetmap.org/wiki/PBF_Format) in the PostGis database. Those files have extension `*.osm.pbf`.
For Nominatim to work, you need to import files in [PBF Format](https://wiki.openstreetmap.org/wiki/PBF_Format) in the PostGis database. Those files have extension `*.osm.pbf`.
Some of these mirrors provide also incremental updates via [OsmChange](https://wiki.openstreetmap.org/wiki/OsmChange), for example:
- Provides updates but with a lower detail
- These provide updates but with a lower detail
[https://download.geofabrik.de/europe/italy/nord-ovest-updates/nord-ovest-latest.osm.pbf](http://download.geofabrik.de/europe/italy/nord-ovest-latest.osm.pbf)
[https://download.geofabrik.de/europe/italy/nord-ovest-updates/](https://download.geofabrik.de/europe/italy/nord-ovest-updates/)
- Does not provide updates but as higher level of detail
- This doesn't provide updates but has an higher level of detail
[https://osmit-estratti-test.wmcloud.org/dati/poly/province/pbf/015_Milano_poly.osm.pbf](https://osmit-estratti-test.wmcloud.org/dati/poly/province/pbf/015_Milano_poly.osm.pbf)
Needs to host multiple areas? Checkout [Osmium](https://osmcode.org/osmium-tool/manual.html), to merge multiple PBF files into one.
Do you need to host multiple areas? Checkout [Osmium](https://osmcode.org/osmium-tool/manual.html), to merge multiple PBF files into one.
---
## Install on Debian
There is a [detailed documentaion](https://nominatim.org/release-docs/latest/appendix/Install-on-Ubuntu-22/) for installing nominatim on `Ubuntu 22` that should be valid also to install on `Debian`.
There is a [detailed documentation](https://nominatim.org/release-docs/latest/appendix/Install-on-Ubuntu-22/) for installing nominatim on `Ubuntu 22` that should be valid also to install on `Debian`.
### Setup
[https://nominatim.org/release-docs/latest/appendix/Install-on-Ubuntu-22/#installing-the-required-software](https://nominatim.org/release-docs/latest/appendix/Install-on-Ubuntu-22/#installing-the-required-software)
@ -54,14 +54,14 @@ There is a [detailed documentaion](https://nominatim.org/release-docs/latest/app
### Building and Configuration
Get the source code from Github and change into the source directory
```
```bash
cd $USERHOME
wget https://nominatim.org/release/Nominatim-4.2.0.tar.bz2
tar xf Nominatim-4.2.0.tar.bz2
```
The code must be built in a separate directory. Create this directory, then configure and build Nominatim in there:
```
```bash
mkdir $USERHOME/build
cd $USERHOME/build
cmake $USERHOME/Nominatim-4.2.0
@ -91,13 +91,12 @@ From [https://github.com/mediagis/nominatim-docker](https://github.com/mediagis/
- Clone the project from sources
```bash
git clone git@github.com:mediagis/nominatim-docker.git
# cd nominatim-docker/<version>
cd nominatim-docker/4.2/contrib # released Nov 29, 2022
docker-compose pull
```
- Or, use the template at `docs/docker/nominatim`
```
```bash
cd /opt/gancio/docs/docker/nominatim
docker-compose pull
```
@ -111,15 +110,13 @@ wget https://download.geofabrik.de/europe/italy/nord-ovest-latest.osm.pbf \
```
### Configure the environment file
```
```bash
cd docs/docker/nominatim/
cp .env.example .env
```
Create a random password for nominatim a add it to .env file
Create a random password for nominatim and add it to .env file
```bash
NOMINATIM_PASSWORD=random_password;
NOMINATIM_PASSWORD=$(echo $NOMINATIM_PASSWORD | openssl passwd --stdin);
echo $NOMINATIM_PASSWORD;
NOMINATIM_PASSWORD=$(echo random_password | openssl passwd --stdin);
sed -i -e 's/\(NOMINATIM_PASSWORD=\)\(.*\)/\1'$NOMINATIM_PASSWORD'/g' .env
```

60
docs/usage/cli.md Normal file
View file

@ -0,0 +1,60 @@
---
layout: default
title: CLI
permalink: /usage/cli
nav_order: 2
parent: Usage
has_toc: true
---
# CLI - Command Line Interface
{: .no_toc }
1. TOC
{:toc}
## Using CLI
Gancio is distributed with an embedded CLI.
To use the CLI you need to specify the `config.json` configuration file via `--config <your_config.json>` flag; by default the CLI will look for one in the current directory, so if your current directory is /opt/gancio (having followed the [installation instructions](/install/debian)) there is no need to specify it.
### Using CLI with Docker installation
To use the CLI in a docker installation you can execute a shell inside the container with:
`docker exec --workdir /home/node/data -it gancio sh` and following the normal CLI usage or running commands with:
`docker exec --workdir /home/node/data gancio gancio <your command>`
(the first "gancio" is the container name)
## Users <span class='label label-yellow'>since 1.6.14</span>
All users related sub-commands starts with `gancio users`.
Note that most of this actions could be done from administration panel (Admin > Users).
### List all users
To list all users use
`gancio users list`
### Create a new user
`gancio users create <username|email>` [password]
To create an user with administrator privileges use the `--admin` flag, e.g. `gancio users create admin@example.com --admin`
### Remove a user
`gancio users remove <username|email>`
### Reset password
`gancio users reset-password <username|email>`
### Change administrator privileges
To add administrator privileges to an user:
`gancio users set-admin <username|email>`
To remove administrator privileges from an user:
`gancio users unset-admin <username|email>`

View file

@ -10,13 +10,12 @@ has_toc: true
# Plugins
{: .no_toc }
This page is a guide to install plugins, if you want to develop one instead look [here](/dev/plugins)
This page is a guide to install plugins, if you want to develop one instead look [here](/dev/plugins).
__Please note that some plugins are officially supported and distributed along with the release__
1. TOC
{:toc}
## Install
To install a plugin you have to:
@ -49,7 +48,7 @@ __with docker__
docker-compose restart
```
# List of plugins
# List of embedded plugins
## __Telegram__
@ -57,6 +56,5 @@ This plugin republishes events to Telegram channels or groups.
The goal is to spread the info of our networks to the capitalist cyberspace, and pull otherwise isolated people to our radical and free part of the internet.
- **Website**: [https://framagit.org/bcn.convocala/gancio-plugin-telegram-bridge](https://framagit.org/bcn.convocala/gancio-plugin-telegram-bridge)
- **Download**: [gancio-plugin-telegram-bridge-v0.2.0.zip](https://framagit.org/les/gancio-plugin-telegram-bridge/-/archive/v0.2.0/gancio-plugin-telegram-bridge-v0.2.0.zip)
- **Release**: v0.2.0 / 10 Dec '22
- **Release**: https://framagit.org/bcn.convocala/gancio-plugin-telegram-bridge/-/commit/af0eed7b42242ba484d9828157f1be0355bba69b

@ -1 +1 @@
Subproject commit 971ea23b6a0d4f120387fa47673424c4a6cea21c
Subproject commit 6536eb079f31f60597fb20e6f0f0a5eefe02364f

View file

@ -26,7 +26,7 @@
"places": "Llocs",
"settings": "Configuració",
"actions": "Accions",
"deactivate": "Deshabilita",
"deactivate": "Desactiva",
"remove_admin": "Treu els permisos d'admin",
"activate": "Activa",
"save": "Desa",
@ -106,7 +106,8 @@
"search_coordinates": "Cerca les coordenades",
"online": "En línia",
"test": "Prova",
"show_preview": "Previsualitza"
"show_preview": "Previsualitza",
"clone": "Clonar"
},
"login": {
"description": "Amb la sessió iniciada pots afegir activitats noves.",

363
locales/cs.json Normal file
View file

@ -0,0 +1,363 @@
{
"admin": {
"announcement_remove_ok": "Oznámení odebráno",
"description_description": "Zobrazuje se v hlavičce stránky vedle názvu",
"config_plugin": "Nastavení doplňků",
"delete_announcement_confirm": "Určitě chceš odebrat toto oznámení?",
"header_image": "Úvodní obrázek",
"instance_locale_description": "Preferovaný jazyk stránek. Někdy je nutné zobrazit zprávy ve stejném jazyce pro všechny (například při zveřejňování událostí skrz ActivityPub nebo v některých e-mailech). V takových případech bude použit vybraný jazyk.",
"delete_footer_link_confirm": "Opravduc chceš odebrat tento odkaz?",
"edit_place": "Upravit místo",
"user_add_help": "Novému uživateli přijde e-mail s potvrzením a odkazem pro vyvoření hesla",
"instance_block_confirm": "Určitě chceš zablokovat instanci {instance}?",
"delete_user_confirm": "Určitě chceš odstranit tohoto uživatele?",
"hide_boost_bookmark_help": "Skryje malé ikony které zobrazují počet boostů a záložek z Fediverse",
"smtp_use_sendmail": "Použít sendmail",
"block_user": "Zablokovat uživatele",
"instance_timezone_description": "Gancio je navrženo aby pracovalo s událostmi z jednoho místa, třeba města. Všechny události v tomto místě budou zobrazování v nastavené časové zóně.",
"geocoding_test_error": "Geokódovací služba není dostupná {service_name}",
"announcement_description": "V této sekci můžeš přidat oznámení které zůstane na domovksé stránce",
"geocoding_provider_type_help": "Defaultní software je Nominatim",
"smtp_test_success": "Testovací email byl odeslán na {admin_email}, prosím zkontroluj svou schránku",
"blocked": "Zablokováno",
"hide_thumbs": "Skrýt náhledy",
"block": "Blokovat",
"domain": "Doména",
"tilelayer_test_button": "Otestovat mapové podklady",
"collections_description": "Sbírky seskupují události podle tagů a míst. Budou se zobrazovat na hlavní stránce",
"edit_tag": "Upravit tag",
"smtp_port": "SMTP Port",
"new_announcement": "Nové oznámení",
"show_resource": "Zobrazit reakci",
"enable_resources": "Povolit reakce",
"title_description": "Používá se v hlavičce stránky, v předmětech e-mailů a v exportech RSS a ICS.",
"allow_recurrent_event": "Povolit pravidelné události",
"add_link": "Přidat odkaz",
"instance_locale": "Defaultní jazyk",
"edit_tag_help": "Můžeš upravit tag tím že ho nahradíš novým nebo existujícím. {n} propojených událostí bude také upraveno.",
"trusted_instances_help": "Seznam spřátelených instancí zobrazených v záhlaví",
"widget": "Widget",
"allow_online_event_hint": "Požadovat URL ",
"known_users": "Známí uživatelé",
"enable_trusted_instances": "Zapnout přátelské instance",
"user_create_ok": "Uživatel vytvořen",
"default_images": "Defaultní obrázky",
"admin_email": "E-mail admina",
"resources": "Reakce",
"smtp_secure": "SMTP zabezpečení (TLS nebo STARTTLS)",
"allow_multidate_event": "Povolit vícedenní události",
"tilelayer_provider": "Poskytovtel mapových podkladů",
"remove_admin": "Odebrat admina",
"instance_place_help": "Zobrazí se na ostatních instancích",
"federation": "Federace / ActivityPub",
"unblock": "Odblokovat",
"footer_links": "Odkazy v patičce",
"instance_name": "Jméno instance",
"delete_trusted_instance_confirm": "Opravdu chceš odebrat tuto položku ze seznamu sprátelených instancí?",
"recurrent_event_visible": "Zobrazit defaultně pravidelné události",
"smtp_description": "<ul><li>Administrátor by měl obdržet e-mail, když je přidána anonymní událost (pokud je to povolené).</li><li>Administrátor by měl obdržet e-mail s žádostí o registraci (pokud jsou povoleny).</li><li>Uživatel by měl obdržet e-mail s žádostí o registraci.</li><li>Uživatel by měl obdržet e-mail s potvrzením registrace.</li><li>Uživatel by měl obdržet potvrzovací e-mail, když ho administrátor přidá přímo.</li><li>Uživatelé by měli obdržet e-mail pro obnovení hesla, když ho zapomněli</li></ul>",
"fallback_image": "Záložní obrázek",
"disable_user_confirm": "Určitě chceš deaktivovat tohoto uživatele?",
"delete_resource_confirm": "Určitě chceš smazat tuto reakci?",
"enable_federation_help": "Bude možné sledovat tuto instanci z Fediverse",
"user_blocked": "Uživatel {user} zablokován",
"smtp_test_button": "Odeslat testovací email",
"event_remove_ok": "Událost odstraněna",
"trusted_instances_label_default": "Spřátelené instance",
"filter_instances": "Filtrovt instance",
"trusted_instances_label": "Štítek zobrazený u spřátelených instancí",
"hide_calendar": "Skrýt kalendář",
"allow_online_event": "Povolit online události",
"allow_geolocation": "Povolit přidávání souřadnic k událostem",
"colors": "Barvy",
"favicon": "Logo",
"geocoding_countrycodes_help": "Umožňuje filtrovat vyhledávání podle PSČ",
"geocoding_provider_help": "Defaultní poskytovatel je Nominatim",
"geocoding_provider": "Poskytovatel geokódování",
"default_images_help": "Musíš <a href='/admin?tab=theme'>obnovit</a> stránku pro zobrazení změn.",
"tilelayer_test_error": "Mapové podklady od {service_name} nejsou dostupné",
"geolocation": "Geolokace",
"event_confirm_description": "Zde můžeš schválit události přidané anonymně",
"tilelayer_test_success": "Mapové podklady od {service_name} jsou funkční",
"geocoding_test_button": "Vyzkoušet geokódování",
"created_at": "Vytvořeno",
"trusted_instances_label_help": "Defaultní štítek je \"Spřátelené instance\"",
"allow_anon_event": "Povolit vytváření anonymních událostí (ty musí být později potvrzeny)?",
"hide_resource": "Skrýt reakci",
"smtp_hostname": "SMTP Hostname",
"select_instance_timezone": "Časové pásmo",
"edit_collection": "Upravit sbírku",
"user_remove_ok": "Uživatel odebrán",
"tilelayer_provider_attribution": "Poděkování",
"user_block_confirm": "Určitě chceš zablokovat uživatele {user}?",
"delete_user": "Odebrat",
"admin_email_help": "Tato adresa bude použitá jako odesílatel e-mailů. Je to také adresa na kterou jsou odesílány zprávy pro admina",
"is_dark": "Tmavý motiv",
"delete_tag_confirm": "Určitě chceš smazat tag \"{tag}\"? Tag bude odstraněn z {0} událostí.",
"allow_registration_description": "Povolit registrace?",
"geolocation_description": "<b>1. Definujte poskytovatele služby geokódování</b>.<br>V současné době jsou z těch uvedených na <a href=\"https://wiki.openstreetmap.org/wiki/Nominatim#Alternatives_.2F_Third-party_providers\">wiki webu OpenStreetMap </a>, podporovány <a href=\"https://github.com/osm-search/Nominatim\">Nominatim</a> a <a href=\"https://github.com/komoot /photon\">Photon</a>.<br>Můžete použít jednu ze souvisejících oficiálních ukázek zkopírováním odkazu v poli 'Geocoding provider':<ul><li>https://nominatim.openstreetmap.org/search (<a href=\"https://operations.osmfoundation.org/policies/nominatim/\">Smluvní podmínky</a>)</li><li>https://photon.komoot.io/api/ (<a href=\"https://photon.komoot.io/\">Smluvní podmínky</a>)</li></ul><br><b>2. Nastavte poskytovatele mapových podkladů.</b><br>Jejich seznam naleznete zde: <a href=\"https://leaflet-extras.github.io/leaflet-providers/preview/\">https: //leaflet-extras.github.io/leaflet-providers/preview/</a>",
"enable_admin_user_confirm": "Určitě chceš dát admin práva {user}?",
"instance_name_help": "Účet pro sledování skrz ActivityPub",
"new_collection": "Nová sbírka",
"geocoding_provider_type": "Software pro geokódování",
"enable_resources_help": "Povolit přidávání reakcí k událostem z Fediverse",
"delete_collection_confirm": "Určitě chceš odstranit sbírku <u>{collection}</u>?",
"add_instance": "Přidat instanci",
"tilelayer_provider_help": "Defaultní posytovatel je OpenStreetMap",
"disable_admin_user_confirm": "Určitě chceš {user} odebrat práva admina?",
"show_smtp_setup": "Nastavení E-mailů",
"geocoding_test_success": "Geokódovací služba {service_name} je funkční",
"hide_boost_bookmark": "Skrýt boosty/záložky",
"filter_users": "Filtrovat uživatele",
"place_description": "Pokud máš adresu místa špatně zadanou, můžeš ji změnit.<br/>Adresa se změní i u všech současných i minulých událostí v tomto místě.",
"instance_place": "Přibližná lokalita této instance",
"add_trusted_instance": "Přidat spřátelenou instanci",
"geocoding_countrycodes": "PSČ",
"delete_resource": "Smazat reakci",
"enable_federation": "Povolit federování",
"wrong_domain_warning": "Adresa v config.json <b>({baseurl})</b> je jiná než ta na kterou se připojuješ <b>({url})</b>"
},
"common": {
"related": "Příbuzné",
"password_updated": "Heslo změněno.",
"follow": "Sledovat",
"hide": "Skrýt",
"embed_help": "Po vložení tohoto kódu do tvého webu bude událost zobrazena takto",
"recover_password": "Obnovit heslo",
"preview": "Náhled",
"media": "Média",
"start": "Spustit",
"email": "E-mail",
"tag": "Štítek",
"events": "Události",
"announcements": "Oznámení",
"edit": "Upravit",
"calendar": "Kalendář",
"plugins": "Doplňky",
"save": "Uložit",
"edit_event": "Upravit událost",
"remove_admin": "Odebrat admina",
"feed": "RSS Zdroj",
"add": "Přidat",
"export": "Export",
"authorize": "Autorizovat",
"feed_url_copied": "Otevři zkopírovaný odkaz ve své RSS čtečce",
"copy_link": "Kopírovat odkaz",
"activate": "Zapnout",
"address": "Adresa",
"user": "Uživatel",
"deactivate": "Vypnout",
"share": "Sdílet",
"add_to_calendar": "Přidat do kalendáře",
"embed": "Vložit na web",
"logout": "Odhlásit se",
"name": "Jméno",
"set_password": "Nastavit heslo",
"new_user": "Nový uživatel",
"moderation": "Moderace",
"latitude": "Latitude",
"ok": "Ok",
"description": "Popis",
"logout_ok": "Odhlášený",
"label": "Označení",
"show_map": "Zobrazit mapu",
"max_events": "N. maximum událostí",
"admin": "Admin",
"info": "Info",
"users": "Uživatelé",
"event": "Událost",
"instances": "Instance",
"admin_actions": "Administrátorské nástroje",
"password": "Heslo",
"me": "Ty",
"enable": "Povolit",
"copied": "Zkopírováno",
"tags": "Štítky",
"delete": "Odstranit",
"cancel": "Zrušit",
"resources": "Zdroje",
"recurring_event_actions": "Akce pravidelných událostí",
"login": "Login",
"about": "About",
"title": "Nadpis",
"search_coordinates": "Vyhledat souřadnice",
"filter": "Filtr",
"federation": "Federace",
"url": "URL",
"follow_me_title": "Sleduj novinky z Fediverse",
"copy": "Kopírovat",
"help_translate": "Pomoc s překladem",
"skip": "Přeskočit",
"places": "Místa",
"pause": "Pozastavit",
"embed_title": "Vložit tuto událost na web",
"collections": "Sbírky",
"displayname": "Zobrazované jméno",
"settings": "Nastavení",
"theme": "Téma",
"actions": "Akce",
"send": "Odeslat",
"import": "Import",
"confirm": "Potvrdit",
"send_via_mail": "Odeslat e-mail",
"home": "Domů",
"reset": "Reset",
"longitude": "Longitude",
"disable": "Zakázat",
"fediverse": "Fediverse",
"add_event": "Přidat událost",
"n_resources": "žádný zdroj|zdroj|{n} zdrojů",
"online": "On-line",
"new_password": "Nové heslo",
"when": "Kdy",
"register": "Registrovat se",
"content": "Obsah",
"activate_user": "Potvrzeno",
"place": "Lokace",
"search": "Vyhledat",
"show_preview": "Zobrazit náhled",
"next": "Další",
"where": "Kde",
"remove": "Odstranit",
"associate": "Propojit",
"what": "Co",
"test": "Test",
"close": "Zavřít"
},
"export": {
"email_description": "Můžeš dostávat události které tě zajímají na e-mail.",
"feed_description": "Chceš-li sledovat nové události z počítače nebo smartphonu bez nutnosti pravidelně chodit na tento web, použij RSS. </p>\n\n<p> S RSS můžeš použávat speciální aplikaci pro příjem novinek z webů, které tě zajímají. Je to dobrý způsob, jak rychle sledovat mnoho stránek, bez nutnosti vytvářet si na nich účet </p>\n\n<li> Pokud máš Android, doporučujeme <a href=\"https://f-droid.org/cs/packages/net.frju.flym/\">Flym</a> nebo Feeder </li>\n<li> Pro iPhone / iPad můžeš použít <a href=\"https://itunes.apple.com/ua/app/feeds4u/id1038456442442?mt=8\"> Feed4U </a> </li> </li>\n<li> Pro stolní / notebook doporučujeme Feedbro, dá se nainstalovat do <a href=\"https://addons.mozilla.org/cs-GB/firefox/addon/feedbroreader/\"> Firefoxu </a> nebo <a href=\"https://chrome.google.com/webstore/detail/feedbro/mefgmmbdailogpfhfblcnnjfmnmdfa\"> Chrome </a>. </li>\n<br/>\nPřidej si tento odkaz do své RSS čtečky a zůstaň v obraze.",
"intro": "Na rozdíl od asociálních platforem které dělají vše proto aby si udrželi uživatele a jejich data, my věříme že informace musí být svobodné, stejně jako lidí. Proto můžete získávat aktuality o událostech i bez nutnosti chodit na tuto stránku.",
"list_description": "Pokud máte vlastní webovou stránku a chcete sdílet seznam událostí, použijte tento kód",
"ical_description": "Počítače a telefony jsou obvykle vybaveny aplikací kalendáře která umožňuje připojení vzdáleného kalendáře.",
"insert_your_address": "Vlož svoji e-mailovou adresu"
},
"event": {
"added_anon": "Událost přidána, ještě ale musí být schválena.",
"image_too_big": "Obrázek nesmí být větší než 4MB",
"where_advanced_options": "Místo - Pokročilé možnosti",
"import_description": "Můžete importovat události z jiných platforem pomocí standartních formátů (ics a h-event)",
"online_locations_fallback_urls": "Záložní odkazy",
"address_description": "Jaká je adresa?",
"anon": "Anonym",
"interact_with_me_at": "Interaguj se mnou ve Fediverse na",
"choose_focal_point": "Vyber střed náhledu",
"follow_me_description": "Jeden ze způsobů, jak zůstat v obraze o událostech zveřejněných zde na {title},\nje sledovat účet <u>{account}</u> ve fediverse, například přes Mastodon, a odtamtud případně reagovat na události.<br/><br/>\nPokud jsi nikdy neslyšel*a o Mastodonu a fediverse, doporučujeme přečíst si <a href='https://www.savjee.be/videos/simply-explained/mastodon-and-fediverse-explained/'>tento článek</a> .<br/><br/>Níže zadejte svou instanci (např. mastodon.social)",
"import_ICS": "Importovat z ICS",
"interact_with_me": "Sledovat",
"show_recurrent": "pravidelné události",
"confirmed": "Událost potvrzena",
"show_multidate": "vícedenní události",
"normal_description": "Vybrat den.",
"from": "Od",
"updated": "Událost aktualizována",
"show_past": "také předchozí události",
"download_flyer": "Stáhnout leták",
"ics": "ICS",
"not_found": "Událost nenalezena",
"added": "Událost přidána",
"recurrent_2m_days": "Vždy {days} každý druhý měsíc",
"multidate_description": "Jde o festival? Vyber kdy začíná a končí",
"where_advanced_options_description": "Zde můžete nastavit další parametry místa",
"online_locations": "Online místa",
"online_locations_help": "Například adresa videokonferenční místosti, nebo záložní adresa (maximálně 3)",
"edit_recurrent": "Upravit pravidelnou událost:",
"recurrent_2w_days": "Každý druhý: {days}",
"each_2w": "Každý druhý týden",
"media_description": "Můžeš přidat leták (volitelně)",
"due": "do",
"address_geocoded_disclaimer": "Pokud ve výsledcích geokódování nemůžete najít <strong>adresu ulice</strong> nebo <strong>číslo domu</strong>, které hledáte, můžete je ručně vložit do pole 'Adresa', aniž byste ztratili souřadnice. Nezapomeňte také, že projekt <a target=\"_blank\" href=\"https://www.openstreetmap.org/\">OpenStreetMap</a> je otevřen úpravám. Pokud máte Android, doporučujeme aplikaci <a target=\"_blank\" href=\"https://f-droid.org/en/packages/de.westnordost.streetcomplete/\">StreetComplete</a> ",
"alt_text_description": "Popis pro lidi s poruchami zraku",
"recurrent_1m_ordinal": "Každý {n} {days} of the month",
"normal": "Normální",
"recurrent_2m_ordinal": "Každý {n} {days} každý druhý měsíc",
"anon_description": "Můžeš přidat událost bez registrace i přihlášení, budeš ale muset počkat než si ji někdo přečte,\na posoudí její schválení. Pak už nebude možné ji upravova.<br/><br/>\nMůžeš se ale taky <a href='/login'>přihlásit</a> či <a href='/register'>zaregistrovat</a>. Jinak můžeš pokračovat a my se pokusíme odpovědět co nejdřív. ",
"recurrent_1w_days": "Každý {days}",
"recurrent_1m_days": "Vždy {days} v měsící",
"each_week": "Každý týden",
"what_description": "Nadpis",
"only_future": "pouze budoucí události",
"multidate": "Více dní",
"description_description": "Popis",
"recurrent": "Pravidelné",
"remove_recurrent_confirmation": "Přejete si odstranit tuto pravidelnou událost?\nMinulé události budou zachovány, nebudou ale vytvořeny žádné budoucí.",
"where_description": "Kde se událost nachází? Pokud místo ještě neexistuje, můžeš ho vytvořit.",
"address_description_osm": "Vyhledat souřadnice podle adresy (díky <a href='http://osm.org/copyright'>OpenStreetMap</a>)",
"same_day": "ve stejný den",
"recurrent_description": "Vybrat frekvenci a dny",
"import_URL": "Importovat z URL",
"remove_media_confirmation": "Chceš opravdu odstranit obrázek?",
"each_month": "Každý měsíc",
"remove_confirmation": "Určitě chceš odstranit tuto událost?",
"tag_description": "Tag",
"saved": "Událost uložena"
},
"validators": {
"latitude": "Vlož platnou zeměpisnou šířku (-90 < šířka < 90)",
"email": "Vlož platný e-mail",
"longitude": "Vlož platnou zeměpisnou délku (-180 < délka < 180)",
"required": "{fieldName} je nutné vyplnit"
},
"login": {
"insert_email": "Vlož svou e-mailovou adresu",
"not_registered": "Nemáš registraci?",
"description": "Po přihlášení můžeš přidávat nové události.",
"ok": "Přihlášení úspěšné",
"forgot_password": "Zapomenuté heslo?",
"check_email": "Zkontroluj svůj e-mail a spam.",
"error": "Přihlášení se nezdařilo. Zkontroluj údaje."
},
"ordinal": {
"-1": "poslední",
"5": "pátý",
"1": "první",
"2": "druhý",
"3": "třetí",
"4": "čtvrtý"
},
"error": {
"email_taken": "Tento email je již používán.",
"nick_taken": "Tato přezdívka je již používána."
},
"settings": {
"password_updated": "Heslo změněno.",
"remove_account": "Kliknutím na tlačítko bude tvůj účet odstraněn. Vytvořené události budou zachovány.",
"update_confirm": "Chceš uložit změny?",
"danger_section": "Nebezpečná sekce",
"change_password": "Změnit heslo",
"remove_account_confirm": "Tímto permanentně smažeš svůj účet"
},
"confirm": {
"valid": "Tvůj účet je potvrzený, nyní se můžeš <a href=\"/login\">přihlásit</a>",
"title": "Ověření uživatele",
"not_valid": "Něco se pokazilo."
},
"oauth": {
"scopes": {
"event:write": "Přidat a upravovat události"
},
"authorization_request": "Aplikace <code>{app}</code> žádá o následující oprávnění na <code>{instance_name}</code>:",
"redirected_to": "Po potvrzení dojde k přesměrování na <code>{url}</code>"
},
"recover": {
"not_valid_code": "Něco se pokazilo."
},
"setup": {
"start": "Začít",
"completed_description": "<p>Nyní se můžeš přihlásit jako tento uživatel:<br/><br/>Uživatel: <b>{email}</b><br/>Heslo: <b>{password}<b/></p>",
"copy_password_dialog": "Ano, opravdu je pořeba okopírovat si heslo!",
"https_warning": "Přístupuješ na web skrz HTTP, nezapomeň změnit baseurl v config.json pokud budeš nastavovat HTTPS!",
"completed": "Nastavení dokončeno"
},
"register": {
"error": "Chyba: ",
"description": "Sociální hnutí by se měla organizovat a samofinancovat.<br/>\n<br/>Než budeš moci zveřejňovat události, <strong> musí být tvůj účet schválen</strong>, měj na paměti, že <strong>za tímto webem najdeš skutečné lidi</strong>, takže nám prosím napiš dva řádky, abyste věděli, jaké události budeš chtít zveřejňovat.",
"complete": "Registrace byla potvrzena.",
"first_user": "Admin vytvořen"
},
"auth": {
"fail": "Přihlášení se nezdařilo. Máš určitě správné heslo?",
"not_confirmed": "Zatím nepotvrzeno…"
},
"about": "\n <p><a href='https://gancio.org'>Gancio</a> je sdílená nástěnka pro místní komunity.</p>\n "
}

View file

@ -65,7 +65,7 @@
"add_event": "Veranstaltung hinzufügen",
"import": "Importieren",
"reset": "Zurücksetzen",
"tags": "Markierung",
"tags": "Stichworte",
"place": "Ort",
"url": "URL",
"announcements": "Ankündigungen",
@ -99,8 +99,14 @@
"plugins": "Plugins",
"help_translate": "Hilf beim Übersetzen mit",
"content": "Inhalt",
"admin_actions": "Aktionen der Administrierenden",
"recurring_event_actions": "Einstellungen für regelmäßige Veranstaltungen"
"admin_actions": "Admin-Aktionen",
"recurring_event_actions": "Einstellungen für regelmäßige Veranstaltungen",
"clone": "Klon",
"tag": "Stichwort",
"search_coordinates": "Suche Koordinaten",
"online": "On-line",
"show_preview": "Vorschau anzeigen",
"test": "Test"
},
"admin": {
"delete_footer_link_confirm": "Möchtest du diesen Link löschen?",
@ -111,7 +117,7 @@
"new_announcement": "Neue Ankündigung",
"edit_place": "Ort bearbeiten",
"enable_resources": "Ressourcen freischalten",
"hide_boost_bookmark_help": "Versteckt die kleinen Icons, die die Anzahl der eingehenden Boosts und Lesezeichen aus dem Fediverse anzeigen",
"hide_boost_bookmark_help": "Blendet die kleinen Bilder aus, die die Anzahl der eingehenden Boosts und Lesezeichen aus dem Fediverse anzeigen",
"user_add_help": "Es wird eine E-Mail an die neue nutzende Person mit einem Hinweis auf die Bestätigung der Registrierung und die Wahl eines Passworts gesendet",
"block_user": "nutzende Person sperren",
"filter_instances": "Instanzen filtern",
@ -132,7 +138,7 @@
"wrong_domain_warning": "Die \"baseurl\" die in config.json konfiguriert ist <b>({baseurl})</b> unterscheidet sich von derjenigen <b>({url})</b> die du besuchst",
"instance_place_help": "Diese Textzeile wird im Menü der anderen befreundeten Instanzen angezeigt",
"place_description": "Falls ein Ort falsch ist oder sich die Adresse ändert, kannst du ihn ändern.<br/>Bitte beachte, dass alle Veranstaltungen, die mit diesem Ort verbunden sind, die Adresse ändern (auch zurückliegende).",
"enable_admin_user_confirm": "Bist du dir sicher, dass du der nutzenden Person {user} Admin-Rechte gewährst?",
"enable_admin_user_confirm": "Bist du dir sicher, dass du {user} Admin-Rechte zuordnen möchtest?",
"trusted_instances_help": "Befreundete Instanzen werden in der Navigationsleiste oben auf der Seite angezeigt",
"trusted_instances_label": "Navigationsbezeichnung zu Friend-Instanzen",
"trusted_instances_label_default": "Freundliche Instanzen",
@ -188,9 +194,9 @@
"config_plugin": "Plugin Konfiguration",
"hide_thumbs": "Vorschaubilder ausblenden",
"hide_calendar": "Kalender verstecken",
"admin_email_help": "Die Adresse, die wir als Absender für den Versand von E-Mails verwenden. Sie ist auch die Adresse, an die deine E-Mails an die Administrator:innen geschickt werden.",
"admin_email_help": "Die Adresse, die wir als Absender für den Versand von E-Mails verwenden. Sie ist auch die Adresse, an die deine Admin-E-Mails geschickt werden",
"blocked": "Geblockt",
"domain": "Domain",
"domain": "Internetadresse",
"known_users": "Bekannte Nutzer:innen",
"created_at": "Erstellt am",
"geocoding_provider_type": "Software für Georeferenzierung",
@ -201,18 +207,22 @@
"geocoding_countrycodes_help": "Ermöglicht die Einrichtung eines Filters für die Suche auf der Grundlage von Ländercodes",
"geocoding_test_button": "Geokodierung testen",
"geocoding_test_success": "Der Geokodierdienst unter {service_name} funktioniert",
"geocoding_test_error": "Der Dienst ist unter der angegebenen Adresse nicht zu erreichen: {service_name}",
"geocoding_test_error": "Der Geokodierungs-Dienst ist unter der angegebenen Adresse nicht erreichbar: {service_name}",
"tilelayer_provider": "Kachel-LayerAnbieter",
"tilelayer_provider_help": "Der Standard-Anbieter ist OpenStreetMap",
"tilelayer_provider_attribution": "Namensnennung",
"tilelayer_test_button": "Kachel-Layer testen",
"tilelayer_test_success": "Der Kachel-Layer-Dienst unter {service_name} funktioniert",
"tilelayer_test_error": "Der Dienst ist unter der angegebenen Adresse nicht zu erreichen: {service_name}",
"tilelayer_test_error": "Der Tilelayer-Dienst {service_name} ist nicht erreichbar",
"geolocation": "Geolokation",
"allow_multidate_event": "Lasse mehrtägige Veranstaltungen zu",
"admin_email": "E-Mail von der administrierenden Person",
"geolocation_description": "<b>1. Bestimme einen Anbieter für einen Geokodierdienst</b>.<br>Derzeit gibt es unter den im <a href=\"https://wiki.openstreetmap.org/wiki/Nominatim#Alternatives_.2F_Third-party_providers\">Wiki von OpenStreetMap</a>, Anbietern Unterstützung für die Software <a href=\"https://github.com/osm-search/Nominatim\">Nominatim</a> und <a href=\"https://github.com/komoot/photon\">Photon</a>.<br>Du kannst eine der entsprechenden offiziellen Demos verwenden, indem du den Link in das Feld \"Geocoding provider\" kopierst:<ul><li>https://nominatim.openstreetmap.org/search (<a href=\"https://operations.osmfoundation.org/policies/nominatim/\">Terms of Service</a>)</li><li>https://photon.komoot.io/api/ (<a href=\"https://photon.komoot.io/\">Terms of Service</a>)</li></ul><br><b>2. Definiere einen Anbieter für Kartenebenen.</b><br>Eine Liste von ihnen findest du hier: <a href=\"https://leaflet-extras.github.io/leaflet-providers/preview/\">https://leaflet-extras.github.io/leaflet-providers/preview/</a>",
"default_images_help": "Du musst <a href='/admin?tab=theme'>die Seite neu laden</a>, um die Änderungen sehen zu können."
"default_images_help": "Du musst <a href='/admin?tab=theme'>die Seite neu laden</a>, um die Änderungen sehen zu können.",
"edit_tag": "Stichwort bearbeiten",
"allow_online_event_hint": "Nach Internetadressen fragen ",
"allow_online_event": "Erlaube Online-Veranstaltungen",
"colors": "Farben"
},
"settings": {
"update_confirm": "Willst du deine Änderung speichern?",
@ -237,7 +247,9 @@
},
"validators": {
"required": "{fieldName} ist erforderlich",
"email": "Füge eine gültige E-Mail ein"
"email": "Füge eine gültige E-Mail ein",
"latitude": "Gib einen gültigen Breitengrad ein (-90 < Breitengrad < 90)",
"longitude": "Gib einen gültigen Längengrad ein (-180 < Längengrad < 180)"
},
"ordinal": {
"-1": "letzte",
@ -255,7 +267,7 @@
"authorization_request": "Die Anwendung <code>{app}</code> verlangt die Berechtigung die folgenden Aktionen auf <code>{instance_name}</code> ausüben zu können:"
},
"event": {
"tag_description": "Markierung",
"tag_description": "Stichwort",
"description_description": "Beschreibung",
"what_description": "Titel",
"same_day": "am selben Tag",
@ -274,14 +286,14 @@
"each_2w": "Jede zweite Woche",
"ics": "ICS",
"remove_recurrent_confirmation": "Bist du dir sicher, dass du diese wiederkehrende Veranstaltung entfernen möchtest?\nFrühere Veranstaltungen werden beibehalten, aber es werden keine zukünftigen Veranstaltungen mehr hinzugefügt.",
"anon_description": "Du kannst eine Veranstaltung hinzufügen, ohne dich zu registrieren oder anzumelden,\nmusst dann aber warten, bis jemand es liest und bestätigt, dass es eine zulässige Veranstaltung ist.\nEs ist nicht möglich, den Eintrag zu verändern.<br/><br/>\nDu kannst dich stattdessen <a href='/login'>anmelden</a> oder <a href='/register'>registrieren</a>. In diesem Fall solltest du so schnell wie möglich eine Antwort erhalten. ",
"anon_description": "Es ist möglich, eine Veranstaltung hinzufügen, ohne vorherige Registrierung oder Anmeldung. Die Veranstaltung wartet, bis sie von einer Person bestätigt wird.\nEs ist nicht möglich, den Eintrag nachträglich zu verändern.<br/><br/>\nDu kannst dich stattdessen <a href='/login'>anmelden</a> oder <a href='/register'>registrieren</a>. Falls nicht, fahre fort. Wir schalten Deine Veranstaltung frei, sobald es uns möglich ist. ",
"where_description": "Wo ist die Veranstaltung? Wenn der Ort noch nicht beschrieben wurde, kannst du ihn selbst eintragen.",
"coordinates_search": "Suche nach Koordinaten",
"coordinates_search_description": "Sie können den Ort anhand des Namens suchen oder das Koordinatenpaar einfügen.",
"follow_me_description": "Eine Möglichkeit, über die hier auf {title} veröffentlichten Veranstaltungen auf dem Laufenden zu bleiben, besteht darin, dem Account <u>{account}</u> aus dem Fediverse zu folgen, zum Beispiel über Mastodon, und von dort aus eventuell Ressourcen für eine Veranstaltung hinzuzufügen.<br/><br/>\nWenn Du noch nie von Mastodon und dem Fediverse gehört hast, empfehlen wir dir, diesen Artikel <a href='https://www.savjee.be/videos/simply-explained/mastodon-and-fediverse-explained/'> zu lesen</a>.<br/><br/>Gib unten deine Instanz ein (z.B. mastodon.social)",
"follow_me_description": "Eine Möglichkeit, über die hier auf {title} veröffentlichten Veranstaltungen auf dem Laufenden zu bleiben,\nbesteht darin, dem Account <u>{account}</u> aus dem Fediverse zu folgen, zum Beispiel über Mastodon, und von dort aus eventuell Ressourcen für eine Veranstaltung hinzuzufügen.<br/><br/>\nWenn Du noch nie von Mastodon und dem Fediverse gehört hast, empfehlen wir dir, diesen Artikel <a href='https://www.savjee.be/videos/simply-explained/mastodon-and-fediverse-explained/'> zu lesen</a>.<br/><br/>Gib unten deine Instanz ein (z.B. mastodon.social)",
"media_description": "Du kannst (optional) einen Flyer hinzufügen",
"edit_recurrent": "Bearbeite eine sich wiederholende Veranstaltung :",
"show_recurrent": "wiederkehrende Termine",
"show_recurrent": "wiederkehrende Veranstaltungen",
"show_past": "auch ältere Veranstaltungen",
"only_future": "nur zukünftige Veranstaltungen",
"recurrent_description": "Wähle die Häufigkeit und Tage aus",
@ -292,10 +304,10 @@
"recurrent_1w_days": "Jeden {days}",
"recurrent_2w_days": "Jeden zweiten {days} eine",
"recurrent_1m_days": "Der {days} in jedem Monat",
"recurrent_2m_days": "Der {days} jeden zweiten Monat",
"recurrent_1m_ordinal": "Jeden {n} {days} im Monat",
"recurrent_2m_days": "{days}, jeden zweiten Monat",
"recurrent_1m_ordinal": "Alle {n} {days}, im Monat",
"each_week": "Jede Woche",
"recurrent_2m_ordinal": "Der {n} {days} jeden zweiten Monat",
"recurrent_2m_ordinal": "Alle {n} {days}, jeden zweiten Monat",
"each_month": "Jeden Monat",
"due": "bis",
"from": "von",
@ -307,7 +319,13 @@
"alt_text_description": "Beschreibung für Menschen mit Sehbehinderungen",
"choose_focal_point": "Auswahl des Schwerpunkts",
"address_description": "Was ist die Adresse?",
"address_description_osm": "Wo ist die Adresse? (<a href='http://osm.org/copyright'>OpenStreetMap</a> contributors)"
"address_description_osm": "Koordinaten ermitteln, indem du nach einer Adresse suchst. (<a href='http://osm.org/copyright'>OpenStreetMap</a>-Mitwirkende)",
"where_advanced_options": "Ort Erweiterte Angaben",
"online_locations_fallback_urls": "Alternativadressen",
"show_multidate": "Veranstaltungen mit mehreren Terminen",
"where_advanced_options_description": "Gib hier zusätzliche Angaben zum Ort an",
"online_locations": "Orte online",
"online_locations_help": "Etwa eine Internetadresse eines Videokonferenzraums und eine Alternativadresse (maximal 3)"
},
"register": {
"first_user": "Admin erstellt",
@ -320,7 +338,7 @@
"ical_description": "Computer und Smartphones sind üblicherweise mit einer Kalenderanwendung ausgestattet, mit der ein Fernkalender importiert werden kann.",
"insert_your_address": "Gib deine E-Mail-Adresse ein",
"email_description": "Du kannst interessante Veranstaltungen per E-Mail erhalten.",
"feed_description": "Um Updates auf deinem Computer oder Smartphone zu erhalten, ohne regelmäßig diese Seite zu öffnen, kannst du RSS-Feeds benutzen. </p>\n\n<p> Mit RSS-Feeds nutzt du eine spezielle App, um Updates von den Seiten, die dich interessieren, zu erhalten. Damit kannst du rasch vielen Seiten folgen, ohne einen\nAccount erstellen zu müssen und ohne sonstige Komplikationen. </p>\n\n<li> Für Android-Geräte empfehlen wir <a href=\"https://f-droid.org/en/packages/net.frju.flym/\">Flym</a> oder Feeder </li>\n<li> Auf iPhones / iPads kannst du <a href=\"https://itunes.apple.com/ua/app/feeds4u/id1038456442?mt=8\"> Feed4U </a> nutzen</li>\n<li> Auf Desktop-PCs oder Laptops empfehlen wir Feedbro, den du in <a href=\"https://addons.mozilla.org/en-GB/firefox/addon/feedbroreader/\"> Firefox </a> oder <a \nref=\"https://chrome.google.com/webstore/detail/feedbro/mefgmmbdailogpfhfblcnnjfmnpnmdfa\"> Chrome </a> installieren kannst. </li>\n<br/>\nIndem du diesen Link deinem RSS-Feed-Reader hinzufügst, wirst du auf dem Laufenden gehalten.",
"feed_description": "Um Aktualisierungen auf deinem Computer oder Smartphone zu erhalten, ohne regelmäßig diese Seite zu öffnen, kannst du RSS-Feeds benutzen. </p>\n\n<p> Mit RSS-Feeds nutzt du eine spezielle App, um Aktualisierungen von den Seiten, die dich interessieren, zu erhalten. Damit kannst du viele Seiten überblicken, ohne ein Benutzerkonto erstellen zu müssen oder sonstige Komplikationen. </p>\n\n\n<li> Für Android-Geräte empfehlen wir <a href=\"https://f-droid.org/en/packages/net.frju.flym/\">Flym</a> oder Feeder </li>\n<li> Auf iPhones / iPads kannst du <a href=\"https://itunes.apple.com/ua/app/feeds4u/id1038456442?mt=8\"> Feed4U </a> nutzen</li>\n<li> Auf Desktop-PCs oder Laptops empfehlen wir Feedbro, den du in <a href=\"https://addons.mozilla.org/en-GB/firefox/addon/feedbroreader/\"> Firefox </a> oder <a \nref=\"https://chrome.google.com/webstore/detail/feedbro/mefgmmbdailogpfhfblcnnjfmnpnmdfa\"> Chrome </a> installieren kannst. </li>\n<br/>\nFügst du diesen Link dem RSS-Feed-Reader hinzu, wird dieser dich auf dem Laufenden halten.",
"intro": "Anders als unsoziale Netzwerke, die alles unternehmen, um nutzende Personen und deren Daten bei sich zu (be)halten, glauben wir, dass Informationen und Menschen gleichermaßen frei sein müssen. Deshalb kannst du dich über Veranstaltungen aktuell informieren, ohne zwangsläufig über diese Seite zu gehen."
},
"recover": {
@ -329,7 +347,7 @@
"login": {
"ok": "Angemeldet",
"insert_email": "Gib deine E-Mail-Adresse ein",
"error": "Anmeldung nicht möglich. Bitte überprüfe deine Informationen zur Anmeldung.",
"error": "Anmeldung nicht möglich. Bitte überprüfe die Anmelde-Informationen.",
"forgot_password": "Passwort vergessen?",
"not_registered": "Nicht registriert?",
"check_email": "Überprüfe deinen E-Mail-Posteingang und Spam.",

29
locales/email/cs.json Normal file
View file

@ -0,0 +1,29 @@
{
"register": {
"content": "Přijali jsme žádost o registraci, potvrdíme ji co nejdříve.",
"subject": "Žádost o registraci byla přijata"
},
"user_confirm": {
"content": "Ahoj, tvůj účet na <a href='{{config.baseurl}}'>{{config.title}}</a> byl vytvořený. <a href='{{config.baseurl}}/user_confirm/{{user.recover_code}}'>Potvrď ho a nastav si heslo.</a>.",
"subject": "Nyní můžeš začít zveřejňovat události"
},
"event_confirm": {
"content": "Tuto událost můžeš potvrdit na <a href='{{url}}'>této stránce </a>"
},
"admin_register": {
"subject": "Nová registrace",
"content": "{{user.email}} požádal o registraci na {{config.title}}: <br/><pre>{{user.description}}</pre><br/> Potvrď ji <a href='{{config.baseurl}}/admin'>zde</a>."
},
"confirm": {
"subject": "Teď můžete začít zveřejňovat události",
"content": "Ahoj, tvůj účet na <a href='{{config.baseurl}}'>{{config.title}}</a> byl schválený. Napiš nám na {{config.admin_email}} pokud potřebuješ další informace."
},
"recover": {
"subject": "Obnova hesla",
"content": "Ahoj, požádali jste o změnu hesla na {{config.title}}. <a href='{{config.baseurl}}/recover/{{user.recover_code}}'>Klikni zde</a> pro potvrzení."
},
"test": {
"content": "Toto je testovací email, nastavení je funkční.",
"subject": "Nastavení SMTP je funkční"
}
}

View file

@ -24,6 +24,6 @@
},
"test": {
"content": "Dieses ist eine Test-E-Mail. Wenn du das hier lesen kannst, dann funktioniert deine Konfiguration richtig.",
"subject": "Deine SMTP Konfiguration funktioniert"
"subject": "Deine SMTP-Konfiguration funktioniert"
}
}

29
locales/email/pt-BR.json Normal file
View file

@ -0,0 +1,29 @@
{
"register": {
"subject": "Pedido de registo recebido",
"content": "Recebemos o pedido de registo. Vamos confirmar assim que possível."
},
"confirm": {
"content": "Olá, sua conta em <a href='{{config.baseurl}}'>{{config.title}}</a> foi confirmada. Escreva para {{config.admin_email}} para obter qualquer informação.",
"subject": "Você pode agora começar a publicar eventos"
},
"event_confirm": {
"content": "Pode confirmar este evento <a href='{{url}}'>nesta página</a>"
},
"test": {
"subject": "A sua configuração SMTP funciona",
"content": "Este é um e-mail de teste, se estiver a ler isto, a sua configuração funciona."
},
"user_confirm": {
"subject": "Você pode agora começar a publicar eventos",
"content": "Olá, a sua conta em <a href='{{config.baseurl}}'>{{config.title}}</a> foi criada. <a href='{{config.baseurl}}/user_confirm/{{user.recover_code}}'>Confirme e escolha uma palavra-passe.</a>."
},
"admin_register": {
"subject": "Novo registo",
"content": "{{user.email}} pediu o registo em {{config.title}}: <br/><pre>{{user.description}}</pre><br/> Confirme <a href='{{config.baseurl}}/admin'>aqui</a>."
},
"recover": {
"subject": "Recuperação da palavra-passe",
"content": "Olá, solicitou a recuperação da sua palavra-passe em {{config.title}}. <a href='{{config.baseurl}}/recover/{{user.recover_code}}'>Clique aqui</a> para confirmar."
}
}

1
locales/email/pt-PT.json Normal file
View file

@ -0,0 +1 @@
{}

View file

@ -8,22 +8,22 @@
"subject": "Você pode agora começar a publicar eventos"
},
"event_confirm": {
"content": "Você pode confirmar este evento <a href='{{url}}'>nesta página</a>"
"content": "Pode confirmar este evento <a href='{{url}}'>nesta página</a>"
},
"test": {
"subject": "Sua configuração SMTP está funcionando",
"content": "Este é um e-mail de teste, se estiver lendo isto, sua configuração está funcionando."
"subject": "A sua configuração SMTP funciona",
"content": "Este é um e-mail de teste, se estiver a ler isto, a sua configuração funciona."
},
"user_confirm": {
"subject": "Você pode agora começar a publicar eventos",
"content": "Olá, sua conta em <a href='{{config.baseurl}}'>{{config.title}}</a> foi criada. <a href='{{config.baseurl}}/user_confirm/{{user.recover_code}}'>Confirme e escolha uma senha.</a>."
"content": "Olá, a sua conta em <a href='{{config.baseurl}}'>{{config.title}}</a> foi criada. <a href='{{config.baseurl}}/user_confirm/{{user.recover_code}}'>Confirme e escolha uma palavra-passe.</a>."
},
"admin_register": {
"subject": "Novo registro",
"content": "{{user.email}} pediu o registro em {{config.title}}: <br/><pre>{{user.description}}</pre><br/> Confirme <a href='{{config.baseurl}}/admin'>aqui</a>."
"subject": "Novo registo",
"content": "{{user.email}} pediu o registo em {{config.title}}: <br/><pre>{{user.description}}</pre><br/> Confirme <a href='{{config.baseurl}}/admin'>aqui</a>."
},
"recover": {
"subject": "Recuperação de senha",
"content": "Olá, você solicitou a recuperação de sua senha em {{config.title}}. <a href='{{config.baseurl}}/recover/{{user.recover_code}}'>Clique aqui</a> para confirmar."
"subject": "Recuperação da palavra-passe",
"content": "Olá, solicitou a recuperação da sua palavra-passe em {{config.title}}. <a href='{{config.baseurl}}/recover/{{user.recover_code}}'>Clique aqui</a> para confirmar."
}
}

View file

@ -104,7 +104,8 @@
"search_coordinates": "Search coordinates",
"online": "On-line",
"test": "Test",
"show_preview": "Show preview"
"show_preview": "Show preview",
"clone": "Clone"
},
"login": {
"description": "By logging in you can publish new events.",
@ -124,7 +125,8 @@
"insert_your_address": "Enter your e-mail address",
"feed_description": "To follow updates from a computer or smartphone without the need to periodically open this site, use RSS feeds. </p>\n\n<p> With RSS feeds you use a special app to receive updates from sites that interest you. It's a good way to follow many sites quickly, without the need to create an account or other complications. </p>\n\n<li> If you have Android, we recommend <a href=\"https://f-droid.org/en/packages/net.frju.flym/\">Flym</a> or Feeder </li>\n<li> For iPhone / iPad you can use <a href=\"https://itunes.apple.com/ua/app/feeds4u/id1038456442?mt=8\"> Feed4U </a> </li>\n<li> For desktop / laptop we recommend Feedbro, to be installed on <a href=\"https://addons.mozilla.org/en-GB/firefox/addon/feedbroreader/\"> Firefox </a> or <a href=\"https://chrome.google.com/webstore/detail/feedbro/mefgmmbdailogpfhfblcnnjfmnpnmdfa\"> Chrome </a>. </li>\n<br/>\nAdding this link to your RSS feed reader will keep you up to date.",
"ical_description": "Computers and smartphones are commonly equipped with a calendar app capable of importing a remote calendar.",
"list_description": "If you have a website and want to show a list of events, use the following code"
"list_description": "If you have a website and want to show a list of events, use the following code",
"filter_description": "You can filter your export here by tags and place or by a preset collection"
},
"register": {
"description": "Social movements should organize and self-finance.<br/>\n<br/>Before you can publish, <strong> the account must be approved</strong>, consider that <strong> behind this site you will find real people</strong>, so write two lines to let us know what events you would like to publish.",
@ -344,7 +346,7 @@
"required": "{fieldName} is required",
"email": "Insert a valid email",
"latitude": "Insert a valid latitude (-90 < latitude < 90)",
"longitude": "Insert a valid latitude (-180 < latitude < 180)"
"longitude": "Insert a valid longitude (-180 < longitude < 180)"
},
"about": "\n <p><a href='https://gancio.org'>Gancio</a> is a shared agenda for local communities.</p>\n ",
"oauth": {

View file

@ -106,7 +106,8 @@
"search_coordinates": "Buscar las coordenadas",
"online": "En línea",
"test": "Prueba",
"show_preview": "Mostrar una vista previa"
"show_preview": "Mostrar una vista previa",
"clone": "Clon"
},
"login": {
"description": "Entrando podrás publicar nuevos eventos.",
@ -356,7 +357,7 @@
"validators": {
"email": "Introduce un correo electrónico valido",
"required": "{fieldName} es requerido",
"longitude": "Introduce una latitud válida (-180 < latitud < 180)",
"longitude": "Introduce una longitud válida (-180 < longitud < 180)",
"latitude": "Introduce una latitud válida (-90 < latitud < 90)"
},
"setup": {

View file

@ -1,7 +1,7 @@
{
"common": {
"add_event": "Sortu ekitaldia",
"next": "Jarraitu",
"next": "Hurrengoa",
"export": "Esportatu",
"send": "Bidali",
"where": "Non",
@ -81,7 +81,7 @@
"announcements": "Iragarpenak",
"url": "URLa",
"place": "Lekua",
"label": "Izena",
"label": "Etiketa",
"max_events": "Gehienezko ekitaldi kopurua",
"import": "Inportatu",
"reset": "Berrezarri",
@ -99,7 +99,14 @@
"recurring_event_actions": "Ekitaldi errepikarien eragiketak",
"content": "Edukia",
"admin_actions": "Administratzaile eragiketak",
"tag": "Etiketa"
"tag": "Etiketa",
"latitude": "Latitudea",
"longitude": "Longitudea",
"search_coordinates": "Bilbatu koordenatuak",
"online": "Online",
"test": "Proba",
"show_preview": "Erakutsi aurrebista",
"clone": "Klonatu"
},
"login": {
"description": "Saioa hasten baduzu ekitaldi berriak sortu ahal izango dituzu.",
@ -181,7 +188,10 @@
"address_description_osm": "Bilatu koordenatuak helbidea idatziz. (<a href='http://osm.org/copyright'>OpenStreetMap</a> kolaboratzaileak)",
"show_multidate": "data anitzeko ekitaldiak",
"where_advanced_options": "Lekua - Aukera aurreratuak",
"where_advanced_options_description": "Zehaztu hemen lekuaren ezaugarri gehigarriak"
"where_advanced_options_description": "Zehaztu hemen lekuaren ezaugarri gehigarriak",
"online_locations_help": "Esaterako bideokonferentzia baten URLa eta URL alternatiboa (gehienez 3)",
"online_locations": "Online kokapenak",
"online_locations_fallback_urls": "Esteka alternatiboak"
},
"admin": {
"place_description": "Lekua edo helbidea oker badago, alda dezakezu.<br/>Leku honekin lotutako iraganeko eta etorkizuneko ekitaldien helbidea aldatuko da.",
@ -297,7 +307,10 @@
"geocoding_test_success": "Geokodeketa zerbitzua {service_name}-(e)n martxan dago",
"tilelayer_test_success": "Lauza-geruzen zerbitzua {service_name}(e)n martxan dago",
"colors": "Koloreak",
"edit_tag": "Editatu etiketa"
"edit_tag": "Editatu etiketa",
"allow_online_event_hint": "URLak eskatu ",
"allow_online_event": "Online ekitaldiak ahalbidetu",
"delete_tag_confirm": "Ziur al zaude \"{tag}\" etiketa ezabatu nahi duzula? Etiketa {n} ekitalditik ezabatuko da."
},
"auth": {
"not_confirmed": "Oraindik baieztatu gabe dago…",
@ -338,7 +351,9 @@
},
"validators": {
"email": "Sartu baliozko eposta bat",
"required": "{fieldName} beharrezkoa da"
"required": "{fieldName} beharrezkoa da",
"latitude": "Sartu baliozko latitude bat (-90 < latitudea < 90)",
"longitude": "Sartu baliozko longitudea bat (-180 < longitudea < 180)"
},
"setup": {
"start": "Hasi",

View file

@ -102,12 +102,17 @@
"tag": "Tag",
"admin_actions": "Admin actions",
"recurring_event_actions": "Evènement Récurrent action",
"content": "Contenu"
"content": "Contenu",
"online": "En ligne",
"search_coordinates": "Rechercher les coordonnées",
"test": "Tester",
"show_preview": "Afficher l'aperçu",
"clone": "Cloner"
},
"event": {
"follow_me_description": "Une des manières de rester informé sur les évènements publiés ici sur {title}\nest de suivre le compte <u>{account}</u> sur le fediverse, par exemple via Mastodon, et pourquoi pas d'ajouter des ressources à un évènement à partir de là.<br/><br/>\nSi vous n'avez jamais entendu parler de Mastodon and du fediverse, nous vous recommandons de lire <a href='https://www.savjee.be/videos/simply-explained/mastodon-and-fediverse-explained/'>cet article (en anglais)</a>.<br/><br/>Saisissez votre nom d'instance ci-dessous (par ex. mastodon.social)",
"interact_with_me_at": "Interagissez avec moi sur le fediverse à",
"recurrent_1m_ordinal": "Le {n} {days} de chaque mois",
"recurrent_1m_ordinal": "Chaque {n} {days} du mois",
"import_ICS": "Importer à partir d'un fichier ICS",
"import_URL": "Importer à partir d'une URL",
"remove_recurrent_confirmation": "Êtes-vous sûr·e de vouloir supprimer cet évènement récurrent ?\nLes évènements passés seront conservés, mais aucun évènement futur de sera créé.",
@ -145,7 +150,7 @@
"anon": "Anonyme",
"ics": "ICS",
"each_2w": "Une semaine sur deux",
"recurrent_2m_ordinal": "Les {n} {days} du mois un mois sur deux",
"recurrent_2m_ordinal": "Chaque {n} {days} par mois un mois sur deux",
"recurrent_2m_days": "Le {days} un mois sur deux",
"recurrent_2w_days": "Un {days} sur deux",
"edit_recurrent": "Modifier lévènement récurrent :",
@ -157,8 +162,14 @@
"download_flyer": "Télécharger le flyer",
"show_multidate": "évènements sur plusieurs jours",
"choose_focal_point": "Choisir le centre d'intérêt",
"address_description_osm": "Quelle est l'adresse? (<a href='http://osm.org/copyright'>OpenStreetMap</a> contributeurs)",
"address_description": "Quelle adresse ?"
"address_description_osm": "Chercher des coordonnées en tapant l'adresse. (<a href='http://osm.org/copyright'>OpenStreetMap</a> contributeurs)",
"address_description": "Quelle adresse ?",
"where_advanced_options": "Lieu - Option avancées",
"online_locations_fallback_urls": "Liens alternatifs",
"where_advanced_options_description": "Définir ici les propriétés additionnelles du lieu",
"online_locations": "Localisations en ligne",
"online_locations_help": "Par exemple l'URL d'un salon de visioconférence et une URL alternative (max. 3)",
"address_geocoded_disclaimer": "Si vous ne pouvez pas trouver l'<strong>adresse</strong> our le <strong>numéro</strong> que vous cherchez dans les résultats de géocodage, vous pouvez les insérer manuellement dans le champ 'Adresse' sans coordonnées précises. Par ailleurs considérez que le projet <a target=\"_blank\" href=\"https://www.openstreetmap.org/\">OpenStreetMap</a> est ouvert aux contributions pour corriger cela. Si vous avez un téléphone Android, nous recommendons <a target=\"_blank\" href=\"https://f-droid.org/en/packages/de.westnordost.streetcomplete/\">StreetComplete</a> "
},
"register": {
"description": "Les mouvements sociaux doivent s'organiser et s'autofinancer.<br/>\n<br/>Avant de pouvoir publier, <strong> le compte doit être approuvé</strong>, considérez que <strong> derrière ce site vous trouverez de vraies personnes</strong>, à qui vous pouvez écrire en deux lignes pour exprimer les évènements que vous souhaiteriez publier.",
@ -265,7 +276,7 @@
"config_plugin": "Configuration du plugin",
"colors": "Couleurs",
"allow_multidate_event": "Autoriser les évènements sur plusieurs jours",
"delete_tag_confirm": "Etes vous certain.e de vouloir supprimer le tag \"{tag}\"? Le tag sera supprimé de {n} évènements.",
"delete_tag_confirm": "Êtes vous certain.e de vouloir supprimer le tag \"{tag}\"? Le tag sera supprimé de {n} évènements.",
"hide_thumbs": "Cacher les vignettes",
"hide_calendar": "Cacher le calendrier",
"default_images": "Images par défaut",
@ -288,9 +299,13 @@
"geolocation": "Géolocalisation",
"edit_tag_help": "Vous pouvez changer le tag en le remplaçant par un nouveau ou bien fusionner celui-ci avec l'existant. Les {n} évènements associés seront modifiés.",
"edit_tag": "Modifier le tag",
"delete_collection_confirm": "Etes vous certain.e de vouloir supprimer la collection <u>{collection}</u>?",
"delete_collection_confirm": "Êtes vous certain⋅e de vouloir supprimer la collection <u>{collection}</u>?",
"admin_email_help": "L'adresse que nous utilisons comme expéditeur pour envoyer des courriels. Il s'agit également de l'adresse à laquelle les mails admin sont envoyés.",
"geolocation_description": "<b>1. Définir un fournisseur de service de géolocalisation</b>.<br>Actuellement, parmi ceux listés dans le <a href=\"https://wiki.openstreetmap.org/wiki/Nominatim#Alternatives_.2F_Third-party_providers\">wiki d'OpenStreetMap</a>, il y a un service de support pour logiciel <a href=\"https://github.com/osm-search/Nominatim\">Nominatim</a> et <a href=\"https://github.com/komoot/photon\">Photon</a>.<br>Vous pouvez utiliser l'une des démos officielles en copiant le lien dans le champs ' Geocoding provider' :<ul><li>https://nominatim.openstreetmap.org/search (<a href=\"https://operations.osmfoundation.org/policies/nominatim/\">Terms of Service</a>)</li><li>https://photon.komoot.io/api/ (<a href=\"https://photon.komoot.io/\">Terms of Service</a>)</li></ul><br><b>2. Definir un fournisseur de fonds de carte.</b><br>Vous pouvez en trouvez une liste ici: <a href=\"https://leaflet-extras.github.io/leaflet-providers/preview/\">https://leaflet-extras.github.io/leaflet-providers/preview/</a>"
"geolocation_description": "<b>1. Définir un fournisseur de service de géolocalisation</b>.<br>Actuellement, parmi ceux listés dans le <a href=\"https://wiki.openstreetmap.org/wiki/Nominatim#Alternatives_.2F_Third-party_providers\">wiki d'OpenStreetMap</a>, il y a un service de support pour logiciel <a href=\"https://github.com/osm-search/Nominatim\">Nominatim</a> et <a href=\"https://github.com/komoot/photon\">Photon</a>.<br>Vous pouvez utiliser l'une des démos officielles en copiant le lien dans le champs ' Fournisseurs de géocodage' :<ul><li>https://nominatim.openstreetmap.org/search (<a href=\"https://operations.osmfoundation.org/policies/nominatim/\">Conditions d'utilisations</a>)</li><li>https://photon.komoot.io/api/ (<a href=\"https://photon.komoot.io/\">Conditions d'utilisations</a>)</li></ul><br><b>2. Définir un fournisseur de fonds de carte.</b><br>Vous pouvez en trouvez une liste ici: <a href=\"https://leaflet-extras.github.io/leaflet-providers/preview/\">https://leaflet-extras.github.io/leaflet-providers/preview/</a>",
"header_image": "Image d'en-tête",
"allow_online_event_hint": "Demander des liens ",
"fallback_image": "Image de rechange",
"allow_online_event": "Permettre les évènements en ligne"
},
"oauth": {
"scopes": {
@ -302,15 +317,17 @@
"about": "\n <p><a href='https://gancio.org'>Gancio</a> est un agenda partagé pour les communautés locales.</p>\n ",
"validators": {
"email": "Saisissez une adresse courriel valide",
"required": "{fieldName} est requis"
"required": "{fieldName} est requis",
"latitude": "Insérer une latitude valide (entre -90 et 90)",
"longitude": "Insérer une longitude valide (entre -180 et 180)"
},
"ordinal": {
"-1": "dernier",
"5": "cinquième",
"4": "quatrième",
"3": "troisième",
"1": "premier",
"2": "deuxième",
"1": "premier"
"3": "troisième",
"4": "quatrième",
"5": "cinquième",
"-1": "dernier"
},
"confirm": {
"valid": "Votre compte a bien été confirmé, vous pouvez désormais <a href=\"/login\">vous connecter</a>",

View file

@ -28,7 +28,7 @@
"feed_url_copied": "Abrir o URL da fonte copiado no teu lector de RSS",
"event": "Evento",
"pause": "Pausa",
"start": "Inicio",
"start": "Comezar",
"fediverse": "Fediverso",
"announcements": "Anuncios",
"reset": "Restablecer",
@ -102,11 +102,12 @@
"content": "Contido",
"admin_actions": "Accións de Admin",
"recurring_event_actions": "Accións de eventos recurrentes",
"tag": "Etiqueta",
"tag": "Etiquetar",
"search_coordinates": "Buscar coordenadas",
"online": "En liña",
"show_preview": "Mostrar vista previa",
"test": "Proba"
"test": "Proba",
"clone": "Clonar"
},
"recover": {
"not_valid_code": "Algo fallou."
@ -170,7 +171,7 @@
"image_too_big": "A imaxe non pode superar os 4MB",
"recurrent_1m_days": "O {days} de cada mes",
"each_2w": "Cada dúas semanas",
"follow_me_description": "Un dos xeitos de recibir actualizacións dos eventos que se publican aquí en {title},\né seguindo a conta <u>{account}</u> no fediverso, por exemplo a través de Mastodon, e posiblemente tamén engadir recursos para un evento desde alí.<br/><br/>\nSe nunco escoitaches falar de Mastodon e o fediverso recomendámosche ler <a href='https://www.savjee.be/videos/simply-explained/mastodon-and-fediverse-explained/'>este artigo</a>.<br/><br/>Escribe aquí a túa instancia (ex. mastodon.social)",
"follow_me_description": "Un dos xeitos de recibir actualizacións dos eventos que se publican aquí en {title},\né seguindo a conta <u>{account}</u> no fediverso, por exemplo a través de Mastodon, e posiblemente tamén engadir recursos para un evento desde alí.<br/><br/>\nSe non escoitaches falar de Mastodon e o fediverso recomendámosche ler <a href='https://www.savjee.be/videos/simply-explained/mastodon-and-fediverse-explained/'>este artigo</a>.<br/><br/>Escribe aquí a túa instancia (ex. mastodon.social)",
"ics": "ICS",
"import_description": "Podes importar eventos desde outras plataformas e outras instancias usando formatos estándar (ics e h-event)",
"alt_text_description": "Descrición para persoas con problemas de visión",
@ -241,11 +242,11 @@
"instance_locale": "Idioma por defecto",
"delete_announcement_confirm": "Tes a certeza de querer eliminar o anuncio?",
"instance_locale_description": "Idioma preferido para as páxinas. A veces as mensaxes teñen que mostrarse no mesmo idioma para tódalas persoas (por exemplo cando publicas vía ActivityPub ou cando envías os emails). Nestos casos usarase o idioma elexido aquí arriba.",
"enable_trusted_instances": "Activar instancias amigas",
"trusted_instances_help": "A lista das instancias amigas será mostrada na cabeceira",
"trusted_instances_label": "Etiqueta de navegação para instâncias de amigos",
"trusted_instances_label_default": "Casos amigáveis",
"trusted_instances_label_help": "A etiqueta padrão é 'Instâncias amigáveis'",
"enable_trusted_instances": "Activar instancias amigables",
"trusted_instances_help": "A lista das instancias recomendadas será mostrada na cabeceira",
"trusted_instances_label": "Etiqueta de navegación para instancias recomendadas",
"trusted_instances_label_default": "Instancias amigables",
"trusted_instances_label_help": "A etiqueta por defecto é 'Instáncias amigables'",
"delete_trusted_instance_confirm": "Tes a certeza de querer eliminar este elemento do menú de instancias amigas?",
"instance_place_help": "A etiqueta a mostrar nas instancias de outras",
"add_link": "Engadir ligazón",
@ -316,7 +317,7 @@
"settings": {
"change_password": "Cambia o contrasinal",
"danger_section": "Sección perigosa",
"remove_account": "Ao premer o seguinte botón vas eliminar túa conta de usuaria. Os eventos que publicaches permanecerán.",
"remove_account": "Ao premer o seguinte botón vas eliminar túa conta. Os eventos que publicaches permanecerán.",
"password_updated": "Contrasinal cambiado.",
"remove_account_confirm": "Vas eliminar permanentemente a túa conta",
"update_confirm": "Queres gardar as modificacións?"
@ -332,11 +333,11 @@
},
"ordinal": {
"1": "primeiro",
"2": "segundo",
"3": "terceiro",
"4": "cuarto",
"5": "quinto",
"-1": "último",
"2": "segundo"
"-1": "último"
},
"validators": {
"required": "{fieldName} é requerido",

View file

@ -1,5 +1,6 @@
module.exports = {
ca: 'Català',
cs: 'Czech',
de: 'Deutsch',
en: 'English',
es: 'Español',
@ -11,6 +12,7 @@ module.exports = {
nl: 'Dutch',
pl: 'Polski',
pt: 'Português',
'pt-BR': 'Português (Brasilian)',
ru: 'Русский',
sk: 'Slovak',
zh: '中国'

View file

@ -105,7 +105,7 @@
"search_coordinates": "Cerca coordinate",
"online": "Online",
"show_preview": "Mostra anteprima",
"test": "Prova"
"clone": "Clona"
},
"login": {
"description": "Entrando puoi pubblicare nuovi eventi.",
@ -343,7 +343,7 @@
"required": "Campo {fieldName} necessario",
"email": "Inserisci un'e-mail valida",
"latitude": "Inserisci una latitudine valida (-90 < latitudine < 90)",
"longitude": "Inserisci una latitudine valida (-180 < latitude < 180)"
"longitude": "Inserisci una longitudine valida (-180 < longitudine < 180)"
},
"about": "\n <p> <a href='https://gancio.org'> Gancio </a> è un'agenda condivisa per le comunità locali. </p>\n ",
"oauth": {

View file

@ -242,7 +242,8 @@
"show_map": "Vis kart",
"latitude": "breddegrad",
"longitude": "Lengdegrad",
"getting_there": "Slik kommer du deg dit"
"getting_there": "Slik kommer du deg dit",
"clone": "Klone"
},
"about": "\n <p><a href='https://gancio.org'>Gancio</a> er en delt agenda for lokale gemenskaper.</p>\n ",
"validators": {
@ -250,12 +251,12 @@
"required": "{fieldName} kreves"
},
"ordinal": {
"-1": "siste",
"5": "femte",
"4": "fjerde",
"3": "tredje",
"1": "første",
"2": "andre",
"1": "første"
"3": "tredje",
"4": "fjerde",
"5": "femte",
"-1": "siste"
},
"export": {
"list_description": "Hvis du har en nettside og ønsker å vise en liste over hendelser, bruk følgende kode",

View file

@ -104,12 +104,12 @@
"tilelayer_test_button": "Tilelayer testen"
},
"ordinal": {
"4": "vierde",
"1": "eerste",
"3": "derde",
"-1": "laatste",
"2": "tweede",
"5": "vijfde"
"3": "derde",
"4": "vierde",
"5": "vijfde",
"-1": "laatste"
},
"common": {
"plugins": "Plugins",
@ -210,7 +210,8 @@
"reset": "Resetten",
"import": "Importeren",
"label": "Label",
"collections": "Collecties"
"collections": "Collecties",
"clone": "Kloon"
},
"login": {
"not_registered": "Niet geregistreerd?",

View file

@ -64,7 +64,8 @@
"embed": "Osadź",
"embed_help": "Skopiuj poniższy kod na swoją stronę internetową, a wydarzenie będzie wyglądało tak jak tutaj",
"feed": "Kanał RSS",
"feed_url_copied": "Otwórz skopiowany link w swoim czytniku RSS"
"feed_url_copied": "Otwórz skopiowany link w swoim czytniku RSS",
"clone": "Klon"
},
"settings": {
"change_password": "Zmień swoje hasło",
@ -75,11 +76,11 @@
},
"ordinal": {
"1": "pierwszy",
"5": "piąty",
"-1": "ostatni",
"2": "drugi",
"3": "trzeci",
"4": "czwarty"
"4": "czwarty",
"5": "piąty",
"-1": "ostatni"
},
"confirm": {
"not_valid": "Coś poszło nie tak.",

356
locales/pt-BR.json Normal file
View file

@ -0,0 +1,356 @@
{
"common": {
"add_event": "Adicionar evento",
"description": "Descrição",
"send": "Enviar",
"address": "Endereço",
"next": "Próximo",
"when": "Quando",
"where": "Onde",
"login": "Login",
"export": "Exportar",
"email": "E-mail",
"what": "O que",
"media": "Media",
"password": "Senha",
"register": "Registrar",
"remove": "Remover",
"confirm": "Confirmar",
"events": "Eventos",
"settings": "Opções",
"actions": "Ações",
"edit": "Editar",
"admin": "Admin",
"places": "Lugares",
"hide": "Ocultar",
"search": "Buscar",
"info": "Info",
"users": "Usuárias",
"share": "Compartilhar",
"name": "Nome",
"associate": "Associar",
"logout": "Sair",
"remove_admin": "Remover admin",
"activate": "Ativar",
"save": "Salvar",
"preview": "Visualizar",
"edit_event": "Editar evento",
"add": "Adicionar",
"copy": "Copiar",
"ok": "Ok",
"cancel": "Cancelar",
"me": "Você",
"password_updated": "Senha alterada.",
"resources": "Recursos",
"activate_user": "Confirmado",
"copy_link": "Copiar link",
"send_via_mail": "Enviar e-mail",
"add_to_calendar": "Adicionar ao calendário",
"copied": "Copiado",
"recover_password": "Recuperar senha",
"new_password": "Nova senha",
"new_user": "Nova usuária",
"deactivate": "Desligar",
"related": "Relacionado",
"enable": "Habilitar",
"disable": "Desabilitar",
"federation": "Federação",
"set_password": "Definir senha",
"instances": "Instâncias",
"follow": "Seguir",
"moderation": "Moderação",
"user": "Usuária",
"authorize": "Autorizar",
"title": "Título",
"filter": "Filtro",
"event": "Evento",
"pause": "Pausar",
"start": "Início",
"feed": "Feed RSS",
"skip": "Pular",
"delete": "Remover",
"fediverse": "Fediverso",
"announcements": "Anúncios",
"place": "Local",
"url": "URL",
"logout_ok": "Deslogado",
"n_resources": "nenhum recurso|um recurso|{n} recursos",
"embed": "Incorporar",
"embed_title": "Incorpore este evento em sua página",
"embed_help": "Copie o seguinte código em sua página e o evento será exibido desta maneira",
"displayname": "Nome de exibição",
"feed_url_copied": "Abra a URL copiada do feed em seu leitor de RSS",
"follow_me_title": "Siga as atualizações pelo Fediverso",
"tags": "Tags",
"theme": "Tema",
"reset": "Reiniciar",
"import": "Importar",
"collections": "Coleções",
"max_events": "N. máximo de eventos",
"label": "Etiqueta",
"close": "Fechar",
"plugins": "Plugins",
"help_translate": "Ajude a traduzir",
"show_map": "Exibir mapa",
"calendar": "Calendário",
"home": "Início",
"about": "Sobre",
"content": "Conteúdo",
"admin_actions": "Ações de admin",
"recurring_event_actions": "Ações para eventos recorrentes",
"tag": "Tag",
"latitude": "Latitude",
"longitude": "Longitude",
"search_coordinates": "Procurar coordenadas",
"online": "On-line",
"test": "Teste",
"show_preview": "Mostrar pré-visualização",
"clone": "Clone"
},
"admin": {
"user_block_confirm": "Têm a certeza que quer bloquear o utilizador {user}?",
"filter_instances": "Filtrar domínios",
"user_add_help": "Um e-mail com instruções para confirmar a inscrição e escolher uma senha será enviada ao novo usuário",
"show_resource": "Mostrar recurso",
"block_user": "Bloquear utilizador",
"filter_users": "Filtrar utilizadores",
"hide_resource": "Ocultar recurso",
"delete_resource": "Remover recurso",
"delete_resource_confirm": "Têm a certeza que quer remover este recurso?",
"show_smtp_setup": "Configurações de e-mail",
"resources": "Recursos",
"delete_announcement_confirm": "Têm a certeza que quer remover o anúncio?",
"smtp_hostname": "Hostname do SMTP",
"collections_description": "Coleções são agrupamentos de eventos por marcadores e locais. Eles serão exibidos na página principal",
"new_collection": "Nova coleção",
"disable_admin_user_confirm": "Têm a certeza que quer remover permissões de administração de {user}?",
"enable_admin_user_confirm": "Têm a certeza que quer adicionar permissões de administrador para {user}?",
"event_remove_ok": "Evento removido",
"smtp_description": "<ul><li>Administrador deve receber um e-mail quando um evento anónimo for adicionado (se habilitado).</li><li>Administrador deve receber um e-mail de requisição de registo (se habilitado).</li><li>Utilizador deve receber um e-mail de solicitação de registro.</li><li>Utilizador deve receber um e-mail de confirmação de registo.</li><li>Utilizador deve receber um e-mail de confirmação quando registado diretamente por um administrador.</li><li>Utilizadores devem receber um e-mail para recuperar a senha quando eles esquecerem ela</li></ul>",
"allow_registration_description": "Permitir registo aberto de utilizadores?",
"block": "Bloquear",
"unblock": "Desbloquear",
"instance_name": "Nome da instância",
"favicon": "Logo",
"instance_block_confirm": "Têm a certeza que quer bloquear o domínio {instance}?",
"enable_federation": "Habilitar federação",
"enable_federation_help": "Será possível seguir está instância a partir do Fediverso",
"add_instance": "Adicionar instância",
"hide_boost_bookmark_help": "Ocultar os pequenos ícones mostrando o número de impulsos e favoritos vindos do Fediverso",
"announcement_remove_ok": "Anúncio removido",
"instance_timezone_description": "Gancio é desenvolvido para coletar os eventos de um local específico, como uma cidade. Todos os eventos nesse local serão exibidos no fuso-horário escolhido para ele.",
"instance_locale_description": "Idioma de preferência para as páginas. Algumas vezes as mensagens precisam ser exibidas em um mesmo idioma para todos (por exemplo, quando publicando através do ActivityPub ou quando enviar alguns e-mails). Nestes casos o idioma seleciona abaixo será o utilizado.",
"title_description": "É utilizado no título da página, no assunto do e-mail para exportar feeds RSS e ICS.",
"instance_name_help": "Conta ActivityPub para seguir",
"enable_trusted_instances": "Habilitar domínios amigáveis",
"trusted_instances_help": "A lista de domínios amigáveis será exibido no cabeçalho",
"trusted_instances_label": "Etiqueta de navegação para domínios amigos",
"trusted_instances_label_default": "Domínios amigos",
"trusted_instances_label_help": "A etiqueta padrão é 'Domínios amigos'",
"add_trusted_instance": "Adicione um domínio amigável",
"footer_links": "Links de rodapé",
"delete_footer_link_confirm": "Têm a certeza que quer remover este link?",
"edit_place": "Editar local",
"smtp_port": "Porta do SMTP",
"smtp_secure": "SMTP Seguro (TLS ou STARTTLS)",
"smtp_use_sendmail": "Utilizar sendmail",
"instance_place_help": "A etiqueta para exibir em outros domínios",
"delete_trusted_instance_confirm": "Quer realmente remover este item do menu de domínios amigos?",
"sender_email": "E-mail do remetente",
"widget": "Widget",
"wrong_domain_warning": "O baseurl configurado no config.json <b>({baseurl})</b> é diferente do que está a usar para visitar <b>({url})</b>",
"edit_collection": "Editar Coleção",
"enable_resources_help": "Permitir adicionar recursos para o evento a partir do Fediverso",
"hide_boost_bookmark": "Ocultar impulsos/favoritos",
"select_instance_timezone": "Fuso horário",
"instance_locale": "Idioma padrão",
"enable_resources": "Habilitar recursos",
"delete_user": "Remover",
"remove_admin": "Remover administrador",
"place_description": "Se colocou o local ou o endereço errado, pode alterá-lo.<br/>Todos os eventos atuais e passados associados com este local terão o endereço alterado.",
"event_confirm_description": "Pode confirmar eventos criados por utilizadores anónimos aqui",
"disable_user_confirm": "Têm a certeza que quer desativar {user}?",
"delete_user_confirm": "Têm a certeza que quer remover {user}?",
"user_remove_ok": "Usuário removido",
"user_create_ok": "Usuário criado",
"allow_anon_event": "Permitir eventos anônimos (precisam ser confirmados)?",
"allow_recurrent_event": "Permitir eventos recorrentes",
"recurrent_event_visible": "Exibir eventos recorrentes por padrão",
"user_blocked": "Utilizador {user} bloqueado",
"announcement_description": "Nesta secção pode inserir anúncios que serão exibidos na página principal",
"description_description": "Exibido no cabeçalho próximo ao título",
"instance_place": "Local indicativo deste domínio",
"is_dark": "Tema escuro",
"add_link": "Adicionar link",
"new_announcement": "Novo anúncio",
"federation": "Federação / ActivityPub",
"smtp_test_success": "Um e-mail de teste foi enviado para {admin_email}, por favor verifique sua caixa de entrada",
"smtp_test_button": "Enviar e-mail de teste",
"allow_geolocation": "Permitir geolocalização de eventos",
"config_plugin": "Configuração da extensão",
"fallback_image": "Imagem alternativa",
"header_image": "Imagem de cabeçalho",
"hide_thumbs": "Ocultar miniaturas",
"default_images_help": "Precisa de <a href='/admin?tab=theme'>recarregar</a> a página para ver as mudanças.",
"domain": "Domínio",
"default_images": "Imagens padrão",
"known_users": "Utilizadores conhecidos",
"created_at": "Criado em",
"hide_calendar": "Ocultar calendário",
"blocked": "Bloqueado",
"admin_email": "E-mail do admin",
"tilelayer_provider_attribution": "Atribuição",
"geolocation": "Geolocalização",
"edit_tag": "Editar etiqueta",
"allow_online_event": "Permitir eventos online",
"allow_online_event_hint": "Pedir por links ",
"admin_email_help": "O e-mail que utilizaremos como remetente para enviar mensagens. Este é também o endereço para o qual são enviadas as mensagens da administração",
"allow_multidate_event": "Permitir eventos com múltiplas datas",
"delete_tag_confirm": "Tem certeza que quer remover a etiqueta \"{tag}\"? A etiqueta será removida de {n} eventos.",
"delete_collection_confirm": "Têm a certeza que quer remover a coleção <u>{collection}</u>?",
"colors": "Cores",
"geocoding_provider_help": "O provedor padrão é o Nominatim",
"geocoding_provider_type_help": "O software padrão é o Nominatim",
"geocoding_countrycodes": "Código de países",
"geocoding_provider_type": "Software de geocodificação",
"geocoding_provider": "Provedor de geocodificação",
"tilelayer_provider_help": "O provedor padrão é o OpenStreetMap",
"edit_tag_help": "Você pode alterar o marcador ao substituí-lo por um novo ou mesclando-o com um já existente. Os {n} eventos associados também serão alterados."
},
"event": {
"follow_me_description": "Uma das maneiras de se manter atualizado com os eventos publicados aqui em {title},\né seguir a conta <u>{account}</u> no Fediverso, por exemplo, via Mastodon, e possivelmente adicionar recursos para um evento a partir de lá.<br/><br/>\nSe nunca ouviu falar sobre Mastodon ou no Fediverso nós recomendamos ler <a href='https://www.savjee.be/videos/simply-explained/mastodon-and-fediverse-explained/'>este artigo</a>.<br/><br/>Entre com o seu domínio abaixo (e.g. mastodon.social)",
"saved": "Evento salvo",
"recurrent": "Recorrente",
"ics": "ICS",
"recurrent_1m_days": "Dia {days} de cada mês",
"interact_with_me": "Siga-me",
"media_description": "Pode adicionar um cartaz (opcional)",
"same_day": "no mesmo dia",
"added": "Evento adicionado",
"what_description": "Título",
"description_description": "Descrição",
"tag_description": "Marcador",
"show_recurrent": "eventos recorrentes",
"anon": "Anônimo",
"anon_description": "Pode adicionar um evento sem se registar ou autenticar, mas precisa de esperar para alguém o ler,\ne confirmar que é um evento adequado. Não será possível modificá-lo depois disso.<br/><br/>\nPodem por vez <a href='/login'>autenticar-se</a> ou <a href='/register'>registar-se</a>. De qualquer modo, vá em frente e poderá obter uma resposta o mais rápido possível. ",
"added_anon": "Evento adicionado, mas ainda precisa ser confirmado.",
"updated": "Evento atualizado",
"where_description": "Onde está o evento? Se não está presente, então pode criá-lo.",
"confirmed": "Evento confirmado",
"not_found": "Não foi possível encontrar o evento",
"remove_confirmation": "Têm a certeza que quer remover este evento?",
"edit_recurrent": "Editar evento recorrente:",
"only_future": "apenas eventos futuros",
"recurrent_description": "Escolha a frequência e selecione os dias",
"multidate_description": "É um festival? Escolha quando ele começa e quando termina",
"multidate": "Mais dias",
"normal": "Normal",
"show_past": "também eventos anteriores",
"normal_description": "Escolha o dia.",
"recurrent_1w_days": "A cada {days}",
"each_week": "Toda semana",
"each_2w": "A cada duas semanas",
"each_month": "Todo mês",
"recurrent_2w_days": "{days} a cada dois",
"recurrent_2m_days": "Dia {days} a cada dois meses",
"recurrent_1m_ordinal": "A cada {n} {days} dias do mês",
"recurrent_2m_ordinal": "{n} {days} a cada dois meses",
"due": "até",
"from": "De",
"image_too_big": "A imagem não pode ser maior que 4MB",
"interact_with_me_at": "Interaja comigo no Fediverso atráves de",
"remove_recurrent_confirmation": "Têm a certeza que quer remover este evento recorrente?\nEventos passados serão mantidos, mas nenhum evento seguinte será criado.",
"import_URL": "Importar a partir de URL",
"import_ICS": "Importar a partir de ICS",
"import_description": "Pode importar eventos de outras plataformas e de outros domínios via formatos padrão (ICS e H-Event)",
"alt_text_description": "Descrição para pessoas com deficiências visuais",
"choose_focal_point": "Escolha o ponto focal",
"remove_media_confirmation": "Confirma a remoção da imagem?",
"download_flyer": "Baixar flyer",
"address_description": "Qual é o endereço?",
"address_description_osm": "Procure as coordenadas escrevendo o endereço. (contribuidores do <a href='http://osm.org/copyright'>OpenStreetMap</a>)",
"show_multidate": "Eventos com múltiplas datas",
"where_advanced_options": "Lugar — Opções avançadas",
"where_advanced_options_description": "Defina aqui propriedades do local adicionais",
"online_locations": "Localizações online",
"address_geocoded_disclaimer": "Se não conseguir encontrar o <strong>endereço da rua</strong> ou a <strong>porta da casa</strong> que procura nos resultados da geocodificação, pode inseri-los manualmente no campo “Endereço” sem perder as coordenadas. Considere também que o projeto <a target=\"_blank\" href=\"https://www.openstreetmap.org/\">OpenStreetMap</a> está aberto a contribuições. Se tiver Android, recomendamos o <a target=\"_blank\" href=\"https://f-droid.org/en/packages/de.westnordost.streetcomplete/\">StreetComplete</a>. ",
"online_locations_help": "Por exemplo, um link para uma sala de video-conferência e um link para outros recursos (máx. 3)",
"online_locations_fallback_urls": "Links de retorno"
},
"confirm": {
"not_valid": "Algo deu errado.",
"title": "Confirmação de usuário",
"valid": "A sua conta está confirmada, pode agora <a href=\"/login\">autenticar-se</a>"
},
"export": {
"intro": "Diferente de plataformas não sociais que fazem tudo para manter os utilizadores e os dados sobre eles, nós acreditamos que a informação, como pessoas, deve ser livre. Para isso deve atualizar-se sobre os eventos do seu interesse, sem necessariamente entrar nesta página.",
"insert_your_address": "Informe seu endereço de e-mail",
"feed_description": "Para seguir as atualizações de um computador ou telemóvel sem que precise de aceder a esta página periodicamente, utilize um leitor de feeds RSS. </p>\n\n<p> Com feeds RSS pode utilizar uma aplicação especial para receber atualizações de páginas que sejam do teu interesse. É uma boa maneira de seguir muitas páginas rapidamente, sem a necessidade de criar contas de utilizadores ou outras complicações. </p>\n\n<li> Se possui um Android, recomendamos <a href=\"https://f-droid.org/en/packages/net.frju.flym/\">Flym</a> ou Feeder </li>\n<li> Para iPhone / iPad pode utilizar <a href=\"https://itunes.apple.com/ua/app/feeds4u/id1038456442?mt=8\"> Feed4U </a> </li>\n<li> Para computador fixo/ portátil nós recomendamos Feedbro, que pode ser instalado no <a href=\"https://addons.mozilla.org/en-GB/firefox/addon/feedbroreader/\"> Firefox </a> ou <a href=\"https://chrome.google.com/webstore/detail/feedbro/mefgmmbdailogpfhfblcnnjfmnpnmdfa\"> Chrome </a>. </li>\n<br/>\nAdicionado este link ao seu leitor de RSS irá mantê-lo atualizado.",
"ical_description": "Computadores e smartphones normalmente possuem aplicações de calendário capazes de importar um calendário remoto.",
"list_description": "Se têm uma página e quer exibir uma lista de eventos, use o seguinte código",
"email_description": "Podes obter eventos que sejam do teu interesse via e-mail."
},
"oauth": {
"authorization_request": "A aplicação <code>{app}</code> solicita autorização em <code>{instance_name}</code>:",
"scopes": {
"event:write": "Adicionar e editar os seus eventos"
},
"redirected_to": "Depois da confirmação, será redirecionado para <code>{url}</code>"
},
"ordinal": {
"1": "primeiro",
"2": "segundo",
"3": "terceiro",
"4": "quarto",
"5": "quinto",
"-1": "último"
},
"settings": {
"remove_account": "Ao pressionar este botão a sua conta de utilizador será apagada. Eventos que publicou serão mantidos.",
"remove_account_confirm": "Está prestes a apagar a sua conta de utilizador permanentemente",
"update_confirm": "Quer salvar as suas alterações?",
"change_password": "Alterar sua senha",
"password_updated": "Senha alterada.",
"danger_section": "Seção perigosa"
},
"error": {
"email_taken": "Este e-mail já está em uso.",
"nick_taken": "Este nome de usuário já está em uso."
},
"setup": {
"https_warning": "Está a aceder por HTTP, lembre-se de alterar o valor de baseurl em config.json se mudar para HTTPS!",
"completed": "Configuração completa",
"start": "Iniciar",
"completed_description": "<p>Pode agora autenticar-se com o seguinte utilizador:<br/><br/>Utilizador: <b>{email}</b><br/>Palavra-passe: <b>{password}<b/></p>",
"copy_password_dialog": "Sim, precisa copiar a palavra-passe!"
},
"validators": {
"email": "Insira um e-mail válido",
"required": "{fieldName} é obrigatório",
"longitude": "Insira uma longitude válida (-180 < longitude < 180)",
"latitude": "Insira uma latitude válida (90 < latitude < 90)"
},
"about": "\n <p><a href='https://gancio.org'>Gancio</a> é uma agenda compartilhada para comunidades locais.</p>\n ",
"login": {
"not_registered": "Não registrado?",
"forgot_password": "Esqueceu sua senha?",
"insert_email": "Informe seu endereço de e-mail",
"ok": "Autenticado",
"description": "Ao autenticar-se poderá publicar novos eventos.",
"check_email": "Verifique sua caixa de entrada e de spam.",
"error": "Autenticação não realizada. Verifique suas informações de autenticação."
},
"recover": {
"not_valid_code": "Algo não funcionou corretamente."
},
"register": {
"error": "Erro: ",
"complete": "Registro precisa ser confirmado.",
"first_user": "Administrador criado",
"description": "Movimentos sociais devem se organizar e autofinanciar-se.<br/>\n<br/>Antes de poder publicar, <strong> a conta precisa ser aprovada por um administrador</strong>, considere que <strong> atrás deste site vai encontrar pessoas reais</strong>, então escreva duas linhas para nos informar que eventos teria interesse em publicar."
},
"auth": {
"fail": "Autenticação não efetuada. Têm a certeza que a sua palavra-passe está correta?",
"not_confirmed": "Não confirmado ainda…"
}
}

View file

@ -25,8 +25,8 @@
"hide": "Ocultar",
"search": "Buscar",
"info": "Info",
"users": "Usuários",
"share": "Compartilhar",
"users": "Utilizadores",
"share": "Partilhar",
"name": "Nome",
"associate": "Associar",
"logout": "Sair",
@ -39,7 +39,7 @@
"copy": "Copiar",
"ok": "Ok",
"cancel": "Cancelar",
"me": "Você",
"me": "Tu",
"password_updated": "Senha alterada.",
"resources": "Recursos",
"activate_user": "Confirmado",
@ -97,60 +97,68 @@
"about": "Sobre",
"content": "Conteúdo",
"admin_actions": "Ações de admin",
"recurring_event_actions": "Ações de eventos recorrentes"
"recurring_event_actions": "Ações de eventos recorrentes",
"tag": "Etiqueta",
"latitude": "Latitude",
"longitude": "Longitude",
"search_coordinates": "Procurar coordenadas",
"online": "On-line",
"test": "Teste",
"show_preview": "Mostrar pré-visualização",
"clone": "Clone"
},
"admin": {
"user_block_confirm": "Você está certo que quer bloquear o usuário {user}?",
"filter_instances": "Filtrar instâncias",
"user_block_confirm": "Têm a certeza que quer bloquear o utilizador {user}?",
"filter_instances": "Filtrar domínios",
"user_add_help": "Um e-mail com instruções para confirmar a inscrição e escolher uma senha será enviada ao novo usuário",
"show_resource": "Mostrar recurso",
"block_user": "Bloquear usuário",
"filter_users": "Filtrar usuários",
"block_user": "Bloquear utilizador",
"filter_users": "Filtrar utilizadores",
"hide_resource": "Ocultar recurso",
"delete_resource": "Remover recurso",
"delete_resource_confirm": "Você está certo que quer remover este recurso?",
"delete_resource_confirm": "Têm a certeza que quer remover este recurso?",
"show_smtp_setup": "Configurações de e-mail",
"resources": "Recursos",
"delete_announcement_confirm": "Você está certo que quer remover o anúncio?",
"smtp_hostname": "Hostname SMTP",
"delete_announcement_confirm": "Têm a certeza que quer remover o anúncio?",
"smtp_hostname": "Hostname do SMTP",
"collections_description": "Coleções são agrupamentos de eventos por marcadores e locais. Eles serão exibidos na página principal",
"new_collection": "Nova coleção",
"disable_admin_user_confirm": "Você está certo que quer remover permissões de administração de {user}?",
"enable_admin_user_confirm": "Você está certo que quer adicionar permissões de administrador para {user}?",
"disable_admin_user_confirm": "Têm a certeza que quer remover permissões de administração de {user}?",
"enable_admin_user_confirm": "Têm a certeza que quer adicionar permissões de administrador para {user}?",
"event_remove_ok": "Evento removido",
"smtp_description": "<ul><li>Administrador deve receber um e-mail quando um evento anônimo for adicionado (se habilitado).</li><li>Administrador deve receber um e-mail de requisição de registro (se habilitado).</li><li>Usuário deve receber um e-mail de solicitação de registro.</li><li>Usuário deve receber um e-mail de confirmação de registro.</li><li>Usuário deve recever um e-mail de confirmação quando registrado diretamente por um administrador.</li><li>Usuários devem receber um e-mail para recuperar a senha quando eles esquecerem ela</li></ul>",
"allow_registration_description": "Permitir registro aberto de usuários?",
"smtp_description": "<ul><li>Administrador deve receber um e-mail quando um evento anónimo for adicionado (se habilitado).</li><li>Administrador deve receber um e-mail de requisição de registo (se habilitado).</li><li>Utilizador deve receber um e-mail de solicitação de registro.</li><li>Utilizador deve receber um e-mail de confirmação de registo.</li><li>Utilizador deve receber um e-mail de confirmação quando registado diretamente por um administrador.</li><li>Utilizadores devem receber um e-mail para recuperar a senha quando eles esquecerem ela</li></ul>",
"allow_registration_description": "Permitir registo aberto de utilizadores?",
"block": "Bloquear",
"unblock": "Desbloquear",
"instance_name": "Nome da instância",
"favicon": "Logo",
"instance_block_confirm": "Você está certo que quer bloquear a instância {instance}?",
"instance_block_confirm": "Têm a certeza que quer bloquear o domínio {instance}?",
"enable_federation": "Habilitar federação",
"enable_federation_help": "Será possível seguir está instância a partir do Fediverso",
"add_instance": "Adicionar instância",
"hide_boost_bookmark_help": "Ocultar os pequenos ícones mostrando o número de impulsos e favoritos vindos do Fediverso",
"announcement_remove_ok": "Anúncio removido",
"instance_timezone_description": "Gancio é desenvolvido para coletar os eventos de um local específico, como uma cidade. Todos os eventos nesse local serão exibidos no fuso-horário escolhido para ele.",
"instance_locale_description": "Idioma de preferência para as páginas. Algumas vezes as mensagens precisam ser exibidas em um mesmo idioma para todos (por exemplo quando publicando através do ActivityPub ou quando enviar alguns e-mails). Nestes casos o idioma seleciona abaixo será o utilizado.",
"instance_locale_description": "Idioma de preferência para as páginas. Algumas vezes as mensagens precisam ser exibidas em um mesmo idioma para todos (por exemplo, quando publicando através do ActivityPub ou quando enviar alguns e-mails). Nestes casos o idioma seleciona abaixo será o utilizado.",
"title_description": "É utilizado no título da página, no assunto do e-mail para exportar feeds RSS e ICS.",
"instance_name_help": "Conta ActivityPub para seguir",
"enable_trusted_instances": "Habilitar instâncias amigáveis",
"trusted_instances_help": "A lista de instâncias amigáveis que serão exibidas no cabeçalho",
"trusted_instances_label": "Etiqueta de navegação para instâncias amigas",
"trusted_instances_label_default": "Instâncias amigas",
"trusted_instances_label_help": "A etiqueta padrão é 'Instâncias amigas'",
"add_trusted_instance": "Adicione uma instância amigável",
"enable_trusted_instances": "Habilitar domínios amigáveis",
"trusted_instances_help": "A lista de domínios amigáveis será exibido no cabeçalho",
"trusted_instances_label": "Etiqueta de navegação para domínios amigos",
"trusted_instances_label_default": "Domínios amigos",
"trusted_instances_label_help": "A etiqueta padrão é 'Domínios amigos'",
"add_trusted_instance": "Adicione um domínio amigável",
"footer_links": "Links de rodapé",
"delete_footer_link_confirm": "Está certo que quer remover este link?",
"delete_footer_link_confirm": "Têm a certeza que quer remover este link?",
"edit_place": "Editar local",
"smtp_port": "Porta SMTP",
"smtp_port": "Porta do SMTP",
"smtp_secure": "SMTP Seguro (TLS ou STARTTLS)",
"smtp_use_sendmail": "Utilizar sendmail",
"instance_place_help": "A etiqueta para exibir em outras instâncias",
"delete_trusted_instance_confirm": "Você quer realmente remover este item do menu de instâncias amigas?",
"instance_place_help": "A etiqueta para exibir em outros domínios",
"delete_trusted_instance_confirm": "Quer realmente remover este item do menu de domínios amigos?",
"sender_email": "E-mail do remetente",
"widget": "Widget",
"wrong_domain_warning": "A baseurl configurado em config.json <b>({baseurl})</b> é diferente da que você está visitando <b>({url})</b>",
"wrong_domain_warning": "O baseurl configurado no config.json <b>({baseurl})</b> é diferente do que está a usar para visitar <b>({url})</b>",
"edit_collection": "Editar Coleção",
"enable_resources_help": "Permitir adicionar recursos para o evento a partir do Fediverso",
"hide_boost_bookmark": "Ocultar impulsos/favoritos",
@ -159,19 +167,19 @@
"enable_resources": "Habilitar recursos",
"delete_user": "Remover",
"remove_admin": "Remover administrador",
"place_description": "Se você colocou o local ou o endereço errado, você pode alterá-lo.<br/>Todos os eventos atuais e passados associados com esse local terão o endereço alterado.",
"event_confirm_description": "Você pode confirmar eventos criados por usuários anônimos aqui",
"disable_user_confirm": "Você está certo que quer desabilitar {user}?",
"delete_user_confirm": "Você está certo que quer remover {user}?",
"place_description": "Se colocou o local ou o endereço errado, pode alterá-lo.<br/>Todos os eventos atuais e passados associados com este local terão o endereço alterado.",
"event_confirm_description": "Pode confirmar eventos criados por utilizadores anónimos aqui",
"disable_user_confirm": "Têm a certeza que quer desativar {user}?",
"delete_user_confirm": "Têm a certeza que quer remover {user}?",
"user_remove_ok": "Usuário removido",
"user_create_ok": "Usuário criado",
"allow_anon_event": "Permitir eventos anônimos (precisam ser confirmados)?",
"allow_recurrent_event": "Permitir eventos recorrentes",
"recurrent_event_visible": "Exibir eventos recorrentes por padrão",
"user_blocked": "Usuário {user} bloqueado",
"announcement_description": "Nesta seção você pode inserir anúncios que serão exibidos na página principal",
"user_blocked": "Utilizador {user} bloqueado",
"announcement_description": "Nesta secção pode inserir anúncios que serão exibidos na página principal",
"description_description": "Exibido no cabeçalho próximo ao título",
"instance_place": "Local indicativo desta instância",
"instance_place": "Local indicativo deste domínio",
"is_dark": "Tema escuro",
"add_link": "Adicionar link",
"new_announcement": "Novo anúncio",
@ -179,29 +187,44 @@
"smtp_test_success": "Um e-mail de teste foi enviado para {admin_email}, por favor verifique sua caixa de entrada",
"smtp_test_button": "Enviar e-mail de teste",
"allow_geolocation": "Permitir geolocalização de eventos",
"config_plugin": "Configuração de plugin",
"config_plugin": "Configuração da extensão",
"fallback_image": "Imagem alternativa",
"header_image": "Imagem de cabeçalho",
"hide_thumbs": "Ocultar miniaturas",
"default_images_help": "Você precisa <a href='/admin?tab=theme'>recarregar</a> a página para ver as mudanças.",
"default_images_help": "Precisa de <a href='/admin?tab=theme'>recarregar</a> a página para ver as mudanças.",
"domain": "Domínio",
"default_images": "Imagens padrão",
"known_users": "Usuários conhecidos",
"known_users": "Utilizadores conhecidos",
"created_at": "Criado em",
"hide_calendar": "Ocultar calendário",
"blocked": "Bloqueado",
"admin_email": "E-mail do admin",
"tilelayer_provider_attribution": "Atribuição",
"geolocation": "Geolocalização"
"geolocation": "Geolocalização",
"edit_tag": "Editar etiqueta",
"allow_online_event": "Permitir eventos online",
"allow_online_event_hint": "Pedir por links ",
"admin_email_help": "O e-mail que utilizaremos como remetente para enviar mensagens. Este é também o endereço para o qual são enviadas as mensagens da administração",
"allow_multidate_event": "Permitir eventos com múltiplas datas",
"delete_tag_confirm": "Tem certeza que quer remover a etiqueta \"{tag}\"? A etiqueta será removida de {n} eventos.",
"delete_collection_confirm": "Têm a certeza que quer remover a coleção <u>{collection}</u>?",
"colors": "Cores",
"geocoding_provider_help": "O provedor padrão é o Nominatim",
"geocoding_provider_type_help": "O software padrão é o Nominatim",
"geocoding_countrycodes": "Código de países",
"geocoding_provider_type": "Software de geocodificação",
"geocoding_provider": "Provedor de geocodificação",
"tilelayer_provider_help": "O provedor padrão é o OpenStreetMap",
"edit_tag_help": "Você pode alterar o marcador ao substituí-lo por um novo ou mesclando-o com um já existente. Os {n} eventos associados também serão alterados."
},
"event": {
"follow_me_description": "Uma das maneiras de se manter atualizado com os eventos publicados aqui em {title},\né seguir a conta <u>{account}</u> no Fediverso, por exemplo via Mastodon, e possivelmente adicionar recursos para um evento a partir de lá.<br/><br/>\nSe você nunca ouviu falar sobre Mastodon ou do Fediverso nós recomendamos ler <a href='https://www.savjee.be/videos/simply-explained/mastodon-and-fediverse-explained/'>este artigo</a>.<br/><br/>Entre com sua instância abaixo (e.g. mastodon.social)",
"follow_me_description": "Uma das maneiras de se manter atualizado com os eventos publicados aqui em {title},\né seguir a conta <u>{account}</u> no Fediverso, por exemplo, via Mastodon, e possivelmente adicionar recursos para um evento a partir de lá.<br/><br/>\nSe nunca ouviu falar sobre Mastodon ou no Fediverso nós recomendamos ler <a href='https://www.savjee.be/videos/simply-explained/mastodon-and-fediverse-explained/'>este artigo</a>.<br/><br/>Entre com o seu domínio abaixo (e.g. mastodon.social)",
"saved": "Evento salvo",
"recurrent": "Recorrente",
"ics": "ICS",
"recurrent_1m_days": "Dia {days} de cada mês",
"interact_with_me": "Siga-me",
"media_description": "Você pode adicionar um flyer (opcional)",
"media_description": "Pode adicionar um cartaz (opcional)",
"same_day": "no mesmo dia",
"added": "Evento adicionado",
"what_description": "Título",
@ -209,13 +232,13 @@
"tag_description": "Marcador",
"show_recurrent": "eventos recorrentes",
"anon": "Anônimo",
"anon_description": "Você pode adicionar um evento sem se registrar ou autenticar-se, mas você precisa esperar alguém para ler,\nconfirmar que é um evento adequado. Não será possível modifiá-lo.<br/><br/>\nVocê pode ao invés <a href='/login'>autenticar-se</a> ou <a href='/register'>registrar-se</a>. De qualquer modo, vá em frente e consiga uma resposta o mais rápido possível. ",
"anon_description": "Pode adicionar um evento sem se registar ou autenticar, mas precisa de esperar para alguém o ler,\ne confirmar que é um evento adequado. Não será possível modificá-lo depois disso.<br/><br/>\nPodem por vez <a href='/login'>autenticar-se</a> ou <a href='/register'>registar-se</a>. De qualquer modo, vá em frente e poderá obter uma resposta o mais rápido possível. ",
"added_anon": "Evento adicionado, mas ainda precisa ser confirmado.",
"updated": "Evento atualizado",
"where_description": "Onde está o evento? Se não está visível você pode criá-lo.",
"where_description": "Onde está o evento? Se não está presente, então pode criá-lo.",
"confirmed": "Evento confirmado",
"not_found": "Não foi possível encontrar o evento",
"remove_confirmation": "Você está certo que quer remover este evento?",
"remove_confirmation": "Têm a certeza que quer remover este evento?",
"edit_recurrent": "Editar evento recorrente:",
"only_future": "apenas eventos futuros",
"recurrent_description": "Escolha a frequência e selecione os dias",
@ -230,55 +253,62 @@
"each_month": "Todo mês",
"recurrent_2w_days": "{days} a cada dois",
"recurrent_2m_days": "Dia {days} a cada dois meses",
"recurrent_1m_ordinal": "{n} {days} de cada mês",
"recurrent_1m_ordinal": "A cada {n} {days} dias do mês",
"recurrent_2m_ordinal": "{n} {days} a cada dois meses",
"due": "até",
"from": "De",
"image_too_big": "A imagem não pode ser maior que 4MB",
"interact_with_me_at": "Interaja comigo no Fediverso atráves de",
"remove_recurrent_confirmation": "Você está certo que quer remover este evento recorrente?\nEventos passados serão mantidos, mas nenhum evento seguinte será criado.",
"remove_recurrent_confirmation": "Têm a certeza que quer remover este evento recorrente?\nEventos passados serão mantidos, mas nenhum evento seguinte será criado.",
"import_URL": "Importar a partir de URL",
"import_ICS": "Importar a partir de ICS",
"import_description": "Você pode importar eventos de outras plataformas e outras instâncias através de formatos padrão (ics e h-event)",
"import_description": "Pode importar eventos de outras plataformas e de outros domínios via formatos padrão (ICS e H-Event)",
"alt_text_description": "Descrição para pessoas com deficiências visuais",
"choose_focal_point": "Escolha o ponto focal",
"remove_media_confirmation": "Você confirma a remoção da imagem?",
"remove_media_confirmation": "Confirma a remoção da imagem?",
"download_flyer": "Baixar flyer",
"address_description": "Qual é o endereço?",
"address_description_osm": "Qual é o endereço? (contribuidores do <a href='http://osm.org/copyright'>OpenStreetMap</a>)"
"address_description_osm": "Procure as coordenadas escrevendo o endereço. (contribuidores do <a href='http://osm.org/copyright'>OpenStreetMap</a>)",
"show_multidate": "Eventos com múltiplas datas",
"where_advanced_options": "Lugar — Opções avançadas",
"where_advanced_options_description": "Defina aqui propriedades do local adicionais",
"online_locations": "Localizações online",
"address_geocoded_disclaimer": "Se não conseguir encontrar o <strong>endereço da rua</strong> ou a <strong>porta da casa</strong> que procura nos resultados da geocodificação, pode inseri-los manualmente no campo “Endereço” sem perder as coordenadas. Considere também que o projeto <a target=\"_blank\" href=\"https://www.openstreetmap.org/\">OpenStreetMap</a> está aberto a contribuições. Se tiver Android, recomendamos o <a target=\"_blank\" href=\"https://f-droid.org/en/packages/de.westnordost.streetcomplete/\">StreetComplete</a>. ",
"online_locations_help": "Por exemplo, um link para uma sala de video-conferência e um link para outros recursos (máx. 3)",
"online_locations_fallback_urls": "Links de retorno"
},
"confirm": {
"not_valid": "Algo deu errado.",
"title": "Confirmação de usuário",
"valid": "Sua conta está confirmada, você pode agora <a href=\"/login\">autenticar-se</a>"
"valid": "A sua conta está confirmada, pode agora <a href=\"/login\">autenticar-se</a>"
},
"export": {
"intro": "Diferente de plataformas não-sociais que fazem tudo para manter os usuários e os dados sobre eles, nós acreditamos que a informação, como pessoas, deve ser livre. Para isso você se atualizar sobre os eventos de seu interesse, sem necessariamente entrar nesta página.",
"intro": "Diferente de plataformas não sociais que fazem tudo para manter os utilizadores e os dados sobre eles, nós acreditamos que a informação, como pessoas, deve ser livre. Para isso deve atualizar-se sobre os eventos do seu interesse, sem necessariamente entrar nesta página.",
"insert_your_address": "Informe seu endereço de e-mail",
"feed_description": "Para seguir as atualizações de um computador ou smartphone sem que você precise acessar essa página periodicamente, utilize um feeds RSS. </p>\n\n<p> Com feeds RSS você pode utilizar um app especial para receber atualizações de páginas que te interessam. É uma boa maneira de seguir muitas páginas rapidamente, sem a necessidade de criar contas de usuários ou outras complicações. </p>\n\n<li> Se você possui um Android, recomendamos <a href=\"https://f-droid.org/en/packages/net.frju.flym/\">Flym</a> ou Feeder </li>\n<li> Para iPhone / iPad você pode utilizar <a href=\"https://itunes.apple.com/ua/app/feeds4u/id1038456442?mt=8\"> Feed4U </a> </li>\n<li> Para desktop / laptop nós recomendamos Feedbro, que pode ser instalado no <a href=\"https://addons.mozilla.org/en-GB/firefox/addon/feedbroreader/\"> Firefox </a> ou <a href=\"https://chrome.google.com/webstore/detail/feedbro/mefgmmbdailogpfhfblcnnjfmnpnmdfa\"> Chrome </a>. </li>\n<br/>\nAdicionado este link ao seu leitor de RSS irá mantê-lo atualizado.",
"feed_description": "Para seguir as atualizações de um computador ou telemóvel sem que precise de aceder a esta página periodicamente, utilize um leitor de feeds RSS. </p>\n\n<p> Com feeds RSS pode utilizar uma aplicação especial para receber atualizações de páginas que sejam do teu interesse. É uma boa maneira de seguir muitas páginas rapidamente, sem a necessidade de criar contas de utilizadores ou outras complicações. </p>\n\n<li> Se possui um Android, recomendamos <a href=\"https://f-droid.org/en/packages/net.frju.flym/\">Flym</a> ou Feeder </li>\n<li> Para iPhone / iPad pode utilizar <a href=\"https://itunes.apple.com/ua/app/feeds4u/id1038456442?mt=8\"> Feed4U </a> </li>\n<li> Para computador fixo/ portátil nós recomendamos Feedbro, que pode ser instalado no <a href=\"https://addons.mozilla.org/en-GB/firefox/addon/feedbroreader/\"> Firefox </a> ou <a href=\"https://chrome.google.com/webstore/detail/feedbro/mefgmmbdailogpfhfblcnnjfmnpnmdfa\"> Chrome </a>. </li>\n<br/>\nAdicionado este link ao seu leitor de RSS irá mantê-lo atualizado.",
"ical_description": "Computadores e smartphones normalmente possuem aplicações de calendário capazes de importar um calendário remoto.",
"list_description": "Se você tem uma página e quer exibir uma lista de eventos, use o seguinte código",
"email_description": "Você pode obter os eventos que te interessam através de e-mail."
"list_description": "Se m uma página e quer exibir uma lista de eventos, use o seguinte código",
"email_description": "Podes obter eventos que sejam do teu interesse via e-mail."
},
"oauth": {
"authorization_request": "A aplicação <code>{app}</code> solicita autorização em <code>{instance_name}</code>:",
"scopes": {
"event:write": "Adicionar e editar os seus eventos"
},
"redirected_to": "Depois da confirmação, você será redirecionado para <code>{url}</code>"
"redirected_to": "Depois da confirmação, será redirecionado para <code>{url}</code>"
},
"ordinal": {
"2": "segundo",
"1": "primeiro",
"5": "quinto",
"-1": "último",
"2": "segundo",
"3": "terceiro",
"4": "quarto"
"4": "quarto",
"5": "quinto",
"-1": "último"
},
"settings": {
"remove_account": "Ao pressionar este botão sua conta de usuário será removida. Eventos que você publicou serão mantidos.",
"remove_account_confirm": "Você está prestes a remover sua conta de usuário permanentemente",
"update_confirm": "Você quer salvar sua modificação?",
"remove_account": "Ao pressionar este botão a sua conta de utilizador será apagada. Eventos que publicou serão mantidos.",
"remove_account_confirm": "Está prestes a apagar a sua conta de utilizador permanentemente",
"update_confirm": "Quer salvar as suas alterações?",
"change_password": "Alterar sua senha",
"password_updated": "Senha alterada.",
"danger_section": "Seção perigosa"
@ -288,15 +318,17 @@
"nick_taken": "Este nome de usuário já está em uso."
},
"setup": {
"https_warning": "Você está acessando por HTTP, lembre-se de alterar o valor de baseurl em config.json se você mudar para HTTPS!",
"https_warning": "Está a aceder por HTTP, lembre-se de alterar o valor de baseurl em config.json se mudar para HTTPS!",
"completed": "Configuração completa",
"start": "Iniciar",
"completed_description": "<p>Você pode agora autenticar-se com o seguinte usuário:<br/><br/>Usuário: <b>{email}</b><br/>Senha: <b>{password}<b/></p>",
"copy_password_dialog": "Sim, você precisa copiar a senha!"
"completed_description": "<p>Pode agora autenticar-se com o seguinte utilizador:<br/><br/>Utilizador: <b>{email}</b><br/>Palavra-passe: <b>{password}<b/></p>",
"copy_password_dialog": "Sim, precisa copiar a palavra-passe!"
},
"validators": {
"email": "Insira um e-mail válido",
"required": "{fieldName} é obrigatório"
"required": "{fieldName} é obrigatório",
"longitude": "Insira uma longitude válida (-180 < longitude < 180)",
"latitude": "Insira uma latitude válida (90 < latitude < 90)"
},
"about": "\n <p><a href='https://gancio.org'>Gancio</a> é uma agenda compartilhada para comunidades locais.</p>\n ",
"login": {
@ -304,7 +336,7 @@
"forgot_password": "Esqueceu sua senha?",
"insert_email": "Informe seu endereço de e-mail",
"ok": "Autenticado",
"description": "Ao autenticar-se você pode publicar novos eventos.",
"description": "Ao autenticar-se pode publicar novos eventos.",
"check_email": "Verifique sua caixa de entrada e de spam.",
"error": "Autenticação não realizada. Verifique suas informações de autenticação."
},
@ -315,10 +347,10 @@
"error": "Erro: ",
"complete": "Registro precisa ser confirmado.",
"first_user": "Administrador criado",
"description": "Movimentos sociais devem se organizar e se auto financiar.<br/>\n<br/>Antes de poder publicar, <strong> a conta precisa ser aprovada</strong>, considere que <strong> atrás deste site você vai encontrar pessoas reais</strong>, então escreva duas linhas para nos informar que eventos você gostaria de publicar."
"description": "Movimentos sociais devem se organizar e autofinanciar-se.<br/>\n<br/>Antes de poder publicar, <strong> a conta precisa ser aprovada por um administrador</strong>, considere que <strong> atrás deste site vai encontrar pessoas reais</strong>, então escreva duas linhas para nos informar que eventos teria interesse em publicar."
},
"auth": {
"fail": "Autenticação não efetuada. Você está certo que sua senha está correta?",
"fail": "Autenticação não efetuada. Têm a certeza que a sua palavra-passe está correta?",
"not_confirmed": "Não confirmado ainda…"
}
}

1
locales/pt_PT.json Normal file
View file

@ -0,0 +1 @@
{}

View file

@ -96,7 +96,8 @@
"tag": "Тег",
"calendar": "Календарь",
"next": "След.",
"export": "Экспорт"
"export": "Экспорт",
"clone": "Клон"
},
"login": {
"description": "Войдя в систему, вы можете публиковать новые события.",

View file

@ -88,7 +88,8 @@
"copied": "Skopírované",
"embed": "Vložiť",
"instances": "Inštancie",
"embed_title": "Vložiť toto podujatie na tvoju web stránku"
"embed_title": "Vložiť toto podujatie na tvoju web stránku",
"clone": "Klonovať"
},
"login": {
"description": "Po prihlásení sa môžete publikovat nové podujatia.",

View file

@ -88,7 +88,8 @@
"close": "关闭",
"disable": "禁用",
"password_updated": "密码已修改。",
"reset": "重置"
"reset": "重置",
"clone": "克隆"
},
"export": {
"list_description": "如果你有一个网站并希望展示一个事件列表,使用以下代码",
@ -264,12 +265,12 @@
"valid": "你的账户已被确认,你现在可以 <a href=\"/login\">登录</a>"
},
"ordinal": {
"1": "第一",
"2": "第二",
"3": "第三",
"4": "第四",
"5": "第五",
"2": "第二",
"-1": "最后",
"1": "第一",
"3": "第三"
"-1": "最后"
},
"validators": {
"required": "{fieldName} 是必填项",

View file

@ -1,6 +1,9 @@
const config = require('./server/config.js')
const locales = require('./locales/index')
import { ca, de, en, es, eu, fr, gl, it, nb, nl, pl, pt, sk, ru, zhHans } from 'vuetify/es5/locale'
import { ca, cs, de, en, es, eu, fr, gl, it, nb, nl, pl, pt, sk, ru, zhHans } from 'vuetify/es5/locale'
const dns = require('node:dns')
dns.setDefaultResultOrder('ipv4first')
const isDev = (process.env.NODE_ENV !== 'production')
module.exports = {
@ -141,7 +144,7 @@ module.exports = {
},
buildModules: ['@nuxtjs/vuetify'],
vuetify: {
lang: { locales: { ca, de, en, es, eu, fr, gl, it, nb, nl, pl, pt, sk, ru, zhHans } },
lang: { locales: { ca, cs, de, en, es, eu, fr, gl, it, nb, nl, pl, pt, sk, ru, zhHans } },
treeShake: true,
defaultAssets: false,
optionsPath: './vuetify.options.js' },

View file

@ -1,6 +1,6 @@
{
"name": "gancio",
"version": "1.6.14-beta",
"version": "1.6.19",
"description": "A shared agenda for local communities",
"author": "lesion",
"scripts": {
@ -33,46 +33,45 @@
"yarn.lock"
],
"engines": {
"node": ">=15 <=16"
"node": ">=14 <=18"
},
"dependencies": {
"@mdi/js": "^7.1.96",
"@mdi/js": "^7.3.67",
"@nuxtjs/auth": "^4.9.1",
"@nuxtjs/axios": "^5.13.5",
"@nuxtjs/i18n": "^7.3.0",
"@nuxtjs/sitemap": "^2.4.0",
"accept-language": "^3.0.18",
"axios": "^0.27.2",
"bcryptjs": "^2.4.3",
"body-parser": "^1.20.2",
"cookie-parser": "^1.4.6",
"cookie-session": "^2.0.0",
"cookie-universal-nuxt": "^2.2.2",
"cors": "^2.8.5",
"dayjs": "^1.11.8",
"dompurify": "^3.0.3",
"email-templates": "^10.0.1",
"dayjs": "^1.11.10",
"dompurify": "^3.0.6",
"email-templates": "^11.1.1",
"express": "^4.18.1",
"express-rate-limit": "^6.7.0",
"express-rate-limit": "^7.1.1",
"http-signature": "^1.3.6",
"https-proxy-agent": "^5.0.1",
"https-proxy-agent": "^7.0.2",
"ical.js": "^1.5.0",
"ics": "^3.1.0",
"jsdom": "^21.1.0",
"ics": "^3.5.0",
"jsdom": "^22.1.0",
"leaflet": "^1.9.4",
"linkify-html": "^4.1.1",
"linkifyjs": "4.1.1",
"lodash": "^4.17.21",
"luxon": "^3.3.0",
"mariadb": "^2.5.6",
"luxon": "^3.4.3",
"mariadb": "^3.2.2",
"memory-cache": "^0.2.0",
"microformat-node": "^2.0.1",
"minify-css-string": "^1.0.0",
"mkdirp": "^2.1.6",
"mkdirp": "^3.0.1",
"multer": "^1.4.5-lts.1",
"mysql2": "^2.3.3",
"nuxt-edge": "2.17.0-28098741.f3c5f95",
"oauth2orize": "^1.11.1",
"nuxt-edge": "2.17.2-28258581.6132947",
"oauth2orize": "^1.12.0",
"passport": "^0.6.0",
"passport-anonymous": "^1.0.1",
"passport-custom": "^1.1.1",
@ -80,32 +79,33 @@
"passport-http-bearer": "^1.0.1",
"passport-oauth2-client-password": "^0.1.2",
"passport-oauth2-client-public": "^0.0.1",
"pg": "^8.11.0",
"sequelize": "^6.32.0",
"pg": "^8.11.3",
"semver": "^7.5.4",
"sequelize": "^6.33.0",
"sequelize-slugify": "^1.6.2",
"sharp": "^0.27.2",
"sqlite3": "^5.1.4",
"telegraf": "^4.12.2",
"telegraf": "^4.14.0",
"tiptap": "^1.32.0",
"tiptap-extensions": "^1.35.0",
"umzug": "^2.3.0",
"v-calendar": "^2.4.1",
"v-calendar": "^2.4.2",
"vue2-leaflet": "^2.7.1",
"vuetify": "2.6.14",
"winston": "^3.8.2",
"winston": "^3.11.0",
"winston-daily-rotate-file": "^4.7.1",
"yargs": "^17.7.2"
},
"devDependencies": {
"@nuxtjs/vuetify": "^1.12.3",
"@vue/language-plugin-pug": "^1.7.0",
"jest": "^29.5.0",
"jest-environment-node": "^29.5.0",
"@vue/language-plugin-pug": "^1.8.19",
"jest": "^29.7.0",
"jest-environment-node": "^29.7.0",
"prettier": "^2.8.8",
"pug": "^3.0.2",
"pug-plain-loader": "^1.1.0",
"sass": "^1.61.0",
"sequelize-cli": "^6.3.0",
"sass": "^1.67.0",
"sequelize-cli": "^6.6.1",
"supertest": "^6.3.3",
"webpack": "4",
"webpack-cli": "^4.10.0"

View file

@ -3,7 +3,8 @@ v-container.container.pa-0.pa-md-3
v-card
v-alert(v-if='url!==settings.baseurl' outlined type='warning' show-icon :icon='mdiAlert')
span(v-html="$t('admin.wrong_domain_warning', { url, baseurl: settings.baseurl })")
v-alert(v-if='!selfReachable' outlined type='warning' show-icon :icon='mdiAlert')
span(v-html="$t('admin.not_reachable')")
v-tabs(v-model='selectedTab' show-arrows :next-icon='mdiChevronRight' :prev-icon='mdiChevronLeft')
//- SETTINGS
@ -102,9 +103,10 @@ export default {
try {
const users = await $axios.$get('/users')
const unconfirmedEvents = await $axios.$get('/event/unconfirmed')
return { users, unconfirmedEvents, url }
const selfReachable = await $axios.$get('/reachable')
return { users, unconfirmedEvents, url, selfReachable }
} catch (e) {
return { users: [], unconfirmedEvents: [], url }
return { users: [], unconfirmedEvents: [], url, selfReachable: false }
}
},
data () {
@ -113,6 +115,7 @@ export default {
users: [],
description: '',
unconfirmedEvents: [],
selfReachable: false
}
},
head () {

View file

@ -105,12 +105,12 @@ export default {
return true
},
async asyncData({ params, $axios, error, $auth, $time }) {
async asyncData({ query, params, $axios, error, $auth, $time, store }) {
if (params.edit) {
const data = { event: { place: {}, media: [] } }
data.id = params.edit
data.edit = true
data.edit = query.clone ? false : true
let event
try {
event = await $axios.$get('/event/detail/' + data.id)
@ -138,8 +138,13 @@ export default {
data.event.title = event.title
data.event.description = event.description
if (data.edit) {
data.event.id = event.id
}
data.event.tags = event.tags
if (event.media && event.media.length > 0 && !data.edit) {
event.media[0].url = `${store.state.settings.baseurl}/media/${event.media[0].url}`
}
data.event.media = event.media || []
data.event.parentId = event.parentId
data.event.recurrent = event.recurrent

View file

@ -1,10 +1,10 @@
<template lang="pug">
v-container#event.h-event.pa-2.pa-sm-2(itemscope itemtype="https://schema.org/Event" v-touch="{ left: goNext, right: goPrev }")
v-container#event.h-event.pa-2.pa-sm-2(v-touch="{ left: goNext, right: goPrev }")
//- EVENT PAGE
//- gancio supports microformats (http://microformats.org/wiki/h-event)
//- and microdata https://schema.org/Event
v-row
v-row(itemscope itemtype="https://schema.org/Event")
v-col.col-12.col-md-8
MyPicture(v-if='hasMedia' :event='event')
.p-description.text-body-1.pa-3.rounded(v-if='!hasMedia && event.description' itemprop='description' v-html='event.description')
@ -19,7 +19,7 @@ v-container#event.h-event.pa-2.pa-sm-2(itemscope itemtype="https://schema.org/Ev
v-container.eventDetails
time.dt-start(:datetime='$time.unixFormat(event.start_datetime, "yyyy-MM-dd HH:mm")' itemprop="startDate" :content='$time.unixFormat(event.start_datetime, "yyyy-MM-dd\'T\'HH:mm")')
v-icon(v-text='mdiCalendar' small)
strong.ml-2.text-uppercase {{$time.when(event)}}
span.ml-2.text-uppercase {{$time.when(event)}}
.d-none.dt-end(v-if='event.end_datetime' itemprop="endDate" :content='$time.unixFormat(event.end_datetime,"yyyy-MM-dd\'T\'HH:mm")') {{$time.unixFormat(event.end_datetime,"yyyy-MM-dd'T'HH:mm")}}
div.font-weight-light.mb-3 {{$time.from(event.start_datetime)}}
small(v-if='event.parentId') ({{$time.recurrentDetail(event)}})
@ -46,9 +46,6 @@ v-container#event.h-event.pa-2.pa-sm-2(itemscope itemtype="https://schema.org/Ev
v-divider
//- info & actions
v-list(dense nav color='transparent')
//- v-list-group(:append-icon='mdiChevronUp' :value='true')
//- template(v-slot:activator)
//- v-list-item.text-overline {{$t('common.actions')}}
//- copy link
v-list-item(@click='clipboard(`${settings.baseurl}/event/${event.slug || event.id}`)')
@ -190,8 +187,6 @@ import EventAdmin from '@/components/eventAdmin'
import EmbedEvent from '@/components/embedEvent'
import EventMapDialog from '@/components/EventMapDialog'
const { htmlToText } = require('html-to-text')
import { mdiArrowLeft, mdiArrowRight, mdiDotsVertical, mdiCodeTags, mdiClose, mdiMap,
mdiEye, mdiEyeOff, mdiDelete, mdiRepeat, mdiLock, mdiFileDownloadOutline, mdiShareAll,
mdiCalendarExport, mdiCalendar, mdiContentCopy, mdiMapMarker, mdiChevronUp, mdiMonitorAccount, mdiBookmark } from '@mdi/js'
@ -314,7 +309,7 @@ export default {
return this.event.media && this.event.media.length
},
plainDescription () {
return htmlToText(this.event.description && this.event.description.replace('\n', '').slice(0, 1000))
return this.event.plain_description || ''
},
currentAttachmentLabel () {
return get(this.selectedResource, `data.attachment[${this.currentAttachment}].name`, '')

View file

@ -4,13 +4,11 @@ v-container.pa-0.pa-md-3
v-card-title {{$t('common.share')}}
v-card-text
p.text-body-1 {{$t('export.intro')}}
v-row
v-col(:md='2' :cols='12')
v-card-title.py-0 {{$t('common.filter')}}
v-col
Search(
:filters='filters'
@update='f => filters = f')
v-card(outlined :dark='is_dark' :color="is_dark ? '#333' : '#ececec'")
v-card-title {{$t('common.filter')}}
v-card-subtitle {{$t('export.filter_description')}}
v-card-text
Search(v-model='filters')
v-tabs(v-model='type' show-arrows :next-icon='mdiChevronRight' :prev-icon='mdiChevronLeft')
//- TOFIX
@ -52,13 +50,14 @@ v-container.pa-0.pa-md-3
v-col.col-12.col-lg-4
v-text-field(v-model='list.title' :label='$t("common.title")')
v-text-field(v-model='list.maxEvents' type='number' min='1' :label='$t("common.max_events")')
v-switch(v-model='list.theme' inset true-value='dark' false-value='light' :label="$t('admin.is_dark')")
v-switch(v-model='list.theme' hide-details inset true-value='dark' false-value='light' :label="$t('admin.is_dark')")
v-switch(v-model='list.sidebar' inset true-value='true' false-value='false' :label="$t('admin.widget')")
v-col.col-12.col-lg-8
gancio-events(:baseurl='settings.baseurl'
:maxlength='list.maxEvents && Number(list.maxEvents)'
:title='list.title'
:theme='list.theme'
:collection='filters.collection'
:places='filters.places.join(",")'
:tags='filters.tags.join(",")'
:show_recurrent='filters.show_recurrent'
@ -81,7 +80,7 @@ v-container.pa-0.pa-md-3
</template>
<script>
import { mapState } from 'vuex'
import { mapState, mapGetters } from 'vuex'
import FollowMe from '../components/FollowMe'
import Search from '@/components/Search'
import clipboard from '../assets/clipboard'
@ -112,7 +111,7 @@ export default {
theme: $store.state.settings['theme.is_dark'] ? 'dark' : 'light',
sidebar: 'true'
},
filters: { tags: [], places: [], show_recurrent: $store.state.settings.recurrent_event_visible },
filters: { tags: [], places: [], collection: undefined, show_recurrent: $store.state.settings.recurrent_event_visible },
events: []
}
},
@ -123,6 +122,7 @@ export default {
},
computed: {
...mapState(['settings']),
...mapGetters(['is_dark']),
code () {
const params = [`baseurl="${this.settings.baseurl}"`]
@ -130,6 +130,9 @@ export default {
params.push(`title="${this.list.title}"`)
}
if (this.filters.collection) {
params.push(`collection="${this.filters.collection}"`)
} else {
if (this.filters.places.length) {
params.push(`places="${this.filters.places.join(',')}"`)
}
@ -137,6 +140,7 @@ export default {
if (this.filters.tags.length) {
params.push(`tags="${this.filters.tags.join(',')}"`)
}
}
if (this.filters.show_recurrent) {
params.push(`show_recurrent="${this.filters.show_recurrent}"`)
@ -158,6 +162,10 @@ export default {
const typeMap = ['rss', 'ics']
const params = []
if (this.filters.collection) {
return `${this.settings.baseurl}/feed/${typeMap[this.type]}/collection/${encodeURIComponent(this.filters.collection)}`
} else {
if (this.filters.tags.length) {
params.push(`tags=${this.filters.tags.map(encodeURIComponent).join(',')}`)
}
@ -165,6 +173,7 @@ export default {
if (this.filters.places.length) {
params.push(`places=${this.filters.places.join(',')}`)
}
}
if (this.filters.show_recurrent) {
params.push('show_recurrent=true')

View file

@ -1,5 +1,6 @@
<template lang='pug'>
v-container
v-form(@submit.prevent="change_password" v-model='valid')
v-row.mt-5(align='center' justify='center')
v-col(cols='12' md="6" lg="5" xl="4")
v-card
@ -11,14 +12,17 @@ v-container
:rules="$validators.password"
autofocus :placeholder='$t("common.new_password")'
v-model='new_password')
div(v-else) {{$t('recover.not_valid_code')}}
template(v-else)
v-card-text
v-alert(type='error' :icon='mdiAlert') {{$t('recover.not_valid_code')}} <br/> {{ error }}
v-card-actions
v-spacer
v-btn(v-if='user' text color='primary' @click='change_password') {{$t('common.send')}}
v-btn(v-if='user' outlined color='primary' type='submit' :disabled='!valid') {{$t('common.send')}}
</template>
<script>
import { mapState } from 'vuex'
import { mdiAlert } from '@mdi/js'
export default {
name: 'Recover',
@ -28,11 +32,11 @@ export default {
const user = await $axios.$post('/user/check_recover_code', { recover_code: code })
return { user, code }
} catch (e) {
return { user: false }
return { user: false, error: String(e) }
}
},
data () {
return { new_password: '' }
return { new_password: '', valid: false, mdiAlert }
},
computed: mapState(['settings']),
methods: {

View file

@ -15,10 +15,11 @@ v-container
v-btn(color="primary" type='submit' :disabled='!new_password' @click='change_password' outlined) {{$t('common.send')}}
v-card-text(v-else)
v-alert.ma-5(type='error') {{$t('recover.not_valid_code')}}
v-alert.ma-5(type='error' :icon='mdiAlert') {{$t('recover.not_valid_code')}} <br/> {{ error }}
</template>
<script>
import { mdiAlert } from '@mdi/js'
export default {
name: 'Recover',
@ -28,11 +29,11 @@ export default {
const user = await $axios.$post('/user/check_recover_code', { recover_code: code })
return { user, code }
} catch (e) {
return { user: false }
return { user: false, error: String(e) }
}
},
data () {
return { new_password: '' }
return { new_password: '', mdiAlert }
},
methods: {
async change_password () {

View file

@ -1,9 +1,62 @@
const express = require('express')
const myPluginRouter = express.Router()
// this will answer at http://localhost:13120/api/plugin/Example/test
myPluginRouter.get('/test', (req, res) => {
return res.json('OK!')
})
const plugin = {
routeAPI: myPluginRouter,
configuration: {
name: 'Example',
author: 'lesion',
url: 'https://framagit.org/les/gancio',
description: 'Example plugin',
settings: {
my_plugin_string_setting: {
type: 'TEXT',
description: 'My plugin string setting',
required: true,
hint: 'My plugin setting support <strong>html too</strong>'
},
enable_this_feature_in_my_plugin: {
type: 'CHECK',
description: 'My plugin best feature',
required: true,
hint: 'This feature is super dupe, enable it!'
},
min_post: {
type: 'NUMBER',
description: 'it supports number too'
},
my_default_language: {
description: 'My default language',
type: 'LIST',
items: ['it', 'en', 'fr']
}
}
},
gancio: null,
load (gancio) {
settings: null,
load (gancio, settings) {
console.error('Plugin GancioPluginExample loaded!')
console.error('Your settings are in ', settings)
console.error(`For example, you can access to your default language setting by using ${settings.my_default_language}`)
plugin.gancio = gancio
plugin.settings = settings
// gancio.db.models.event.findAll({ where: })
// gancio.db.query('CREATE TABLE IF NOT EXISTS ()... ')
},
unload () {
console.error('Unload this plugin!')
},
onTest () {
console.error('called on "TEST" button pressed in admin interface')
},
onEventCreate (event) {

View file

@ -4,6 +4,22 @@ export default ({ app, store }, inject) => {
Settings.defaultLocale = app.i18n.locale || store.state.settings.instance_locale
const time = {
timeFormat () {
const time = DateTime.fromObject({ hour: 14 }, {
zone: store.state.settings.instance_timezone,
locale: app.i18n.locale || store.state.settings.instance_locale
}).toLocaleString({ hour: 'numeric'})
return time === '2 PM' ? 'ampm' : '24hr'
},
formatHour (value, format) {
if (!value) return ''
return DateTime.fromFormat(value, 'HH:mm', {
zone: store.state.settings.instance_timezone,
locale: app.i18n.locale || store.state.settings.instance_locale
}).toLocaleString({ hour: '2-digit', minute: '2-digit'})
},
format (date, format) {
return DateTime.fromISO(date, {
zone: store.state.settings.instance_timezone,
@ -46,11 +62,11 @@ export default ({ app, store }, inject) => {
}
const start = DateTime.fromSeconds(event.start_datetime, opt)
let time = start.toFormat('EEEE d MMMM HH:mm')
let time = start.toLocaleString({ weekday: 'long', month: 'short', day: '2-digit', hour: '2-digit', minute: '2-digit' })
const end = event.end_datetime && DateTime.fromSeconds(event.end_datetime, opt)
if (end) {
time += event.multidate ? `${end.toFormat('EEEE d MMMM')}` : `-${end.toFormat('HH:mm')}`
time += event.multidate ? `${end.toLocaleString({ weekday: 'long', month: 'short', day: '2-digit'})}` : `-${end.toLocaleString({hour: '2-digit', minute: '2-digit'})}`
}
if (currentYear !== start.year) {
@ -73,14 +89,18 @@ export default ({ app, store }, inject) => {
recurrentDetail (event) {
const opt = {
zone,
locale: app.i18n.locale || store.state.settings.instance_locale
}
const parent = event.parent
if (!parent.recurrent || !parent.recurrent.frequency) return 'error!'
const { frequency, type } = parent.recurrent
let recurrent
if (frequency === '1w' || frequency === '2w') {
recurrent = app.i18n.t(`event.recurrent_${frequency}_days`, { days: DateTime.fromSeconds(parent.start_datetime).toFormat('EEEE') })
recurrent = app.i18n.t(`event.recurrent_${frequency}_days`, { days: DateTime.fromSeconds(parent.start_datetime, opt).toFormat('EEEE')})
} else if (frequency === '1m' || frequency === '2m') {
const d = type === 'ordinal' ? DateTime.fromSeconds(parent.start_datetime).day : DateTime.fromSeconds(parent.start_datetime).toFormat('EEEE')
const d = type === 'ordinal' ? DateTime.fromSeconds(parent.start_datetime, opt).day : DateTime.fromSeconds(parent.start_datetime, opt).toFormat('EEEE')
if (type === 'ordinal') {
recurrent = app.i18n.t(`event.recurrent_${frequency}_days`, { days: d })
} else {
@ -116,6 +136,7 @@ export default ({ app, store }, inject) => {
const now = DateTime.local(opt).toUnixInteger()
for (const e of events) {
const tmp = DateTime.fromSeconds(e.start_datetime, opt)
if (!tmp || !tmp.year) continue
const start = DateTime.local().set({ year: tmp.year, month: tmp.month, day: tmp.day })
// merge events with same date
const key = `${start.month}${start.day}`

View file

@ -1,14 +1,15 @@
const { Collection, Filter, Event, Tag, Place } = require('../models/models')
const exportController = require('./export')
const log = require('../../log')
const { DateTime } = require('luxon')
const { col: Col } = require('../../helpers')
const { col: Col, queryParamToBool } = require('../../helpers')
const { Op, Sequelize } = require('sequelize')
const collectionController = {
async getAll (req, res) {
const withFilters = req.query.withFilters
const withFilters = queryParamToBool(req.query.withFilters)
let collections
if (withFilters) {
collections = await Collection.findAll({ include: [ Filter ] })
@ -19,18 +20,39 @@ const collectionController = {
return res.json(collections)
},
// return events from collection
async getEvents (req, res) {
const name = req.params.name
const format = req.params.format || 'json'
try {
const events = await collectionController._getEvents(name)
switch (format) {
case 'rss':
return exportController.feed(req, res, events,
`${res.locals.settings.title} - Collection @${name}`,
`${res.locals.settings.baseurl}/feed/rss/collection/${name}`)
case 'ics':
return exportController.ics(req, res, events)
default:
return res.json(events )
}
} catch (e) {
log.error(e)
return res.sendStatus(404)
}
},
// return events from collection
async _getEvents (name) {
const collection = await Collection.findOne({ where: { name } })
if (!collection) {
return res.sendStatus(404)
throw new Error(`Collection ${name} not found`)
}
const filters = await Filter.findAll({ where: { collectionId: collection.id } })
const filters = await Filter.findAll({ where: { collectionId: collection.id } })
if (!filters.length) {
return res.json([])
return []
}
const start = DateTime.local().toUnixInteger()
const where = {
@ -40,10 +62,7 @@ const collectionController = {
// confirmed event only
is_visible: true,
// [Op.or]: {
start_datetime: { [Op.gte]: start },
// end_datetime: { [Op.gte]: start }
// }
}
const replacements = []
@ -67,7 +86,7 @@ const collectionController = {
const events = await Event.findAll({
where,
attributes: {
exclude: ['likes', 'boost', 'userId', 'is_visible', 'createdAt', 'updatedAt', 'description', 'resources']
exclude: ['likes', 'boost', 'userId', 'is_visible', 'createdAt', 'description', 'resources']
},
order: ['start_datetime'],
include: [
@ -86,14 +105,12 @@ const collectionController = {
return []
})
const ret = events.map(e => {
return events.map(e => {
e = e.get()
e.tags = e.tags ? e.tags.map(t => t && t.tag) : []
return e
})
return res.json(ret)
},
async add (req, res) {

View file

@ -9,8 +9,9 @@ const { DateTime } = require('luxon')
const helpers = require('../../helpers')
const Col = helpers.col
const notifier = require('../../notifier')
const { htmlToText } = require('html-to-text')
const { Event, Resource, Tag, Place, Notification, APUser } = require('../models/models')
const { Event, Resource, Tag, Place, Notification, APUser, Collection } = require('../models/models')
const exportController = require('./export')
@ -47,7 +48,7 @@ const eventController = {
},
async searchMeta(req, res) {
const search = req.query.search
const search = req.query.search.toLocaleLowerCase()
const places = await Place.findAll({
order: [[Sequelize.col('w'), 'DESC']],
@ -74,6 +75,7 @@ const eventController = {
raw: true
})
const ret = places.map(p => {
p.type = 'place'
return p
@ -181,6 +183,8 @@ const eventController = {
event.next = next && (next.slug || next.id)
event.prev = prev && (prev.slug || prev.id)
event.tags = event.tags.map(t => t.tag)
event.plain_description = htmlToText(event.description, event.description.replace('\n', '').slice(0, 1000) )
if (format === 'json') {
res.json(event)
} else if (format === 'ics') {
@ -315,6 +319,26 @@ const eventController = {
return res.status(400).send(`${missing_field} required`)
}
// validate start_datetime and end_datetime
if (body.end_datetime) {
if (body.start_datetime > body.end_datetime) {
return res.status(400).send(`start datetime is greater than end datetime`)
}
if (Number(body.end_datetime) > 1000*24*60*60*365) {
return res.status(400).send('are you sure?')
}
}
if (!Number(body.start_datetime)) {
return res.status(400).send(`Wrong format for start datetime`)
}
if (Number(body.start_datetime) > 1000*24*60*60*365) {
return res.status(400).send('are you sure?')
}
// find or create the place
let place
try {
@ -597,6 +621,8 @@ const eventController = {
}
if (query) {
query = query.toLocaleLowerCase()
replacements.push(query)
replacements.push(query)
where[Op.or] =
[
@ -690,7 +716,7 @@ const eventController = {
const parentStartDatetime = DateTime.fromSeconds(e.start_datetime)
// cursor is when start to count
// sets it to
// in case parent is in past, start to calculate from now
let cursor = parentStartDatetime > startAt ? parentStartDatetime : startAt
startAt = cursor
@ -711,6 +737,8 @@ const eventController = {
cursor = cursor.plus({ days: 7 * Number(frequency[0]) })
}
} else if (frequency === '1m') {
// day n.X each month
if (type === 'ordinal') {
cursor = cursor.set({ day: parentStartDatetime.day })
@ -718,10 +746,10 @@ const eventController = {
cursor = cursor.plus({ months: 1 })
}
} else { // weekday
// get weekday
// get recurrent freq details
cursor = helpers.getWeekdayN(cursor, type, parentStartDatetime.weekday)
if (cursor< startAt) {
if (cursor < startAt) {
cursor = cursor.plus({ months: 1 })
cursor = helpers.getWeekdayN(cursor, type, parentStartDatetime.weekday)
}

View file

@ -4,6 +4,7 @@ const { htmlToText } = require('html-to-text')
const { Op, literal } = require('sequelize')
const { DateTime } = require('luxon')
const ics = require('ics')
const collectionController = require('./collection')
const exportController = {
@ -11,6 +12,7 @@ const exportController = {
const format = req.params.format
const tags = req.query.tags
const places = req.query.places
const collection = req.query.collection
const show_recurrent = !!req.query.show_recurrent
const opt = {
@ -21,6 +23,7 @@ const exportController = {
const where = {}
const yesterday = DateTime.local(opt).minus({day: 1}).toUnixInteger()
if (!collection) {
if (tags && places) {
where[Op.or] = {
@ -37,11 +40,19 @@ const exportController = {
where.placeId = places.split(',')
}
}
if (!show_recurrent) {
where.parentId = null
}
const events = await Event.findAll({
let events = []
if (collection) {
events = await collectionController._getEvents(collection)
console.error(events.map(e => e))
} else {
events = await Event.findAll({
order: ['start_datetime'],
attributes: { exclude: ['is_visible', 'recurrent', 'createdAt', 'likes', 'boost', 'userId', 'placeId'] },
where: {
@ -60,6 +71,7 @@ const exportController = {
},
{ model: Place, attributes: ['name', 'id', 'address'] }]
})
}
switch (format) {
case 'rss':
@ -109,11 +121,11 @@ const exportController = {
endInputType: 'utc',
title: `[${settings.title}] ${e.title}`,
description: htmlToText(e.description),
htmlContent: e.description.replace(/\n/g,"<br>"),
htmlContent: e.description && e.description.replace(/\n/g,"<br>"),
location,
url: `${settings.baseurl}/event/${e.slug || e.id}`,
status: 'CONFIRMED',
categories: e.tags.map(t => t.tag),
categories: e.tags.map(t => t.tag || t),
alarms
}

View file

@ -4,6 +4,7 @@ const log = require('../../log')
const config = require('../../config')
const settingsController = require('./settings')
const notifier = require('../../notifier')
const db = require('../models/index.js')
const pluginController = {
plugins: [],
@ -32,6 +33,22 @@ const pluginController = {
res.json()
},
async routeAPI (req, res, next) {
const pluginName = req.params.plugin
const plugin = pluginController.plugins.find(p => p.configuration.name === pluginName)
if (!plugin) {
log.warn(`Plugin ${pluginName} not found`)
return res.sendStatus(404)
}
if (typeof plugin.routeAPI !== 'function') {
log.warn(`Plugin ${pluginName} does not expose a 'routeAPI' function`)
return res.sendStatus(404)
}
return plugin.routeAPI(req, res, next)
},
async testPlugin (req, res) {
const pluginName = req.params.plugin
const plugin = pluginController.plugins.find(p => p.configuration.name === pluginName)
@ -69,7 +86,7 @@ const pluginController = {
}
if (plugin.unload && typeof plugin.unload === 'function') {
plugin.unload({ settings: settingsController.settings }, settings)
plugin.unload()
}
},
@ -96,7 +113,8 @@ const pluginController = {
plugin.load({
helpers: require('../../helpers'),
log,
settings: settingsController.settings
settings: settingsController.settings,
db: db.sequelize
},
settings)
}
@ -116,6 +134,8 @@ const pluginController = {
const pluginSetting = settingsController.settings['plugin_' + name]
if (pluginSetting.enable) {
pluginController.loadPlugin(name)
} else {
log.info(`Do not load plugin ${name} (${pluginFile}) as it is not enabled!`)
}
} else {
settingsController.set('plugin_' + name, { enable: false })

View file

@ -11,7 +11,7 @@ const userController = {
async forgotPassword (req, res) {
const email = req.body.email
const user = await User.findOne({ where: { email: { [Op.eq]: email } } })
const user = await User.findOne({ where: { email, is_active: true } })
if (!user) { return res.sendStatus(200) }
user.recover_code = crypto.randomBytes(16).toString('hex')
@ -62,13 +62,9 @@ const userController = {
if (!user) { return res.status(404).json({ success: false, message: 'User not found!' }) }
if (req.body.id !== req.user.id && !req.user.is_admin) {
return res.status(400).json({ succes: false, message: 'Not allowed' })
}
if (!req.body.password) { delete req.body.password }
if (!user.is_active && req.body.is_active && user.recover_code) {
if ((!user.is_active && req.body.is_active) || user.recover_code) {
mail.send(user.email, 'confirm', { user, config }, res.locals.settings.locale)
}
@ -89,6 +85,7 @@ const userController = {
}
req.body.is_active = false
req.body.is_admin = false
// check email
if (!linkify.test(req.body.email, 'email')) {

View file

@ -70,6 +70,7 @@ module.exports = () => {
```
*/
api.get('/ping', (_req, res) => res.sendStatus(200))
api.get('/reachable', helpers.reachable)
api.get('/user', isAuth, (req, res) => res.json(req.user))
api.post('/user/recover', SPAMProtectionApiRateLimiter, userController.forgotPassword)
@ -81,7 +82,7 @@ module.exports = () => {
api.post('/user', isAdmin, userController.create)
// update user
api.put('/user', isAuth, userController.update)
api.put('/user', isAdmin, userController.update)
// delete user
api.delete('/user/:id', isAdmin, userController.remove)
@ -145,7 +146,7 @@ module.exports = () => {
// remove event
api.delete('/event/:id', isAuth, eventController.remove)
// get tags/places
// get tags/places/collection
api.get('/event/meta', eventController.searchMeta)
// add event notification TODO
@ -223,6 +224,8 @@ module.exports = () => {
api.post('/plugin/test/:plugin', isAdmin, pluginController.testPlugin)
api.put('/plugin/:plugin', isAdmin, pluginController.togglePlugin)
api.use('/plugin/:plugin', pluginController.routeAPI)
// OAUTH
api.get('/clients', isAuth, oauthController.getClients)
api.get('/client/:client_id', isAuth, oauthController.getClient)

View file

@ -21,11 +21,11 @@ const instanceApiRateLimiter = {
* (used during the registration, pass recovery, posting events) */
SPAMProtectionApiRateLimiter: (process.env.NODE_ENV === 'test' ? next : rateLimit({
windowMs: 5 * 60 * 1000, // 5 minutes
max: 3, // Limit each IP to 3 requests per `window` (here, per 5 minutes)
max: 6, // Limit each IP to 3 requests per `window` (here, per 5 minutes)
standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
legacyHeaders: false, // Disable the `X-RateLimit-*` headers
handler: (request, response, next, options) => {
log.warn(`SPAM protection api rate limiter: 3req/5min/ip ${request.ip}`)
log.warn(`SPAM protection api rate limiter: 6req/5min/ip ${request.ip}`)
return response.status(options.statusCode).send(options.message)
}
}))

View file

@ -37,7 +37,7 @@ const mail = {
}
},
message: {
from: `📅 ${settings.title} <${settings.admin_email}>`
from: `"📅 ${settings.title}" <${settings.admin_email}>`
},
send: true,
i18n: {
@ -49,7 +49,7 @@ const mail = {
locale,
locales: Object.keys(locales)
},
transport: settings.smtp || {}
transport: { ...settings.smtp, tls: { ciphers: 'SSLv3'}, requireTLS: true } || {}
})
const opt = {

View file

@ -72,6 +72,7 @@ module.exports = (sequelize, DataTypes) => {
startTime: DateTime.fromSeconds(this.start_datetime, opt).toISO(),
...( this.end_datetime ? { endTime : DateTime.fromSeconds(this.end_datetime, opt).toISO() } : {} ),
location: {
type: 'Place',
name: this.place.name,
address: this.place.address,
latitude: this.place.latitude,

View file

@ -6,7 +6,7 @@ const config = require('../../config')
const log = require('../../log')
const SequelizeSlugify = require('sequelize-slugify')
const DB = require('./models')
const semver = require('semver')
const models = {
Announcement: require('./announcement'),
APUser: require('./ap_user'),
@ -107,8 +107,39 @@ const db = {
return true
}
},
async fixMariaDBJSON () {
// manually fix mariadb JSON wrong parse
if (db.sequelize.options.dialect === 'mariadb' && semver.lt('10.5.2', db.sequelize.options.databaseVersion)) {
try {
const ret = await db.sequelize.query('SHOW CREATE TABLE `settings`')
if (!ret[0][0]['Create Table'].toLowerCase().includes('json_valid')){
await db.sequelize.query('alter table settings modify `value` JSON')
await db.sequelize.query('alter table ap_users modify `object` JSON')
await db.sequelize.query('alter table events modify `recurrent` JSON')
await db.sequelize.query('alter table events modify `likes` JSON')
await db.sequelize.query('alter table events modify `boost` JSON')
await db.sequelize.query('alter table events modify `media` JSON')
await db.sequelize.query('alter table events modify `online_locations` JSON')
await db.sequelize.query('alter table filters modify `tags` JSON')
await db.sequelize.query('alter table filters modify `places` JSON')
await db.sequelize.query('alter table instances modify `data` JSON')
await db.sequelize.query('alter table notifications modify `filters` JSON')
await db.sequelize.query('alter table resources modify `data` JSON')
await db.sequelize.query('alter table users modify `settings` JSON')
await db.sequelize.query('alter table users modify `rsa` JSON')
log.info(`MariaDB JSON migrations done`)
} else {
log.debug('MariaDB JSON issue already fixed')
}
} catch (e) {
console.error(e)
}
}
},
async runMigrations() {
const logging = config.status !== 'READY' ? false : log.debug.bind(log)
const umzug = new Umzug({
storage: 'sequelize',
storageOptions: { sequelize: db.sequelize },

View file

@ -1,7 +1,7 @@
#!/usr/bin/env node
const pkg = require('../package.json')
const path = require('path')
const accountsCLI = require('./cli/accounts')
const usersCLI = require('./cli/users')
process.env.cwd = process.env.GANCIO_DATA || path.resolve('./')
@ -29,7 +29,7 @@ require('yargs')
return absolute_config_path
}})
.command(['start', 'run', '$0'], 'Start gancio', {}, start)
.command(['accounts'], 'Manage accounts', accountsCLI)
.command(['users'], 'Manage users', usersCLI)
.help('h')
.alias('h', 'help')
.epilog('Made with ❤ by underscore hacklab - https://gancio.org')

View file

@ -1,92 +0,0 @@
let db
function _initializeDB () {
const config = require('../config')
config.log_level = 'error'
db = require('../api/models/index')
return db.initialize()
}
async function modify (args) {
await _initializeDB()
const helpers = require('../helpers')
const { User } = require('../api/models/models')
const user = await User.findOne({ where: { email: args.account } })
console.log()
if (!user) {
console.error(`User ${args.account} not found`)
return
}
if (args['reset-password']) {
const password = helpers.randomString()
user.password = password
await user.save()
console.log(`New password for user ${user.email} is '${password}'`)
}
if (args.admin) {
user.is_admin = true
await user.save()
}
await db.close()
}
async function create (args) {
await _initializeDB()
const { User } = require('../api/models/models')
const user = await User.create({
email: args.email,
is_active: true,
is_admin: args.admin || false
}).catch(e => console.error(String(e)))
console.error(JSON.stringify(user, null, 2))
await db.close()
}
async function remove (args) {
await _initializeDB()
const { User } = require('../api/models/models')
const user = await User.findOne({
where: { email: args.email }
})
if (user) {
await user.destroy()
}
await db.close()
}
async function list () {
await _initializeDB()
const { User } = require('../api/models/models')
const users = await User.findAll()
console.log()
users.forEach(u => console.log(`${u.id}\tadmin: ${u.is_admin}\tenabled: ${u.is_active}\temail: ${u.email}`))
console.log()
await db.close()
}
const accountsCLI = yargs => yargs
.command('list', 'List all accounts', list)
.command('modify', 'Modify', {
account: {
describe: 'Account to modify',
type: 'string',
demandOption: true
},
'reset-password': {
describe: 'Resets the password of the given account ',
type: 'boolean'
},
admin: { describe: 'Define this account as administrator', type: 'boolean' }
}, modify)
.command('create <email|username> [admin]', 'Create an account', {
admin: { describe: 'Define this account as administrator', type: 'boolean' }
}, create)
.command('remove <email|username>', 'Remove an account', {}, remove)
.positional('email', { describe: 'account email or username', type: 'string', demandOption: true })
.recommendCommands()
.demandCommand(1, '')
.argv
module.exports = accountsCLI

124
server/cli/users.js Normal file
View file

@ -0,0 +1,124 @@
let db
function _initializeDB () {
const config = require('../config')
if (config.status !== 'CONFIGURED') {
console.error(`> Cannot run CLI before setup (are you in the correct path?)`)
process.exit(1)
}
config.log_level = 'error'
db = require('../api/models/index')
return db.initialize()
}
async function setAdmin (args) {
await _initializeDB()
const { User } = require('../api/models/models')
const user = await User.findOne({ where: { email: args.email } })
console.log()
if (!user) {
console.error(`User ${args.email} not found`)
return
}
user.is_admin = true
await user.save()
console.log(`User ${user.email} is now an administrator!`)
await db.close()
}
async function unsetAdmin (args) {
await _initializeDB()
const helpers = require('../helpers')
const { User } = require('../api/models/models')
const user = await User.findOne({ where: { email: args.email } })
console.log()
if (!user) {
console.error(`User ${args.email} not found`)
return
}
user.is_admin = false
await user.save()
console.log(`User ${user.email} is not an administrator anymore!`)
await db.close()
}
async function resetPassword (args) {
await _initializeDB()
const helpers = require('../helpers')
const { User } = require('../api/models/models')
const user = await User.findOne({ where: { email: args.email } })
console.log()
if (!user) {
console.error(`User ${args.email} not found`)
return
}
const password = helpers.randomString()
user.password = password
await user.save()
console.log(`New password for user ${user.email} is '${password}'`)
await db.close()
}
async function create (args) {
await _initializeDB()
const { User } = require('../api/models/models')
try {
const user = await User.create({
email: args.email,
password: args.password,
is_active: true,
is_admin: args.admin || false
})
console.error(`User ${args.email} created`)
} catch(e) {
console.error(String(e))
}
await db.close()
}
async function remove (args) {
await _initializeDB()
const { User } = require('../api/models/models')
const user = await User.findOne({
where: { email: args.email }
})
if (user) {
await user.destroy()
console.error(`User "${args.email}" succesfully removed`)
} else {
console.error(`User "${args.email}" not found!`)
}
await db.close()
}
async function list () {
await _initializeDB()
const { User } = require('../api/models/models')
const users = await User.findAll()
console.log()
users.forEach(u => console.log(`${u.id}\tadmin: ${u.is_admin}\tenabled: ${u.is_active}\temail: ${u.email}`))
console.log()
await db.close()
}
const usersCLI = yargs => yargs
.command('list', 'List all users', list)
.command('reset-password <email|username>', 'Resets the password of the given user', {
}, resetPassword)
.command('set-admin <email|username>', 'Set administrator privileges to the given user', {}, setAdmin)
.command('unset-admin <email|username>', 'Remove administrator privileges to the given user', {}, unsetAdmin)
.command('create <email|username> [password] [admin]', 'Create an user', {
admin: { describe: 'Define this user as administrator', type: 'boolean' },
}, create)
.command('remove <email|username>', 'Remove an user', {}, remove)
.positional('email', { describe: 'user email or username', type: 'string', demandOption: true })
.positional('password', { describe: 'Password', type: 'string', demandOption: false })
.recommendCommands()
.demandCommand(1, '')
.argv
module.exports = usersCLI

View file

@ -44,7 +44,7 @@ let config = {
}
} else {
config.status = 'SETUP'
console.info('> Configuration file does not exists, running setup..')
console.info('> Configuration file does not exists...')
}
}
}

View file

@ -36,7 +36,14 @@ router.get('/m/:event_id', async (req, res) => {
if (!event) { return res.status(404).send('Not found') }
const eventAp = event.toAP(settingsController.settings)
eventAp['@context'] = [
"https://www.w3.org/ns/activitystreams"
"https://www.w3.org/ns/activitystreams",
{
"sc": "http://schema.org/",
"address": {
"@id": "sc:address",
"@type": "sc:Text"
}
}
]
res.type('application/activity+json; charset=utf-8')

View file

@ -258,8 +258,8 @@ module.exports = {
}
} else {
cursor = date.startOf('month')
cursor = cursor.add(cursor.day() <= date.day() ? n - 1 : n, 'week')
cursor = cursor.plus({ days: cursor.weekday <= date.weekday ? (n-1) * 7 : n * 7})
// cursor = cursor.add(cursor.day <= date.day ? n - 1 : n, 'week')
cursor = cursor.plus({ weeks: cursor.weekday <= weekday ? n-1 : n })
cursor = cursor.set({ weekday })
}
cursor = cursor.set({ hour: date.hour, minute: date.minute, second: 0 })
@ -287,11 +287,26 @@ module.exports = {
next()
},
async reachable(req, res) {
try {
const response = await axios({ url: config.baseurl })
return res.sendStatus(200)
} catch(e) {
return res.status(400).json(e)
}
},
async isGeocodingEnabled(req, res, next) {
if (res.locals.settings.allow_geolocation) {
next()
} else {
res.sendStatus(403)
}
},
queryParamToBool (value, defaultValue) {
if (typeof value === 'undefined') return defaultValue
return (String(value).toLowerCase() === 'true')
}
}

View file

@ -30,6 +30,7 @@ const initialize = {
await db.sequelize.authenticate()
log.debug('Running migrations')
await db.runMigrations()
await db.fixMariaDBJSON()
await settingsController.load()
config.status = 'READY'
} else {

View file

@ -25,10 +25,10 @@ function ye(t) {
function u(t, e) {
t.appendChild(e);
}
function p(t, e, i) {
function k(t, e, i) {
t.insertBefore(e, i || null);
}
function k(t) {
function x(t) {
t.parentNode.removeChild(t);
}
function be(t, e) {
@ -38,14 +38,14 @@ function be(t, e) {
function m(t) {
return document.createElement(t);
}
function $(t) {
function z(t) {
return document.createTextNode(t);
}
function M() {
return $(" ");
function C() {
return z(" ");
}
function pe() {
return $("");
return z("");
}
function a(t, e, i) {
i == null ? t.removeAttribute(e) : t.getAttribute(e) !== i && t.setAttribute(e, i);
@ -69,25 +69,25 @@ let O;
function I(t) {
O = t;
}
function $e() {
function Ee() {
if (!O)
throw new Error("Function called outside component initialization");
return O;
}
function ke(t) {
$e().$$.on_mount.push(t);
Ee().$$.on_mount.push(t);
}
const R = [], Z = [], P = [], ee = [], Ee = Promise.resolve();
const R = [], Z = [], P = [], ee = [], $e = Promise.resolve();
let K = !1;
function je() {
K || (K = !0, Ee.then(x));
K || (K = !0, $e.then(y));
}
function Q(t) {
P.push(t);
}
const J = /* @__PURE__ */ new Set();
let D = 0;
function x() {
function y() {
const t = O;
do {
for (; D < R.length; ) {
@ -120,8 +120,8 @@ function Ce(t, e) {
function Ae(t, e, i, l) {
const { fragment: n, on_mount: r, on_destroy: o, after_update: f } = t.$$;
n && n.m(e, i), l || Q(() => {
const c = r.map(W).filter(ge);
o ? o.push(...c) : U(c), t.$$.on_mount = [];
const s = r.map(W).filter(ge);
o ? o.push(...s) : U(s), t.$$.on_mount = [];
}), f.forEach(Q);
}
function Me(t, e) {
@ -132,9 +132,9 @@ function Ne(t, e) {
t.$$.dirty[0] === -1 && (R.push(t), je(), t.$$.dirty.fill(0)), t.$$.dirty[e / 31 | 0] |= 1 << e % 31;
}
function we(t, e, i, l, n, r, o, f = [-1]) {
const c = O;
const s = O;
I(t);
const s = t.$$ = {
const c = t.$$ = {
fragment: null,
ctx: null,
props: r,
@ -146,26 +146,26 @@ function we(t, e, i, l, n, r, o, f = [-1]) {
on_disconnect: [],
before_update: [],
after_update: [],
context: new Map(e.context || (c ? c.$$.context : [])),
context: new Map(e.context || (s ? s.$$.context : [])),
callbacks: Y(),
dirty: f,
skip_bound: !1,
root: e.target || c.$$.root
root: e.target || s.$$.root
};
o && o(s.root);
o && o(c.root);
let w = !1;
if (s.ctx = i ? i(t, e.props || {}, (g, _, ...A) => {
const y = A.length ? A[0] : _;
return s.ctx && n(s.ctx[g], s.ctx[g] = y) && (!s.skip_bound && s.bound[g] && s.bound[g](y), w && Ne(t, g)), _;
}) : [], s.update(), w = !0, U(s.before_update), s.fragment = l ? l(s.ctx) : !1, e.target) {
if (c.ctx = i ? i(t, e.props || {}, (g, _, ...A) => {
const E = A.length ? A[0] : _;
return c.ctx && n(c.ctx[g], c.ctx[g] = E) && (!c.skip_bound && c.bound[g] && c.bound[g](E), w && Ne(t, g)), _;
}) : [], c.update(), w = !0, U(c.before_update), c.fragment = l ? l(c.ctx) : !1, e.target) {
if (e.hydrate) {
const g = xe(e.target);
s.fragment && s.fragment.l(g), g.forEach(k);
c.fragment && c.fragment.l(g), g.forEach(x);
} else
s.fragment && s.fragment.c();
e.intro && Ce(t.$$.fragment), Ae(t, e.target, e.anchor, e.customElement), x();
c.fragment && c.fragment.c();
e.intro && Ce(t.$$.fragment), Ae(t, e.target, e.anchor, e.customElement), y();
}
I(c);
I(s);
}
let X;
typeof HTMLElement == "function" && (X = class extends HTMLElement {
@ -213,11 +213,11 @@ function V(t) {
}
function te(t, e, i) {
const l = t.slice();
return l[12] = e[i], l;
return l[13] = e[i], l;
}
function ie(t, e, i) {
const l = t.slice();
return l[15] = e[i], l;
return l[16] = e[i], l;
}
function le(t) {
let e;
@ -226,13 +226,13 @@ function le(t) {
e = m("link"), a(e, "rel", "stylesheet"), a(e, "href", t[4]);
},
m(i, l) {
p(i, e, l);
k(i, e, l);
},
p(i, l) {
l & 16 && a(e, "href", i[4]);
},
d(i) {
i && k(e);
i && x(e);
}
};
}
@ -242,32 +242,32 @@ function ne(t) {
r[o] = fe(te(t, n, o));
return {
c() {
e = m("div"), l && l.c(), i = M();
e = m("div"), l && l.c(), i = C();
for (let o = 0; o < r.length; o += 1)
r[o].c();
a(e, "id", "gancioEvents"), L(e, "dark", t[2] === "dark"), L(e, "light", t[2] === "light"), L(e, "sidebar", t[3] === "true"), L(e, "nosidebar", t[3] !== "true");
},
m(o, f) {
p(o, e, f), l && l.m(e, null), u(e, i);
for (let c = 0; c < r.length; c += 1)
r[c].m(e, null);
k(o, e, f), l && l.m(e, null), u(e, i);
for (let s = 0; s < r.length; s += 1)
r[s].m(e, null);
},
p(o, f) {
if (o[1] && o[3] === "true" ? l ? l.p(o, f) : (l = re(o), l.c(), l.m(e, i)) : l && (l.d(1), l = null), f & 41) {
n = o[5];
let c;
for (c = 0; c < n.length; c += 1) {
const s = te(o, n, c);
r[c] ? r[c].p(s, f) : (r[c] = fe(s), r[c].c(), r[c].m(e, null));
let s;
for (s = 0; s < n.length; s += 1) {
const c = te(o, n, s);
r[s] ? r[s].p(c, f) : (r[s] = fe(c), r[s].c(), r[s].m(e, null));
}
for (; c < r.length; c += 1)
r[c].d(1);
for (; s < r.length; s += 1)
r[s].d(1);
r.length = n.length;
}
f & 4 && L(e, "dark", o[2] === "dark"), f & 4 && L(e, "light", o[2] === "light"), f & 8 && L(e, "sidebar", o[3] === "true"), f & 8 && L(e, "nosidebar", o[3] !== "true");
},
d(o) {
o && k(e), l && l.d(), be(r, o);
o && x(e), l && l.d(), be(r, o);
}
};
}
@ -275,23 +275,23 @@ function re(t) {
let e, i, l, n, r, o, f;
return {
c() {
e = m("a"), i = m("div"), l = m("div"), n = $(t[1]), r = M(), o = m("img"), a(l, "class", "title"), a(o, "id", "logo"), a(o, "alt", "logo"), H(o.src, f = t[0] + "/logo.png") || a(o, "src", f), a(i, "class", "content"), a(e, "href", t[0]), a(e, "target", "_blank"), a(e, "id", "header");
e = m("a"), i = m("div"), l = m("div"), n = z(t[1]), r = C(), o = m("img"), a(l, "class", "title"), a(o, "id", "logo"), a(o, "alt", "logo"), H(o.src, f = t[0] + "/logo.png") || a(o, "src", f), a(i, "class", "content"), a(e, "href", t[0]), a(e, "target", "_blank"), a(e, "id", "header");
},
m(c, s) {
p(c, e, s), u(e, i), u(i, l), u(l, n), u(i, r), u(i, o);
m(s, c) {
k(s, e, c), u(e, i), u(i, l), u(l, n), u(i, r), u(i, o);
},
p(c, s) {
s & 2 && T(n, c[1]), s & 1 && !H(o.src, f = c[0] + "/logo.png") && a(o, "src", f), s & 1 && a(e, "href", c[0]);
p(s, c) {
c & 2 && T(n, s[1]), c & 1 && !H(o.src, f = s[0] + "/logo.png") && a(o, "src", f), c & 1 && a(e, "href", s[0]);
},
d(c) {
c && k(e);
d(s) {
s && x(e);
}
};
}
function oe(t) {
let e;
function i(r, o) {
return r[12].media.length ? Le : Te;
return r[13].media.length ? Le : Te;
}
let l = i(t), n = l(t);
return {
@ -299,13 +299,13 @@ function oe(t) {
e = m("div"), n.c(), a(e, "class", "img");
},
m(r, o) {
p(r, e, o), n.m(e, null);
k(r, e, o), n.m(e, null);
},
p(r, o) {
l === (l = i(r)) && n ? n.p(r, o) : (n.d(1), n = l(r), n && (n.c(), n.m(e, null)));
},
d(r) {
r && k(e), n.d();
r && x(e), n.d();
}
};
}
@ -313,16 +313,16 @@ function Te(t) {
let e, i, l;
return {
c() {
e = m("img"), a(e, "style", "aspect-ratio=1.7778;"), a(e, "alt", i = t[12].title), H(e.src, l = t[0] + "/fallbackimage.png") || a(e, "src", l), a(e, "loading", "lazy");
e = m("img"), a(e, "style", "aspect-ratio=1.7778;"), a(e, "alt", i = t[13].title), H(e.src, l = t[0] + "/fallbackimage.png") || a(e, "src", l), a(e, "loading", "lazy");
},
m(n, r) {
p(n, e, r);
k(n, e, r);
},
p(n, r) {
r & 32 && i !== (i = n[12].title) && a(e, "alt", i), r & 1 && !H(e.src, l = n[0] + "/fallbackimage.png") && a(e, "src", l);
r & 32 && i !== (i = n[13].title) && a(e, "alt", i), r & 1 && !H(e.src, l = n[0] + "/fallbackimage.png") && a(e, "src", l);
},
d(n) {
n && k(e);
n && x(e);
}
};
}
@ -330,38 +330,38 @@ function Le(t) {
let e, i, l, n;
return {
c() {
e = m("img"), a(e, "style", i = "object-position: " + ue(t[12]) + "; aspect-ratio=1.7778;"), a(e, "alt", l = t[12].media[0].name), H(e.src, n = t[0] + "/media/thumb/" + t[12].media[0].url) || a(e, "src", n), a(e, "loading", "lazy");
e = m("img"), a(e, "style", i = "object-position: " + ue(t[13]) + "; aspect-ratio=1.7778;"), a(e, "alt", l = t[13].media[0].name), H(e.src, n = t[0] + "/media/thumb/" + t[13].media[0].url) || a(e, "src", n), a(e, "loading", "lazy");
},
m(r, o) {
p(r, e, o);
k(r, e, o);
},
p(r, o) {
o & 32 && i !== (i = "object-position: " + ue(r[12]) + "; aspect-ratio=1.7778;") && a(e, "style", i), o & 32 && l !== (l = r[12].media[0].name) && a(e, "alt", l), o & 33 && !H(e.src, n = r[0] + "/media/thumb/" + r[12].media[0].url) && a(e, "src", n);
o & 32 && i !== (i = "object-position: " + ue(r[13]) + "; aspect-ratio=1.7778;") && a(e, "style", i), o & 32 && l !== (l = r[13].media[0].name) && a(e, "alt", l), o & 33 && !H(e.src, n = r[0] + "/media/thumb/" + r[13].media[0].url) && a(e, "src", n);
},
d(r) {
r && k(e);
r && x(e);
}
};
}
function ae(t) {
let e, i = t[12].place.address + "", l;
let e, i = t[13].place.address + "", l;
return {
c() {
e = m("span"), l = $(i), a(e, "class", "subtitle");
e = m("span"), l = z(i), a(e, "class", "subtitle");
},
m(n, r) {
p(n, e, r), u(e, l);
k(n, e, r), u(e, l);
},
p(n, r) {
r & 32 && i !== (i = n[12].place.address + "") && T(l, i);
r & 32 && i !== (i = n[13].place.address + "") && T(l, i);
},
d(n) {
n && k(e);
n && x(e);
}
};
}
function se(t) {
let e, i = t[12].tags, l = [];
let e, i = t[13].tags, l = [];
for (let n = 0; n < i.length; n += 1)
l[n] = ce(ie(t, i, n));
return {
@ -372,13 +372,13 @@ function se(t) {
a(e, "class", "tags");
},
m(n, r) {
p(n, e, r);
k(n, e, r);
for (let o = 0; o < l.length; o += 1)
l[o].m(e, null);
},
p(n, r) {
if (r & 32) {
i = n[12].tags;
i = n[13].tags;
let o;
for (o = 0; o < i.length; o += 1) {
const f = ie(n, i, o);
@ -390,42 +390,41 @@ function se(t) {
}
},
d(n) {
n && k(e), be(l, n);
n && x(e), be(l, n);
}
};
}
function ce(t) {
let e, i, l = t[15] + "", n;
let e, i, l = t[16] + "", n;
return {
c() {
e = m("span"), i = $("#"), n = $(l), a(e, "class", "tag");
e = m("span"), i = z("#"), n = z(l), a(e, "class", "tag");
},
m(r, o) {
p(r, e, o), u(e, i), u(e, n);
k(r, e, o), u(e, i), u(e, n);
},
p(r, o) {
o & 32 && l !== (l = r[15] + "") && T(n, l);
o & 32 && l !== (l = r[16] + "") && T(n, l);
},
d(r) {
r && k(e);
r && x(e);
}
};
}
function fe(t) {
let e, i, l, n, r = V(t[12]) + "", o, f, c, s = t[12].title + "", w, g, _, A, y = t[12].place.name + "", d, z, h, v, C, q, E = t[3] !== "true" && oe(t), j = t[12].place.name !== "online" && ae(t), S = t[12].tags.length && se(t);
let e, i, l, n, r = V(t[13]) + "", o, f, s, c = t[13].title + "", w, g, _, A, E = t[13].place.name + "", M, d, h, p, v, q, $ = t[3] !== "true" && oe(t), j = t[13].place.name !== "online" && ae(t), S = t[13].tags.length && se(t);
return {
c() {
e = m("a"), E && E.c(), i = M(), l = m("div"), n = m("div"), o = $(r), f = M(), c = m("div"), w = $(s), g = M(), _ = m("span"), A = $('@"'), d = $(y), z = $(`"
`), j && j.c(), h = M(), S && S.c(), v = M(), a(n, "class", "subtitle"), a(c, "class", "title"), a(_, "class", "place"), a(l, "class", "content"), a(e, "href", C = t[0] + "/event/" + (t[12].slug || t[12].id)), a(e, "class", "event"), a(e, "title", q = t[12].title), a(e, "target", "_blank");
e = m("a"), $ && $.c(), i = C(), l = m("div"), n = m("div"), o = z(r), f = C(), s = m("div"), w = z(c), g = C(), _ = m("span"), A = z("@"), M = z(E), d = C(), j && j.c(), h = C(), S && S.c(), p = C(), a(n, "class", "subtitle"), a(s, "class", "title"), a(_, "class", "place"), a(l, "class", "content"), a(e, "href", v = t[0] + "/event/" + (t[13].slug || t[13].id)), a(e, "class", "event"), a(e, "title", q = t[13].title), a(e, "target", "_blank");
},
m(b, N) {
p(b, e, N), E && E.m(e, null), u(e, i), u(e, l), u(l, n), u(n, o), u(l, f), u(l, c), u(c, w), u(l, g), u(l, _), u(_, A), u(_, d), u(_, z), j && j.m(_, null), u(l, h), S && S.m(l, null), u(e, v);
k(b, e, N), $ && $.m(e, null), u(e, i), u(e, l), u(l, n), u(n, o), u(l, f), u(l, s), u(s, w), u(l, g), u(l, _), u(_, A), u(_, M), u(_, d), j && j.m(_, null), u(l, h), S && S.m(l, null), u(e, p);
},
p(b, N) {
b[3] !== "true" ? E ? E.p(b, N) : (E = oe(b), E.c(), E.m(e, i)) : E && (E.d(1), E = null), N & 32 && r !== (r = V(b[12]) + "") && T(o, r), N & 32 && s !== (s = b[12].title + "") && T(w, s), N & 32 && y !== (y = b[12].place.name + "") && T(d, y), b[12].place.name !== "online" ? j ? j.p(b, N) : (j = ae(b), j.c(), j.m(_, null)) : j && (j.d(1), j = null), b[12].tags.length ? S ? S.p(b, N) : (S = se(b), S.c(), S.m(l, null)) : S && (S.d(1), S = null), N & 33 && C !== (C = b[0] + "/event/" + (b[12].slug || b[12].id)) && a(e, "href", C), N & 32 && q !== (q = b[12].title) && a(e, "title", q);
b[3] !== "true" ? $ ? $.p(b, N) : ($ = oe(b), $.c(), $.m(e, i)) : $ && ($.d(1), $ = null), N & 32 && r !== (r = V(b[13]) + "") && T(o, r), N & 32 && c !== (c = b[13].title + "") && T(w, c), N & 32 && E !== (E = b[13].place.name + "") && T(M, E), b[13].place.name !== "online" ? j ? j.p(b, N) : (j = ae(b), j.c(), j.m(_, null)) : j && (j.d(1), j = null), b[13].tags.length ? S ? S.p(b, N) : (S = se(b), S.c(), S.m(l, null)) : S && (S.d(1), S = null), N & 33 && v !== (v = b[0] + "/event/" + (b[13].slug || b[13].id)) && a(e, "href", v), N & 32 && q !== (q = b[13].title) && a(e, "title", q);
},
d(b) {
b && k(e), E && E.d(), j && j.d(), S && S.d();
b && x(e), $ && $.d(), j && j.d(), S && S.d();
}
};
}
@ -433,10 +432,10 @@ function Ge(t) {
let e, i, l = t[4] && le(t), n = t[5].length && ne(t);
return {
c() {
l && l.c(), e = M(), n && n.c(), i = pe(), this.c = G;
l && l.c(), e = C(), n && n.c(), i = pe(), this.c = G;
},
m(r, o) {
l && l.m(r, o), p(r, e, o), n && n.m(r, o), p(r, i, o);
l && l.m(r, o), k(r, e, o), n && n.m(r, o), k(r, i, o);
},
p(r, [o]) {
r[4] ? l ? l.p(r, o) : (l = le(r), l.c(), l.m(e.parentNode, e)) : l && (l.d(1), l = null), r[5].length ? n ? n.p(r, o) : (n = ne(r), n.c(), n.m(i.parentNode, i)) : n && (n.d(1), n = null);
@ -444,7 +443,7 @@ function Ge(t) {
i: G,
o: G,
d(r) {
l && l.d(r), r && k(e), n && n.d(r), r && k(i);
l && l.d(r), r && x(e), n && n.d(r), r && x(i);
}
};
}
@ -456,34 +455,37 @@ function ue(t) {
return "center center";
}
function He(t, e, i) {
let { baseurl: l = "" } = e, { title: n = "" } = e, { maxlength: r = !1 } = e, { tags: o = "" } = e, { places: f = "" } = e, { theme: c = "light" } = e, { show_recurrent: s = !1 } = e, { sidebar: w = "true" } = e, { external_style: g = "" } = e, _ = !1, A = [];
function y(d) {
if (!_)
let { baseurl: l = "" } = e, { title: n = "" } = e, { maxlength: r = !1 } = e, { collection: o = "" } = e, { tags: f = "" } = e, { places: s = "" } = e, { theme: c = "light" } = e, { show_recurrent: w = !1 } = e, { sidebar: g = "true" } = e, { external_style: _ = "" } = e, A = !1, E = [];
function M(d) {
if (!A)
return;
const z = [];
r && z.push(`max=${r}`), o && z.push(`tags=${o}`), f && z.push(`places=${f}`), z.push(`show_recurrent=${s ? "true" : "false"}`), fetch(`${l}/api/events?${z.join("&")}`).then((h) => h.json()).then((h) => {
i(5, A = h);
}).catch((h) => {
console.error("Error loading Gancio API -> ", h);
const h = [];
r && h.push(`max=${r}`);
let p = "/api/events";
o ? p = `/api/collections/${o}` : (f && h.push(`tags=${f}`), s && h.push(`places=${s}`)), h.push(`show_recurrent=${w ? "true" : "false"}`), fetch(`${l}${p}?${h.join("&")}`).then((v) => v.json()).then((v) => {
i(5, E = v.events || v);
}).catch((v) => {
console.error("Error loading Gancio API -> ", v);
});
}
return ke(() => {
_ = !0, y();
A = !0, M();
}), t.$$set = (d) => {
"baseurl" in d && i(0, l = d.baseurl), "title" in d && i(1, n = d.title), "maxlength" in d && i(6, r = d.maxlength), "tags" in d && i(7, o = d.tags), "places" in d && i(8, f = d.places), "theme" in d && i(2, c = d.theme), "show_recurrent" in d && i(9, s = d.show_recurrent), "sidebar" in d && i(3, w = d.sidebar), "external_style" in d && i(4, g = d.external_style);
"baseurl" in d && i(0, l = d.baseurl), "title" in d && i(1, n = d.title), "maxlength" in d && i(6, r = d.maxlength), "collection" in d && i(7, o = d.collection), "tags" in d && i(8, f = d.tags), "places" in d && i(9, s = d.places), "theme" in d && i(2, c = d.theme), "show_recurrent" in d && i(10, w = d.show_recurrent), "sidebar" in d && i(3, g = d.sidebar), "external_style" in d && i(4, _ = d.external_style);
}, t.$$.update = () => {
t.$$.dirty & 975 && y();
t.$$.dirty & 1999 && M();
}, [
l,
n,
c,
w,
g,
A,
_,
E,
r,
o,
f,
s
s,
w
];
}
class Re extends X {
@ -508,21 +510,23 @@ class Re extends X {
baseurl: 0,
title: 1,
maxlength: 6,
tags: 7,
places: 8,
collection: 7,
tags: 8,
places: 9,
theme: 2,
show_recurrent: 9,
show_recurrent: 10,
sidebar: 3,
external_style: 4
},
null
), e && (e.target && p(e.target, this, e.anchor), e.props && (this.$set(e.props), x()));
), e && (e.target && k(e.target, this, e.anchor), e.props && (this.$set(e.props), y()));
}
static get observedAttributes() {
return [
"baseurl",
"title",
"maxlength",
"collection",
"tags",
"places",
"theme",
@ -535,72 +539,78 @@ class Re extends X {
return this.$$.ctx[0];
}
set baseurl(e) {
this.$$set({ baseurl: e }), x();
this.$$set({ baseurl: e }), y();
}
get title() {
return this.$$.ctx[1];
}
set title(e) {
this.$$set({ title: e }), x();
this.$$set({ title: e }), y();
}
get maxlength() {
return this.$$.ctx[6];
}
set maxlength(e) {
this.$$set({ maxlength: e }), x();
this.$$set({ maxlength: e }), y();
}
get tags() {
get collection() {
return this.$$.ctx[7];
}
set tags(e) {
this.$$set({ tags: e }), x();
set collection(e) {
this.$$set({ collection: e }), y();
}
get places() {
get tags() {
return this.$$.ctx[8];
}
set tags(e) {
this.$$set({ tags: e }), y();
}
get places() {
return this.$$.ctx[9];
}
set places(e) {
this.$$set({ places: e }), x();
this.$$set({ places: e }), y();
}
get theme() {
return this.$$.ctx[2];
}
set theme(e) {
this.$$set({ theme: e }), x();
this.$$set({ theme: e }), y();
}
get show_recurrent() {
return this.$$.ctx[9];
return this.$$.ctx[10];
}
set show_recurrent(e) {
this.$$set({ show_recurrent: e }), x();
this.$$set({ show_recurrent: e }), y();
}
get sidebar() {
return this.$$.ctx[3];
}
set sidebar(e) {
this.$$set({ sidebar: e }), x();
this.$$set({ sidebar: e }), y();
}
get external_style() {
return this.$$.ctx[4];
}
set external_style(e) {
this.$$set({ external_style: e }), x();
this.$$set({ external_style: e }), y();
}
}
customElements.define("gancio-events", Re);
function de(t) {
let e, i, l, n, r = t[1].title + "", o, f, c, s = V(t[1]) + "", w, g, _, A, y = t[1].place.name + "", d, z, h = t[1].media.length && he(t);
let e, i, l, n, r = t[1].title + "", o, f, s, c = V(t[1]) + "", w, g, _, A, E = t[1].place.name + "", M, d, h = t[1].media.length && he(t);
return {
c() {
e = m("a"), h && h.c(), i = M(), l = m("div"), n = m("strong"), o = $(r), f = M(), c = m("div"), w = $(s), g = M(), _ = m("div"), A = $("@"), d = $(y), a(_, "class", "place"), a(l, "class", "container"), a(e, "href", z = t[0] + "/event/" + (t[1].slug || t[1].id)), a(e, "class", "card"), a(e, "target", "_blank");
e = m("a"), h && h.c(), i = C(), l = m("div"), n = m("strong"), o = z(r), f = C(), s = m("div"), w = z(c), g = C(), _ = m("div"), A = z("@"), M = z(E), a(_, "class", "place"), a(l, "class", "container"), a(e, "href", d = t[0] + "/event/" + (t[1].slug || t[1].id)), a(e, "class", "card"), a(e, "target", "_blank");
},
m(v, C) {
p(v, e, C), h && h.m(e, null), u(e, i), u(e, l), u(l, n), u(n, o), u(l, f), u(l, c), u(c, w), u(l, g), u(l, _), u(_, A), u(_, d);
m(p, v) {
k(p, e, v), h && h.m(e, null), u(e, i), u(e, l), u(l, n), u(n, o), u(l, f), u(l, s), u(s, w), u(l, g), u(l, _), u(_, A), u(_, M);
},
p(v, C) {
v[1].media.length ? h ? h.p(v, C) : (h = he(v), h.c(), h.m(e, i)) : h && (h.d(1), h = null), C & 2 && r !== (r = v[1].title + "") && T(o, r), C & 2 && s !== (s = V(v[1]) + "") && T(w, s), C & 2 && y !== (y = v[1].place.name + "") && T(d, y), C & 3 && z !== (z = v[0] + "/event/" + (v[1].slug || v[1].id)) && a(e, "href", z);
p(p, v) {
p[1].media.length ? h ? h.p(p, v) : (h = he(p), h.c(), h.m(e, i)) : h && (h.d(1), h = null), v & 2 && r !== (r = p[1].title + "") && T(o, r), v & 2 && c !== (c = V(p[1]) + "") && T(w, c), v & 2 && E !== (E = p[1].place.name + "") && T(M, E), v & 3 && d !== (d = p[0] + "/event/" + (p[1].slug || p[1].id)) && a(e, "href", d);
},
d(v) {
v && k(e), h && h.d();
d(p) {
p && x(e), h && h.d();
}
};
}
@ -611,13 +621,13 @@ function he(t) {
e = m("img"), H(e.src, i = t[2](t[1])) || a(e, "src", i), a(e, "alt", l = t[1].media[0].name), a(e, "style", n = "object-position: " + me(t[1]) + "; aspect-ratio=1.7778;");
},
m(r, o) {
p(r, e, o);
k(r, e, o);
},
p(r, o) {
o & 2 && !H(e.src, i = r[2](r[1])) && a(e, "src", i), o & 2 && l !== (l = r[1].media[0].name) && a(e, "alt", l), o & 2 && n !== (n = "object-position: " + me(r[1]) + "; aspect-ratio=1.7778;") && a(e, "style", n);
},
d(r) {
r && k(e);
r && x(e);
}
};
}
@ -628,7 +638,7 @@ function Ie(t) {
i && i.c(), e = pe(), this.c = G;
},
m(l, n) {
i && i.m(l, n), p(l, e, n);
i && i.m(l, n), k(l, e, n);
},
p(l, [n]) {
l[1] ? i ? i.p(l, n) : (i = de(l), i.c(), i.m(e.parentNode, e)) : i && (i.d(1), i = null);
@ -636,7 +646,7 @@ function Ie(t) {
i: G,
o: G,
d(l) {
i && i.d(l), l && k(e);
i && i.d(l), l && x(e);
}
};
}
@ -649,20 +659,20 @@ function me(t) {
}
function Oe(t, e, i) {
let { baseurl: l = "https://demo.gancio.org" } = e, { id: n } = e, r = !1, o;
function f(s, w) {
r && fetch(`${w}/api/event/detail/${s}`).then((g) => g.json()).then((g) => i(1, o = g));
function f(c, w) {
r && fetch(`${w}/api/event/detail/${c}`).then((g) => g.json()).then((g) => i(1, o = g));
}
ke(() => {
r = !0, f(n, l);
});
function c(s) {
return `${l}/media/thumb/${s.media[0].url}`;
function s(c) {
return `${l}/media/thumb/${c.media[0].url}`;
}
return t.$$set = (s) => {
"baseurl" in s && i(0, l = s.baseurl), "id" in s && i(3, n = s.id);
return t.$$set = (c) => {
"baseurl" in c && i(0, l = c.baseurl), "id" in c && i(3, n = c.id);
}, t.$$.update = () => {
t.$$.dirty & 9 && f(n, l);
}, [l, o, c, n];
}, [l, o, s, n];
}
class Ue extends X {
constructor(e) {
@ -679,7 +689,7 @@ class Ue extends X {
_e,
{ baseurl: 0, id: 3 },
null
), e && (e.target && p(e.target, this, e.anchor), e.props && (this.$set(e.props), x()));
), e && (e.target && k(e.target, this, e.anchor), e.props && (this.$set(e.props), y()));
}
static get observedAttributes() {
return ["baseurl", "id"];
@ -688,13 +698,13 @@ class Ue extends X {
return this.$$.ctx[0];
}
set baseurl(e) {
this.$$set({ baseurl: e }), x();
this.$$set({ baseurl: e }), y();
}
get id() {
return this.$$.ctx[3];
}
set id(e) {
this.$$set({ id: e }), x();
this.$$set({ id: e }), y();
}
}
customElements.define("gancio-event", Ue);

View file

@ -207,6 +207,49 @@ describe('Events', () => {
})
test('should not allow start_datetime greater than end_datetime', async () => {
const event = {
title: ' test title 5',
place_id: places[0],
start_datetime: dayjs().unix() + 1000,
end_datetime: dayjs().unix(),
}
const response = await request(app).post('/api/event')
.send(event)
.expect(400)
expect(response.text).toBe('start datetime is greater than end datetime')
})
test('should not allow start_datetime greater than 3000', async () => {
const event = {
title: ' test title 5',
start_datetime: dayjs().set('year', 4000).unix(),
place_id: places[0],
}
const response = await request(app).post('/api/event')
.send(event)
.expect(400)
expect(response.text).toBe('are you sure?')
})
test('should validate start_datime', async () => {
const event = {
title: ' test title 5',
start_datetime: "antani",
place_id: places[0],
}
const response = await request(app).post('/api/event')
.send(event)
.expect(400)
})
test('should trim tags and title', async () => {
const event = {
title: ' test title 4 ',
@ -384,7 +427,7 @@ describe('Collection', () => {
})
test('shoud get collection\'s filters using withFilters parameter', async () => {
const response = await request(app)
let response = await request(app)
.get('/api/collections?withFilters=true')
.expect(200)
@ -393,6 +436,18 @@ describe('Collection', () => {
expect(response.body[0].filters.length).toBe(1)
expect(response.body[0].filters[0].tags.length).toBe(1)
expect(response.body[0].filters[0].tags[0]).toBe('test')
response = await request(app)
.get('/api/collections')
.expect(200)
expect(response.body[0].filters).toBeUndefined()
response = await request(app)
.get('/api/collections?withFilters=false')
.expect(200)
expect(response.body[0].filters).toBeUndefined()
})
test('should get collection events', async () => {

View file

@ -50,13 +50,14 @@ describe('Recurrent events', () => {
start_datetime: DateTime.local(2023, 3, 27, 8).toUnixInteger(),
})
// 27 March 2023 08:00 -> 1w -> 3 April 2023 08:00
// 27 March 2023 08:00 -> 1w
let ev = await eventController._createRecurrentOccurrence(ret)
expect(ev.start_datetime).toBe(DateTime.local(2023, 4, 3, 8).toUnixInteger())
expect(ev.start_datetime).toBeGreaterThan(DateTime.local().toUnixInteger())
expect(DateTime.fromSeconds(ev.start_datetime).hour).toBe(8)
// 3 April 2023 08:00 -> 1w -> 10 April 2023 08:00
ev = await eventController._createRecurrentOccurrence(ret, DateTime.fromSeconds(ev.start_datetime+1), false)
expect(ev.start_datetime).toBe(DateTime.local(2023, 4, 10, 8).toUnixInteger())
// ev = await eventController._createRecurrentOccurrence(ret, DateTime.fromSeconds(ev.start_datetime+1), false)
// expect(ev.start_datetime).
// weekly test
// data di inizio prima di oggi
@ -94,27 +95,6 @@ describe('Recurrent events', () => {
})
test('shoud create a 2 week occurrence in future when start date time is in past', async () => {
const eventController = require('../server/api/controller/event')
const { Event } = require('../server/api/models/models')
// each week starting from past
let ret = await Event.create({
title: 'each 2 weeks starting from past',
is_visible: true,
recurrent: { frequency: '2w' },
start_datetime: DateTime.local(2023, 3, 27, 8).toUnixInteger(),
})
// 27 March 2023 08:00 -> 2w -> 10 April 2023 08:00
let ev = await eventController._createRecurrentOccurrence(ret)
expect(ev.start_datetime).toBe(DateTime.local(2023, 4, 10, 8).toUnixInteger())
// 10 April 2023 08:00 -> 2w -> 24 April 2023 08:00
ev = await eventController._createRecurrentOccurrence(ret, DateTime.fromSeconds(ev.start_datetime+1), false)
expect(ev.start_datetime).toBe(DateTime.local(2023, 4, 24, 8).toUnixInteger())
})
test('shoud create a 2 week occurrence in future when start date time is in future', async () => {
const eventController = require('../server/api/controller/event')
const { Event } = require('../server/api/models/models')
@ -163,22 +143,60 @@ describe('Recurrent events', () => {
const eventController = require('../server/api/controller/event')
const { Event } = require('../server/api/models/models')
// each week starting from past
// each week
let ret = await Event.create({
title: 'each last monday starting from past',
title: 'each last monday starting',
is_visible: true,
recurrent: { frequency: '1m', type: -1 },
start_datetime: DateTime.local(2023, 3, 27, 8).toUnixInteger(),
start_datetime: DateTime.local(2033, 3, 27, 8).toUnixInteger(),
})
// 27 March 2033 08:00 -> 1m -> 24 April 2033 08:00
ev = await eventController._createRecurrentOccurrence(ret)
expect(ev.start_datetime).toBe(DateTime.local(2023, 4, 24, 8).toUnixInteger())
expect(ev.start_datetime).toBe(DateTime.local(2033, 3, 27, 8).toUnixInteger())
// 27 March 2033 08:00 -> 1m -> 24 April 2033 08:00
ev = await eventController._createRecurrentOccurrence(ret, DateTime.fromSeconds(ev.start_datetime+1), false)
expect(ev.start_datetime).toBe(DateTime.local(2033, 4, 24, 8).toUnixInteger())
// 24 April 2033 08:00 -> 1m -> 29 May 2033 08:00
ev = await eventController._createRecurrentOccurrence(ret, DateTime.fromSeconds(ev.start_datetime+1), false)
expect(ev.start_datetime).toBe(DateTime.local(2023, 5, 29, 8).toUnixInteger())
expect(ev.start_datetime).toBe(DateTime.local(2033, 5, 29, 8).toUnixInteger())
})
test('shoud create an occurrence each second tuesday', async () => {
const eventController = require('../server/api/controller/event')
const { Event } = require('../server/api/models/models')
// each week starting from past
let ret = await Event.create({
title: 'each second tuesday',
is_visible: true,
recurrent: { frequency: '1m', type: 2 },
start_datetime: DateTime.local(2033, 2, 8, 8).toUnixInteger(),
})
ev = await eventController._createRecurrentOccurrence(ret)
expect(ev.start_datetime).toBe(DateTime.local(2033, 2, 8, 8).toUnixInteger())
ev = await eventController._createRecurrentOccurrence(ret, DateTime.fromSeconds(ev.start_datetime+1), false)
expect(ev.start_datetime).toBe(DateTime.local(2033, 3, 8, 8).toUnixInteger())
// 8 March 2033 08:00 -> 1m -> 12 April 2033 08:00
ev = await eventController._createRecurrentOccurrence(ret, DateTime.fromSeconds(ev.start_datetime+1), false)
expect(ev.start_datetime).toBe(DateTime.local(2033, 4, 12, 8).toUnixInteger())
// 12 Apr 2033 08:00 -> 1m -> 10 May 2033 08:00
ev = await eventController._createRecurrentOccurrence(ret, DateTime.fromSeconds(ev.start_datetime+1), false)
expect(ev.start_datetime).toBe(DateTime.local(2033, 5, 10, 8).toUnixInteger())
// 10 May 2033 08:00 -> 1m -> 9 June 2033 08:00
ev = await eventController._createRecurrentOccurrence(ret, DateTime.fromSeconds(ev.start_datetime+1), false)
expect(ev.start_datetime).toBe(DateTime.local(2033, 6, 14, 8).toUnixInteger())
})
})

View file

@ -9,10 +9,10 @@ rss(version='2.0' xmlns:atom="http://www.w3.org/2005/Atom")
item
if (event.media && event.media.length)
<enclosure url="#{settings.baseurl}/media/#{event.media[0].url}" type='image/jpeg' length="#{event.media[0].size||1}"></enclosure>
title [#{unixFormat(event.start_datetime,"yy-MM-dd")}] #{event.title} @ #{event.place.name}
title [#{unixFormat(event.start_datetime,"yyyy-MM-dd")}] #{event.title} @ #{event.place.name}
link #{settings.baseurl}/event/#{event.slug || event.id}
each tag in event.tags
category #{tag.tag}
category #{tag.tag || tag}
description
| <![CDATA[
| <h4>#{event.title}</h4>

View file

@ -1,12 +1,12 @@
const minifyTheme = require('minify-css-string').default
import { ca, de, en, es, eu, fr, gl, it, nb, nl, pl, pt, sk, ru, zhHans } from 'vuetify/es5/locale'
import { ca, cs, de, en, es, eu, fr, gl, it, nb, nl, pl, pt, sk, ru, zhHans } from 'vuetify/es5/locale'
export default ({ res, nuxtState }) => {
const settings = process.server ? res.locals.settings : nuxtState.state.settings
const settings = process.server ? (res.locals.settings || {}) : nuxtState.state.settings || {}
return {
lang: { locales: { ca, de, en, es, eu, fr, gl, it, nb, nl, pl, pt, sk, ru, zhHans } },
lang: { locales: { ca, cs, de, en, es, eu, fr, gl, it, nb, nl, pl, pt, sk, ru, zhHans } },
treeShake: true,
theme: {
options: {

View file

@ -6,6 +6,7 @@
export let baseurl = ''
export let title = ''
export let maxlength = false
export let collection = ''
export let tags = ''
export let places = ''
export let theme = 'light'
@ -24,6 +25,10 @@
params.push(`max=${maxlength}`)
}
let api = '/api/events'
if (collection) {
api = `/api/collections/${collection}`
} else {
if (tags) {
params.push(`tags=${tags}`)
}
@ -31,13 +36,13 @@
if (places) {
params.push(`places=${places}`)
}
}
params.push(`show_recurrent=${show_recurrent ? 'true' : 'false'}`)
fetch(`${baseurl}/api/events?${params.join('&')}`)
fetch(`${baseurl}${api}?${params.join('&')}`)
.then((res) => res.json())
.then((e) => {
events = e
events = e.events || e
})
.catch((e) => {
console.error('Error loading Gancio API -> ', e)
@ -57,7 +62,7 @@
update()
})
$: update(
maxlength && title && places && tags && theme && show_recurrent && sidebar && baseurl
maxlength && title && places && tags && theme && show_recurrent && sidebar && baseurl && collection
)
</script>

View file

@ -25,10 +25,10 @@ function ye(t) {
function u(t, e) {
t.appendChild(e);
}
function p(t, e, i) {
function k(t, e, i) {
t.insertBefore(e, i || null);
}
function k(t) {
function x(t) {
t.parentNode.removeChild(t);
}
function be(t, e) {
@ -38,14 +38,14 @@ function be(t, e) {
function m(t) {
return document.createElement(t);
}
function $(t) {
function z(t) {
return document.createTextNode(t);
}
function M() {
return $(" ");
function C() {
return z(" ");
}
function pe() {
return $("");
return z("");
}
function a(t, e, i) {
i == null ? t.removeAttribute(e) : t.getAttribute(e) !== i && t.setAttribute(e, i);
@ -69,25 +69,25 @@ let O;
function I(t) {
O = t;
}
function $e() {
function Ee() {
if (!O)
throw new Error("Function called outside component initialization");
return O;
}
function ke(t) {
$e().$$.on_mount.push(t);
Ee().$$.on_mount.push(t);
}
const R = [], Z = [], P = [], ee = [], Ee = Promise.resolve();
const R = [], Z = [], P = [], ee = [], $e = Promise.resolve();
let K = !1;
function je() {
K || (K = !0, Ee.then(x));
K || (K = !0, $e.then(y));
}
function Q(t) {
P.push(t);
}
const J = /* @__PURE__ */ new Set();
let D = 0;
function x() {
function y() {
const t = O;
do {
for (; D < R.length; ) {
@ -120,8 +120,8 @@ function Ce(t, e) {
function Ae(t, e, i, l) {
const { fragment: n, on_mount: r, on_destroy: o, after_update: f } = t.$$;
n && n.m(e, i), l || Q(() => {
const c = r.map(W).filter(ge);
o ? o.push(...c) : U(c), t.$$.on_mount = [];
const s = r.map(W).filter(ge);
o ? o.push(...s) : U(s), t.$$.on_mount = [];
}), f.forEach(Q);
}
function Me(t, e) {
@ -132,9 +132,9 @@ function Ne(t, e) {
t.$$.dirty[0] === -1 && (R.push(t), je(), t.$$.dirty.fill(0)), t.$$.dirty[e / 31 | 0] |= 1 << e % 31;
}
function we(t, e, i, l, n, r, o, f = [-1]) {
const c = O;
const s = O;
I(t);
const s = t.$$ = {
const c = t.$$ = {
fragment: null,
ctx: null,
props: r,
@ -146,26 +146,26 @@ function we(t, e, i, l, n, r, o, f = [-1]) {
on_disconnect: [],
before_update: [],
after_update: [],
context: new Map(e.context || (c ? c.$$.context : [])),
context: new Map(e.context || (s ? s.$$.context : [])),
callbacks: Y(),
dirty: f,
skip_bound: !1,
root: e.target || c.$$.root
root: e.target || s.$$.root
};
o && o(s.root);
o && o(c.root);
let w = !1;
if (s.ctx = i ? i(t, e.props || {}, (g, _, ...A) => {
const y = A.length ? A[0] : _;
return s.ctx && n(s.ctx[g], s.ctx[g] = y) && (!s.skip_bound && s.bound[g] && s.bound[g](y), w && Ne(t, g)), _;
}) : [], s.update(), w = !0, U(s.before_update), s.fragment = l ? l(s.ctx) : !1, e.target) {
if (c.ctx = i ? i(t, e.props || {}, (g, _, ...A) => {
const E = A.length ? A[0] : _;
return c.ctx && n(c.ctx[g], c.ctx[g] = E) && (!c.skip_bound && c.bound[g] && c.bound[g](E), w && Ne(t, g)), _;
}) : [], c.update(), w = !0, U(c.before_update), c.fragment = l ? l(c.ctx) : !1, e.target) {
if (e.hydrate) {
const g = xe(e.target);
s.fragment && s.fragment.l(g), g.forEach(k);
c.fragment && c.fragment.l(g), g.forEach(x);
} else
s.fragment && s.fragment.c();
e.intro && Ce(t.$$.fragment), Ae(t, e.target, e.anchor, e.customElement), x();
c.fragment && c.fragment.c();
e.intro && Ce(t.$$.fragment), Ae(t, e.target, e.anchor, e.customElement), y();
}
I(c);
I(s);
}
let X;
typeof HTMLElement == "function" && (X = class extends HTMLElement {
@ -213,11 +213,11 @@ function V(t) {
}
function te(t, e, i) {
const l = t.slice();
return l[12] = e[i], l;
return l[13] = e[i], l;
}
function ie(t, e, i) {
const l = t.slice();
return l[15] = e[i], l;
return l[16] = e[i], l;
}
function le(t) {
let e;
@ -226,13 +226,13 @@ function le(t) {
e = m("link"), a(e, "rel", "stylesheet"), a(e, "href", t[4]);
},
m(i, l) {
p(i, e, l);
k(i, e, l);
},
p(i, l) {
l & 16 && a(e, "href", i[4]);
},
d(i) {
i && k(e);
i && x(e);
}
};
}
@ -242,32 +242,32 @@ function ne(t) {
r[o] = fe(te(t, n, o));
return {
c() {
e = m("div"), l && l.c(), i = M();
e = m("div"), l && l.c(), i = C();
for (let o = 0; o < r.length; o += 1)
r[o].c();
a(e, "id", "gancioEvents"), L(e, "dark", t[2] === "dark"), L(e, "light", t[2] === "light"), L(e, "sidebar", t[3] === "true"), L(e, "nosidebar", t[3] !== "true");
},
m(o, f) {
p(o, e, f), l && l.m(e, null), u(e, i);
for (let c = 0; c < r.length; c += 1)
r[c].m(e, null);
k(o, e, f), l && l.m(e, null), u(e, i);
for (let s = 0; s < r.length; s += 1)
r[s].m(e, null);
},
p(o, f) {
if (o[1] && o[3] === "true" ? l ? l.p(o, f) : (l = re(o), l.c(), l.m(e, i)) : l && (l.d(1), l = null), f & 41) {
n = o[5];
let c;
for (c = 0; c < n.length; c += 1) {
const s = te(o, n, c);
r[c] ? r[c].p(s, f) : (r[c] = fe(s), r[c].c(), r[c].m(e, null));
let s;
for (s = 0; s < n.length; s += 1) {
const c = te(o, n, s);
r[s] ? r[s].p(c, f) : (r[s] = fe(c), r[s].c(), r[s].m(e, null));
}
for (; c < r.length; c += 1)
r[c].d(1);
for (; s < r.length; s += 1)
r[s].d(1);
r.length = n.length;
}
f & 4 && L(e, "dark", o[2] === "dark"), f & 4 && L(e, "light", o[2] === "light"), f & 8 && L(e, "sidebar", o[3] === "true"), f & 8 && L(e, "nosidebar", o[3] !== "true");
},
d(o) {
o && k(e), l && l.d(), be(r, o);
o && x(e), l && l.d(), be(r, o);
}
};
}
@ -275,23 +275,23 @@ function re(t) {
let e, i, l, n, r, o, f;
return {
c() {
e = m("a"), i = m("div"), l = m("div"), n = $(t[1]), r = M(), o = m("img"), a(l, "class", "title"), a(o, "id", "logo"), a(o, "alt", "logo"), H(o.src, f = t[0] + "/logo.png") || a(o, "src", f), a(i, "class", "content"), a(e, "href", t[0]), a(e, "target", "_blank"), a(e, "id", "header");
e = m("a"), i = m("div"), l = m("div"), n = z(t[1]), r = C(), o = m("img"), a(l, "class", "title"), a(o, "id", "logo"), a(o, "alt", "logo"), H(o.src, f = t[0] + "/logo.png") || a(o, "src", f), a(i, "class", "content"), a(e, "href", t[0]), a(e, "target", "_blank"), a(e, "id", "header");
},
m(c, s) {
p(c, e, s), u(e, i), u(i, l), u(l, n), u(i, r), u(i, o);
m(s, c) {
k(s, e, c), u(e, i), u(i, l), u(l, n), u(i, r), u(i, o);
},
p(c, s) {
s & 2 && T(n, c[1]), s & 1 && !H(o.src, f = c[0] + "/logo.png") && a(o, "src", f), s & 1 && a(e, "href", c[0]);
p(s, c) {
c & 2 && T(n, s[1]), c & 1 && !H(o.src, f = s[0] + "/logo.png") && a(o, "src", f), c & 1 && a(e, "href", s[0]);
},
d(c) {
c && k(e);
d(s) {
s && x(e);
}
};
}
function oe(t) {
let e;
function i(r, o) {
return r[12].media.length ? Le : Te;
return r[13].media.length ? Le : Te;
}
let l = i(t), n = l(t);
return {
@ -299,13 +299,13 @@ function oe(t) {
e = m("div"), n.c(), a(e, "class", "img");
},
m(r, o) {
p(r, e, o), n.m(e, null);
k(r, e, o), n.m(e, null);
},
p(r, o) {
l === (l = i(r)) && n ? n.p(r, o) : (n.d(1), n = l(r), n && (n.c(), n.m(e, null)));
},
d(r) {
r && k(e), n.d();
r && x(e), n.d();
}
};
}
@ -313,16 +313,16 @@ function Te(t) {
let e, i, l;
return {
c() {
e = m("img"), a(e, "style", "aspect-ratio=1.7778;"), a(e, "alt", i = t[12].title), H(e.src, l = t[0] + "/fallbackimage.png") || a(e, "src", l), a(e, "loading", "lazy");
e = m("img"), a(e, "style", "aspect-ratio=1.7778;"), a(e, "alt", i = t[13].title), H(e.src, l = t[0] + "/fallbackimage.png") || a(e, "src", l), a(e, "loading", "lazy");
},
m(n, r) {
p(n, e, r);
k(n, e, r);
},
p(n, r) {
r & 32 && i !== (i = n[12].title) && a(e, "alt", i), r & 1 && !H(e.src, l = n[0] + "/fallbackimage.png") && a(e, "src", l);
r & 32 && i !== (i = n[13].title) && a(e, "alt", i), r & 1 && !H(e.src, l = n[0] + "/fallbackimage.png") && a(e, "src", l);
},
d(n) {
n && k(e);
n && x(e);
}
};
}
@ -330,38 +330,38 @@ function Le(t) {
let e, i, l, n;
return {
c() {
e = m("img"), a(e, "style", i = "object-position: " + ue(t[12]) + "; aspect-ratio=1.7778;"), a(e, "alt", l = t[12].media[0].name), H(e.src, n = t[0] + "/media/thumb/" + t[12].media[0].url) || a(e, "src", n), a(e, "loading", "lazy");
e = m("img"), a(e, "style", i = "object-position: " + ue(t[13]) + "; aspect-ratio=1.7778;"), a(e, "alt", l = t[13].media[0].name), H(e.src, n = t[0] + "/media/thumb/" + t[13].media[0].url) || a(e, "src", n), a(e, "loading", "lazy");
},
m(r, o) {
p(r, e, o);
k(r, e, o);
},
p(r, o) {
o & 32 && i !== (i = "object-position: " + ue(r[12]) + "; aspect-ratio=1.7778;") && a(e, "style", i), o & 32 && l !== (l = r[12].media[0].name) && a(e, "alt", l), o & 33 && !H(e.src, n = r[0] + "/media/thumb/" + r[12].media[0].url) && a(e, "src", n);
o & 32 && i !== (i = "object-position: " + ue(r[13]) + "; aspect-ratio=1.7778;") && a(e, "style", i), o & 32 && l !== (l = r[13].media[0].name) && a(e, "alt", l), o & 33 && !H(e.src, n = r[0] + "/media/thumb/" + r[13].media[0].url) && a(e, "src", n);
},
d(r) {
r && k(e);
r && x(e);
}
};
}
function ae(t) {
let e, i = t[12].place.address + "", l;
let e, i = t[13].place.address + "", l;
return {
c() {
e = m("span"), l = $(i), a(e, "class", "subtitle");
e = m("span"), l = z(i), a(e, "class", "subtitle");
},
m(n, r) {
p(n, e, r), u(e, l);
k(n, e, r), u(e, l);
},
p(n, r) {
r & 32 && i !== (i = n[12].place.address + "") && T(l, i);
r & 32 && i !== (i = n[13].place.address + "") && T(l, i);
},
d(n) {
n && k(e);
n && x(e);
}
};
}
function se(t) {
let e, i = t[12].tags, l = [];
let e, i = t[13].tags, l = [];
for (let n = 0; n < i.length; n += 1)
l[n] = ce(ie(t, i, n));
return {
@ -372,13 +372,13 @@ function se(t) {
a(e, "class", "tags");
},
m(n, r) {
p(n, e, r);
k(n, e, r);
for (let o = 0; o < l.length; o += 1)
l[o].m(e, null);
},
p(n, r) {
if (r & 32) {
i = n[12].tags;
i = n[13].tags;
let o;
for (o = 0; o < i.length; o += 1) {
const f = ie(n, i, o);
@ -390,42 +390,41 @@ function se(t) {
}
},
d(n) {
n && k(e), be(l, n);
n && x(e), be(l, n);
}
};
}
function ce(t) {
let e, i, l = t[15] + "", n;
let e, i, l = t[16] + "", n;
return {
c() {
e = m("span"), i = $("#"), n = $(l), a(e, "class", "tag");
e = m("span"), i = z("#"), n = z(l), a(e, "class", "tag");
},
m(r, o) {
p(r, e, o), u(e, i), u(e, n);
k(r, e, o), u(e, i), u(e, n);
},
p(r, o) {
o & 32 && l !== (l = r[15] + "") && T(n, l);
o & 32 && l !== (l = r[16] + "") && T(n, l);
},
d(r) {
r && k(e);
r && x(e);
}
};
}
function fe(t) {
let e, i, l, n, r = V(t[12]) + "", o, f, c, s = t[12].title + "", w, g, _, A, y = t[12].place.name + "", d, z, h, v, C, q, E = t[3] !== "true" && oe(t), j = t[12].place.name !== "online" && ae(t), S = t[12].tags.length && se(t);
let e, i, l, n, r = V(t[13]) + "", o, f, s, c = t[13].title + "", w, g, _, A, E = t[13].place.name + "", M, d, h, p, v, q, $ = t[3] !== "true" && oe(t), j = t[13].place.name !== "online" && ae(t), S = t[13].tags.length && se(t);
return {
c() {
e = m("a"), E && E.c(), i = M(), l = m("div"), n = m("div"), o = $(r), f = M(), c = m("div"), w = $(s), g = M(), _ = m("span"), A = $('@"'), d = $(y), z = $(`"
`), j && j.c(), h = M(), S && S.c(), v = M(), a(n, "class", "subtitle"), a(c, "class", "title"), a(_, "class", "place"), a(l, "class", "content"), a(e, "href", C = t[0] + "/event/" + (t[12].slug || t[12].id)), a(e, "class", "event"), a(e, "title", q = t[12].title), a(e, "target", "_blank");
e = m("a"), $ && $.c(), i = C(), l = m("div"), n = m("div"), o = z(r), f = C(), s = m("div"), w = z(c), g = C(), _ = m("span"), A = z("@"), M = z(E), d = C(), j && j.c(), h = C(), S && S.c(), p = C(), a(n, "class", "subtitle"), a(s, "class", "title"), a(_, "class", "place"), a(l, "class", "content"), a(e, "href", v = t[0] + "/event/" + (t[13].slug || t[13].id)), a(e, "class", "event"), a(e, "title", q = t[13].title), a(e, "target", "_blank");
},
m(b, N) {
p(b, e, N), E && E.m(e, null), u(e, i), u(e, l), u(l, n), u(n, o), u(l, f), u(l, c), u(c, w), u(l, g), u(l, _), u(_, A), u(_, d), u(_, z), j && j.m(_, null), u(l, h), S && S.m(l, null), u(e, v);
k(b, e, N), $ && $.m(e, null), u(e, i), u(e, l), u(l, n), u(n, o), u(l, f), u(l, s), u(s, w), u(l, g), u(l, _), u(_, A), u(_, M), u(_, d), j && j.m(_, null), u(l, h), S && S.m(l, null), u(e, p);
},
p(b, N) {
b[3] !== "true" ? E ? E.p(b, N) : (E = oe(b), E.c(), E.m(e, i)) : E && (E.d(1), E = null), N & 32 && r !== (r = V(b[12]) + "") && T(o, r), N & 32 && s !== (s = b[12].title + "") && T(w, s), N & 32 && y !== (y = b[12].place.name + "") && T(d, y), b[12].place.name !== "online" ? j ? j.p(b, N) : (j = ae(b), j.c(), j.m(_, null)) : j && (j.d(1), j = null), b[12].tags.length ? S ? S.p(b, N) : (S = se(b), S.c(), S.m(l, null)) : S && (S.d(1), S = null), N & 33 && C !== (C = b[0] + "/event/" + (b[12].slug || b[12].id)) && a(e, "href", C), N & 32 && q !== (q = b[12].title) && a(e, "title", q);
b[3] !== "true" ? $ ? $.p(b, N) : ($ = oe(b), $.c(), $.m(e, i)) : $ && ($.d(1), $ = null), N & 32 && r !== (r = V(b[13]) + "") && T(o, r), N & 32 && c !== (c = b[13].title + "") && T(w, c), N & 32 && E !== (E = b[13].place.name + "") && T(M, E), b[13].place.name !== "online" ? j ? j.p(b, N) : (j = ae(b), j.c(), j.m(_, null)) : j && (j.d(1), j = null), b[13].tags.length ? S ? S.p(b, N) : (S = se(b), S.c(), S.m(l, null)) : S && (S.d(1), S = null), N & 33 && v !== (v = b[0] + "/event/" + (b[13].slug || b[13].id)) && a(e, "href", v), N & 32 && q !== (q = b[13].title) && a(e, "title", q);
},
d(b) {
b && k(e), E && E.d(), j && j.d(), S && S.d();
b && x(e), $ && $.d(), j && j.d(), S && S.d();
}
};
}
@ -433,10 +432,10 @@ function Ge(t) {
let e, i, l = t[4] && le(t), n = t[5].length && ne(t);
return {
c() {
l && l.c(), e = M(), n && n.c(), i = pe(), this.c = G;
l && l.c(), e = C(), n && n.c(), i = pe(), this.c = G;
},
m(r, o) {
l && l.m(r, o), p(r, e, o), n && n.m(r, o), p(r, i, o);
l && l.m(r, o), k(r, e, o), n && n.m(r, o), k(r, i, o);
},
p(r, [o]) {
r[4] ? l ? l.p(r, o) : (l = le(r), l.c(), l.m(e.parentNode, e)) : l && (l.d(1), l = null), r[5].length ? n ? n.p(r, o) : (n = ne(r), n.c(), n.m(i.parentNode, i)) : n && (n.d(1), n = null);
@ -444,7 +443,7 @@ function Ge(t) {
i: G,
o: G,
d(r) {
l && l.d(r), r && k(e), n && n.d(r), r && k(i);
l && l.d(r), r && x(e), n && n.d(r), r && x(i);
}
};
}
@ -456,34 +455,37 @@ function ue(t) {
return "center center";
}
function He(t, e, i) {
let { baseurl: l = "" } = e, { title: n = "" } = e, { maxlength: r = !1 } = e, { tags: o = "" } = e, { places: f = "" } = e, { theme: c = "light" } = e, { show_recurrent: s = !1 } = e, { sidebar: w = "true" } = e, { external_style: g = "" } = e, _ = !1, A = [];
function y(d) {
if (!_)
let { baseurl: l = "" } = e, { title: n = "" } = e, { maxlength: r = !1 } = e, { collection: o = "" } = e, { tags: f = "" } = e, { places: s = "" } = e, { theme: c = "light" } = e, { show_recurrent: w = !1 } = e, { sidebar: g = "true" } = e, { external_style: _ = "" } = e, A = !1, E = [];
function M(d) {
if (!A)
return;
const z = [];
r && z.push(`max=${r}`), o && z.push(`tags=${o}`), f && z.push(`places=${f}`), z.push(`show_recurrent=${s ? "true" : "false"}`), fetch(`${l}/api/events?${z.join("&")}`).then((h) => h.json()).then((h) => {
i(5, A = h);
}).catch((h) => {
console.error("Error loading Gancio API -> ", h);
const h = [];
r && h.push(`max=${r}`);
let p = "/api/events";
o ? p = `/api/collections/${o}` : (f && h.push(`tags=${f}`), s && h.push(`places=${s}`)), h.push(`show_recurrent=${w ? "true" : "false"}`), fetch(`${l}${p}?${h.join("&")}`).then((v) => v.json()).then((v) => {
i(5, E = v.events || v);
}).catch((v) => {
console.error("Error loading Gancio API -> ", v);
});
}
return ke(() => {
_ = !0, y();
A = !0, M();
}), t.$$set = (d) => {
"baseurl" in d && i(0, l = d.baseurl), "title" in d && i(1, n = d.title), "maxlength" in d && i(6, r = d.maxlength), "tags" in d && i(7, o = d.tags), "places" in d && i(8, f = d.places), "theme" in d && i(2, c = d.theme), "show_recurrent" in d && i(9, s = d.show_recurrent), "sidebar" in d && i(3, w = d.sidebar), "external_style" in d && i(4, g = d.external_style);
"baseurl" in d && i(0, l = d.baseurl), "title" in d && i(1, n = d.title), "maxlength" in d && i(6, r = d.maxlength), "collection" in d && i(7, o = d.collection), "tags" in d && i(8, f = d.tags), "places" in d && i(9, s = d.places), "theme" in d && i(2, c = d.theme), "show_recurrent" in d && i(10, w = d.show_recurrent), "sidebar" in d && i(3, g = d.sidebar), "external_style" in d && i(4, _ = d.external_style);
}, t.$$.update = () => {
t.$$.dirty & 975 && y();
t.$$.dirty & 1999 && M();
}, [
l,
n,
c,
w,
g,
A,
_,
E,
r,
o,
f,
s
s,
w
];
}
class Re extends X {
@ -508,21 +510,23 @@ class Re extends X {
baseurl: 0,
title: 1,
maxlength: 6,
tags: 7,
places: 8,
collection: 7,
tags: 8,
places: 9,
theme: 2,
show_recurrent: 9,
show_recurrent: 10,
sidebar: 3,
external_style: 4
},
null
), e && (e.target && p(e.target, this, e.anchor), e.props && (this.$set(e.props), x()));
), e && (e.target && k(e.target, this, e.anchor), e.props && (this.$set(e.props), y()));
}
static get observedAttributes() {
return [
"baseurl",
"title",
"maxlength",
"collection",
"tags",
"places",
"theme",
@ -535,72 +539,78 @@ class Re extends X {
return this.$$.ctx[0];
}
set baseurl(e) {
this.$$set({ baseurl: e }), x();
this.$$set({ baseurl: e }), y();
}
get title() {
return this.$$.ctx[1];
}
set title(e) {
this.$$set({ title: e }), x();
this.$$set({ title: e }), y();
}
get maxlength() {
return this.$$.ctx[6];
}
set maxlength(e) {
this.$$set({ maxlength: e }), x();
this.$$set({ maxlength: e }), y();
}
get tags() {
get collection() {
return this.$$.ctx[7];
}
set tags(e) {
this.$$set({ tags: e }), x();
set collection(e) {
this.$$set({ collection: e }), y();
}
get places() {
get tags() {
return this.$$.ctx[8];
}
set tags(e) {
this.$$set({ tags: e }), y();
}
get places() {
return this.$$.ctx[9];
}
set places(e) {
this.$$set({ places: e }), x();
this.$$set({ places: e }), y();
}
get theme() {
return this.$$.ctx[2];
}
set theme(e) {
this.$$set({ theme: e }), x();
this.$$set({ theme: e }), y();
}
get show_recurrent() {
return this.$$.ctx[9];
return this.$$.ctx[10];
}
set show_recurrent(e) {
this.$$set({ show_recurrent: e }), x();
this.$$set({ show_recurrent: e }), y();
}
get sidebar() {
return this.$$.ctx[3];
}
set sidebar(e) {
this.$$set({ sidebar: e }), x();
this.$$set({ sidebar: e }), y();
}
get external_style() {
return this.$$.ctx[4];
}
set external_style(e) {
this.$$set({ external_style: e }), x();
this.$$set({ external_style: e }), y();
}
}
customElements.define("gancio-events", Re);
function de(t) {
let e, i, l, n, r = t[1].title + "", o, f, c, s = V(t[1]) + "", w, g, _, A, y = t[1].place.name + "", d, z, h = t[1].media.length && he(t);
let e, i, l, n, r = t[1].title + "", o, f, s, c = V(t[1]) + "", w, g, _, A, E = t[1].place.name + "", M, d, h = t[1].media.length && he(t);
return {
c() {
e = m("a"), h && h.c(), i = M(), l = m("div"), n = m("strong"), o = $(r), f = M(), c = m("div"), w = $(s), g = M(), _ = m("div"), A = $("@"), d = $(y), a(_, "class", "place"), a(l, "class", "container"), a(e, "href", z = t[0] + "/event/" + (t[1].slug || t[1].id)), a(e, "class", "card"), a(e, "target", "_blank");
e = m("a"), h && h.c(), i = C(), l = m("div"), n = m("strong"), o = z(r), f = C(), s = m("div"), w = z(c), g = C(), _ = m("div"), A = z("@"), M = z(E), a(_, "class", "place"), a(l, "class", "container"), a(e, "href", d = t[0] + "/event/" + (t[1].slug || t[1].id)), a(e, "class", "card"), a(e, "target", "_blank");
},
m(v, C) {
p(v, e, C), h && h.m(e, null), u(e, i), u(e, l), u(l, n), u(n, o), u(l, f), u(l, c), u(c, w), u(l, g), u(l, _), u(_, A), u(_, d);
m(p, v) {
k(p, e, v), h && h.m(e, null), u(e, i), u(e, l), u(l, n), u(n, o), u(l, f), u(l, s), u(s, w), u(l, g), u(l, _), u(_, A), u(_, M);
},
p(v, C) {
v[1].media.length ? h ? h.p(v, C) : (h = he(v), h.c(), h.m(e, i)) : h && (h.d(1), h = null), C & 2 && r !== (r = v[1].title + "") && T(o, r), C & 2 && s !== (s = V(v[1]) + "") && T(w, s), C & 2 && y !== (y = v[1].place.name + "") && T(d, y), C & 3 && z !== (z = v[0] + "/event/" + (v[1].slug || v[1].id)) && a(e, "href", z);
p(p, v) {
p[1].media.length ? h ? h.p(p, v) : (h = he(p), h.c(), h.m(e, i)) : h && (h.d(1), h = null), v & 2 && r !== (r = p[1].title + "") && T(o, r), v & 2 && c !== (c = V(p[1]) + "") && T(w, c), v & 2 && E !== (E = p[1].place.name + "") && T(M, E), v & 3 && d !== (d = p[0] + "/event/" + (p[1].slug || p[1].id)) && a(e, "href", d);
},
d(v) {
v && k(e), h && h.d();
d(p) {
p && x(e), h && h.d();
}
};
}
@ -611,13 +621,13 @@ function he(t) {
e = m("img"), H(e.src, i = t[2](t[1])) || a(e, "src", i), a(e, "alt", l = t[1].media[0].name), a(e, "style", n = "object-position: " + me(t[1]) + "; aspect-ratio=1.7778;");
},
m(r, o) {
p(r, e, o);
k(r, e, o);
},
p(r, o) {
o & 2 && !H(e.src, i = r[2](r[1])) && a(e, "src", i), o & 2 && l !== (l = r[1].media[0].name) && a(e, "alt", l), o & 2 && n !== (n = "object-position: " + me(r[1]) + "; aspect-ratio=1.7778;") && a(e, "style", n);
},
d(r) {
r && k(e);
r && x(e);
}
};
}
@ -628,7 +638,7 @@ function Ie(t) {
i && i.c(), e = pe(), this.c = G;
},
m(l, n) {
i && i.m(l, n), p(l, e, n);
i && i.m(l, n), k(l, e, n);
},
p(l, [n]) {
l[1] ? i ? i.p(l, n) : (i = de(l), i.c(), i.m(e.parentNode, e)) : i && (i.d(1), i = null);
@ -636,7 +646,7 @@ function Ie(t) {
i: G,
o: G,
d(l) {
i && i.d(l), l && k(e);
i && i.d(l), l && x(e);
}
};
}
@ -649,20 +659,20 @@ function me(t) {
}
function Oe(t, e, i) {
let { baseurl: l = "https://demo.gancio.org" } = e, { id: n } = e, r = !1, o;
function f(s, w) {
r && fetch(`${w}/api/event/detail/${s}`).then((g) => g.json()).then((g) => i(1, o = g));
function f(c, w) {
r && fetch(`${w}/api/event/detail/${c}`).then((g) => g.json()).then((g) => i(1, o = g));
}
ke(() => {
r = !0, f(n, l);
});
function c(s) {
return `${l}/media/thumb/${s.media[0].url}`;
function s(c) {
return `${l}/media/thumb/${c.media[0].url}`;
}
return t.$$set = (s) => {
"baseurl" in s && i(0, l = s.baseurl), "id" in s && i(3, n = s.id);
return t.$$set = (c) => {
"baseurl" in c && i(0, l = c.baseurl), "id" in c && i(3, n = c.id);
}, t.$$.update = () => {
t.$$.dirty & 9 && f(n, l);
}, [l, o, c, n];
}, [l, o, s, n];
}
class Ue extends X {
constructor(e) {
@ -679,7 +689,7 @@ class Ue extends X {
_e,
{ baseurl: 0, id: 3 },
null
), e && (e.target && p(e.target, this, e.anchor), e.props && (this.$set(e.props), x()));
), e && (e.target && k(e.target, this, e.anchor), e.props && (this.$set(e.props), y()));
}
static get observedAttributes() {
return ["baseurl", "id"];
@ -688,13 +698,13 @@ class Ue extends X {
return this.$$.ctx[0];
}
set baseurl(e) {
this.$$set({ baseurl: e }), x();
this.$$set({ baseurl: e }), y();
}
get id() {
return this.$$.ctx[3];
}
set id(e) {
this.$$set({ id: e }), x();
this.$$set({ id: e }), y();
}
}
customElements.define("gancio-event", Ue);

4334
yarn.lock

File diff suppressed because it is too large Load diff