This repository has been archived by the owner on Aug 28, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Creation of the share modal * Update package.json * Addressed comments * Fixed dependency * Update ShareModal.vue * Fixed url * Update ShareModal.vue * Adressed changes
- Loading branch information
1 parent
227652d
commit 42f97f6
Showing
12 changed files
with
345 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
# Share Modal | ||
|
||
<DemoContainer> | ||
<Button @click="$refs.shareContent.show('This is content')"> | ||
<EditIcon/> | ||
Share Content | ||
</Button> | ||
<Button @click="$refs.shareLink.show('https://modrinth.com')"> | ||
<GlobeIcon/> | ||
Share Link | ||
</Button> | ||
<ShareModal | ||
ref="shareContent" | ||
share-title="This is the title for the content" | ||
share-text="Share this content" | ||
/> | ||
<ShareModal | ||
ref="shareLink" | ||
share-title="This is the title for the link" | ||
share-text="Share this link" | ||
link | ||
/> | ||
</DemoContainer> | ||
|
||
```vue | ||
<ShareModal | ||
ref="shareContent" | ||
share-title="This is the title for the content" | ||
share-text="Share this content" | ||
/> | ||
<ShareModal | ||
ref="shareLink" | ||
share-title="This is the title for the link" | ||
share-text="Share this link" | ||
link | ||
/> | ||
``` | ||
You can use ref to open the modal, calling the show method | ||
|
||
`content` is what will be shown in the text of the input for sharing | ||
```text | ||
$refs.shareContent.show(content) | ||
``` |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,270 @@ | ||
<script setup> | ||
import { | ||
Button, | ||
Modal, | ||
ClipboardCopyIcon, | ||
LinkIcon, | ||
ShareIcon, | ||
MailIcon, | ||
GlobeIcon, | ||
TwitterIcon, | ||
MastodonIcon, | ||
RedditIcon, | ||
} from '@/components' | ||
import { computed, ref, nextTick } from 'vue' | ||
import QrcodeVue from 'qrcode.vue' | ||
const props = defineProps({ | ||
header: { | ||
type: String, | ||
default: 'Share', | ||
}, | ||
shareTitle: { | ||
type: String, | ||
default: 'Modrinth', | ||
}, | ||
shareText: { | ||
type: String, | ||
default: null, | ||
}, | ||
link: { | ||
type: Boolean, | ||
default: false, | ||
}, | ||
}) | ||
const shareModal = ref(null) | ||
const qrCode = ref(null) | ||
const qrImage = ref(null) | ||
const content = ref(null) | ||
const url = ref(null) | ||
const canShare = ref(false) | ||
const share = () => { | ||
navigator.share( | ||
props.link | ||
? { | ||
title: props.shareTitle.toString(), | ||
text: props.shareText, | ||
url: url.value, | ||
} | ||
: { | ||
title: props.shareTitle.toString(), | ||
text: content.value, | ||
} | ||
) | ||
} | ||
const show = async (passedContent) => { | ||
content.value = props.shareText ? `${props.shareText}\n\n${passedContent}` : passedContent | ||
shareModal.value.show() | ||
if (props.link) { | ||
url.value = passedContent | ||
nextTick(() => { | ||
console.log(qrCode.value) | ||
fetch(qrCode.value.getElementsByTagName('canvas')[0].toDataURL('image/png')) | ||
.then((res) => res.blob()) | ||
.then((blob) => { | ||
console.log(blob) | ||
qrImage.value = blob | ||
}) | ||
}) | ||
} | ||
if (navigator.canShare({ title: props.shareTitle.toString(), text: content.value })) { | ||
canShare.value = true | ||
} | ||
} | ||
const copyImage = async () => { | ||
const item = new ClipboardItem({ 'image/png': qrImage.value }) | ||
await navigator.clipboard.write([item]) | ||
} | ||
const copyText = async () => { | ||
await navigator.clipboard.writeText(url.value ?? content.value) | ||
} | ||
const sendEmail = computed( | ||
() => | ||
`mailto:[email protected] | ||
?subject=${encodeURIComponent(props.shareTitle)} | ||
&body=` + encodeURIComponent(content.value) | ||
) | ||
const sendTweet = computed( | ||
() => `https://twitter.com/intent/tweet?text=` + encodeURIComponent(content.value) | ||
) | ||
const sendToot = computed(() => `https://tootpick.org/#text=` + encodeURIComponent(content.value)) | ||
const postOnReddit = computed( | ||
() => | ||
`https://www.reddit.com/submit?title=${encodeURIComponent(props.shareTitle)}&text=` + | ||
encodeURIComponent(content.value) | ||
) | ||
defineExpose({ | ||
show, | ||
}) | ||
</script> | ||
<template> | ||
<Modal ref="shareModal" :header="header"> | ||
<div class="share-body"> | ||
<div v-if="link" class="qr-wrapper"> | ||
<div ref="qrCode"> | ||
<QrcodeVue :value="url" class="qr-code" margin="3" /> | ||
</div> | ||
<Button v-tooltip="'Copy QR code'" icon-only class="copy-button" @click="copyImage"> | ||
<ClipboardCopyIcon /> | ||
</Button> | ||
</div> | ||
<div v-else class="resizable-textarea-wrapper"> | ||
<textarea v-model="content" /> | ||
<Button v-tooltip="'Copy Text'" icon-only class="copy-button transparent" @click="copyText"> | ||
<ClipboardCopyIcon /> | ||
</Button> | ||
</div> | ||
<div class="all-buttons"> | ||
<div v-if="link" class="iconified-input"> | ||
<LinkIcon /> | ||
<input type="text" :value="url" readonly /> | ||
<Button v-tooltip="'Copy Text'" @click="copyText"> | ||
<ClipboardCopyIcon /> | ||
</Button> | ||
</div> | ||
<div class="button-row"> | ||
<Button v-if="canShare" v-tooltip="'Share'" icon-only @click="share"> | ||
<ShareIcon /> | ||
</Button> | ||
<a v-tooltip="'Send as an email'" class="btn icon-only" target="_blank" :href="sendEmail"> | ||
<MailIcon /> | ||
</a> | ||
<a | ||
v-if="link" | ||
v-tooltip="'Open link in browser'" | ||
class="btn icon-only" | ||
target="_blank" | ||
:href="url" | ||
> | ||
<GlobeIcon /> | ||
</a> | ||
<a | ||
v-tooltip="'Toot about it'" | ||
class="btn mastodon icon-only" | ||
target="_blank" | ||
:href="sendToot" | ||
> | ||
<MastodonIcon /> | ||
</a> | ||
<a | ||
v-tooltip="'Tweet about it'" | ||
class="btn twitter icon-only" | ||
target="_blank" | ||
:href="sendTweet" | ||
> | ||
<TwitterIcon /> | ||
</a> | ||
<a | ||
v-tooltip="'Share on Reddit'" | ||
class="btn reddit icon-only" | ||
target="_blank" | ||
:href="postOnReddit" | ||
> | ||
<RedditIcon /> | ||
</a> | ||
</div> | ||
</div> | ||
</div> | ||
</Modal> | ||
</template> | ||
<style scoped lang="scss"> | ||
.share-body { | ||
display: flex; | ||
flex-direction: row; | ||
align-items: center; | ||
flex-wrap: wrap; | ||
gap: var(--gap-sm); | ||
padding: var(--gap-lg); | ||
} | ||
.all-buttons { | ||
display: flex; | ||
flex-direction: column; | ||
gap: var(--gap-sm); | ||
flex-grow: 1; | ||
justify-content: center; | ||
} | ||
.iconified-input { | ||
width: 100%; | ||
input { | ||
flex-basis: auto; | ||
} | ||
} | ||
.button-row { | ||
display: flex; | ||
flex-direction: row; | ||
gap: var(--gap-sm); | ||
.btn { | ||
fill: var(--color-contrast); | ||
color: var(--color-contrast); | ||
&.reddit { | ||
background-color: #ff4500; | ||
} | ||
&.mastodon { | ||
background-color: #563acc; | ||
} | ||
&.twitter { | ||
background-color: #1da1f2; | ||
} | ||
} | ||
} | ||
.qr-wrapper { | ||
position: relative; | ||
margin: 0 auto; | ||
&:hover { | ||
.copy-button { | ||
opacity: 1; | ||
} | ||
} | ||
} | ||
.qr-code { | ||
background-color: white !important; | ||
border-radius: var(--radius-md); | ||
} | ||
.copy-button { | ||
position: absolute; | ||
top: 0; | ||
right: 0; | ||
margin: var(--gap-sm); | ||
transition: all 0.2s ease-in-out; | ||
opacity: 0; | ||
} | ||
.resizable-textarea-wrapper { | ||
position: relative; | ||
height: 100%; | ||
textarea { | ||
width: 100%; | ||
margin: 0; | ||
} | ||
.btn { | ||
opacity: 1; | ||
margin: 0; | ||
} | ||
} | ||
</style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.