Commit fcf8d461 authored by Domi's avatar Domi

feat: Sidebar support drag and drop

parent ac39b82b
......@@ -406,9 +406,8 @@ const handleEditCommand = (e: MouseEvent) => {
text-wrap: nowrap;
}
.shortcut .key {
padding: 2px 4px;
border-radius: 4px;
background: var(--color-background-soft);
@apply text-xs uppercase px-1 py-0.5 rounded;
}
@keyframes fadein {
......
......@@ -26,6 +26,7 @@ defineEmits(["click", "remove"])
]"
@click="(e) => (e.preventDefault(), $emit('click'))"
:href="url"
draggable="true"
>
<div class="p-2.5 rounded-full bg-background-soft">
<img
......@@ -57,13 +58,7 @@ defineEmits(["click", "remove"])
'size-4 absolute top-[-4px] right-[-4px] opacity-0 group-hover:opacity-65 rounded-full',
'bg-background-soft hover:bg-red-100 hover:text-red-600 hover:scale-105 flex items-center justify-center',
]"
@click="
(e) => {
e.stopPropagation()
e.preventDefault()
$emit('remove')
}
"
@click="(e) => (e.stopPropagation(), $emit('remove'))"
>
<IconClose class="size-3" />
</div>
......
......@@ -211,4 +211,5 @@ onUnmounted(() => {
</div>
</template>
<style scoped></style>@/utils/const
\ No newline at end of file
<style scoped></style>
@/utils/const
<template>
<svg
xmlns="http://www.w3.org/2000/svg"
height="24"
viewBox="0 -960 960 960"
width="24"
fill="currentColor"
>
<path d="M440-440H200v-80h240v-240h80v240h240v80H520v240h-80v-240Z" />
</svg>
</template>
......@@ -139,29 +139,6 @@ onUnmounted(() => {
@pointerdown="autoPointerCapture"
@pointermove="pointermove"
></div>
<div
v-if="false"
class="flex gap-2 items-center justify-between h-8 px-2"
>
<button
@click=""
class="size-7 flex items-center justify-center mr-auto"
>
<img class="size-4" :src="logoUrl" />
</button>
<button
@click="emit('hide')"
class="size-7 rounded-full hover:bg-background-soft flex items-center justify-center"
>
<IconSplitscreenRight class="size-5 scale-95" />
</button>
<button
@click="emit('close')"
class="size-7 rounded-full hover:bg-background-soft flex items-center justify-center"
>
<IconClose class="size-5" />
</button>
</div>
<iframe class="w-full h-full flex-1" :src="sidebarUrl"></iframe>
</div>
</div>
......
<script setup lang="ts">
import { ref } from "vue"
import { homeUrl } from "@/utils/const"
import { useI18n } from "@/utils/i18n"
import { handleImgError } from "@/utils/dom"
import { type PageInfo } from "../Webview.vue"
import IconClose from "@/components/icons/IconClose.vue"
import IconRefresh from "@/components/icons/IconRefresh.vue"
import IconPhone from "@/components/icons/IconPhone.vue"
import IconHide from "@/components/icons/IconHide.vue"
import IconNavigateBefore from "@/components/icons/IconNavigateBefore.vue"
import IconNavigateNext from "@/components/icons/IconNavigateNext.vue"
import IconAdd from "@/components/icons/IconAdd.vue"
defineProps<{
active: number
pages: { url: string }[]
pagesInfo: (PageInfo | null)[]
isMobileUA: boolean
isPointerIn: boolean
closeWebview?: (index: number) => void
reload?: () => void
toggleMobileUA: () => void
collapseSidebar?: () => void
closeSidebar?: () => void
goBack?: () => void
goForward?: () => void
}>()
const emit = defineEmits<{
switch: [number]
drop: [string]
}>()
const { t } = useI18n()
const logoUrl = chrome.runtime.getURL("/logo.svg")
const globeImg = chrome.runtime.getURL("img/globe.svg")
let count = 0
const dragActive = ref(false)
const handleDragEnter = (e: DragEvent) => {
count++
if (e.dataTransfer?.types.includes("text/uri-list")) {
e.preventDefault()
dragActive.value = true
}
}
const handleDragLeave = (e: DragEvent) => {
count--
if (count <= 0) {
dragActive.value = false
}
console.log("count: ", count)
}
const handleDragOver = (e: DragEvent) => {
if (e.dataTransfer?.types.includes("text/uri-list")) {
e.preventDefault()
}
}
const handleDrop = (e: DragEvent) => {
e.preventDefault()
dragActive.value = false
if (!e.dataTransfer) {
return
}
const url = e.dataTransfer.getData("text/uri-list")
console.log("url: ", url)
emit("drop", url)
}
</script>
<template>
<div
:class="[
'flex gap-1 items-center justify-between h-9 px-1 z-10 shadow-sm',
'*:size-7 *:flex *:items-center *:justify-center ',
]"
@dragenter="handleDragEnter"
@dragover="handleDragOver"
@dragleave="handleDragLeave"
@drop="handleDrop"
>
<a
draggable="true"
@click="(e) => (e.preventDefault(), $emit('switch', -1))"
:href="homeUrl"
title="Anything Copilot"
:class="[
'group rounded-full relative box-border border',
active === -1
? 'bg-primary/10 border-primary-500'
: 'border-transparent hover:bg-background-mute bg-background-soft',
]"
>
<img
:class="[
'size-4 group-hover:opacity-85 transition-all pointer-events-none',
false ? 'opacity-85' : 'opacity-50',
]"
:src="logoUrl"
/>
<!-- <IconHome class="size-5 group-active:scale-90 transition-transform" /> -->
</a>
<a
v-for="(page, i) of pages"
draggable="true"
@click="(e) => (e.preventDefault(), $emit('switch', i))"
:href="pagesInfo[i]?.url"
:title="pagesInfo[i]?.title"
:class="[
'group rounded-full relative box-border border',
active === i
? 'bg-primary/10 border-primary-500'
: 'border-transparent hover:bg-background-mute bg-background-soft',
]"
>
<img
class="size-4 pointer-events-none"
loading="lazy"
:src="pagesInfo[i]?.icon || globeImg"
:data-fallback="globeImg"
@error="handleImgError"
/>
<span
v-if="active === i && closeWebview"
class="absolute hidden group-hover:block rounded-full bg-primary-500 text-white -top-0.5 -right-0.5 transition-all p-0.5"
@click="
(e) => (e.preventDefault(), e.stopPropagation(), closeWebview?.(i))
"
>
<IconClose class="size-2" />
</span>
</a>
<a
v-if="dragActive"
class="rounded-full box-border border border-primary-500 bg-primary/10 text-primary"
>
<IconAdd class="size-5 group-active:scale-90 transition-transform" />
</a>
<span class="mx-auto"></span>
<button
v-if="goBack"
@click="goBack()"
class="group hover:bg-background-soft rounded-full"
>
<IconNavigateBefore
class="size-5 scale-125 group-active:-translate-x-1 transition-transform"
/>
</button>
<button
v-if="goForward"
@click="goForward()"
class="group hover:bg-background-soft rounded-full"
>
<IconNavigateNext
class="size-5 scale-125 group-active:translate-x-1 transition-transform"
/>
</button>
<button
v-if="reload"
@click="reload()"
:title="t('refresh')"
class="group hover:bg-background-soft rounded-full"
>
<IconRefresh
class="size-5 group-active:rotate-180 transition-transform"
/>
</button>
<button
v-if="toggleMobileUA"
@click="toggleMobileUA"
:title="t('mobileView')"
:class="[
'group hover:bg-background-soft rounded-full transition ease-in-out delay-200',
{ 'bg-background-soft text-primary-500 ': isMobileUA },
isPointerIn ? '' : ' opacity-75',
]"
>
<IconPhone class="size-4 group-active:scale-90 transition-transform" />
</button>
<button
v-if="collapseSidebar"
@click="collapseSidebar()"
:title="t('minimize')"
class="group hover:bg-background-soft rounded-full"
>
<IconHide
class="size-5 scale-95 group-active:scale-90 transition-transform"
/>
</button>
<button
v-if="closeSidebar"
@click="closeSidebar()"
:title="t('close')"
class="group hover:bg-background-soft rounded-full"
>
<IconClose class="size-5 group-active:scale-90 transition-transform" />
</button>
</div>
</template>
<style scoped></style>
......@@ -22,7 +22,7 @@ const emit = defineEmits({
<div class="flex flex-col p-6 w-full max-w-md mx-auto">
<div class="flex flex-col items-center gap-2 mx-auto mt-16">
<img :src="logoUrl" class="size-16" />
<span class="text-2xl font-bold my-2">{{ t("sidebar") }}</span>
<span class="text-2xl font-bold my-2">Anything Copilot</span>
</div>
<div class="my-12">
......
......@@ -24,7 +24,7 @@ export const defaultSidebarPath = "sidebar.html"
const manifest = {
// maximum of 45 characters
name: "__MSG_name__",
version: "1.2.9",
version: "1.2.10",
// edge 12 characters
// short_name: "__MSG_short_name__",
// no more than 132 characters
......
<script setup lang="ts">
import Webview from "@/components/Webview.vue"
import Multitasking from "@/components/Multitasking.vue";
</script>
<template>
<!-- <div class="w-screen h-screen">
<Webview url="https://github.com" />
</div> -->
<Multitasking />
</template>
<style scoped></style>
......@@ -12,20 +12,9 @@ import Webview, { type PageInfo } from "@/components/Webview.vue"
import { useI18n } from "@/utils/i18n"
import { MessageType } from "@/types"
import SidebarHome from "@/components/sidebar/SidebarHome.vue"
import IconClose from "@/components/icons/IconClose.vue"
import IconSplitscreenRight from "@/components/icons/IconSplitscreenRight.vue"
import IconNavigateBefore from "@/components/icons/IconNavigateBefore.vue"
import IconNavigateNext from "@/components/icons/IconNavigateNext.vue"
import IconRefresh from "@/components/icons/IconRefresh.vue"
import IconHome from "@/components/icons/IconHome.vue"
import IconPhone from "@/components/icons/IconPhone.vue"
import IconHide from "@/components/icons/IconHide.vue"
import { handleImgError } from "@/utils/dom"
import Navbar from "@/components/sidebar/Navbar.vue"
import { FrameMessageType } from "@/types"
import { homeUrl } from "@/utils/const"
const logoUrl = chrome.runtime.getURL("/logo.svg")
const globeImg = chrome.runtime.getURL("img/globe.svg")
const { t } = useI18n()
const mobileUA =
"Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1"
......@@ -320,123 +309,20 @@ function handlePointerLeave() {
@pointerenter="handlePointerEnter"
@pointerleave="handlePointerLeave"
>
<div
:class="[
'flex gap-1 items-center justify-between h-9 px-1 z-10 shadow-sm',
'*:size-7 *:flex *:items-center *:justify-center ',
]"
>
<a
@click="(e) => (e.preventDefault(), (active = -1))"
:href="homeUrl"
title="Anything Copilot"
:class="[
'group rounded-full relative box-border border',
active === -1
? 'bg-primary/10 border-primary-500'
: 'border-transparent hover:bg-background-mute bg-background-soft',
]"
>
<img
:class="[
'size-4 group-hover:opacity-85 transition-all pointer-events-none',
false ? 'opacity-85' : 'opacity-50',
]"
:src="logoUrl"
/>
<!-- <IconHome class="size-5 group-active:scale-90 transition-transform" /> -->
</a>
<a
v-for="(page, i) of pages"
@click="(e) => (e.preventDefault(), (active = i))"
:href="pagesInfo[i]?.url"
:title="pagesInfo[i]?.title"
:class="[
'group rounded-full relative box-border border',
active === i
? 'bg-primary/10 border-primary-500'
: 'border-transparent hover:bg-background-mute bg-background-soft',
]"
>
<img
class="size-4 pointer-events-none"
loading="lazy"
:src="pagesInfo[i]?.icon || globeImg"
:data-fallback="globeImg"
@error="handleImgError"
/>
<span
v-if="active === i"
class="absolute hidden group-hover:block rounded-full bg-primary-500 text-white -top-0.5 -right-0.5 transition-all p-0.5"
@click="
(e) => {
e.preventDefault()
e.stopPropagation()
closeWebview(i)
}
"
>
<IconClose class="size-2" />
</span>
</a>
<span class="mx-auto"></span>
<!-- <button
@click="goBack()"
class="group hover:bg-background-soft rounded-full"
>
<IconNavigateBefore
class="size-5 scale-125 group-active:-translate-x-1 transition-transform"
/>
</button>
<button
@click="goForward()"
class="group hover:bg-background-soft rounded-full"
>
<IconNavigateNext
class="size-5 scale-125 group-active:translate-x-1 transition-transform"
/>
</button> -->
<button
@click="reload()"
:title="t('refresh')"
class="group hover:bg-background-soft rounded-full"
>
<IconRefresh
class="size-5 group-active:rotate-180 transition-transform"
<Navbar
:active="active"
:pages="pages"
:pagesInfo="pagesInfo"
:isMobileUA="isMobileUA"
:isPointerIn="isPointerIn"
:closeWebview="closeWebview"
:reload="reload"
:toggleMobileUA="toggleMobileUA"
:collapseSidebar="mode == 'content' ? collapseSidebar : undefined"
:closeSidebar="mode == 'content' ? closeSidebar : undefined"
@switch="active = $event"
@drop="go"
/>
</button>
<button
@click="toggleMobileUA"
:title="t('mobileView')"
:class="[
'group hover:bg-background-soft rounded-full transition ease-in-out delay-200',
{ 'bg-background-soft text-primary-500 ': isMobileUA },
isPointerIn ? '' : ' opacity-75',
]"
>
<IconPhone class="size-4 group-active:scale-90 transition-transform" />
</button>
<button
v-if="mode == 'content'"
@click="collapseSidebar()"
:title="t('minimize')"
class="group hover:bg-background-soft rounded-full"
>
<IconHide
class="size-5 scale-95 group-active:scale-90 transition-transform"
/>
</button>
<button
v-if="mode == 'content'"
@click="closeSidebar()"
:title="t('close')"
class="group hover:bg-background-soft rounded-full"
>
<IconClose class="size-5 group-active:scale-90 transition-transform" />
</button>
</div>
<div :class="['w-full h-full', { hidden: active != -1 }]">
<SidebarHome
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment