Skip to content

Commit c154a09

Browse files
authored
Merge pull request #214 from vuejs-jp/feature/creation-namecard-for-share
add share_image_url to public.sponsors
2 parents d12050d + 64218e8 commit c154a09

File tree

15 files changed

+466
-34
lines changed

15 files changed

+466
-34
lines changed

apps/web/app/components/admin/SponsorItem.vue

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const newSponsor = ref({
2020
name: props.sponsor?.name ?? '',
2121
detail_page_id: props.sponsor?.detail_page_id ?? '',
2222
image_url: props.sponsor?.image_url ?? '',
23+
share_image_url: props.sponsor?.share_image_url ?? '',
2324
description_ja: props.sponsor?.description_ja ?? '',
2425
description_en: props.sponsor?.description_en ?? '',
2526
link_url: props.sponsor?.link_url ?? '',
@@ -48,6 +49,18 @@ const checkFiles = async (files: File[]) => {
4849
4950
newSponsor.value.image_url = getFullAvatarUrl(filePath)
5051
}
52+
const checkShareFiles = async (files: File[]) => {
53+
if (files.length === 0) return
54+
55+
const file = files[0]
56+
// const filename = file.name
57+
const fileExt = file.name.split('.').pop()
58+
const filePath = `/${Math.random()}.${fileExt}`
59+
60+
uploadAvatar(filePath, file)
61+
62+
newSponsor.value.share_image_url = getFullAvatarUrl(filePath)
63+
}
5164
const updateDescriptionJa = (e: any) => {
5265
newSponsor.value.description_ja = e.target.value
5366
}
@@ -99,9 +112,23 @@ const onSubmit = () => {
99112
height="60"
100113
decoding="async"
101114
/>
102-
<p>Drag & drop a file</p>
115+
<p>Drag & drop an image file</p>
116+
<p>または</p>
117+
<p>Select an image file</p>
118+
</div>
119+
</VFDragDropArea>
120+
<VFDragDropArea file-name="profiledata" file-accept="image/*" @check-files="checkShareFiles">
121+
<div class="upload">
122+
<img
123+
v-if="newSponsor.share_image_url"
124+
alt=""
125+
:src="newSponsor.share_image_url"
126+
height="60"
127+
decoding="async"
128+
/>
129+
<p>Drag & drop a share image file</p>
103130
<p>または</p>
104-
<p>Select a file</p>
131+
<p>Select a share image file</p>
105132
</div>
106133
</VFDragDropArea>
107134
<VFTextAreaField

apps/web/app/components/admin/SponsorList.vue

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ const handleDialog = (id?: string) => {
2525
<th>name</th>
2626
<th>detail_page_id</th>
2727
<th>image_url</th>
28+
<th>share_image_url</th>
2829
<th>description</th>
2930
<th>link_url</th>
3031
<th>speaker_id</th>
@@ -47,6 +48,19 @@ const handleDialog = (id?: string) => {
4748
No image
4849
</p>
4950
</td>
51+
<td>
52+
<img
53+
v-if="sponsor.share_image_url"
54+
alt=""
55+
:src="sponsor.share_image_url"
56+
width="60"
57+
height="60"
58+
decoding="async"
59+
/>
60+
<p v-if="!sponsor.share_image_url">
61+
No share image
62+
</p>
63+
</td>
5064
<td>
5165
<p>{{ sponsor.description_ja }}</p>
5266
<p>{{ sponsor.description_en }}</p>
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
※注文番号は、チケット購入時にPeatixから送信されるメール内に含まれる[領収データ](https://help-attendee.peatix.com/ja-JP/support/solutions/articles/44001821741)から確認できます。
1+
※注文番号は、チケット購入時に Peatix から送信されるメール内に含まれる[領収データ](https://help-attendee.peatix.com/ja-JP/support/solutions/articles/44001821741)から確認できます。

apps/web/app/pages/namecard/[id]/edit/complete.vue

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,13 @@ const { authUserId, statusKey, attendee } = await useNamecard()
4444
can-hover
4545
class="sns-button"
4646
/>
47-
<!-- TODO facebook追加 -->
48-
<!-- <VFIconButton
49-
class="sns-button"
50-
name="facebook"
47+
<VFIconButton
48+
name="Facebook"
49+
color="black"
5150
:href="`/namecard/${authUserId}/share/`"
5251
can-hover
53-
/> -->
52+
class="sns-button"
53+
/>
5454
</div>
5555
<CreationStatus :status-key="statusKey" size="small" class="creation-status" />
5656
<!-- TODO 24に置き換え&smallサイズ指定 -->

apps/web/app/pages/namecard/[id]/share.vue

Lines changed: 72 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,15 @@ if (!attendee) {
1717
1818
const currentLocale = useLocaleCurrent().locale
1919
20+
function copyUrl() {
21+
const element = document.createElement('input')
22+
element.value = `https://vuefes.jp/2024/namecard/${id}/share`
23+
document.body.appendChild(element)
24+
element.select()
25+
document.execCommand('copy')
26+
document.body.removeChild(element)
27+
}
28+
2029
const officialSiteUrl = computed(() => {
2130
return currentLocale.value === 'ja' ? linkUrl : `${linkUrl}/en`
2231
})
@@ -50,11 +59,36 @@ useHead({
5059
>{{ t('official_site') }}</VFLinkButton
5160
>
5261
<VFComment class="share-namecard" :title="t('share_namecard')" />
53-
<!-- TODO snsアイコン&リンク設置 -->
5462
<ul class="sns-list">
55-
<li>x</li>
56-
<li>facebook</li>
57-
<li>copy</li>
63+
<li>
64+
<VFIconButton
65+
color="vue-blue"
66+
name="x40"
67+
:href="`https://x.com/share?url=${encodeURIComponent(
68+
`https://vuefes.jp/2024/namecard/${id}/share`,
69+
)}`"
70+
target-blank
71+
can-hover
72+
/>
73+
</li>
74+
<li>
75+
<VFIconButton
76+
color="vue-blue"
77+
name="Facebook"
78+
:href="`https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(
79+
`https://vuefes.jp/2024/namecard/${id}/share`,
80+
)}`"
81+
target-blank
82+
/>
83+
</li>
84+
<li>
85+
<div class="copycode">
86+
<VFCssResetButton @click="copyUrl">
87+
<VFIcon color="vue-blue" name="external" :can-hover="false" />
88+
</VFCssResetButton>
89+
<span>コピーしました!</span>
90+
</div>
91+
</li>
5892
</ul>
5993
</div>
6094
</template>
@@ -72,7 +106,8 @@ useHead({
72106
max-width: 960px;
73107
margin: 0 auto calc(var(--unit) * 7.5);
74108
}
75-
.invite-comment {
109+
.invite-comment,
110+
.share-session {
76111
margin: 0 auto calc(var(--unit) * 2.5);
77112
}
78113
.link-button {
@@ -86,4 +121,36 @@ useHead({
86121
border-radius: var(--height-button);
87122
margin: 0 auto calc(var(--unit) * 7.5);
88123
}
124+
.sns-list {
125+
display: flex;
126+
justify-content: center;
127+
gap: calc(var(--unit) * 2.5);
128+
padding: 0;
129+
margin: 0;
130+
}
131+
.sns-list li {
132+
padding: 0;
133+
margin: 0;
134+
}
135+
.copycode {
136+
position: relative;
137+
display: inline-block;
138+
}
139+
.copycode span {
140+
opacity: 0;
141+
position: absolute;
142+
top: 0px;
143+
right: -5px;
144+
color: #fff;
145+
background: rgba(0, 0, 0, 0.5);
146+
padding: 2px 5px;
147+
transform: translate(100%);
148+
}
149+
.copycode button:focus + span {
150+
animation: fade-out 2s ease-in;
151+
}
152+
@keyframes fade-out {
153+
0% { visibility: visible; opacity: 1; }
154+
100% { visibility: hidden; opacity: 0; }
155+
}
89156
</style>
Lines changed: 164 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,164 @@
1-
<script setup lang="ts"></script>
2-
<template></template>
1+
<script setup lang="ts">
2+
import { createError, useAsyncData, useHead, useLocaleCurrent, useRoute, useSupabase } from '#imports'
3+
import { conferenceTitle, linkUrl, ogSpeakerDescription } from '~/utils/constants'
4+
import { generalOg, twitterOg } from '~/utils/og.constants'
5+
import type { Speaker } from '@vuejs-jp/model'
6+
7+
const route = useRoute()
8+
const id = route.params.id as string
9+
10+
const { fetchData } = useSupabase()
11+
const { data: speakers } = await useAsyncData('speakers', async () => {
12+
return await fetchData('speakers', { detailPageId: id })
13+
})
14+
const speakerData = speakers.value?.data as Speaker[]
15+
if (!speakerData) {
16+
throw createError({ statusCode: 404, statusMessage: 'Speaker not found' })
17+
}
18+
19+
if (!speakerData[0].detail_page_id) {
20+
throw createError({ statusCode: 404, statusMessage: 'Speaker not found' })
21+
}
22+
23+
const currentLocale = useLocaleCurrent().locale
24+
25+
function copyUrl() {
26+
const element = document.createElement('input')
27+
element.value = `https://vuefes.jp/2024/namecard/${id}/share`
28+
document.body.appendChild(element)
29+
element.select()
30+
document.execCommand('copy')
31+
document.body.removeChild(element)
32+
}
33+
34+
useHead({
35+
titleTemplate: (titleChunk) => `${conferenceTitle}`,
36+
meta: [
37+
...generalOg({
38+
title: `${conferenceTitle}`,
39+
description: ogSpeakerDescription,
40+
url: `${linkUrl}sessions/${id}/share`,
41+
}),
42+
...twitterOg({
43+
title: `${conferenceTitle}`,
44+
description: ogSpeakerDescription,
45+
url: `${linkUrl}sessions/${id}/share`,
46+
}),
47+
],
48+
})
49+
</script>
50+
<template>
51+
<div class="session-share-root">
52+
<VFOgCard23
53+
class="session"
54+
:user="{
55+
display_name: speakerData[0].name_ja,
56+
avatar_url: speakerData[0].image_url,
57+
role: 'speaker',
58+
}"
59+
/>
60+
<VFComment class="invite-comment" :title="$t('invite_vue_fes')" />
61+
<VFLinkButton
62+
class="link-button"
63+
:href="currentLocale === 'ja' ? linkUrl : `${linkUrl}/en`"
64+
background-color="vue-green/200"
65+
color="white"
66+
>
67+
{{ $t('official_site') }}
68+
</VFLinkButton>
69+
<VFComment class="share-session" :title="$t('share_namecard')" />
70+
<ul class="sns-list">
71+
<li>
72+
<VFIconButton
73+
color="vue-blue"
74+
name="x40"
75+
:href="`https://x.com/share?url=${encodeURIComponent(
76+
`https://vuefes.jp/2024/namecard/${id}/share`,
77+
)}`"
78+
target-blank
79+
can-hover
80+
/>
81+
</li>
82+
<li>
83+
<VFIconButton
84+
color="vue-blue"
85+
name="Facebook"
86+
:href="`https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(
87+
`https://vuefes.jp/2024/namecard/${id}/share`,
88+
)}`"
89+
target-blank
90+
/>
91+
</li>
92+
<li>
93+
<div class="copycode">
94+
<VFCssResetButton @click="copyUrl">
95+
<VFIcon color="vue-blue" name="external" :can-hover="false" />
96+
</VFCssResetButton>
97+
<span>コピーしました!</span>
98+
</div>
99+
</li>
100+
</ul>
101+
</div>
102+
</template>
103+
104+
<style scoped>
105+
.session-share-root {
106+
--header-height: calc(var(--unit) * 10);
107+
--content-padding: calc(var(--unit) * 15);
108+
padding-top: calc(var(--header-height) + var(--content-padding));
109+
padding-bottom: var(--content-padding);
110+
max-width: 960px;
111+
margin: 0 auto;
112+
}
113+
.session {
114+
max-width: 960px;
115+
margin: 0 auto calc(var(--unit) * 7.5);
116+
}
117+
.invite-comment,
118+
.share-session {
119+
margin: 0 auto calc(var(--unit) * 2.5);
120+
}
121+
.link-button {
122+
--height-button: 66px;
123+
124+
display: flex;
125+
justify-content: center;
126+
align-items: center;
127+
width: 400px;
128+
height: var(--height-button);
129+
border-radius: var(--height-button);
130+
margin: 0 auto calc(var(--unit) * 7.5);
131+
}
132+
.sns-list {
133+
display: flex;
134+
justify-content: center;
135+
gap: calc(var(--unit) * 2.5);
136+
padding: 0;
137+
margin: 0;
138+
}
139+
.sns-list li {
140+
padding: 0;
141+
margin: 0;
142+
}
143+
.copycode {
144+
position: relative;
145+
display: inline-block;
146+
}
147+
.copycode span {
148+
opacity: 0;
149+
position: absolute;
150+
top: 0px;
151+
right: -5px;
152+
color: #fff;
153+
background: rgba(0, 0, 0, 0.5);
154+
padding: 2px 5px;
155+
transform: translate(100%);
156+
}
157+
.copycode button:focus + span {
158+
animation: fade-out 2s ease-in;
159+
}
160+
@keyframes fade-out {
161+
0% { visibility: visible; opacity: 1; }
162+
100% { visibility: hidden; opacity: 0; }
163+
}
164+
</style>

0 commit comments

Comments
 (0)