Skip to content

Commit

Permalink
Merge branch 'feature/composable'
Browse files Browse the repository at this point in the history
  • Loading branch information
stefanobartoletti committed Nov 7, 2023
2 parents eaaac3b + fb6ea22 commit 0388f5f
Show file tree
Hide file tree
Showing 5 changed files with 173 additions and 86 deletions.
128 changes: 82 additions & 46 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@ Simple Social Sharing for Nuxt

## 🌟 Features

- Provides an easy to use `SocialShare` component
- Component unstyled by default for easy integration in any design
- Provides a minimal config `<SocialShare>` component
- The component is unstyled by default for easy integration in any design
- Optional styled version, that can still be further customized
- A `useSocialShare` composable is exposed, to provide even more flexibility if needed
- Many major social networks supported

## 🛠️ Quick Setup
Expand Down Expand Up @@ -61,15 +62,15 @@ export default defineNuxtConfig({

That's it! You can now use Nuxt Social Share in your Nuxt app ✨

## 🔩 Use
## 🎨 Using the `<SocialShare>` component

The `SocialShare` component provides a share button for a single social network, that you must select from the `network` prop; you will need to use it as many times as your total needed networks.
The `<SocialShare>` component provides a share button for a single social network, that you must select with the `network` prop; you will need to use it as many times as your total needed networks.

```vue
<!-- Basic use -->
<SocialShare network="facebook" />
<SocialShare network="twitter" />
<SocialShare network="linkdin" />
<SocialShare network="linkedin" />
<!-- Customization with props -->
<SocialShare network="facebook" :styled="true" :label="false" />
Expand All @@ -87,7 +88,7 @@ The component will render by default the following minimal HTML:
An additional `social-share-button--styled` class will be added to the `<a>` element if `:styled="true"`, while the `<span>` element will not be rendered if `:label="false"`.

> **Note**
> - The component comes unstyled by default, only providing some minimal flex properties to correctly align icon and label; you can use the elements classes to apply every style according to your design. Or, if you use Tailwind, you can style it by directly applying classes to the component, that will be applied to the `<a>` element.
> - The component comes unstyled by default, only providing some minimal flex properties to correctly align icon and label; you can use the elements classes to apply every style according to your design. Or, if you use Tailwind, you can style it by directly applying classes to the component, that will be passed down to the `<a>` element.
> - Custom styles or additional classes can also be used when using the `styled` version.
> - The only required prop is `network`, other like `styled` or `label` are best set from the module options (see 'Configuration' below)
> - The component only provides a single share button. As you will typically need to use more of them at once, you should place them inside a wrapper to distribute them according to your design.
Expand All @@ -108,79 +109,114 @@ A common use when using i.e. Tailwind could be as follows:
</div>
```

## 🎛️ Configuration
### Props

Module options can be set from the `socialShare` key in `nuxt.config.ts`:
#### `network`

```ts
export default defineNuxtConfig({
// optional configuration
socialShare: {
// module options
}
})
```
- Required: `Yes`
- Type: `String`

Available options:
The social network or messaging service where the content should be shared. This is required for the component to work.

### `styled`
A list of the supported networks is available below.

#### `styled`

- Required: `No`
- Type: `Boolean`
- Default: `false`

Whether the `socialShare` components should be styled or not. It is `false` by default to allow for easier custom styling.
Whether the component should be styled or not. It is `false` by default to allow for easier custom styling. Additional customization is possible also when set to `true`.

It can be set also on a single component level via props, but is us usually better to set this from the module options to create your defaults, and override it from props only if needed.
This property should be typically set globally from the module options, it is available as a prop to allow a different behavior on a single instance of the component.

### `label`
#### `label`

- Required: `No`
- Type: `Boolean`
- Default: `true`

Whether the text label should be rendered or not. It is `true` by default, when set to `false` only the icon will be displayed.

It can be set also on a single component level via props, but is us usually better to set this from the module options to create your defaults, and override it from props only if needed.

## 🎨 Props
This property should be usually set globally from the module options, it is available as a prop to allow a different behavior on a single instance of the component.

### `network`
#### `url`

- Required: `Yes`
- Required: `No`
- Type: `String`
- Default: `the current page URL`

The social network or messaging service where the content should be shared. This is the only required prop.
The URL that will be shared on the selected social network.

A list of the supported networks is available below.
Defaults to the current page URL. On most cases you don't need another value, but if you need to provide a different URL, you can do so with this prop.

### `styled`
## 🔩 Using the `useSocialShare` composable

- Required: `No`
- Type: `Boolean`
- Default: `false`
Using the customizable component should cover almost every use case, but if needed the `useSocialShare` composable can be directly accessed for even more flexibility. This composable is used internally to create the `<SocialShare>` components.

Whether the component should be styled or not. It is `false` by default to allow for easier custom styling. Additional customization is possible also when set to `true`.
Like the component, one instance of `useSocialShare` should be used for every needed share.

This property should be typically set globally from the module options, it is available as a prop to allow a different behavior on a single instance of the component.
An options object should be passed as an argument, like in the following example:

### `label`
```vue
<script setup>
// Basic minimal use
const shareFacebook = useSocialShare({ network: 'facebook' })
// All possible options
const shareFacebook = useSocialShare({
network: 'facebook', // Required
url: 'https://www.example.com' // Optional, defaults to current page URL if not provided
})
</script>
```

It will return the following object, e:

```js
{
"name": "facebook", // Name of the selected social network
"shareUrl": "https://www.facebook.com/sharer/sharer.php?u=https://www.example.com", // Sharing url
"iconName": "ri:facebook-fill", // Icon name from "@iconify/vue" package
"color": "#0866FF" // Main brand color of the selected network
}
```

You can then use some or all the returned properties, according to your project setup and requirements.


## 🎛️ Configuration

Module options can be set from the `socialShare` key in `nuxt.config.ts`:

```ts
export default defineNuxtConfig({
// optional configuration
socialShare: {
// module options
}
})
```

Available options:

### `styled`

- Required: `No`
- Type: `Boolean`
- Default: `true`
- Default: `false`

Whether the text label should be rendered or not. It is `true` by default, when set to `false` only the icon will be displayed.
Whether the `<SocialShare>` components should be styled or not. It is `false` by default to allow for easier custom styling.

This property should be usually set globally from the module options, it is available as a prop to allow a different behavior on a single instance of the component.
It can be set also on a single component level via props, but is us usually better to set this from the module options to create your defaults, and override it from props only if needed.

### `url`
### `label`

- Required: `No`
- Type: `String`
- Default: `the current page URL`
- Type: `Boolean`
- Default: `true`

The URL that will be shared on the selected social network.
Whether the text label in the `<SocialShare>` components should be rendered or not. It is `true` by default, when set to `false` only the icon will be displayed.

Defaults to the current page URL. On most cases you don't need another value, but if you need to provide another URL, you can do so with this prop.
It can be set also on a single component level via props, but is us usually better to set this from the module options to create your defaults, and override it from props only if needed.

## ↗️ Supported networks

Expand All @@ -202,7 +238,7 @@ A list of the currently supported networks and of their URL arguments.
> **Important**
> At the moment only the `url` argument is implemented. More, like `title`, `text` and other, are planned for a future release.
> Please note that only `url` is strictly required for the sharing to work. When not explicity set, other metadata will be automatically retrived from Open Graph meta tags, that you always should properly set in your webpages anyway.
> Anyway, please note that only `url` is strictly required for the sharing to work. When not explicity set, other metadata will be retrived by the social network from Open Graph meta tags, that you always should properly set in your webpages anyway.
## ✅ Todo

Expand Down
14 changes: 14 additions & 0 deletions playground/app.vue
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,17 @@
:network="network"
/>
</div>

<h2>composable output</h2>
<pre>{{ testComposable }}</pre>
</div>
</template>

<script setup>
import { useSocialShare } from '#imports';
const testComposable = useSocialShare({network: 'facebook'})
const testNetworks = [
'facebook',
'twitter',
Expand Down Expand Up @@ -87,4 +94,11 @@ const testNetworks = [
font-size: 1rem;
border-radius: 0;
}
pre {
background-color: lightgray;
padding: 1rem;
font-family: monospace;
max-width: max-content;
}
</style>
9 changes: 7 additions & 2 deletions src/module.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { defineNuxtModule, addComponent, createResolver } from '@nuxt/kit'
import { defineNuxtModule, addComponent, addImports, createResolver } from '@nuxt/kit'
import { defu } from 'defu'

// Module options TypeScript interface definition
Expand Down Expand Up @@ -27,7 +27,12 @@ export default defineNuxtModule<ModuleOptions>({
// From the runtime directory
addComponent({
name: 'SocialShare', // name of the component to be used in vue templates
filePath: resolver.resolve('./runtime/components/SocialShare.vue')
filePath: resolver.resolve('./runtime/SocialShare.vue')
})

addImports({
name: 'useSocialShare',
from: resolver.resolve('./runtime/useSocialShare')
})

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
>
<Icon
class="social-share-button__icon"
:icon="socialNetwork.icon"
:icon="socialNetwork.iconName"
/>
<span
v-if="optionLabel"
Expand All @@ -18,7 +18,8 @@

<script setup>
import { Icon } from '@iconify/vue';
import { useRequestURL, useRuntimeConfig } from '#imports';
import { useRuntimeConfig } from '#imports';
import { useSocialShare } from './useSocialShare';
const props = defineProps({
network: { type: String, required: true },
Expand All @@ -31,44 +32,12 @@ const options = useRuntimeConfig().public.socialShare
const optionStyled = props.styled != null ? props.styled : options.styled
const optionLabel = props.label != null ? props.label : options.label
const pageUrl = props.url != null ? props.url : useRequestURL().href
const networksMap = {
facebook : {
shareUrl: `https://www.facebook.com/sharer/sharer.php?u=${pageUrl}`,
icon: 'ri:facebook-fill'
},
twitter : {
shareUrl: `https://twitter.com/intent/tweet?url=${pageUrl}`,
icon: 'ri:twitter-x-fill'
},
linkedin : {
shareUrl: `https://www.linkedin.com/sharing/share-offsite/?url=${pageUrl}`,
icon: 'ri:linkedin-fill'
},
pinterest : {
shareUrl: `https://pinterest.com/pin/create/button/?url=${pageUrl}`,
icon: 'jam:pinterest'
},
pocket : {
shareUrl: `https://getpocket.com/edit?url=${pageUrl}`,
icon: 'fe:pocket'
},
whatsapp : {
shareUrl: `https://api.whatsapp.com/send?text=${pageUrl}`,
icon: 'ri:whatsapp-line'
},
telegram : {
shareUrl: `https://t.me/share/url?url=${pageUrl}`,
icon: 'mingcute:telegram-fill'
},
email : {
shareUrl: `mailto:?body=${pageUrl}`,
icon: 'ic:round-mail'
},
}
const socialNetwork = useSocialShare({
network: props.network,
url: props.url,
})
const socialNetwork = networksMap[props.network]
</script>

<style lang="scss">
Expand Down
63 changes: 63 additions & 0 deletions src/runtime/useSocialShare.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { useRequestURL } from '#imports';

export const useSocialShare = (options = {}) => {
const { network, url } = options;

const pageUrl = url != null ? url : useRequestURL().href

const networksMap = {
facebook : {
name: 'facebook',
shareUrl: `https://www.facebook.com/sharer/sharer.php?u=${pageUrl}`,
iconName: 'ri:facebook-fill',
color: '#0866FF'
},
twitter : {
name: 'twitter',
shareUrl: `https://twitter.com/intent/tweet?url=${pageUrl}`,
iconName: 'ri:twitter-x-fill',
'color': '#000000'
},
linkedin : {
name: 'linkedin',
shareUrl: `https://www.linkedin.com/sharing/share-offsite/?url=${pageUrl}`,
iconName: 'ri:linkedin-fill',
color: '#0A66C2'
},
pinterest : {
name: 'pinterest',
shareUrl: `https://pinterest.com/pin/create/button/?url=${pageUrl}`,
iconName: 'jam:pinterest',
color: '#BD081C'
},
pocket : {
name: 'pocket',
shareUrl: `https://getpocket.com/edit?url=${pageUrl}`,
iconName: 'fe:pocket',
color: '#EF3F56'
},
whatsapp : {
name: 'whatsapp',
shareUrl: `https://api.whatsapp.com/send?text=${pageUrl}`,
iconName: 'ri:whatsapp-line',
color: '#25D366'
},
telegram : {
name: 'telegram',
shareUrl: `https://t.me/share/url?url=${pageUrl}`,
iconName: 'mingcute:telegram-fill',
color: '#26A5E4'
},
email : {
name: 'email',
shareUrl: `mailto:?body=${pageUrl}`,
iconName: 'ic:round-mail',
color: '#7e7e7e'
},
}

const socialNetwork = networksMap[network]

return socialNetwork
}

0 comments on commit 0388f5f

Please sign in to comment.