Skip to content

Commit

Permalink
feat: Open in new tab (fix #52) (#59)
Browse files Browse the repository at this point in the history
Co-authored-by: Guillaume Chau <[email protected]>
  • Loading branch information
hugoattal and Akryum authored Mar 22, 2022
1 parent 4d21425 commit 93a5095
Show file tree
Hide file tree
Showing 8 changed files with 226 additions and 161 deletions.
8 changes: 8 additions & 0 deletions packages/histoire/src/client/app/components/sandbox/lib.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Story, Variant } from '../../types'

export function getSandboxUrl (story: Story, variant: Variant) {
const url = new URLSearchParams()
url.append('storyId', story.id)
url.append('variantId', variant.id)
return '/__sandbox?' + url.toString()
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import HatchedPattern from '../misc/HatchedPattern.vue'
import CheckerboardPattern from '../misc/CheckerboardPattern.vue'
import { toRawDeep } from '../../util/reactivity'
import { Settings } from 'http2'
import { getSandboxUrl } from '../sandbox/lib'
const props = defineProps<{
story: Story
Expand Down Expand Up @@ -61,10 +62,7 @@ useEventListener(window, 'message', (event) => {
})
const sandboxUrl = computed(() => {
const url = new URLSearchParams()
url.append('storyId', props.story.id)
url.append('variantId', props.variant.id)
return '/__sandbox?' + url.toString()
return getSandboxUrl(props.story, props.variant)
})
const isIframeLoaded = ref(false)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,18 @@
<script lang="ts" setup>
import { PropType, ref } from 'vue'
import { Icon } from '@iconify/vue'
import { PropType } from 'vue'
import type { Story, Variant } from '../../types'
import { histoireConfig } from '../../util/config'
import { usePreviewSettings } from '../../util/preview-settings'
import StoryResponsivePreview from './StoryResponsivePreview.vue'
import BaseCheckbox from '../base/BaseCheckbox.vue'
import { isMobile } from '../../util/responsive'
import StoryVariantTitle from './variant/StoryVariantTitle.vue'
import StoryVariantResponsiveSize from './variant/StoryVariantResponsiveSize.vue'
import StoryVariantBackground from './variant/StoryVariantBackground.vue'
import StoryVariantNewTab from './variant/StoryVariantNewTab.vue'
defineProps({
variant: {
type: Object as PropType<Variant>,
required: true,
},
story: {
type: Object as PropType<Story>,
required: true,
},
})
defineProps<{
variant: Variant
story: Story
}>()
const settings = usePreviewSettings()
</script>
Expand All @@ -33,141 +27,13 @@ const settings = usePreviewSettings()
v-if="!isMobile"
class="htw-flex-none htw-flex htw-items-center htw-h-8 -htw-mt-1"
>
<!-- Variant title -->
<div class="htw-flex htw-items-center htw-gap-1 htw-text-gray-500 htw-flex-1 htw-truncate htw-min-w-0">
<Icon
:icon="variant.icon ?? 'carbon:cube'"
class="base-list-item-link-icon htw-w-4 htw-h-4 htw-opacity-50"
:class="[
variant.iconColor ? 'bind-icon-color' : 'htw-text-gray-500',
]"
/>
<span>{{ variant.title }}</span>
</div>

<!-- Responsive size -->
<VDropdown
placement="bottom-end"
:skidding="6"
:disabled="!histoireConfig.responsivePresets?.length"
class="htw-h-full htw-flex-none"
>
<div
v-tooltip="'Responsive sizes'"
class="htw-flex htw-items-center htw-gap-1 htw-h-full htw-px-2"
:class="{
'htw-cursor-pointer hover:htw-text-primary-500': histoireConfig.responsivePresets?.length,
}"
>
<Icon
icon="ic:baseline-phone-android"
class="htw-w-4 htw-h-4 htw-opacity-50"
/>
<Icon
icon="carbon:caret-down"
class="htw-w-4 htw-h-4 htw-opacity-50"
/>
</div>

<template #popper="{ hide }">
<div class="htw-flex htw-flex-col htw-items-stretch">
<BaseCheckbox v-model="settings.rotate">
Rotate
</BaseCheckbox>

<div class="htw-flex htw-gap-2 htw-px-4 htw-py-3">
<input
v-model.number="settings.responsiveWidth"
v-tooltip="'Responsive width (px)'"
type="number"
class="htw-bg-transparent htw-border htw-border-gray-200 dark:htw-border-gray-850 htw-rounded htw-w-20 htw-opacity-50 focus:htw-opacity-100 htw-flex-1 htw-min-w-0"
step="16"
placeholder="Auto"
>
<span class="htw-opacity-50">x</span>
<input
v-model.number="settings.responsiveHeight"
v-tooltip="'Responsive height (px)'"
type="number"
class="htw-bg-transparent htw-border htw-border-gray-200 dark:htw-border-gray-850 htw-rounded htw-w-20 htw-opacity-50 focus:htw-opacity-100 htw-flex-1 htw-min-w-0"
step="16"
placeholder="Auto"
>
</div>

<button
v-for="(preset, index) in histoireConfig.responsivePresets"
:key="index"
class="htw-px-4 htw-py-3 htw-cursor-pointer htw-text-left htw-flex htw-gap-4"
:class="[
settings.responsiveWidth === preset.width && settings.responsiveHeight === preset.height
? 'htw-bg-primary-500 hover:htw-bg-primary-600 htw-text-white dark:htw-text-black'
: 'htw-bg-transparent hover:htw-bg-primary-100 dark:hover:htw-bg-primary-700',
]"
@click="settings.responsiveWidth = preset.width;settings.responsiveHeight = preset.height;hide()"
>
{{ preset.label }}
<span class="htw-ml-auto htw-opacity-70 htw-flex htw-gap-1">
<span v-if="preset.width">{{ preset.width }}<span v-if="!preset.height">px</span></span>
<span v-if="preset.width && preset.height">x</span>
<span v-if="preset.height">{{ preset.height }}<span v-if="!preset.width">px</span></span>
</span>
</button>
</div>
</template>
</VDropdown>

<!-- Background -->
<VDropdown
v-if="histoireConfig.backgroundPresets.length"
placement="bottom-end"
:skidding="6"
class="htw-h-full htw-flex-none"
>
<div
v-tooltip="'Background color'"
class="htw-cursor-pointer hover:htw-text-primary-500 htw-flex htw-items-center htw-gap-1 htw-h-full htw-px-2"
>
<div
class="bind-preview-bg htw-w-4 htw-h-4 htw-rounded-full htw-border htw-border-black/20 dark:htw-border-white/20"
/>
<Icon
icon="carbon:caret-down"
class="htw-w-4 htw-h-4 htw-opacity-50"
/>
</div>

<template #popper="{ hide }">
<div class="htw-flex htw-flex-col htw-items-stretch">
<BaseCheckbox v-model="settings.checkerboard">
Checkerboard
</BaseCheckbox>

<button
v-for="(option, index) in histoireConfig.backgroundPresets"
:key="index"
class="htw-px-4 htw-py-3 htw-cursor-pointer htw-text-left htw-flex htw-gap-4"
:class="[
settings.backgroundColor === option.color
? 'htw-bg-primary-500 hover:htw-bg-primary-600 htw-text-white dark:htw-text-black'
: 'htw-bg-transparent hover:htw-bg-primary-100 dark:hover:htw-bg-primary-700',
]"
@click="settings.backgroundColor = option.color;hide()"
>
<span class="htw-mr-auto">{{ option.label }}</span>
<template v-if="option.color !== '$checkerboard'">
<span class="htw-ml-auto htw-opacity-70">{{ option.color }}</span>
<div
class="htw-w-4 htw-h-4 htw-rounded-full htw-border htw-border-black/20 dark:htw-border-white/20"
:style="{
backgroundColor: option.color,
}"
/>
</template>
</button>
</div>
</template>
</VDropdown>
<StoryVariantTitle :variant="variant" />
<StoryVariantResponsiveSize />
<StoryVariantBackground />
<StoryVariantNewTab
:variant="variant"
:story="story"
/>
</div>

<!-- Preview -->
Expand All @@ -178,9 +44,3 @@ const settings = usePreviewSettings()
/>
</div>
</template>

<style scoped>
.bind-preview-bg {
background-color: v-bind('settings.backgroundColor');
}
</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<script lang="ts" setup>
import { Icon } from '@iconify/vue'
import { histoireConfig } from '../../../util/config'
import { usePreviewSettings } from '../../../util/preview-settings'
import BaseCheckbox from '../../base/BaseCheckbox.vue'
const settings = usePreviewSettings()
</script>

<template>
<VDropdown
v-if="histoireConfig.backgroundPresets.length"
placement="bottom-end"
:skidding="6"
class="htw-h-full htw-flex-none"
>
<div
v-tooltip="'Background color'"
class="htw-cursor-pointer hover:htw-text-primary-500 htw-flex htw-items-center htw-gap-1 htw-h-full htw-px-2"
>
<div
class="bind-preview-bg htw-w-4 htw-h-4 htw-rounded-full htw-border htw-border-black/50 dark:htw-border-white/50"
/>
<Icon
icon="carbon:caret-down"
class="htw-w-4 htw-h-4 htw-opacity-50"
/>
</div>

<template #popper="{ hide }">
<div class="htw-flex htw-flex-col htw-items-stretch">
<BaseCheckbox v-model="settings.checkerboard">
Checkerboard
</BaseCheckbox>

<button
v-for="(option, index) in histoireConfig.backgroundPresets"
:key="index"
class="htw-px-4 htw-py-3 htw-cursor-pointer htw-text-left htw-flex htw-gap-4"
:class="[
settings.backgroundColor === option.color
? 'htw-bg-primary-500 hover:htw-bg-primary-600 htw-text-white dark:htw-text-black'
: 'htw-bg-transparent hover:htw-bg-primary-100 dark:hover:htw-bg-primary-700',
]"
@click="settings.backgroundColor = option.color;hide()"
>
<span class="htw-mr-auto">{{ option.label }}</span>
<template v-if="option.color !== '$checkerboard'">
<span class="htw-ml-auto htw-opacity-70">{{ option.color }}</span>
<div
class="htw-w-4 htw-h-4 htw-rounded-full htw-border htw-border-black/20 dark:htw-border-white/20"
:style="{
backgroundColor: option.color,
}"
/>
</template>
</button>
</div>
</template>
</VDropdown>
</template>

<style scoped>
.bind-preview-bg {
background-color: v-bind('settings.backgroundColor');
}
</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<script lang="ts" setup>
import { Icon } from '@iconify/vue'
import type { Story, Variant } from '../../../types'
import { computed } from 'vue'
import { getSandboxUrl } from '../../sandbox/lib'
const props = defineProps<{
variant: Variant
story: Story
}>()
const sandboxUrl = computed(() => {
return getSandboxUrl(props.story, props.variant)
})
</script>

<template>
<a
v-tooltip="'Open variant in new tab'"
:href="sandboxUrl"
target="_blank"
class="htw-flex htw-items-center htw-gap-1 htw-h-full htw-px-2 hover:htw-text-primary-500"
>
<Icon
icon="carbon:launch"
class="base-list-item-link-icon htw-w-4 htw-h-4 htw-opacity-50"
/>
</a>
</template>
Loading

0 comments on commit 93a5095

Please sign in to comment.