Skip to content

Commit

Permalink
Merge pull request #141 from vuejs-jp/feature/locale-switch
Browse files Browse the repository at this point in the history
Feat/Add LocaleSwitch component
  • Loading branch information
genj11 authored May 23, 2024
2 parents 6d4cd2e + 2a9e462 commit 9dbd3bf
Show file tree
Hide file tree
Showing 4 changed files with 179 additions and 5 deletions.
8 changes: 4 additions & 4 deletions apps/web/app/components/FooterPageSection.vue
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ const snsLinkList: LinkList[] = [
const internalLinkList: LinkList[] = [
{
href: '/privacy',
text: t('privacy.title'),
text: 'privacy.title',
},
{
href: '/code-of-conduct',
text: t('code_of_conduct.title'),
text: 'code_of_conduct.title',
},
]
const vueFesLinkList: LinkList[] = [
Expand Down Expand Up @@ -86,14 +86,14 @@ const vueFesLinkList: LinkList[] = [
<ul class="footer-list">
<li v-for="(link, index) in internalLinkList" :key="index">
<VFTextLink :href="`${localePath}${link.href}`" color="white">
{{ link.text }}
{{ t(link.text) }}
</VFTextLink>
</li>
</ul>
<ul class="footer-list">
<li v-for="(link, index) in vueFesLinkList" :key="index">
<VFTextLink :href="link.href" target="_blank" color="white">
{{ link.text }}
{{ t(link.text) }}
</VFTextLink>
</li>
</ul>
Expand Down
18 changes: 17 additions & 1 deletion packages/ui/.storybook/preview.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { setup } from '@storybook/vue3'
import { INITIAL_VIEWPORTS } from '@storybook/addon-viewport'
import { createI18n } from 'vue-i18n'
import { createRouter, createMemoryHistory } from 'vue-router'

import './global.css'

Expand Down Expand Up @@ -33,14 +34,29 @@ const i18n = createI18n({
// end dummy
sponsor: {
start_date: 'April 8',
end_date: '25,',
end_date: '25,',
},
},
},
})

const routes = [
{
path: '/',
name: 'ja',
},
{
path: '/en',
name: 'en',
},
]

// 画面遷移は発生しないが、StorybookではURLを直接使えないため、createMemoryHistoryで生成
const router = createRouter({ history: createMemoryHistory(), routes })

setup((app) => {
app.use(i18n)
app.use(router)
})

export const parameters = {
Expand Down
17 changes: 17 additions & 0 deletions packages/ui/components/common/LocaleSwitch.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { StoryFn } from '@storybook/vue3'
import LocaleSwitch from './LocaleSwitch.vue'

export default {
title: 'common/LocaleSwitch',
component: LocaleSwitch,
}

const Template: StoryFn<unknown> = () => ({
components: { LocaleSwitch },
setup() {
return {}
},
template: '<LocaleSwitch />',
})

export const Default = Template.bind({})
141 changes: 141 additions & 0 deletions packages/ui/components/common/LocaleSwitch.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
<script setup lang="ts">
import { onMounted, ref, watch } from 'vue'
import { useRouter } from 'vue-router'
const LANGUAGES = {
JAPANESE: 'ja',
ENGLISH: 'en',
} as const
const router = useRouter()
const isLoaded = ref(false)
const isChecked = ref(false)
const getPath = () => {
if (isChecked.value) {
return `/${LANGUAGES.ENGLISH}${router.currentRoute.value.path}`
}
return router.currentRoute.value.path.replace(`/${LANGUAGES.ENGLISH}`, '')
}
const setSwitchStatus = () => {
isChecked.value = router.currentRoute.value.path.includes(`/${LANGUAGES.ENGLISH}/`)
}
const toggleStatus = () => {
isChecked.value = !isChecked.value
const path = getPath()
router.push(path)
}
onMounted(() => {
setSwitchStatus()
isLoaded.value = true
})
watch(
() => router.currentRoute.value.path,
() => {
setSwitchStatus()
},
)
</script>

<template>
<button
v-if="isLoaded"
type="button"
role="switch"
class="locale-switch-button"
aria-label="translate english"
:aria-checked="isChecked"
@click="toggleStatus"
>
<span
class="locale-switch-button-switch"
:class="{ 'locale-switch-button-switch-checked': !isChecked }"
aria-hidden="true"
>
<span
v-if="isChecked"
class="locale-switch-button-language"
:class="{ 'locale-switch-button-language-checked': !isChecked }"
>
<span>{{ LANGUAGES.JAPANESE }}</span>
</span>
<span class="locale-switch-button-circle">
{{ isChecked ? LANGUAGES.ENGLISH : LANGUAGES.JAPANESE }}
</span>
<span
v-if="!isChecked"
class="locale-switch-button-language"
:class="{ 'locale-switch-button-language-checked': isChecked }"
>
<span>{{ LANGUAGES.ENGLISH }}</span>
</span>
</span>
</button>
</template>

<style scoped>
.locale-switch-button {
--box-shadow: 0 1px 4px color-mix(in srgb, var(--color-vue-blue), transparent calc(100% - 14%));
border: 0;
user-select: none;
line-height: 1.2;
width: 5.125rem;
height: 2.5rem;
display: grid;
place-content: center;
color: var(--color-white);
background-color: transparent;
position: relative;
}
.locale-switch-button-switch {
display: flex;
align-items: center;
box-shadow: var(--box-shadow);
background-color: #d2d6db;
border-radius: 0.9375rem;
height: 1.8125rem;
width: 3.5625rem;
font-size: 1.125rem;
font-weight: bold;
padding-left: 0.5rem;
box-sizing: border-box;
}
.locale-switch-button-switch-checked {
justify-content: flex-end;
padding-left: 0;
padding-right: 0.5rem;
}
.locale-switch-button-language {
font-size: 0.875rem;
font-weight: bold;
}
.locale-switch-button-circle {
position: absolute;
display: flex;
justify-content: center;
padding-top: 0.25rem;
box-sizing: border-box;
border-radius: 50%;
top: calc(50% - 1rem);
right: 50%;
height: 2rem;
width: 2rem;
background: #34495e;
box-shadow: var(--box-shadow);
}
.locale-switch-button[aria-checked='true'] .locale-switch-button-circle {
right: 0;
left: 50%;
}
.locale-switch-button:hover {
cursor: pointer;
}
</style>

0 comments on commit 9dbd3bf

Please sign in to comment.