This commit is contained in:
@@ -35,7 +35,9 @@ export default {
|
||||
return {
|
||||
feed: {
|
||||
checkNewFeed: this.checkNewFeed,
|
||||
toggle: this.toggle
|
||||
toggle: this.toggle,
|
||||
reply: this.reply,
|
||||
findLinkedPost: this.findLinkedPost
|
||||
}
|
||||
};
|
||||
},
|
||||
@@ -90,7 +92,7 @@ export default {
|
||||
getScrollElement() {
|
||||
return this.$refs.feedSimpleBar?.scrollElement;
|
||||
},
|
||||
async findLinkedPost(sPostType, iPostId, pMapIsReady) {
|
||||
async findLinkedPost(sPostType, iPostId, pMapIsReady=Promise.resolve()) {
|
||||
let vPost = await this.findPost(sPostType, iPostId, true);
|
||||
if(vPost) {
|
||||
await pMapIsReady;
|
||||
@@ -206,6 +208,9 @@ export default {
|
||||
if(aoMarkers.length > 0) this.$emit('new-markers', aoMarkers);
|
||||
this.$emit('request-last-update');
|
||||
},
|
||||
reply(oQuote) {
|
||||
this.$refs.poster?.addQuote(oQuote);
|
||||
},
|
||||
toggle(bShow, iAnimDuration=500) {
|
||||
this.isOpen = (typeof bShow == 'boolean')?bShow:(!this.isOpen);
|
||||
this.$emit('toggle', this.isOpen, iAnimDuration);
|
||||
@@ -223,7 +228,7 @@ export default {
|
||||
<Simplebar id="feed-panel" class="panel-content" ref="feedSimpleBar" :aria-busy="loading">
|
||||
<div id="feed-header">
|
||||
<ProjectPost v-if="modeHisto" :options="{type: 'archived', headerless: true}" />
|
||||
<ProjectPost v-else :options="{type: 'poster', relative_time: lang.get('post.new_message')}" />
|
||||
<ProjectPost v-else :options="{type: 'poster', relative_time: lang.get('post.new_message')}" ref="poster" />
|
||||
</div>
|
||||
<div v-if="project" v-show="!loadingPost" id="feed-posts">
|
||||
<ProjectPost v-for="post in posts" :key="post.ref" :options="post" ref="posts" />
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
import projectMediaLink from '@components/ProjectMediaLink';
|
||||
import projectMapLink from '@components/ProjectMapLink';
|
||||
import projectRelTime from '@components/ProjectRelTime';
|
||||
import projectPostQuote from '@components/ProjectPostQuote';
|
||||
import projectPostSignature from '@components/ProjectPostSignature';
|
||||
import { LngLat } from 'maplibre-gl';
|
||||
import { copyTextToClipboard } from '@scripts/common';
|
||||
|
||||
@@ -17,7 +19,9 @@
|
||||
appButton,
|
||||
projectMediaLink,
|
||||
projectMapLink,
|
||||
projectRelTime
|
||||
projectRelTime,
|
||||
projectPostQuote,
|
||||
projectPostSignature
|
||||
},
|
||||
props: {
|
||||
options: Object
|
||||
@@ -31,9 +35,11 @@
|
||||
anchorVisible: ['message', 'media', 'post'].includes(this.options.type),
|
||||
anchorTitle: this.lang.get('post.copy_to_clipboard'),
|
||||
anchorIcon: 'link',
|
||||
replyTitle: this.lang.get('post.reply'),
|
||||
popupRequested: false,
|
||||
mouseOverDrill: false,
|
||||
postMessage: '',
|
||||
quote: null,
|
||||
sending: false,
|
||||
focusZoomLevel: 15
|
||||
};
|
||||
@@ -65,8 +71,13 @@
|
||||
modeHisto() {
|
||||
return (this.project?.project?.mode == this.consts.modes.histo);
|
||||
},
|
||||
replyVisible() {
|
||||
return this.anchorVisible && !this.modeHisto;
|
||||
},
|
||||
relTime() {
|
||||
return this.modeHisto?(this.options.formatted_time || '').substr(0, 10):this.options.relative_time;
|
||||
return this.modeHisto?
|
||||
(this.options.formatted_time || '').substr(0, 10):
|
||||
this.options.relative_time;
|
||||
},
|
||||
relatedMarker() {
|
||||
//Find corresponding marker
|
||||
@@ -88,9 +99,54 @@
|
||||
},
|
||||
messageLines() {
|
||||
return (this.options.content || '').split('\n');
|
||||
},
|
||||
quoteRef() {
|
||||
return this.options.ref_item?this.buildQuote(this.options.ref_item):null;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
buildQuote(oItem) {
|
||||
let sContent = '', sImage = null;
|
||||
switch(oItem.type) {
|
||||
case 'post':
|
||||
sContent = oItem.content || '';
|
||||
break;
|
||||
case 'media':
|
||||
sContent = oItem.comment || this.lang.get('media.posted_on', oItem.posted_on_formatted_time);
|
||||
sImage = oItem.thumb_path;
|
||||
break;
|
||||
case 'message':
|
||||
sContent = oItem.lat_dms+' '+oItem.lon_dms;
|
||||
sImage = oItem.static_img_url;
|
||||
break;
|
||||
}
|
||||
|
||||
return {
|
||||
type: oItem.type,
|
||||
id: oItem.id,
|
||||
author: oItem.formatted_name || '',
|
||||
gravatar: oItem.gravatar || null,
|
||||
content: sContent,
|
||||
image: sImage
|
||||
};
|
||||
},
|
||||
reply() {
|
||||
this.feed.reply(this.buildQuote(this.options));
|
||||
},
|
||||
goToQuote() {
|
||||
if(this.quoteRef) this.feed.findLinkedPost(this.quoteRef.type, this.quoteRef.id);
|
||||
},
|
||||
addQuote(oQuote) {
|
||||
this.quote = oQuote;
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.$refs.post.focus();
|
||||
});
|
||||
},
|
||||
formatQuote(oQuote) {
|
||||
return (oQuote.author?oQuote.author+':\n':'')
|
||||
+ oQuote.content.split('\n').map((sLine) => '> '+sLine).join('\n');
|
||||
},
|
||||
copyAnchor() {
|
||||
copyTextToClipboard(this.consts.server+this.anchorLink);
|
||||
this.anchorTitle = this.lang.get('post.link_copied');
|
||||
@@ -138,11 +194,14 @@
|
||||
{
|
||||
id_project: this.project.project.id,
|
||||
name: this.user.name,
|
||||
content: this.postMessage
|
||||
content: this.postMessage,
|
||||
ref_type: this.quote?.type || '',
|
||||
ref_id: this.quote?.id || 0
|
||||
}
|
||||
)
|
||||
.then(() => {
|
||||
this.postMessage = '';
|
||||
this.quote = null;
|
||||
this.feed.checkNewFeed();
|
||||
this.sending = false;
|
||||
})
|
||||
@@ -176,6 +235,9 @@
|
||||
<div class="header" v-if="!options.headerless">
|
||||
<div class="index">
|
||||
<appIcon :icon="subType" :text="displayedId" width="auto" />
|
||||
<a v-if="replyVisible" class="reply clickable" @click="reply" :title="replyTitle">
|
||||
<appIcon :icon="'reply'" />
|
||||
</a>
|
||||
<a v-if="anchorVisible" class="link desktop" @click="copyAnchor" ref="anchor" :href="anchorLink" :title="anchorTitle">
|
||||
<appIcon :icon="anchorIcon" />
|
||||
</a>
|
||||
@@ -210,16 +272,14 @@
|
||||
<projectMediaLink :options="options" :type="'post'" ref="medialink" @opening-lightbox="panMapToMarker" />
|
||||
</div>
|
||||
<template v-else-if="options.type == 'post'">
|
||||
<projectPostQuote v-if="quoteRef" :quote="quoteRef" class="clickable" @click="goToQuote" />
|
||||
<div class="message">
|
||||
<p v-for="(sLine, iIndex) in messageLines" :key="iIndex">{{ sLine }}</p>
|
||||
</div>
|
||||
<div class="signature">
|
||||
<img v-if="options.gravatar" :src="'data:image/png;base64, '+options.gravatar" width="24" height="24" alt="--" />
|
||||
<span v-else>-- </span>
|
||||
<span>{{ options.formatted_name }}</span>
|
||||
</div>
|
||||
<projectPostSignature :name="options.formatted_name" :gravatar="options.gravatar" />
|
||||
</template>
|
||||
<div v-else-if="options.type == 'poster'" class="poster-form">
|
||||
<projectPostQuote v-if="quote" :quote="quote" />
|
||||
<textarea ref="post" name="post" :placeholder="lang.get('post.message')" class="autoExpand" rows="1" v-model="postMessage"></textarea>
|
||||
<div class="poster-actions">
|
||||
<input type="text" name="name" :placeholder="lang.get('post.name')" v-model="user.name" />
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<script>
|
||||
import projectPostSignature from '@components/ProjectPostSignature';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
projectPostSignature
|
||||
},
|
||||
props: {
|
||||
quote: Object
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="'quote '+quote.type">
|
||||
<img v-if="quote.image" class="image" :src="quote.image" />
|
||||
<div class="text">
|
||||
<p class="content">{{ quote.content }}</p>
|
||||
<projectPostSignature v-if="quote.author" :name="quote.author" :gravatar="quote.gravatar" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,29 @@
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
name: String,
|
||||
gravatar: String
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="signature">
|
||||
<img v-if="gravatar" :src="'data:image/png;base64, '+gravatar" width="24" height="24" alt="--" />
|
||||
<span v-else>-- </span>
|
||||
<span>{{ name }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.signature {
|
||||
text-align: right;
|
||||
font-style: italic;
|
||||
|
||||
img {
|
||||
vertical-align: baseline;
|
||||
margin: 0 0.2em calc((1em - 24px)/2) 0;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -45,6 +45,7 @@ import {
|
||||
faPersonHiking,
|
||||
faPhotoFilm,
|
||||
faPlus,
|
||||
faReply,
|
||||
faScrewdriverWrench,
|
||||
faShoePrints,
|
||||
faSun,
|
||||
@@ -134,6 +135,7 @@ const ICONS = {
|
||||
'image-shot': faCamera,
|
||||
link: faLink,
|
||||
copied: faCheck,
|
||||
reply: faReply,
|
||||
'find-me-spot': findMeSpot,
|
||||
|
||||
/* Feed - Poster */
|
||||
|
||||
@@ -4,6 +4,66 @@
|
||||
|
||||
#feed {
|
||||
#feed-panel {
|
||||
.quote {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var.$elem-spacing;
|
||||
padding: var.$elem-spacing;
|
||||
border-radius: var.$block-radius;
|
||||
border-left-width: var.$border-thick;
|
||||
border-left-style: solid;
|
||||
font-size: 0.9em;
|
||||
box-shadow: var.$elem-shadow;
|
||||
|
||||
&.post {
|
||||
border-left-color: color.$post;
|
||||
background: color.$post-bg;
|
||||
color: color.$post;
|
||||
}
|
||||
|
||||
&.message {
|
||||
border-left-color: color.$message;
|
||||
background: color.$message-bg;
|
||||
color: color.$message;
|
||||
}
|
||||
|
||||
&.media {
|
||||
border-left-color: color.$media;
|
||||
background: color.$media-bg;
|
||||
color: color.$media;
|
||||
}
|
||||
|
||||
.image {
|
||||
flex: 0 0 auto;
|
||||
width: 3 * var.$block-spacing;
|
||||
height: 3 * var.$block-spacing;
|
||||
object-fit: cover;
|
||||
border-radius: var.$block-radius;
|
||||
}
|
||||
|
||||
.text {
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var.$text-spacing;
|
||||
|
||||
.content {
|
||||
margin: 0;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 3;
|
||||
line-clamp: 3;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
img {
|
||||
transform: scaleX(90%) scaleY(90%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#feed-header {
|
||||
.poster {
|
||||
.poster-form {
|
||||
@@ -70,7 +130,7 @@
|
||||
gap: var.$elem-spacing;
|
||||
flex: 0 0 auto;
|
||||
|
||||
.link {
|
||||
.link, .reply {
|
||||
padding: 0;
|
||||
line-height: 1;
|
||||
}
|
||||
@@ -203,7 +263,10 @@
|
||||
|
||||
&.post {
|
||||
.body {
|
||||
padding: 0 var.$block-spacing var.$elem-spacing;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var.$elem-spacing;
|
||||
padding-bottom: var.$elem-spacing;
|
||||
|
||||
.message p {
|
||||
margin: 0;
|
||||
@@ -212,18 +275,6 @@
|
||||
margin-top: var.$text-spacing;
|
||||
}
|
||||
}
|
||||
|
||||
.signature {
|
||||
margin-top: var.$elem-spacing;
|
||||
text-align: right;
|
||||
font-style: italic;
|
||||
|
||||
img {
|
||||
vertical-align: baseline;
|
||||
margin: 0 0.2em calc((1em - 24px)/2) 0;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,4 +14,8 @@ $elem-shadow: 0px 1px 1px color.$over-img-shadow;
|
||||
//Transitions
|
||||
$trans-quick: 200ms;
|
||||
$trans-slow: 500ms;
|
||||
$zoom-scale: 1.15;
|
||||
$zoom-scale: 1.15;
|
||||
|
||||
//Border
|
||||
$border-thin: 1px;
|
||||
$border-thick: 3px;
|
||||
|
||||
Reference in New Issue
Block a user