diff --git a/js/package.json b/js/package.json
index 3d418dbde..f10b3f45c 100644
--- a/js/package.json
+++ b/js/package.json
@@ -36,16 +36,16 @@
"ngeohash": "^0.6.3",
"phoenix": "^1.4.11",
"register-service-worker": "^1.7.1",
- "tippy.js": "4.3.5",
+ "tippy.js": "^6.2.3",
"tiptap": "^1.26.0",
- "tiptap-extensions": "^1.28.0",
+ "tiptap-extensions": "^1.29.1",
"v-tooltip": "2.0.2",
"vue": "^2.6.11",
"vue-apollo": "^3.0.3",
"vue-class-component": "^7.2.3",
"vue-i18n": "^8.14.0",
"vue-meta": "^2.3.1",
- "vue-property-decorator": "^8.4.1",
+ "vue-property-decorator": "^9.0.0",
"vue-router": "^3.1.6",
"vue-scrollto": "^2.17.1",
"vue2-leaflet": "^2.0.3",
@@ -90,7 +90,7 @@
"prettier-eslint": "^10.1.1",
"sass-loader": "^8.0.2",
"typescript": "~3.9.3",
- "vue-cli-plugin-styleguidist": "~4.24.0",
+ "vue-cli-plugin-styleguidist": "^4.25.0",
"vue-cli-plugin-svg": "~0.1.3",
"vue-i18n-extract": "^1.0.2",
"vue-template-compiler": "^2.6.11",
diff --git a/js/src/components/Editor.vue b/js/src/components/Editor.vue
index beae1205a..43800c8fa 100644
--- a/js/src/components/Editor.vue
+++ b/js/src/components/Editor.vue
@@ -156,14 +156,21 @@
- {{ actor.name }}
+
+
+ {{ actor.name }}
+
- {{ $t("No actors found") }}
+ {{ $t("No profiles found") }}
@@ -189,7 +196,7 @@ import {
Placeholder,
Mention,
} from "tiptap-extensions";
-import tippy, { Instance } from "tippy.js";
+import tippy, { Instance, sticky } from "tippy.js";
import { SEARCH_PERSONS } from "../graphql/search";
import { Actor, IActor, IPerson } from "../types/actor";
import Image from "./Editor/Image";
@@ -226,7 +233,7 @@ export default class EditorComponent extends Vue {
navigatedActorIndex = 0;
- popup!: Instance | null;
+ popup!: Instance[] | null;
get isDescriptionMode() {
return this.mode === "description";
@@ -319,18 +326,15 @@ export default class EditorComponent extends Vue {
* is called on every keyDown event while a suggestion is active
*/
onKeyDown: ({ event }: { event: KeyboardEvent }) => {
- // pressing up arrow
- if (event.keyCode === 38) {
+ if (event.key === "ArrowUp") {
this.upHandler();
return true;
}
- // pressing down arrow
- if (event.keyCode === 40) {
+ if (event.key === "ArrowDown") {
this.downHandler();
return true;
}
- // pressing enter
- if (event.keyCode === 13) {
+ if (event.key === "Enter") {
this.enterHandler();
return true;
}
@@ -440,6 +444,7 @@ export default class EditorComponent extends Vue {
this.editor.focus();
}
+ /** We use this to programatically insert an actor mention when creating a reply to comment */
replyToComment(comment: IComment) {
const actorModel = new Actor(comment.actor);
if (!this.editor) return;
@@ -455,40 +460,31 @@ export default class EditorComponent extends Vue {
* tiptap provides a virtualNode object for using popper.js (or tippy.js) for popups
* @param node
*/
- renderPopup(node: any) {
+ renderPopup(node: Element) {
if (this.popup) {
return;
}
- this.popup = tippy(node, {
+ this.popup = tippy("#mobilizon", {
+ // @ts-ignore
+ getReferenceClientRect: node.getBoundingClientRect,
+ appendTo: () => document.body,
content: this.$refs.suggestions as HTMLElement,
trigger: "mouseenter",
interactive: true,
+ sticky: true, // make sure position of tippy is updated when content changes
+ plugins: [sticky],
+ showOnCreate: true,
theme: "dark",
placement: "top-start",
inertia: true,
duration: [400, 200],
- showOnInit: true,
- arrow: true,
- arrowType: "round",
- }) as Instance;
- // we have to update tippy whenever the DOM is updated
- if (MutationObserver) {
- this.observer = new MutationObserver(() => {
- if (this.popup != null && this.popup.popperInstance) {
- this.popup.popperInstance.scheduleUpdate();
- }
- });
- this.observer.observe(this.$refs.suggestions as HTMLElement, {
- childList: true,
- subtree: true,
- characterData: true,
- });
- }
+ }) as Instance[];
}
destroyPopup() {
if (this.popup) {
- this.popup.destroy();
+ // @ts-ignore
+ this.popup[0].destroy();
this.popup = null;
}
if (this.observer) {
@@ -517,6 +513,7 @@ export default class EditorComponent extends Vue {
beforeDestroy() {
if (!this.editor) return;
+ this.destroyPopup();
this.editor.destroy();
}
}
@@ -733,32 +730,19 @@ $color-white: #eee;
opacity: 0.5;
}
}
+
+ .media + .media {
+ margin-top: 0;
+ padding-top: 0;
+ }
}
-.tippy-tooltip.dark-theme {
+.tippy-box[data-theme~="dark"] {
background-color: $color-black;
padding: 0;
font-size: 1rem;
text-align: inherit;
color: $color-white;
border-radius: 5px;
- .tippy-backdrop {
- display: none;
- }
- .tippy-roundarrow {
- fill: $color-black;
- }
- .tippy-popper[x-placement^="top"] & .tippy-arrow {
- border-top-color: $color-black;
- }
- .tippy-popper[x-placement^="bottom"] & .tippy-arrow {
- border-bottom-color: $color-black;
- }
- .tippy-popper[x-placement^="left"] & .tippy-arrow {
- border-left-color: $color-black;
- }
- .tippy-popper[x-placement^="right"] & .tippy-arrow {
- border-right-color: $color-black;
- }
}
.visually-hidden {
diff --git a/js/src/components/Settings/SettingsMenu.vue b/js/src/components/Settings/SettingsMenu.vue
index 8084e8238..419ce3f3b 100644
--- a/js/src/components/Settings/SettingsMenu.vue
+++ b/js/src/components/Settings/SettingsMenu.vue
@@ -1,7 +1,13 @@
-
+
+
+
diff --git a/js/src/views/About/AboutMobilizon.vue b/js/src/views/About/AboutMobilizon.vue
new file mode 100644
index 000000000..33bfbb182
--- /dev/null
+++ b/js/src/views/About/AboutMobilizon.vue
@@ -0,0 +1,236 @@
+
+
+
+
+
+
+
{{ $t("Gather ⋅ Organize ⋅ Mobilize") }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{{ $t("To change the world, change the software") }}
+
+ {{
+ $t(
+ "We won’t change the world from Facebook. The tool we dream of, surveillance capitalism corporations won’t develop it, as they couldn’t profit from it. This is an opportunity to build something better, by taking another approach."
+ )
+ }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{{ $t("Concieved with care for humans") }}
+
+ {{ $t("digital habits of activists") }}
+
+
+ {{ $t("fit the needs and uses of the people") }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/js/src/views/About/Glossary.vue b/js/src/views/About/Glossary.vue
new file mode 100644
index 000000000..1c14cbf34
--- /dev/null
+++ b/js/src/views/About/Glossary.vue
@@ -0,0 +1,86 @@
+
+
+
{{ $t("Glossary") }}
+
+
+ {{
+ $t(
+ "Some terms, technical or otherwise, used in the text below may cover concepts that are difficult to grasp. We have provided a glossary here to help you understand them better:"
+ )
+ }}
+
+
+ {{ $t("Instance") }}
+
+ {{
+ $t("Mobilizon software")
+ }}
+ {{ config.name }}
+
+ {{ $t("Instance administrator") }}
+
+ {{
+ $t(
+ "The instance administrator is the person or entity that runs this Mobilizon instance."
+ )
+ }}
+
+ {{ $t("Application") }}
+
+ {{
+ $t(
+ "In the following context, an application is a software, either provided by the Mobilizon team or by a 3rd-party, used to interact with your instance."
+ )
+ }}
+
+ {{ $t("API") }}
+
+ {{
+ $t(
+ "An “application programming interface” or “API” is a communication protocol that allows software components to communicate with each other. The Mobilizon API, for example, can allow third-party software tools to communicate with Mobilizon instances to carry out certain actions, such as posting events on your behalf, automatically and remotely."
+ )
+ }}
+
+ {{ $t("SSL/TLS") }}
+
+ https://
+
+ {{ $t("Cookies and Local storage") }}
+
+ {{
+ $t(
+ "A cookie is a small file containing informations that is sent to your computer when you visit a website. When you visit the site again, the cookie allows that site to recognize your browser. Cookies may store user preferences and other information. You can configure your browser to refuse all cookies. However, this may result in some website features or services partially working. Local storage works the same way but allows to store more data."
+ )
+ }}
+
+
+
+
+
+
+
+
+
diff --git a/js/src/views/About/Privacy.vue b/js/src/views/About/Privacy.vue
new file mode 100644
index 000000000..b6ee7e69f
--- /dev/null
+++ b/js/src/views/About/Privacy.vue
@@ -0,0 +1,66 @@
+
+
+
{{ $t("Privacy Policy") }}
+
+
+
+
+
+
diff --git a/js/src/views/Rules.vue b/js/src/views/About/Rules.vue
similarity index 89%
rename from js/src/views/Rules.vue
rename to js/src/views/About/Rules.vue
index f8a48f2d8..3750b5acc 100644
--- a/js/src/views/Rules.vue
+++ b/js/src/views/About/Rules.vue
@@ -11,7 +11,7 @@ import { Component, Vue, Watch } from "vue-property-decorator";
import { RULES } from "@/graphql/config";
import { IConfig } from "@/types/config.model";
import { InstanceTermsType } from "@/types/admin.model";
-import RouteName from "../router/name";
+import RouteName from "../../router/name";
@Component({
apollo: {
@@ -32,4 +32,7 @@ export default class Rules extends Vue {
main > .container {
background: $white;
}
+.content /deep/ li {
+ margin-bottom: 1rem;
+}
diff --git a/js/src/views/Terms.vue b/js/src/views/About/Terms.vue
similarity index 85%
rename from js/src/views/Terms.vue
rename to js/src/views/About/Terms.vue
index caa200994..466189a62 100644
--- a/js/src/views/Terms.vue
+++ b/js/src/views/About/Terms.vue
@@ -1,6 +1,6 @@
-
{{ $t("Privacy Policy") }}
+
{{ $t("Terms") }}
@@ -10,7 +10,6 @@ import { Component, Vue, Watch } from "vue-property-decorator";
import { TERMS } from "@/graphql/config";
import { IConfig } from "@/types/config.model";
import { InstanceTermsType } from "@/types/admin.model";
-import RouteName from "../router/name";
@Component({
apollo: {
@@ -49,14 +48,10 @@ export default class Terms extends Vue {
window.location.replace(this.config.terms.url);
}
}
-
- RouteName = RouteName;
}
diff --git a/js/src/views/Admin/Profiles.vue b/js/src/views/Admin/Profiles.vue
index e4a2ee53c..f757e2f51 100644
--- a/js/src/views/Admin/Profiles.vue
+++ b/js/src/views/Admin/Profiles.vue
@@ -23,7 +23,10 @@
size="is-small"
/>
-
+
@@ -136,3 +139,8 @@ export default class Profiles extends Vue {
}
}
+
diff --git a/js/src/views/Admin/Settings.vue b/js/src/views/Admin/Settings.vue
index 74a9f1a16..519c031e8 100644
--- a/js/src/views/Admin/Settings.vue
+++ b/js/src/views/Admin/Settings.vue
@@ -4,9 +4,24 @@
-
-
-
+
+ {{ $t("Instance Short Description") }}
+
+ {{
+ $t(
+ "Displayed on homepage and meta tags. Describe what Mobilizon is and what makes this instance special in a single paragraph."
+ )
+ }}
+
+
+
+
+ {{ $t("Contact") }}
+
+ {{ $t("Can be an email or a link, or just plain text.") }}
+
+
+
@@ -15,9 +30,24 @@
{{ $t("Registration is closed.") }}
-
+
+ {{ $t("Instance Long Description") }}
+
+ {{
+ $t(
+ "A place to explain who you are and the things that set your instance apart. You can use HTML tags."
+ )
+ }}
+
+
+
+
+ {{ $t("Instance Rules") }}
+
+ {{ $t("A place for your code of conduct, rules or guidelines. You can use HTML tags.") }}
+
-
+
@@ -26,7 +56,7 @@
v-model="adminSettings.instanceTermsType"
name="instanceTermsType"
:native-value="InstanceTermsType.DEFAULT"
- >{{ $t("Default Mobilizon.org terms") }}{{ $t("Default Mobilizon terms") }}
@@ -65,6 +95,11 @@
>{{ $t("default Mobilizon terms") }}
+ {{
+ $t(
+ "NOTE! The default terms have not been checked over by a lawyer and thus are unlikely to provide full legal protection for all situations for an instance admin using them. They are also not specific to all countries and jurisdictions. If you are unsure, please check with a lawyer."
+ )
+ }}
@@ -99,7 +141,97 @@
:label="$t('Instance Terms')"
v-if="adminSettings.instanceTermsType === InstanceTermsType.CUSTOM"
>
-
+
+
+
+
+
+
+ {{ $t("Default Mobilizon privacy policy") }}
+
+
+ {{ $t("Custom URL") }}
+
+
+ {{ $t("Custom text") }}
+
+
+
+
+
+
{{ $t("URL") }}
+
{{ $t("Set an URL to a page with your own privacy policy.") }}
+
+
+
+
+
+
+
+
+
+
{{ $t("Save") }}
@@ -108,7 +240,7 @@