web/satellite: share bucket feature

Implemented share bucket feature.
Refactored share object modal a bit (has to be refactored entirely).

Issue:
https://github.com/storj/storj/issues/4945

Change-Id: Icefd4bfe3eef9173ae824eea44d30450acde8044
This commit is contained in:
Vitalii 2022-08-29 14:08:38 +03:00
parent a57cbc4e0b
commit d585f2550d
18 changed files with 536 additions and 502 deletions

View File

@ -80,7 +80,7 @@ type Config struct {
PartneredSatellites console.Satellites `help:"names and addresses of partnered satellites in JSON list format" default:"[{\"name\":\"US1\",\"address\":\"https://us1.storj.io\"},{\"name\":\"EU1\",\"address\":\"https://eu1.storj.io\"},{\"name\":\"AP1\",\"address\":\"https://ap1.storj.io\"}]"`
GeneralRequestURL string `help:"url link to general request page" default:"https://supportdcs.storj.io/hc/en-us/requests/new?ticket_form_id=360000379291"`
ProjectLimitsIncreaseRequestURL string `help:"url link to project limit increase request page" default:"https://supportdcs.storj.io/hc/en-us/requests/new?ticket_form_id=360000683212"`
GatewayCredentialsRequestURL string `help:"url link for gateway credentials requests" default:"https://auth.storjshare.io" devDefault:""`
GatewayCredentialsRequestURL string `help:"url link for gateway credentials requests" default:"https://auth.storjshare.io" devDefault:"http://localhost:8000"`
IsBetaSatellite bool `help:"indicates if satellite is in beta" default:"false"`
BetaSatelliteFeedbackURL string `help:"url link for for beta satellite feedback" default:""`
BetaSatelliteSupportURL string `help:"url link for for beta satellite support" default:""`
@ -89,7 +89,7 @@ type Config struct {
CouponCodeSignupUIEnabled bool `help:"indicates if user is allowed to add coupon codes to account from signup" default:"false"`
FileBrowserFlowDisabled bool `help:"indicates if file browser flow is disabled" default:"false"`
CSPEnabled bool `help:"indicates if Content Security Policy is enabled" devDefault:"false" releaseDefault:"true"`
LinksharingURL string `help:"url link for linksharing requests" default:"https://link.storjshare.io" devDefault:""`
LinksharingURL string `help:"url link for linksharing requests" default:"https://link.storjshare.io" devDefault:"http://localhost:8001"`
PathwayOverviewEnabled bool `help:"indicates if the overview onboarding step should render with pathways" default:"true"`
NewProjectDashboard bool `help:"indicates if new project dashboard should be used" default:"true"`
NewObjectsFlow bool `help:"indicates if new objects flow should be used" default:"true"`

View File

@ -32,287 +32,7 @@
<hr>
<div class="social-share-icons my-4">
<p>Share this link via</p>
<!-- Sharingbutton Reddit -->
<a
class="resp-sharing-button__link"
:href="redditLink"
target="_blank"
rel="noopener"
aria-label="Reddit"
>
<div
class="
resp-sharing-button
resp-sharing-button--reddit
resp-sharing-button--medium
"
>
<div
aria-hidden="true"
class="
resp-sharing-button__icon
resp-sharing-button__icon--solid
"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
>
<path
d="M24 11.5c0-1.65-1.35-3-3-3-.96 0-1.86.48-2.42 1.24-1.64-1-3.75-1.64-6.07-1.72.08-1.1.4-3.05 1.52-3.7.72-.4 1.73-.24 3 .5C17.2 6.3 18.46 7.5 20 7.5c1.65 0 3-1.35 3-3s-1.35-3-3-3c-1.38 0-2.54.94-2.88 2.22-1.43-.72-2.64-.8-3.6-.25-1.64.94-1.95 3.47-2 4.55-2.33.08-4.45.7-6.1 1.72C4.86 8.98 3.96 8.5 3 8.5c-1.65 0-3 1.35-3 3 0 1.32.84 2.44 2.05 2.84-.03.22-.05.44-.05.66 0 3.86 4.5 7 10 7s10-3.14 10-7c0-.22-.02-.44-.05-.66 1.2-.4 2.05-1.54 2.05-2.84zM2.3 13.37C1.5 13.07 1 12.35 1 11.5c0-1.1.9-2 2-2 .64 0 1.22.32 1.6.82-1.1.85-1.92 1.9-2.3 3.05zm3.7.13c0-1.1.9-2 2-2s2 .9 2 2-.9 2-2 2-2-.9-2-2zm9.8 4.8c-1.08.63-2.42.96-3.8.96-1.4 0-2.74-.34-3.8-.95-.24-.13-.32-.44-.2-.68.15-.24.46-.32.7-.18 1.83 1.06 4.76 1.06 6.6 0 .23-.13.53-.05.67.2.14.23.06.54-.18.67zm.2-2.8c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm5.7-2.13c-.38-1.16-1.2-2.2-2.3-3.05.38-.5.97-.82 1.6-.82 1.1 0 2 .9 2 2 0 .84-.53 1.57-1.3 1.87z"
/>
</svg>
</div>
Reddit
</div>
</a>
<!-- Sharingbutton Facebook -->
<a
class="resp-sharing-button__link"
:href="facebookLink"
target="_blank"
rel="noopener"
aria-label="Facebook"
>
<div
class="
resp-sharing-button
resp-sharing-button--facebook
resp-sharing-button--medium
"
>
<div
aria-hidden="true"
class="
resp-sharing-button__icon
resp-sharing-button__icon--solid
"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
>
<path
d="M18.77 7.46H14.5v-1.9c0-.9.6-1.1 1-1.1h3V.5h-4.33C10.24.5 9.5 3.44 9.5 5.32v2.15h-3v4h3v12h5v-12h3.85l.42-4z"
/>
</svg>
</div>
Facebook
</div>
</a>
<!-- Sharingbutton Twitter -->
<a
class="resp-sharing-button__link"
:href="twitterLink"
target="_blank"
rel="noopener"
aria-label="Twitter"
>
<div
class="
resp-sharing-button
resp-sharing-button--twitter
resp-sharing-button--medium
"
>
<div
aria-hidden="true"
class="
resp-sharing-button__icon
resp-sharing-button__icon--solid
"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
>
<path
d="M23.44 4.83c-.8.37-1.5.38-2.22.02.93-.56.98-.96 1.32-2.02-.88.52-1.86.9-2.9 1.1-.82-.88-2-1.43-3.3-1.43-2.5 0-4.55 2.04-4.55 4.54 0 .36.03.7.1 1.04-3.77-.2-7.12-2-9.36-4.75-.4.67-.6 1.45-.6 2.3 0 1.56.8 2.95 2 3.77-.74-.03-1.44-.23-2.05-.57v.06c0 2.2 1.56 4.03 3.64 4.44-.67.2-1.37.2-2.06.08.58 1.8 2.26 3.12 4.25 3.16C5.78 18.1 3.37 18.74 1 18.46c2 1.3 4.4 2.04 6.97 2.04 8.35 0 12.92-6.92 12.92-12.93 0-.2 0-.4-.02-.6.9-.63 1.96-1.22 2.56-2.14z"
/>
</svg>
</div>
Twitter
</div>
</a>
<!-- Sharingbutton Hacker News -->
<a
class="resp-sharing-button__link"
:href="ycombinatorLink"
target="_blank"
rel="noopener"
aria-label="Hacker News"
>
<div
class="
resp-sharing-button
resp-sharing-button--hackernews
resp-sharing-button--medium
"
>
<div
aria-hidden="true"
class="
resp-sharing-button__icon
resp-sharing-button__icon--solid
"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 140 140"
>
<path
fill-rule="evenodd"
d="M60.94 82.314L17 0h20.08l25.85 52.093c.397.927.86 1.888 1.39 2.883.53.994.995 2.02 1.393 3.08.265.4.463.764.596 1.095.13.334.262.63.395.898.662 1.325 1.26 2.618 1.79 3.877.53 1.26.993 2.42 1.39 3.48 1.06-2.254 2.22-4.673 3.48-7.258 1.26-2.585 2.552-5.27 3.877-8.052L103.49 0h18.69L77.84 83.308v53.087h-16.9v-54.08z"
/>
</svg>
</div>
Hacker News
</div>
</a>
<!-- Sharingbutton LinkedIn -->
<a
class="resp-sharing-button__link"
:href="linkedinLink"
target="_blank"
rel="noopener"
aria-label="LinkedIn"
>
<div
class="
resp-sharing-button
resp-sharing-button--linkedin
resp-sharing-button--medium
"
>
<div
aria-hidden="true"
class="
resp-sharing-button__icon
resp-sharing-button__icon--solid
"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
>
<path
d="M6.5 21.5h-5v-13h5v13zM4 6.5C2.5 6.5 1.5 5.3 1.5 4s1-2.4 2.5-2.4c1.6 0 2.5 1 2.6 2.5 0 1.4-1 2.5-2.6 2.5zm11.5 6c-1 0-2 1-2 2v7h-5v-13h5V10s1.6-1.5 4-1.5c3 0 5 2.2 5 6.3v6.7h-5v-7c0-1-1-2-2-2z"
/>
</svg>
</div>
LinkedIn
</div>
</a>
<!-- Sharingbutton Telegram -->
<a
class="resp-sharing-button__link"
:href="telegramLink"
target="_blank"
rel="noopener"
aria-label="Telegram"
>
<div
class="
resp-sharing-button
resp-sharing-button--telegram
resp-sharing-button--medium
"
>
<div
aria-hidden="true"
class="
resp-sharing-button__icon
resp-sharing-button__icon--solid
"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
>
<path
d="M.707 8.475C.275 8.64 0 9.508 0 9.508s.284.867.718 1.03l5.09 1.897 1.986 6.38a1.102 1.102 0 0 0 1.75.527l2.96-2.41a.405.405 0 0 1 .494-.013l5.34 3.87a1.1 1.1 0 0 0 1.046.135 1.1 1.1 0 0 0 .682-.803l3.91-18.795A1.102 1.102 0 0 0 22.5.075L.706 8.475z"
/>
</svg>
</div>
Telegram
</div>
</a>
<!-- Sharingbutton WhatsApp -->
<a
class="resp-sharing-button__link"
:href="whatsappLink"
target="_blank"
rel="noopener"
aria-label="WhatsApp"
>
<div
class="
resp-sharing-button
resp-sharing-button--whatsapp
resp-sharing-button--medium
"
>
<div
aria-hidden="true"
class="
resp-sharing-button__icon
resp-sharing-button__icon--solid
"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
>
<path
d="M20.1 3.9C17.9 1.7 15 .5 12 .5 5.8.5.7 5.6.7 11.9c0 2 .5 3.9 1.5 5.6L.6 23.4l6-1.6c1.6.9 3.5 1.3 5.4 1.3 6.3 0 11.4-5.1 11.4-11.4-.1-2.8-1.2-5.7-3.3-7.8zM12 21.4c-1.7 0-3.3-.5-4.8-1.3l-.4-.2-3.5 1 1-3.4L4 17c-1-1.5-1.4-3.2-1.4-5.1 0-5.2 4.2-9.4 9.4-9.4 2.5 0 4.9 1 6.7 2.8 1.8 1.8 2.8 4.2 2.8 6.7-.1 5.2-4.3 9.4-9.5 9.4zm5.1-7.1c-.3-.1-1.7-.9-1.9-1-.3-.1-.5-.1-.7.1-.2.3-.8 1-.9 1.1-.2.2-.3.2-.6.1s-1.2-.5-2.3-1.4c-.9-.8-1.4-1.7-1.6-2-.2-.3 0-.5.1-.6s.3-.3.4-.5c.2-.1.3-.3.4-.5.1-.2 0-.4 0-.5C10 9 9.3 7.6 9 7c-.1-.4-.4-.3-.5-.3h-.6s-.4.1-.7.3c-.3.3-1 1-1 2.4s1 2.8 1.1 3c.1.2 2 3.1 4.9 4.3.7.3 1.2.5 1.6.6.7.2 1.3.2 1.8.1.6-.1 1.7-.7 1.9-1.3.2-.7.2-1.2.2-1.3-.1-.3-.3-.4-.6-.5z"
/>
</svg>
</div>
WhatsApp
</div>
</a>
<!-- Sharingbutton E-Mail -->
<a
class="resp-sharing-button__link"
:href="emailLink"
target="_self"
rel="noopener"
aria-label="E-Mail"
>
<div
class="
resp-sharing-button
resp-sharing-button--email
resp-sharing-button--medium
"
>
<div
aria-hidden="true"
class="
resp-sharing-button__icon
resp-sharing-button__icon--solid
"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
>
<path
d="M22 4H2C.9 4 0 4.9 0 6v12c0 1.1.9 2 2 2h20c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zM7.25 14.43l-3.5 2c-.08.05-.17.07-.25.07-.17 0-.34-.1-.43-.25-.14-.24-.06-.55.18-.68l3.5-2c.24-.14.55-.06.68.18.14.24.06.55-.18.68zm4.75.07c-.1 0-.2-.03-.27-.08l-8.5-5.5c-.23-.15-.3-.46-.15-.7.15-.22.46-.3.7-.14L12 13.4l8.23-5.32c.23-.15.54-.08.7.15.14.23.07.54-.16.7l-8.5 5.5c-.08.04-.17.07-.27.07zm8.93 1.75c-.1.16-.26.25-.43.25-.08 0-.17-.02-.25-.07l-3.5-2c-.24-.13-.32-.44-.18-.68s.44-.32.68-.18l3.5 2c.24.13.32.44.18.68z"
/>
</svg>
</div>
E-Mail
</div>
</a>
<ShareContainer :link="objectLink" />
</div>
<hr>
@ -345,16 +65,6 @@
</div>
</div>
</div>
<!-- <button
v-else
type="button"
name="copy"
class="btn btn-primary btn-block share-btn my-4"
v-on:click="getSharedLink"
>
Generate Share Link
</button> -->
</div>
</div>
</div>
@ -366,8 +76,14 @@
<script lang="ts">
import { Component, Vue } from "vue-property-decorator";
import ShareContainer from "@/components/common/share/ShareContainer.vue";
// @vue/component
@Component
@Component({
components: {
ShareContainer,
}
})
export default class FileShareModal extends Vue {
public objectLink = "";
public copyText = "Copy Link";
@ -379,89 +95,6 @@ export default class FileShareModal extends Vue {
return this.$store.state.files.fileShareModal;
}
/**
* Return the reddit link to share the current file on reddit.
*/
public get redditLink(): string {
return (
"https://reddit.com/submit/?url=" +
this.objectLink +
"&resubmit=true&title=Shared%20using%20Storj%20Decentralized%20Cloud%20Storage"
);
}
/**
* Return the facebook link to share the current file on facebook.
*/
public get facebookLink(): string {
return (
"https://facebook.com/sharer/sharer.php?u=" + this.objectLink
);
}
/**
* Return the twitter link to share the current file on twitter.
*/
public get twitterLink(): string {
return (
"https://twitter.com/intent/tweet/?text=Shared%20using%20Storj%20Decentralized%20Cloud%20Storage&url=" +
this.objectLink
);
}
/**
* Return the ycombinator link to share the current file on ycombinator.
*/
public get ycombinatorLink(): string {
return (
"https://news.ycombinator.com/submitlink?u=" +
this.objectLink +
"&t=Shared%20using%20Storj%20Decentralized%20Cloud%20Storage"
);
}
/**
* Return the linkedin link to share the current file on linkedin.
*/
public get linkedinLink(): string {
return (
"https://www.linkedin.com/shareArticle?mini=true&url=" +
this.objectLink +
"&title=Shared%20using%20Storj%20Decentralized%20Cloud%20Storage&summary=Shared%20using%20Storj%20Decentralized%20Cloud%20Storage&source=" +
this.objectLink
);
}
/**
* Return the telegram link to share the current file on telegram.
*/
public get telegramLink(): string {
return (
"https://telegram.me/share/url?text=Shared%20using%20Storj%20Decentralized%20Cloud%20Storage&url=" +
this.objectLink
);
}
/**
* Return the whatsapp link to share the current file on whatsapp.
*/
public get whatsappLink(): string {
return (
"whatsapp://send?text=Shared%20using%20Storj%20Decentralized%20Cloud%20Storage%20" +
this.objectLink
);
}
/**
* Return the email link to share the current file through email.
*/
public get emailLink(): string {
return (
"mailto:?subject=Shared%20using%20Storj%20Decentralized%20Cloud%20Storage&body=" +
this.objectLink
);
}
/**
* Set the objectLink by calling the store's fetchSharedLink function.
*/
@ -475,7 +108,7 @@ export default class FileShareModal extends Vue {
* Copy the selected link to the user's clipboard and update the copyText accordingly.
*/
public async copy(): Promise<void> {
await navigator.clipboard.writeText(this.objectLink);
await this.$copyText(this.objectLink);
this.copyText = "Copied!";
setTimeout(() => {
this.copyText = "Copy Link";
@ -529,127 +162,4 @@ export default class FileShareModal extends Vue {
font-size: 14px;
padding: 0 16px;
}
/* Social Share Buttons Styles */
.resp-sharing-button__link,
.resp-sharing-button__icon {
display: inline-block;
}
.resp-sharing-button__link {
text-decoration: none;
color: #fff;
margin-right: 1em;
margin-bottom: 1em;
}
.resp-sharing-button {
border-radius: 5px;
transition: 25ms ease-out;
padding: 0.5em 0.75em;
font-size: 12px;
}
.resp-sharing-button__icon svg {
width: 1em;
height: 1em;
margin-right: 0.4em;
vertical-align: middle;
}
.resp-sharing-button--small svg {
margin: 0;
vertical-align: middle;
}
.resp-sharing-button__icon--solid,
.resp-sharing-button__icon--solidcircle {
fill: #fff;
stroke: none;
}
.resp-sharing-button--facebook {
background-color: #3b5998;
border-color: #3b5998;
}
.resp-sharing-button--facebook:hover,
.resp-sharing-button--facebook:active {
background-color: #2d4373;
border-color: #2d4373;
}
.resp-sharing-button--twitter {
background-color: #55acee;
border-color: #55acee;
}
.resp-sharing-button--twitter:hover,
.resp-sharing-button--twitter:active {
background-color: #2795e9;
border-color: #2795e9;
}
.resp-sharing-button--email {
background-color: #777;
border-color: #777;
}
.resp-sharing-button--email:hover,
.resp-sharing-button--email:active {
background-color: #5e5e5e;
border-color: #5e5e5e;
}
.resp-sharing-button--reddit {
background-color: #5f99cf;
border-color: #5f99cf;
}
.resp-sharing-button--reddit:hover,
.resp-sharing-button--reddit:active {
background-color: #3a80c1;
border-color: #3a80c1;
}
.resp-sharing-button--hackernews {
background-color: #f60;
border-color: #f60;
}
.resp-sharing-button--hackernews:hover .resp-sharing-button--hackernews:active .resp-sharing-button--hackernews:focus {
background-color: #fb6200;
border-color: #fb6200;
}
.resp-sharing-button--whatsapp {
background-color: #25d366;
border-color: #25d366;
}
.resp-sharing-button--whatsapp:hover,
.resp-sharing-button--whatsapp:active {
background-color: #1da851;
border-color: #1da851;
}
.resp-sharing-button--linkedin {
background-color: #0077b5;
border-color: #0077b5;
}
.resp-sharing-button--linkedin:hover,
.resp-sharing-button--linkedin:active {
background-color: #046293;
border-color: #046293;
}
.resp-sharing-button--telegram {
background-color: #54a9eb;
}
.resp-sharing-button--telegram:hover {
background-color: #4b97d1;
}
</style>

View File

@ -0,0 +1,83 @@
// Copyright (C) 2022 Storj Labs, Inc.
// See LICENSE for copying information.
<template>
<a
class="share-button"
:href="link"
target="_blank"
rel="noopener noreferrer"
:aria-label="label"
:style="style"
>
<component :is="images[label]" />
<span>{{ label }}</span>
</a>
</template>
<script lang="ts">
import {Component, Prop, Vue} from "vue-property-decorator";
import {VueConstructor} from "vue";
import {ShareOptions} from "@/components/common/share/ShareContainer.vue";
import RedditIcon from "@/../static/images/objects/reddit.svg";
import FacebookIcon from "@/../static/images/objects/facebook.svg";
import TwitterIcon from "@/../static/images/objects/twitter.svg";
import HackerNewsIcon from "@/../static/images/objects/hackerNews.svg";
import LinkedInIcon from "@/../static/images/objects/linkedIn.svg";
import TelegramIcon from "@/../static/images/objects/telegram.svg";
import WhatsAppIcon from "@/../static/images/objects/whatsApp.svg";
import EmailIcon from "@/../static/images/objects/email.svg";
// @vue/component
@Component
export default class ShareButton extends Vue {
@Prop({default: ''})
public readonly label: ShareOptions;
@Prop({default: ''})
public readonly link: string;
@Prop({default: '#000'})
public readonly color: string;
private readonly images: Record<string, VueConstructor<Vue>> = {
[ShareOptions.Reddit]: RedditIcon,
[ShareOptions.Facebook]: FacebookIcon,
[ShareOptions.Twitter]: TwitterIcon,
[ShareOptions.HackerNews]: HackerNewsIcon,
[ShareOptions.LinkedIn]: LinkedInIcon,
[ShareOptions.Telegram]: TelegramIcon,
[ShareOptions.WhatsApp]: WhatsAppIcon,
[ShareOptions.Email]: EmailIcon,
}
/**
* Returns share button background color.
*/
public get style(): Record<string, string> {
return {'background-color': this.color};
}
}
</script>
<style scoped lang="scss">
.share-button {
display: flex;
align-items: center;
text-decoration: none;
color: #fff;
margin-right: 1em;
margin-bottom: 1em;
border-radius: 5px;
transition: 25ms ease-out;
padding: 0.5em 0.75em;
font-size: 12px;
font-family: 'font_regular', sans-serif;
svg {
width: 12px;
height: 12px;
margin-right: 5px;
}
}
</style>

View File

@ -0,0 +1,131 @@
// Copyright (C) 2022 Storj Labs, Inc.
// See LICENSE for copying information.
<template>
<div class="share-container">
<ShareButton
v-for="button of shareButtons"
:key="button.label"
:label="button.label"
:link="button.link"
:color="button.color"
/>
</div>
</template>
<script lang="ts">
import {Component, Prop, Vue} from "vue-property-decorator";
import ShareButton from "@/components/common/share/ShareButton.vue";
export enum ShareOptions {
Reddit = 'Reddit',
Facebook = 'Facebook',
Twitter = 'Twitter',
HackerNews = 'Hacker News',
LinkedIn = 'LinkedIn',
Telegram = 'Telegram',
WhatsApp = 'WhatsApp',
Email = 'E-Mail',
}
type ShareButtonConfig = {
link: string,
label: ShareOptions,
color: string,
}
// @vue/component
@Component({
components: {
ShareButton,
}
})
export default class ShareContainer extends Vue {
@Prop({default: ''})
private readonly link: string;
private readonly ShareOptions = ShareOptions
/**
* Returns share buttons list.
*/
private get shareButtons(): ShareButtonConfig[] {
return [
{label: ShareOptions.Reddit, color: '#5f99cf', link: this.redditLink},
{label: ShareOptions.Facebook, color: '#3b5998', link: this.facebookLink},
{label: ShareOptions.Twitter, color: '#55acee', link: this.twitterLink},
{label: ShareOptions.HackerNews, color: '#f60', link: this.hackernewsLink},
{label: ShareOptions.LinkedIn, color: '#0077b5', link: this.linkedinLink},
{label: ShareOptions.Telegram, color: '#54a9eb', link: this.telegramLink},
{label: ShareOptions.WhatsApp, color: '#25d366', link: this.whatsappLink},
{label: ShareOptions.Email, color: '#777', link: this.emailLink},
]
}
/**
* Return the reddit link to share the current bucket on reddit.
*/
private get redditLink(): string {
return `https://reddit.com/submit/?url=${this.link}&resubmit=true&title=Shared%20using%20Storj%20Decentralized%20Cloud%20Storage`;
}
/**
* Return the facebook link to share the current bucket on facebook.
*/
public get facebookLink(): string {
return `https://facebook.com/sharer/sharer.php?u=${this.link}`;
}
/**
* Return the twitter link to share the current bucket on twitter.
*/
public get twitterLink(): string {
return `https://twitter.com/intent/tweet/?text=Shared%20using%20Storj%20Decentralized%20Cloud%20Storage&url=${this.link}`;
}
/**
* Return the hacker news link to share the current bucket on hacker news.
*/
public get hackernewsLink(): string {
return `https://news.ycombinator.com/submitlink?u=${this.link}&t=Shared%20using%20Storj%20Decentralized%20Cloud%20Storage`;
}
/**
* Return the linkedin link to share the current bucket on linkedin.
*/
public get linkedinLink(): string {
return `https://www.linkedin.com/shareArticle?mini=true&url=${this.link}&title=Shared%20using%20Storj%20Decentralized%20Cloud%20Storage&summary=Shared%20using%20Storj%20Decentralized%20Cloud%20Storage&source=${this.link}`;
}
/**
* Return the telegram link to share the current bucket on telegram.
*/
public get telegramLink(): string {
return `https://telegram.me/share/url?text=Shared%20using%20Storj%20Decentralized%20Cloud%20Storage&url=${this.link}`;
}
/**
* Return the whatsapp link to share the current bucket on whatsapp.
*/
public get whatsappLink(): string {
return `whatsapp://send?text=Shared%20using%20Storj%20Decentralized%20Cloud%20Storage%20${this.link}`;
}
/**
* Return the email link to share the current bucket through email.
*/
public get emailLink(): string {
return `mailto:?subject=Shared%20using%20Storj%20Decentralized%20Cloud%20Storage&body=${this.link}`;
}
}
</script>
<style scoped lang="scss">
.share-container {
width: 100%;
display: flex;
align-items: center;
flex-wrap: wrap;
}
</style>

View File

@ -14,6 +14,7 @@
<ChangePasswordModal v-if="isChangePasswordModal" />
<AddTeamMemberModal v-if="isAddTeamMembersModal" />
<AddTokenFundsModal v-if="isAddTokenFundsModal" />
<ShareBucketModal v-if="isShareBucketModal" />
</div>
</template>
@ -31,6 +32,7 @@ import EditProfileModal from "@/components/modals/EditProfileModal.vue";
import ChangePasswordModal from "@/components/modals/ChangePasswordModal.vue";
import AddTeamMemberModal from "@/components/modals/AddTeamMemberModal.vue";
import AddTokenFundsModal from "@/components/modals/AddTokenFundsModal.vue";
import ShareBucketModal from "@/components/modals/ShareBucketModal.vue";
// @vue/component
@Component({
@ -46,9 +48,11 @@ import AddTokenFundsModal from "@/components/modals/AddTokenFundsModal.vue";
ChangePasswordModal,
AddTeamMemberModal,
AddTokenFundsModal,
ShareBucketModal,
},
})
export default class AllModals extends Vue {
// TODO: add active modal indicator.
/**
* Indicates if create project prompt modal is shown.
*/
@ -125,5 +129,12 @@ export default class AllModals extends Vue {
public get isAddTokenFundsModal(): boolean {
return this.$store.state.appStateModule.appState.isAddTokenFundsModalShown;
}
/**
* Indicates if share bucket modal is shown.
*/
public get isShareBucketModal(): boolean {
return this.$store.state.appStateModule.appState.isShareBucketModalShown;
}
}
</script>

View File

@ -0,0 +1,244 @@
// Copyright (C) 2022 Storj Labs, Inc.
// See LICENSE for copying information.
<template>
<VModal :on-close="closeModal">
<template #content>
<div class="modal">
<h1 class="modal__title">Share Bucket</h1>
<p class="modal__label">
Share this link via...
</p>
<ShareContainer :link="link" />
<p class="modal__label">
Or copy link
</p>
<VLoader v-if="isLoading" width="20px" height="20px" />
<p v-else class="modal__link">{{ link }}</p>
<div class="modal__buttons">
<VButton
label="Cancel"
height="48px"
is-transparent="true"
:on-press="closeModal"
:is-disabled="isLoading"
/>
<VButton
:label="copyButtonState === ButtonStates.Copy ? 'Copy Link' : 'Link Copied'"
height="48px"
:on-press="onCopy"
:is-disabled="isLoading"
:is-green-white="copyButtonState === ButtonStates.Copied"
/>
</div>
</div>
</template>
</VModal>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import { APP_STATE_MUTATIONS } from "@/store/mutationConstants";
import { ACCESS_GRANTS_ACTIONS } from "@/store/modules/accessGrants";
import { MetaUtils } from "@/utils/meta";
import { AccessGrant, EdgeCredentials } from "@/types/accessGrants";
import VModal from "@/components/common/VModal.vue";
import VLoader from "@/components/common/VLoader.vue";
import VButton from "@/components/common/VButton.vue";
import ShareContainer from "@/components/common/share/ShareContainer.vue";
enum ButtonStates {
Copy,
Copied,
}
// @vue/component
@Component({
components: {
VModal,
VButton,
VLoader,
ShareContainer,
},
})
export default class ShareBucketModal extends Vue {
private worker: Worker;
private readonly ButtonStates = ButtonStates
public isLoading = true;
public link = '';
public copyButtonState = ButtonStates.Copy;
/**
* Lifecycle hook after initial render.
* Sets local worker.
*/
public async mounted(): Promise<void> {
this.setWorker();
await this.setShareLink();
}
/**
* Copies link to users clipboard.
*/
public async onCopy(): Promise<void> {
await this.$copyText(this.link);
this.copyButtonState = ButtonStates.Copied;
setTimeout(() => {
this.copyButtonState = ButtonStates.Copy;
}, 2000)
await this.$notify.success('Link copied successfully.');
}
/**
* Sets share bucket link.
*/
private async setShareLink(): Promise<void> {
try {
let path = `${this.bucketName}`;
const now = new Date();
const LINK_SHARING_AG_NAME = `${path}_shared-bucket_${now.toISOString()}`;
const cleanAPIKey: AccessGrant = await this.$store.dispatch(ACCESS_GRANTS_ACTIONS.CREATE, LINK_SHARING_AG_NAME);
const satelliteNodeURL = MetaUtils.getMetaContent('satellite-nodeurl');
this.worker.postMessage({
'type': 'GenerateAccess',
'apiKey': cleanAPIKey.secret,
'passphrase': this.passphrase,
'projectID': this.$store.getters.selectedProject.id,
'satelliteNodeURL': satelliteNodeURL,
});
const grantEvent: MessageEvent = await new Promise(resolve => this.worker.onmessage = resolve);
const grantData = grantEvent.data;
if (grantData.error) {
await this.$notify.error(grantData.error);
return;
}
this.worker.postMessage({
'type': 'RestrictGrant',
'isDownload': true,
'isUpload': true,
'isList': true,
'isDelete': true,
'paths': [path],
'grant': grantData.value,
});
const event: MessageEvent = await new Promise(resolve => this.worker.onmessage = resolve);
const data = event.data;
if (data.error) {
await this.$notify.error(data.error);
return;
}
const credentials: EdgeCredentials =
await this.$store.dispatch(ACCESS_GRANTS_ACTIONS.GET_GATEWAY_CREDENTIALS, {accessGrant: data.value, isPublic: true});
path = encodeURIComponent(path.trim());
const linksharingURL = MetaUtils.getMetaContent('linksharing-url');
this.link = `${linksharingURL}/${credentials.accessKeyId}/${path}`;
} catch (error) {
await this.$notify.error(error.message);
} finally {
this.isLoading = false;
}
}
/**
* Sets local worker with worker instantiated in store.
*/
public setWorker(): void {
this.worker = this.$store.state.accessGrantsModule.accessGrantsWebWorker;
this.worker.onerror = (error: ErrorEvent) => {
this.$notify.error(error.message);
};
}
/**
* Closes open bucket modal.
*/
public closeModal(): void {
if (this.isLoading) return;
this.$store.commit(APP_STATE_MUTATIONS.TOGGLE_SHARE_BUCKET_MODAL_SHOWN);
}
/**
* Returns chosen bucket name from store.
*/
private get bucketName(): string {
return this.$store.state.objectsModule.fileComponentBucketName;
}
/**
* Returns passphrase from store.
*/
private get passphrase(): string {
return this.$store.state.objectsModule.passphrase;
}
}
</script>
<style scoped lang="scss">
.modal {
font-family: 'font_regular', sans-serif;
display: flex;
flex-direction: column;
align-items: center;
padding: 35px 35px 35px 50px;
max-width: 470px;
@media screen and (max-width: 430px) {
padding: 20px;
}
&__title {
font-family: 'font_bold', sans-serif;
font-size: 22px;
line-height: 29px;
color: #1b2533;
}
&__label {
font-family: 'font_medium', sans-serif;
font-size: 16px;
line-height: 21px;
color: #354049;
align-self: flex-start;
margin: 32px 0 16px;
}
&__link {
font-size: 16px;
line-height: 21px;
color: #384b65;
align-self: flex-start;
word-break: break-all;
text-align: left;
}
&__buttons {
display: flex;
column-gap: 20px;
margin-top: 32px;
width: 100%;
@media screen and (max-width: 430px) {
flex-direction: column-reverse;
column-gap: unset;
row-gap: 15px;
}
}
}
</style>

View File

@ -13,6 +13,10 @@
<details-icon class="bucket-settings-nav__dropdown__item__icon" />
<p class="bucket-settings-nav__dropdown__item__label">View Bucket Details</p>
</div>
<div v-if="filesCount" class="bucket-settings-nav__dropdown__item" @click.stop="onShareBucketClick">
<share-icon class="bucket-settings-nav__dropdown__item__icon" />
<p class="bucket-settings-nav__dropdown__item__label">Share bucket</p>
</div>
</div>
</div>
</template>
@ -20,10 +24,13 @@
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
import { RouteConfig } from "@/router";
import { APP_STATE_MUTATIONS } from "@/store/mutationConstants";
import ArrowDownIcon from '@/../static/images/objects/arrowDown.svg';
import DetailsIcon from '@/../static/images/objects/details.svg';
import ShareIcon from '@/../static/images/objects/share.svg';
import GearIcon from '@/../static/images/common/gearIcon.svg';
import { RouteConfig } from "@/router";
// @vue/component
@Component({
@ -31,6 +38,7 @@ import { RouteConfig } from "@/router";
ArrowDownIcon,
GearIcon,
DetailsIcon,
ShareIcon,
},
})
export default class BucketSettingsNav extends Vue {
@ -58,6 +66,21 @@ export default class BucketSettingsNav extends Vue {
});
this.isDropdownOpen = false;
}
/**
* Toggles share bucket modal.
*/
public onShareBucketClick(): void {
this.$store.commit(APP_STATE_MUTATIONS.TOGGLE_SHARE_BUCKET_MODAL_SHOWN);
this.isDropdownOpen = false;
}
/**
* Returns files amount from store.
*/
public get filesCount(): number {
return this.$store.getters["files/sortedFiles"].length;
}
}
</script>

View File

@ -37,6 +37,7 @@ class ViewsState {
public isEnableMFAModalShown = false,
public isDisableMFAModalShown = false,
public isAddTokenFundsModalShown = false,
public isShareBucketModalShown = false,
public isBillingNotificationShown = true,
public onbAGStepBackRoute = "",
@ -148,6 +149,9 @@ export const appStateModule = {
[APP_STATE_MUTATIONS.TOGGLE_ADD_TOKEN_FUNDS_MODAL_SHOWN](state: State): void {
state.appState.isAddTokenFundsModalShown = !state.appState.isAddTokenFundsModalShown;
},
[APP_STATE_MUTATIONS.TOGGLE_SHARE_BUCKET_MODAL_SHOWN](state: State): void {
state.appState.isShareBucketModalShown = !state.appState.isShareBucketModalShown;
},
[APP_STATE_MUTATIONS.SHOW_SET_DEFAULT_PAYMENT_METHOD_POPUP](state: State, id: string): void {
state.appState.setDefaultPaymentMethodID = id;
},

View File

@ -37,6 +37,7 @@ export const APP_STATE_MUTATIONS = {
TOGGLE_ENABLE_MFA_MODAL_SHOWN: 'TOGGLE_ENABLE_MFA_MODAL_SHOWN',
TOGGLE_DISABLE_MFA_MODAL_SHOWN: 'TOGGLE_DISABLE_MFA_MODAL_SHOWN',
TOGGLE_ADD_TOKEN_FUNDS_MODAL_SHOWN: 'TOGGLE_ADD_TOKEN_FUNDS_MODAL_SHOWN',
TOGGLE_SHARE_BUCKET_MODAL_SHOWN: 'TOGGLE_SHARE_BUCKET_MODAL_SHOWN',
SHOW_DELETE_PAYMENT_METHOD_POPUP: 'SHOW_DELETE_PAYMENT_METHOD_POPUP',
SHOW_SET_DEFAULT_PAYMENT_METHOD_POPUP: 'SHOW_SET_DEFAULT_PAYMENT_METHOD_POPUP',
CLOSE_ALL: 'CLOSE_ALL',

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M22 4H2C.9 4 0 4.9 0 6v12c0 1.1.9 2 2 2h20c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zM7.25 14.43l-3.5 2c-.08.05-.17.07-.25.07-.17 0-.34-.1-.43-.25-.14-.24-.06-.55.18-.68l3.5-2c.24-.14.55-.06.68.18.14.24.06.55-.18.68zm4.75.07c-.1 0-.2-.03-.27-.08l-8.5-5.5c-.23-.15-.3-.46-.15-.7.15-.22.46-.3.7-.14L12 13.4l8.23-5.32c.23-.15.54-.08.7.15.14.23.07.54-.16.7l-8.5 5.5c-.08.04-.17.07-.27.07zm8.93 1.75c-.1.16-.26.25-.43.25-.08 0-.17-.02-.25-.07l-3.5-2c-.24-.13-.32-.44-.18-.68s.44-.32.68-.18l3.5 2c.24.13.32.44.18.68z" fill="#fff"/>
</svg>

After

Width:  |  Height:  |  Size: 597 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M18.77 7.46H14.5v-1.9c0-.9.6-1.1 1-1.1h3V.5h-4.33C10.24.5 9.5 3.44 9.5 5.32v2.15h-3v4h3v12h5v-12h3.85l.42-4z" fill="#fff"/>
</svg>

After

Width:  |  Height:  |  Size: 205 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 140 140">
<path fill-rule="evenodd" d="M60.94 82.314L17 0h20.08l25.85 52.093c.397.927.86 1.888 1.39 2.883.53.994.995 2.02 1.393 3.08.265.4.463.764.596 1.095.13.334.262.63.395.898.662 1.325 1.26 2.618 1.79 3.877.53 1.26.993 2.42 1.39 3.48 1.06-2.254 2.22-4.673 3.48-7.258 1.26-2.585 2.552-5.27 3.877-8.052L103.49 0h18.69L77.84 83.308v53.087h-16.9v-54.08z" fill="#fff"/>
</svg>

After

Width:  |  Height:  |  Size: 433 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M6.5 21.5h-5v-13h5v13zM4 6.5C2.5 6.5 1.5 5.3 1.5 4s1-2.4 2.5-2.4c1.6 0 2.5 1 2.6 2.5 0 1.4-1 2.5-2.6 2.5zm11.5 6c-1 0-2 1-2 2v7h-5v-13h5V10s1.6-1.5 4-1.5c3 0 5 2.2 5 6.3v6.7h-5v-7c0-1-1-2-2-2z" fill="#fff"/>
</svg>

After

Width:  |  Height:  |  Size: 289 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M24 11.5c0-1.65-1.35-3-3-3-.96 0-1.86.48-2.42 1.24-1.64-1-3.75-1.64-6.07-1.72.08-1.1.4-3.05 1.52-3.7.72-.4 1.73-.24 3 .5C17.2 6.3 18.46 7.5 20 7.5c1.65 0 3-1.35 3-3s-1.35-3-3-3c-1.38 0-2.54.94-2.88 2.22-1.43-.72-2.64-.8-3.6-.25-1.64.94-1.95 3.47-2 4.55-2.33.08-4.45.7-6.1 1.72C4.86 8.98 3.96 8.5 3 8.5c-1.65 0-3 1.35-3 3 0 1.32.84 2.44 2.05 2.84-.03.22-.05.44-.05.66 0 3.86 4.5 7 10 7s10-3.14 10-7c0-.22-.02-.44-.05-.66 1.2-.4 2.05-1.54 2.05-2.84zM2.3 13.37C1.5 13.07 1 12.35 1 11.5c0-1.1.9-2 2-2 .64 0 1.22.32 1.6.82-1.1.85-1.92 1.9-2.3 3.05zm3.7.13c0-1.1.9-2 2-2s2 .9 2 2-.9 2-2 2-2-.9-2-2zm9.8 4.8c-1.08.63-2.42.96-3.8.96-1.4 0-2.74-.34-3.8-.95-.24-.13-.32-.44-.2-.68.15-.24.46-.32.7-.18 1.83 1.06 4.76 1.06 6.6 0 .23-.13.53-.05.67.2.14.23.06.54-.18.67zm.2-2.8c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm5.7-2.13c-.38-1.16-1.2-2.2-2.3-3.05.38-.5.97-.82 1.6-.82 1.1 0 2 .9 2 2 0 .84-.53 1.57-1.3 1.87z" fill="#fff"/>
</svg>

After

Width:  |  Height:  |  Size: 1001 B

View File

@ -0,0 +1,3 @@
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0.900391 10.2752L0.900949 10.0503C0.912716 8.17775 1.11196 7.2088 1.63425 6.22342C1.88613 5.7482 2.20039 5.32285 2.57261 4.95385C2.85829 4.67065 3.31946 4.67265 3.60266 4.95833C3.88586 5.24401 3.88385 5.70517 3.59817 5.98837C3.33121 6.25302 3.10485 6.5594 2.92134 6.90562C2.5143 7.67358 2.36188 8.43402 2.35721 10.149L2.3571 10.2731L2.35804 10.4358C2.37167 11.9802 2.5165 12.7235 2.87237 13.4281L2.92134 13.5226C3.27753 14.1946 3.79552 14.7173 4.46057 15.0762L4.534 15.115C5.26865 15.4953 6.02462 15.639 7.66597 15.6436L10.2838 15.6437L10.5231 15.6419C11.9723 15.6243 12.6934 15.4824 13.3669 15.1438L13.439 15.1068L13.4965 15.0762C14.1615 14.7173 14.6795 14.1946 15.0357 13.5226C15.4428 12.7546 15.5952 11.9942 15.5998 10.2793L15.6 10.1551L15.599 9.99246C15.5854 8.44797 15.4406 7.70471 15.0847 7.00012L15.0357 6.90562C14.8781 6.60821 14.6888 6.3402 14.4694 6.10281C14.1963 5.80742 14.2145 5.3466 14.5099 5.07356C14.8053 4.80051 15.2661 4.81863 15.5391 5.11403C15.8227 5.42088 16.069 5.76284 16.2772 6.13935L16.3246 6.22685L16.3586 6.29191C16.8377 7.21986 17.0321 8.15937 17.0546 9.88377L17.0567 10.153L17.0561 10.378C17.0443 12.2505 16.8451 13.2194 16.3228 14.2048C15.8449 15.1065 15.145 15.8237 14.2572 16.3202L14.1848 16.36L14.1203 16.3943L14.0265 16.4426C13.1186 16.8999 12.1741 17.0827 10.4654 17.0993L10.2859 17.1004H7.74878L7.56629 17.0998C5.70967 17.0877 4.74711 16.886 3.76879 16.3581C2.87423 15.8754 2.16337 15.1692 1.67181 14.2743L1.63244 14.2014L1.59841 14.1363C1.09498 13.1612 0.905921 12.1733 0.900391 10.2752ZM5.6622 3.94408L5.6825 3.92295L8.49173 1.11372C8.76924 0.836218 9.21495 0.82945 9.50066 1.09342L9.52179 1.11372L12.331 3.92295C12.6155 4.20739 12.6155 4.66856 12.331 4.953C12.0535 5.23051 11.6078 5.23728 11.3221 4.97331L11.301 4.953L9.71078 3.36277V11.5919C9.71078 11.9941 9.38468 12.3202 8.98242 12.3202C8.58998 12.3202 8.27002 12.0098 8.25465 11.6212L8.25407 11.5919V3.41124L6.71255 4.953C6.43505 5.23051 5.98933 5.23728 5.70363 4.97331L5.6825 4.953C5.405 4.6755 5.39823 4.22978 5.6622 3.94408Z" fill="#56606D"/>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M.707 8.475C.275 8.64 0 9.508 0 9.508s.284.867.718 1.03l5.09 1.897 1.986 6.38a1.102 1.102 0 0 0 1.75.527l2.96-2.41a.405.405 0 0 1 .494-.013l5.34 3.87a1.1 1.1 0 0 0 1.046.135 1.1 1.1 0 0 0 .682-.803l3.91-18.795A1.102 1.102 0 0 0 22.5.075L.706 8.475z" fill="#fff"/>
</svg>

After

Width:  |  Height:  |  Size: 345 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M23.44 4.83c-.8.37-1.5.38-2.22.02.93-.56.98-.96 1.32-2.02-.88.52-1.86.9-2.9 1.1-.82-.88-2-1.43-3.3-1.43-2.5 0-4.55 2.04-4.55 4.54 0 .36.03.7.1 1.04-3.77-.2-7.12-2-9.36-4.75-.4.67-.6 1.45-.6 2.3 0 1.56.8 2.95 2 3.77-.74-.03-1.44-.23-2.05-.57v.06c0 2.2 1.56 4.03 3.64 4.44-.67.2-1.37.2-2.06.08.58 1.8 2.26 3.12 4.25 3.16C5.78 18.1 3.37 18.74 1 18.46c2 1.3 4.4 2.04 6.97 2.04 8.35 0 12.92-6.92 12.92-12.93 0-.2 0-.4-.02-.6.9-.63 1.96-1.22 2.56-2.14z" fill="#fff"/>
</svg>

After

Width:  |  Height:  |  Size: 543 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M20.1 3.9C17.9 1.7 15 .5 12 .5 5.8.5.7 5.6.7 11.9c0 2 .5 3.9 1.5 5.6L.6 23.4l6-1.6c1.6.9 3.5 1.3 5.4 1.3 6.3 0 11.4-5.1 11.4-11.4-.1-2.8-1.2-5.7-3.3-7.8zM12 21.4c-1.7 0-3.3-.5-4.8-1.3l-.4-.2-3.5 1 1-3.4L4 17c-1-1.5-1.4-3.2-1.4-5.1 0-5.2 4.2-9.4 9.4-9.4 2.5 0 4.9 1 6.7 2.8 1.8 1.8 2.8 4.2 2.8 6.7-.1 5.2-4.3 9.4-9.5 9.4zm5.1-7.1c-.3-.1-1.7-.9-1.9-1-.3-.1-.5-.1-.7.1-.2.3-.8 1-.9 1.1-.2.2-.3.2-.6.1s-1.2-.5-2.3-1.4c-.9-.8-1.4-1.7-1.6-2-.2-.3 0-.5.1-.6s.3-.3.4-.5c.2-.1.3-.3.4-.5.1-.2 0-.4 0-.5C10 9 9.3 7.6 9 7c-.1-.4-.4-.3-.5-.3h-.6s-.4.1-.7.3c-.3.3-1 1-1 2.4s1 2.8 1.1 3c.1.2 2 3.1 4.9 4.3.7.3 1.2.5 1.6.6.7.2 1.3.2 1.8.1.6-.1 1.7-.7 1.9-1.3.2-.7.2-1.2.2-1.3-.1-.3-.3-.4-.6-.5z" fill="#fff"/>
</svg>

After

Width:  |  Height:  |  Size: 775 B