Skip to content

Commit

Permalink
Extracted Button element and fix button hover issue on mobile devices. (
Browse files Browse the repository at this point in the history
  • Loading branch information
nicholasnet authored Dec 17, 2023
1 parent dc8815a commit 0092106
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 119 deletions.
107 changes: 35 additions & 72 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import GithubIcon from '@/icons/GithubIcon.vue'
import XIcon from '@/icons/XIcon.vue'
import BaseInput from '@/components/BaseInput.vue'
import ShareIcon from '@/icons/ShareIcon.vue'
import BaseButton from '@/components/BaseButton.vue'
const defaultGroup = import.meta.env.VITE_DEFAULT_GROUP ?? 'com.example'
const dependencyStore = dStore()
Expand Down Expand Up @@ -65,11 +66,10 @@ const isMac = inject<boolean>('isMac') as boolean
const isMobile = inject<boolean>('isMobile') as boolean
const showDependenciesDialog = ref<boolean>(false)
const selectedPackagesPerProject = ref<Map<string, Set<string>>>(new Map())
const addDependencyButton = ref<HTMLElement | null>(null)
const addDependencyButton = ref<InstanceType<typeof BaseButton> | null>(null)
const focusTrapInputElement = ref<HTMLInputElement | null>(null)
const generateButton = ref<HTMLElement | null>(null)
const exploreButton = ref<HTMLElement | null>(null)
const shareButton = ref<HTMLElement | null>(null)
const exploreButton = ref<InstanceType<typeof BaseButton> | null>(null)
const shareButton = ref<InstanceType<typeof BaseButton> | null>(null)
//const selectedPackages = ref<Set<string>>(new Set<string>())
const projectMetadata = ref<
Map<
Expand Down Expand Up @@ -472,18 +472,15 @@ function onCloseShareDialog() {
<div class="flex-1 xl:flex xl:flex-col p-2">
<div class="flex items-center justify-between">
<div class="font-medium">Dependencies</div>
<button
class="focus:ring-1 ring-indigo-600 dark:ring-gray-600 relative flex dark:border-gray-950 border-primary-400 items-center overflow-hidden rounded border px-4 py-2 transition duration-200 ease-linear hover:bg-gray-200 hover:shadow-lg dark:text-primary-dark-100 dark:bg-primary-dark-600 dark:hover:bg-gray-700"
type="button"
tabindex="-1"
ref="addDependencyButton"
@click="displayDependencyDialog"
>
<ripple></ripple>
<BaseButton :primary="false" ref="addDependencyButton" @click="displayDependencyDialog">
<template #shortcut>
<span v-if="!isMobile && isMac" class="ml-2 block font-extralight">⌘ + b</span>
<span v-if="!isMobile && !isMac" class="font-mono ml-2 block font-extralight"
>Ctrl + b</span
>
</template>
<span class="block">Add dependencies</span>
<span v-if="!isMobile && isMac" class="ml-2 block font-extralight">⌘ + b</span>
<span v-if="!isMobile && !isMac" class="font-mono ml-2 block font-extralight">Ctrl + b</span>
</button>
</BaseButton>
</div>
<hr class="my-2 dark:border-gray-500" />
<div class="mt-2 italic" v-if="selectedPackages.size === 0">No dependency selected</div>
Expand Down Expand Up @@ -546,68 +543,34 @@ function onCloseShareDialog() {
<div
class="h-16 flex relative flex-1 z-0 bg-white items-center justify-center space-x-4 border-t dark:border-gray-900 dark:bg-primary-dark-700"
>
<button
v-if="haveValidProjectMetaData()"
ref="generateButton"
@click="onGenerate"
type="button"
tabindex="-1"
class="relative flex focus:ring-1 ring-indigo-600 dark:ring-gray-600 items-center overflow-hidden rounded border border-primary-600 bg-primary-500 px-4 py-2 text-white transition duration-200 ease-linear hover:bg-primary-600 hover:shadow-lg"
>
<Ripple></Ripple>
<BaseButton :primary="true" :enabled="haveValidProjectMetaData()" @click="onGenerate">
<span class="block">{{ generateButtonLabel }}</span>
<span class="ml-2 font-extralight hidden md:block" v-if="!isMobile && isMac">⌘ + ⏎</span>
<span class="ml-2 hidden md:block font-extralight" v-if="!isMobile && !isMac">Ctrl + ⏎</span>
</button>
<button
v-else
type="button"
class="relative flex cursor-not-allowed items-center overflow-hidden rounded border border-gray-600 bg-gray-500 px-4 py-2 text-white"
>
<span class="block">Generate</span>
</button>
<button
v-if="haveValidProjectMetaData()"
type="button"
tabindex="-1"
ref="exploreButton"
@click="onExplore"
class="relative flex focus:ring-1 ring-indigo-600 dark:ring-gray-600 dark:border-gray-950 border-primary-400 items-center overflow-hidden rounded border px-4 py-2 transition duration-200 ease-linear hover:bg-gray-200 hover:shadow-lg dark:text-primary-dark-100 dark:bg-primary-dark-600 dark:hover:bg-gray-700"
>
<Ripple></Ripple>
<span>Explore</span>
<span v-if="!isMobile" class="ml-2 font-extralight hidden md:block">Ctrl + Space</span>
</button>
<button
v-else
type="button"
class="relative flex cursor-not-allowed dark:border-gray-950 border-primary-400 items-center overflow-hidden rounded border px-4 py-2 text-gray-400 dark:text-primary-dark-100"
>
<template #shortcut>
<span class="ml-2 font-extralight hidden md:block" v-if="!isMobile && isMac">⌘ + ⏎</span>
<span class="ml-2 hidden md:block font-extralight" v-if="!isMobile && !isMac">Ctrl + ⏎</span>
</template>
</BaseButton>

<BaseButton :enabled="haveValidProjectMetaData()" ref="exploreButton" @click="onExplore">
<span>Explore</span>
</button>
<button
type="button"
v-if="haveValidProjectMetaData()"
@click="onShare"
<template #shortcut>
<span v-if="!isMobile" class="ml-2 font-extralight hidden md:block">Ctrl + Space</span>
</template>
</BaseButton>

<BaseButton
:enabled="haveValidProjectMetaData()"
ref="shareButton"
tabindex="-1"
class="relative flex focus:ring-1 ring-indigo-600 dark:ring-gray-600 dark:border-gray-950 border-primary-400 items-center overflow-hidden rounded border px-4 py-2 transition duration-200 ease-linear hover:bg-gray-200 hover:shadow-lg dark:text-primary-dark-100 dark:bg-primary-dark-600 dark:hover:bg-gray-700"
>
<span class="w-4 h-4 hidden md:block mr-2"
><ShareIcon class="fill-current text-primary-500 dark:text-primary-200"></ShareIcon
></span>
<span>Share</span>
</button>
<button
v-else
type="button"
class="relative flex cursor-not-allowed dark:border-gray-950 border-gray-400 items-center overflow-hidden rounded border px-4 py-2 text-gray-400 dark:text-primary-dark-100"
@click="onShare"
class="flex-row-reverse"
>
<span class="w-4 h-4 hidden md:block mr-2"
><ShareIcon class="fill-current text-gray-500 dark:text-primary-200"></ShareIcon
></span>
<template #shortcut>
<span class="w-4 h-4 hidden md:block mr-2"
><ShareIcon class="fill-current text-primary-500 dark:text-primary-200"></ShareIcon
></span>
</template>
<span>Share</span>
</button>
</BaseButton>
</div>
</footer>
</template>
55 changes: 55 additions & 0 deletions src/components/BaseButton.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<script setup lang="ts">
import { inject, ref } from 'vue'
import Ripple from '@/components/Ripple.vue'
withDefaults(defineProps<{ enabled?: boolean; primary?: boolean }>(), {
enabled: true,
primary: false
})
defineEmits(['click'])
const isMobile = inject<boolean>('isMobile') as boolean
const root = ref<HTMLElement | null>(null)
function focus() {
root.value?.focus()
}
defineExpose({
focus
})
</script>

<template>
<button
ref="root"
v-if="enabled"
@click="$emit('click')"
type="button"
tabindex="-1"
:class="[
primary
? 'border-primary-600 bg-primary-500 text-white'
: 'dark:border-gray-950 border-primary-400 dark:text-primary-dark-100 dark:bg-primary-dark-600 dark:hover:bg-gray-700',
{ 'hover:bg-primary-600 hover:shadow-lg': !isMobile && primary },
{ 'hover:bg-gray-200 hover:shadow-lg': !isMobile && !primary }
]"
class="relative flex focus:ring-1 ring-indigo-600 dark:ring-gray-600 items-center overflow-hidden rounded border px-4 py-2 transition duration-200 ease-linear"
>
<Ripple></Ripple>
<slot name="default" class="block"></slot>
<slot name="shortcut"></slot>
</button>
<button
v-else
type="button"
class="relative flex cursor-not-allowed items-center overflow-hidden rounded border border-gray-600 bg-gray-500 px-4 py-2 text-white"
>
<span class="block">
<slot name="default"></slot>
</span>
</button>
</template>

<style scoped></style>
44 changes: 16 additions & 28 deletions src/components/Explorer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { ContentType } from '@/entity/ContentType'
import { Language } from '@/entity/Language'
import NestedOption from '@/components/NestedOption.vue'
import AppComponentLoader from '@/components/AppComponentLoader.vue'
import BaseButton from '@/components/BaseButton.vue'
const dialog = ref<typeof Dialog | null>(null)
const isMac = inject<boolean>('isMac') as boolean
Expand Down Expand Up @@ -242,37 +243,24 @@ onMounted(async () => {
<!-- <pre class="code-display flex-1 rounded-bl overflow-auto relative" v-html="code"></pre>-->
</div>
<div class="flex justify-center space-x-4 bg-primary-50 dark:bg-primary-dark-800 py-2">
<button
type="button"
v-if="!isMobile"
@click="emit('downloadClicked')"
tabindex="-1"
class="relative focus:ring-1 ring-indigo-600 dark:ring-gray-600 flex items-center overflow-hidden rounded border border-primary-600 bg-primary-500 px-4 py-2 text-white transition duration-200 ease-linear hover:bg-primary-600 hover:shadow-lg"
>
<Ripple></Ripple>
<BaseButton :primary="true" @click="emit('downloadClicked')" v-if="!isMobile">
<span class="block">Download</span>
<span class="ml-2 font-extralight hidden md:block" v-if="isMac">⌘ + ⏎</span>
<span class="ml-2 font-extralight hidden md:block" v-else>Ctrl + ⏎</span>
</button>
<button
type="button"
@click="copyContent"
tabindex="-1"
class="relative flex focus:ring-1 ring-indigo-600 dark:ring-gray-600 dark:border-gray-950 border-primary-400 items-center overflow-hidden rounded border px-4 py-2 transition duration-200 ease-linear hover:bg-gray-200 hover:shadow-lg dark:text-primary-dark-100 dark:bg-primary-dark-600 dark:hover:bg-gray-700"
>
<Ripple></Ripple>
<template #shortcut>
<span class="ml-2 font-extralight hidden md:block" v-if="isMac">⌘ + ⏎</span>
<span class="ml-2 font-extralight hidden md:block" v-else>Ctrl + ⏎</span>
</template>
</BaseButton>

<BaseButton @click="copyContent">
<span>{{ copyText }}</span>
</button>
<button
type="button"
@click="closeDialog"
tabindex="-1"
class="relative flex focus:ring-1 ring-indigo-600 dark:ring-gray-600 dark:border-gray-950 border-primary-400 items-center overflow-hidden rounded border px-4 py-2 transition duration-200 ease-linear hover:bg-gray-200 hover:shadow-lg dark:text-primary-dark-100 dark:bg-primary-dark-600 dark:hover:bg-gray-700"
>
<Ripple></Ripple>
</BaseButton>

<BaseButton @click="closeDialog">
<span>Close</span>
<span v-if="!isMobile" class="ml-2 font-extralight hidden md:block">Esc</span>
</button>
<template #shortcut>
<span v-if="!isMobile" class="ml-2 font-extralight hidden md:block">Esc</span>
</template>
</BaseButton>
</div>
</div>
</div>
Expand Down
23 changes: 8 additions & 15 deletions src/components/ShareDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type { VueJsProject as VueJsProjectType } from '@/entity/VueJsProject'
import type { Package } from '@/entity/Dependency'
import BaseInput from '@/components/BaseInput.vue'
import type { ProjectType } from '@/entity/ProjectType'
import BaseButton from '@/components/BaseButton.vue'
const { metaData, packages, projectType } = defineProps<{
projectType: ProjectType
Expand Down Expand Up @@ -73,23 +74,15 @@ function closeDialog() {
</div>
<div class="flex items-center justify-center relative footer z-0">
<div class="bg-white dark:bg-primary-dark-700 w-full flex justify-center py-2 space-x-3">
<button
@click="copyToClipboard(information)"
type="button"
tabindex="-1"
class="relative flex items-center focus:ring-1 ring-indigo-600 dark:ring-gray-600 overflow-hidden rounded border border-primary-600 bg-primary-500 px-4 py-2 text-white transition duration-200 ease-linear hover:bg-primary-600 hover:shadow-lg"
>
<Ripple></Ripple>
<BaseButton :primary="true" @click="copyToClipboard(information)">
<span class="block">{{ copyText }}</span>
</button>
<button
@click="closeDialog"
tabindex="-1"
class="relative flex focus:ring-1 ring-indigo-600 dark:ring-gray-600 dark:border-gray-950 border-primary-400 items-center overflow-hidden rounded border px-4 py-2 transition duration-200 ease-linear hover:bg-gray-200 hover:shadow-lg dark:text-primary-dark-100 dark:bg-primary-dark-600 dark:hover:bg-gray-700"
>
</BaseButton>
<BaseButton :primary="false" @click="closeDialog">
<span>Close</span>
<span v-if="!isMobile" class="ml-2 font-extralight hidden md:block">Esc</span>
</button>
<template #shortcut>
<span v-if="!isMobile" class="ml-2 font-extralight hidden md:block">Esc</span>
</template>
</BaseButton>
</div>
</div>
</div>
Expand Down
16 changes: 12 additions & 4 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,19 @@ const app = createApp(App)

app.use(createPinia())

const ua = window.navigator.userAgent
const iOSSafari = /^(?=.*(iPhone|iPad|iPod))(?=.*AppleWebKit)(?!.*(criOS|fxiOS|opiOS|chrome|android)).*/i.test(ua)
function isMobile(userAgent: string): boolean {
return !!(
userAgent.match(/Android/i) ||
userAgent.match(/webOS/i) ||
userAgent.match(/iPhone/i) ||
userAgent.match(/iPad/i) ||
userAgent.match(/iPod/i) ||
userAgent.match(/BlackBerry/i) ||
userAgent.match(/Windows Phone/i)
)
}

app.provide('isMac', window.navigator.userAgent.includes('Macintosh'))
app.provide('isMobile', /iPhone|iPad|iPod|Android/i.test(window.navigator.userAgent))
app.provide('isIOSSafari', iOSSafari)
app.provide('isMobile', isMobile(window.navigator.userAgent))

app.mount('#app')

0 comments on commit 0092106

Please sign in to comment.