Skip to content
This repository has been archived by the owner on Sep 27, 2024. It is now read-only.

Commit

Permalink
Merge pull request #66 from MozillaSocial/compose-optimistic
Browse files Browse the repository at this point in the history
feat: Adding Post button and snackbar UI [MOSOWEB-24]
  • Loading branch information
gvn authored Oct 19, 2023
2 parents 719183c + 0952ffc commit 0b174b9
Show file tree
Hide file tree
Showing 8 changed files with 129 additions and 11 deletions.
4 changes: 3 additions & 1 deletion components/nav/NavSide.vue
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ const useStarFavoriteIcon = usePreferences('useStarFavoriteIcon')
<NavSideItem :text="$t('nav.bookmarks')" to="/bookmarks" icon="i-ri:bookmark-line" user-only :command="command" />

<div class="spacer" shrink hidden sm:block />
<NavSideItem :text="$t('action.compose')" to="/compose" icon="i-ri:quill-pen-line" user-only :command="command" />

<div class="spacer" shrink hidden sm:block />
<NavSideItem :text="$t('nav.explore')" :to="isHydrated ? `/${currentServer}/explore` : '/explore'" icon="i-ri:hashtag" :command="command" />
Expand All @@ -38,6 +37,9 @@ const useStarFavoriteIcon = usePreferences('useStarFavoriteIcon')

<div class="spacer" shrink hidden sm:block />
<NavSideItem :text="$t('nav.settings')" to="/settings" icon="i-ri:settings-3-line" :command="command" />

<div class="spacer" shrink hidden sm:block />
<NavSideItem lozenge :text="$t('action.compose')" to="/compose" icon="i-ri:add-fill" user-only :command="command" />
</nav>
</template>

Expand Down
36 changes: 35 additions & 1 deletion components/nav/NavSideItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ const props = withDefaults(defineProps<{
to: string | Record<string, string>
userOnly?: boolean
command?: boolean
lozenge?: boolean
}>(), {
userOnly: false,
lozenge: false,
})
defineSlots<{
Expand Down Expand Up @@ -56,12 +58,14 @@ const noUserVisual = computed(() => isHydrated.value && props.userOnly && !curre
<CommonTooltip :disabled="!isMediumOrLargeScreen" :content="text" placement="right">
<div
class="item"
:class="lozenge ? 'lozenge' : ''"
flex items-center gap4
w-fit rounded-3
px2 mx3 sm:mxa
xl="ml0 mr5 px5 w-auto"
transition-100
elk-group-hover="bg-active" group-focus-visible:ring="2 current"
:elk-group-hover="lozenge ? '' : 'bg-active'"
group-focus-visible:ring="2 current"
>
<slot name="icon">
<div :class="icon" text-xl />
Expand All @@ -75,6 +79,36 @@ const noUserVisual = computed(() => isHydrated.value && props.userOnly && !curre
</template>

<style scoped>
.lozenge {
color: var(--c-text-base-light);
font-size: 15px;
line-height: 20px;
max-width: 160px;
border-radius: 360px;
align-items: center;
background: var(--c-primary);
display: flex;
justify-content: center;
padding-right: 50px;
&:hover {
background: var(--c-primary-active);
}
}
@media screen and ( min-width: 640px ) {
.lozenge.item {
padding: 0.2rem;
}
}
@media screen and ( min-width: 1280px ) {
.lozenge.item {
padding-top: 12px;
padding-bottom: 12px;
}
}
.item {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
Expand Down
57 changes: 57 additions & 0 deletions components/publish/PublishSnackbar.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<script setup lang="ts">
import { ref } from 'vue'
const isVisible = ref(false)
function show() {
isVisible.value = true
setTimeout(() => {
hide()
}, 10000)
}
function hide() {
isVisible.value = false
}
defineExpose({
show,
hide,
})
</script>

<template>
<div class="snackbar-wrapper">
<div
:class="{ active: isVisible }"
class="snackbar"
>
Your post was published
</div>
</div>
</template>

<style scoped>
.snackbar-wrapper {
display: flex;
justify-content: center;
}
.snackbar {
background: var(--c-primary);
border-radius: 8px;
border: 1px solid var(--c-primary-light);
color: var(--c-text-base-light);
font-size: 12px;
font-weight: 600;
line-height: 16px;
min-width: 280px;
opacity: 0;
padding: 8px 16px;
text-align: center;
transition: opacity 800ms ease-in-out;
}
.snackbar.active {
opacity: 1;
}
</style>
11 changes: 10 additions & 1 deletion components/publish/PublishWidget.vue
Original file line number Diff line number Diff line change
Expand Up @@ -494,7 +494,7 @@ onDeactivated(() => {
</span>
<span v-if="draft.editingStatus">{{ $t('action.save_changes') }}</span>
<span v-else-if="draft.params.inReplyToId">{{ $t('action.reply') }}</span>
<span v-else>{{ !isSending ? $t('action.publish') : $t('state.publishing') }}</span>
<span v-else>{{ !isSending ? $t('action.post') : $t('state.publishing') }}</span>
</button>
</CommonTooltip>
</div>
Expand All @@ -504,6 +504,15 @@ onDeactivated(() => {
</template>
<style scoped>
.publish-button {
background: var(--c-primary);
border-radius: 360px;
&:hover {
background: var(--c-primary-active);
}
}
.publish-button[aria-disabled=true] {
cursor: not-allowed;
background-color: var(--c-bg-btn-disabled);
Expand Down
11 changes: 9 additions & 2 deletions components/publish/PublishWidgetFull.client.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
<script setup lang="ts">
import { formatTimeAgo } from '@vueuse/core'
const emit = defineEmits<{
(evt: 'published'): void
}>()
const route = useRoute()
const { formatNumber } = useHumanReadableNumber()
const timeAgoOptions = useTimeAgoOptions()
Expand All @@ -13,6 +16,10 @@ const nonEmptyDrafts = $computed(() => draftKeys
.map(i => [i, currentUserDrafts.value[i]] as const),
)
async function onPublish() {
emit('published')
}
watchEffect(() => {
draftKey = route.query.draft?.toString() || 'home'
})
Expand All @@ -23,7 +30,7 @@ onDeactivated(() => {
</script>

<template>
<div flex="~ col" pt-6 h-screen>
<div flex="~ col" pt-6 mb-6>
<div inline-flex justify-end h-8>
<VDropdown v-if="nonEmptyDrafts.length" placement="bottom-end">
<button btn-text flex="inline center">
Expand Down Expand Up @@ -57,7 +64,7 @@ onDeactivated(() => {
</VDropdown>
</div>
<div>
<PublishWidget :key="draftKey" expanded class="min-h-100!" :draft-key="draftKey" />
<PublishWidget :key="draftKey" expanded class="min-h-100!" :draft-key="draftKey" @published="onPublish" />
</div>
</div>
</template>
4 changes: 2 additions & 2 deletions locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
"clear_publish_failed": "Clear publish errors",
"clear_upload_failed": "Clear file upload errors",
"close": "Close",
"compose": "Compose",
"compose": "Post",
"confirm": "Confirm",
"create_account": "Create account",
"done": "Done",
Expand All @@ -64,8 +64,8 @@
"favourited": "Favorited",
"more": "More",
"next": "Next",
"post": "Post",
"prev": "Prev",
"publish": "Publish",
"reply": "Reply",
"reply_count": "{0}",
"reset": "Reset",
Expand Down
11 changes: 10 additions & 1 deletion pages/compose.vue
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
<script setup lang="ts">
import { ref } from 'vue'
definePageMeta({
middleware: 'auth',
})
Expand All @@ -8,8 +10,15 @@ const { t } = useI18n()
useHydratedHead({
title: () => t('nav.compose'),
})
const publishSnackbar = ref(null)
function onPublish() {
publishSnackbar.value.show()
}
</script>

<template>
<PublishWidgetFull />
<PublishWidgetFull @published="onPublish" />
<PublishSnackbar ref="publishSnackbar" />
</template>
6 changes: 3 additions & 3 deletions styles/vars.css
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,14 @@
--c-bg-code: #ffffff06;
--c-bg-dm: #0a2f35;

--c-text-base: #f3f3f3;
--c-text-base: #FBFBFE;
--c-text-base-light: #232323;
--c-text-code: #ecd88e;
--c-text-secondary: #888;
--c-text-secondary-light: #686868;

--c-bg-btn-disabled: #2a2a2a;
--c-text-btn-disabled: #919191;
--c-bg-btn-disabled: #9F9FAD;
--c-text-btn-disabled: #15141A;

--c-moz-logo-background: white;
--c-moz-logo-text: black;
Expand Down

0 comments on commit 0b174b9

Please sign in to comment.