Skip to content

Commit

Permalink
feat: 🚀 Add page search function
Browse files Browse the repository at this point in the history
  • Loading branch information
viarotel committed May 11, 2024
1 parent 603e4e9 commit 6dd8244
Show file tree
Hide file tree
Showing 5 changed files with 187 additions and 82 deletions.
5 changes: 5 additions & 0 deletions components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ declare module 'vue' {
export interface GlobalComponents {
About: typeof import('./src/components/About/index.vue')['default']
AppInstall: typeof import('./src/components/Device/components/ControlBar/AppInstall/index.vue')['default']
AppSearch: typeof import('./src/components/AppSearch/index.vue')['default']
AudioCodecSelect: typeof import('./src/components/Preference/components/AudioCodecSelect/index.vue')['default']
Camera: typeof import('./src/components/Device/components/MoreDropdown/components/Camera/index.vue')['default']
ControlBar: typeof import('./src/components/Device/components/ControlBar/index.vue')['default']
Expand All @@ -27,6 +28,8 @@ declare module 'vue' {
ElForm: typeof import('element-plus/es')['ElForm']
ElFormItem: typeof import('element-plus/es')['ElFormItem']
ElIcon: typeof import('element-plus/es')['ElIcon']
ElIconArrowDownBold: typeof import('@element-plus/icons-vue')['ArrowDownBold']
ElIconArrowUpBold: typeof import('@element-plus/icons-vue')['ArrowUpBold']
ElIconCaretLeft: typeof import('@element-plus/icons-vue')['CaretLeft']
ElIconCaretRight: typeof import('@element-plus/icons-vue')['CaretRight']
ElIconClose: typeof import('@element-plus/icons-vue')['Close']
Expand All @@ -35,6 +38,7 @@ declare module 'vue' {
ElIconLoading: typeof import('@element-plus/icons-vue')['Loading']
ElIconOperation: typeof import('@element-plus/icons-vue')['Operation']
ElIconQuestionFilled: typeof import('@element-plus/icons-vue')['QuestionFilled']
ElIconSelect: typeof import('@element-plus/icons-vue')['Select']
ElIconWarningFilled: typeof import('@element-plus/icons-vue')['WarningFilled']
ElInput: typeof import('element-plus/es')['ElInput']
ElLink: typeof import('element-plus/es')['ElLink']
Expand Down Expand Up @@ -65,6 +69,7 @@ declare module 'vue' {
Remark: typeof import('./src/components/Device/components/Remark/index.vue')['default']
Rotation: typeof import('./src/components/Device/components/ControlBar/Rotation/index.vue')['default']
Screenshot: typeof import('./src/components/Device/components/ControlBar/Screenshot/index.vue')['default']
Search: typeof import('./src/components/Search/index.vue')['default']
TerminalAction: typeof import('./src/components/Device/components/TerminalAction/index.vue')['default']
TerminalDialog: typeof import('./src/components/Device/components/TerminalAction/components/TerminalDialog/index.vue')['default']
VideoCodecSelect: typeof import('./src/components/Preference/components/VideoCodecSelect/index.vue')['default']
Expand Down
2 changes: 2 additions & 0 deletions electron/events/handles/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import fs from 'fs-extra'
import { dialog, ipcMain, shell } from 'electron'
import themeHandles from './theme/index.js'
import searchHandles from './search/index.js'

export default (mainWindow) => {
themeHandles(mainWindow)
searchHandles(mainWindow)

ipcMain.handle(
'show-open-dialog',
Expand Down
12 changes: 12 additions & 0 deletions electron/events/handles/search/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { ipcMain } from 'electron'

export default (mainWindow) => {
ipcMain.handle('find-in-page', async (_, { text, ...args } = {}) => {
return mainWindow.webContents.findInPage(text, {
...args,
})
})
ipcMain.handle('stop-find-in-page', async (_, action = 'clearSelection') => {
return mainWindow.webContents.stopFindInPage(action)
})
}
176 changes: 94 additions & 82 deletions src/App.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
<template>
<div class="absolute inset-0 px-4 pb-4 h-full overflow-hidden">
<el-tabs v-model="activeTab" class="el-tabs-flex" @tab-change="onTabChange">
<div class="absolute inset-0 px-4 pb-4 h-full">
<el-tabs
v-model="activeTab"
class="el-tabs-flex"
addable
@tab-change="onTabChange"
>
<template #add-icon>
<AppSearch />
</template>
<el-tab-pane
v-for="(item, index) of tabsModel"
:key="index"
Expand All @@ -9,7 +17,7 @@
lazy
>
<component
:is="item.prop"
:is="item.component"
v-if="isRender(item)"
:ref="item.prop"
:re-render="reRender"
Expand All @@ -19,112 +27,116 @@
</div>
</template>

<script>
<script setup>
import { ElMessageBox } from 'element-plus'
import Device from './components/Device/index.vue'
import Preference from './components/Preference/index.vue'
import About from './components/About/index.vue'
import AppSearch from './components/AppSearch/index.vue'
import { useThemeStore } from '@/store/theme/index.js'
import { usePreferenceStore } from '@/store/preference/index.js'
export default {
components: {
Device,
Preference,
About,
const tabsModel = ref([
{
label: 'device.list',
prop: 'Device',
component: markRaw(Device),
},
data() {
return {
tabsModel: [
{
label: 'device.list',
prop: 'Device',
},
{
label: 'preferences.name',
prop: 'Preference',
},
{
label: 'about.name',
prop: 'About',
},
],
activeTab: 'Device',
renderTab: '',
rendered: true,
renderSign: false,
}
{
label: 'preferences.name',
prop: 'Preference',
component: markRaw(Preference),
},
created() {
this.$store.theme.init()
this.$store.preference.init()
this.showTips()
{
label: 'about.name',
prop: 'About',
component: markRaw(About),
},
methods: {
async showTips() {
const { scrcpyPath } = this.$electron?.configs || {}
])
const activeTab = ref('Device')
const renderTab = ref('')
const rendered = ref(true)
const renderSign = ref(false)
const themeStore = useThemeStore()
const preferenceStore = usePreferenceStore()
themeStore.init()
preferenceStore.init()
showTips()
if (scrcpyPath) {
return false
}
async function showTips() {
const { scrcpyPath } = window.electron?.configs || {}
this.$alert(
`<div>
${this.$t('dependencies.lack.content', {
if (scrcpyPath) {
return false
}
ElMessageBox.alert(
`<div>
${window.t('dependencies.lack.content', {
name: '<a class="hover:underline text-primary-500" href="https://github.com/Genymobile/scrcpy" target="_blank">scrcpy</a>',
})}
<div>`,
this.$t('dependencies.lack.title'),
{
dangerouslyUseHTMLString: true,
confirmButtonText: this.$t('common.confirm'),
},
)
window.t('dependencies.lack.title'),
{
dangerouslyUseHTMLString: true,
confirmButtonText: window.t('common.confirm'),
},
)
}
isRender(item) {
if (this.renderTab === item.prop) {
return this.rendered
}
function isRender(item) {
if (renderTab.value === item.prop) {
return rendered.value
}
return true
},
return true
}
async reRender(other) {
this.renderTab = other || this.activeTab
async function reRender(other) {
renderTab.value = other || activeTab.value
this.rendered = false
await this.$nextTick()
this.rendered = true
rendered.value = false
await nextTick()
rendered.value = true
this.renderTab = ''
},
renderTab.value = ''
}
reRenderPost() {
this.renderSign = true
},
function reRenderPost() {
renderSign.value = true
}
async onTabChange(prop) {
if (!this.renderSign) {
return false
}
switch (prop) {
case 'Device':
this.reRender()
break
case 'Preference':
this.reRender()
break
}
this.renderSign = false
},
},
async function onTabChange(prop) {
if (!renderSign.value) {
return false
}
if (['Device', 'Preference'].includes(prop)) {
reRender()
}
renderSign.value = false
}
defineExpose({
reRenderPost,
reRender,
})
</script>
<style lang="postcss" scoped>
:deep() {
.el-tabs__header {
@apply !mb-3;
}
.el-tabs__new-tab {
@apply !absolute !inset-y-0 !right-0 !border-none;
}
}
</style>
74 changes: 74 additions & 0 deletions src/components/AppSearch/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<template>
<div class="absolute -bottom-1 right-0 z-10">
<el-input
ref="elInputRef"
v-model="keyword"
prefix-icon="Search"
placeholder="搜索"
clearable
class="transition-all overflow-hidden"
:class="activated || keyword ? '!w-96' : '!w-24'"
@focus="onFocus"
@blur="onBlur"
@input="onInput"
@clear="onClear"
>
<template v-if="keyword" #append>
<div
class="flex flex-col size-full absolute inset-0 justify-center items-center"
>
<div class="flex-1 h-0 flex items-end">
<el-icon size="12">
<ElIconArrowUpBold />
</el-icon>
</div>

<div class="h-px w-full border-[0.5px] border-gray-200"></div>

<div class="flex-1 h-0 flex items-start">
<el-icon size="12">
<ElIconArrowDownBold />
</el-icon>
</div>
</div>
</template>
</el-input>
</div>
</template>

<script setup>
const elInputRef = ref(null)
const keyword = ref('')
const activated = ref(false)
function handleFocus() {
elInputRef.value.focus()
}
async function onFocus() {
activated.value = true
}
function onBlur() {
activated.value = false
}
function onClear() {
window.electron.ipcRenderer.invoke('stop-find-in-page', 'clearSelection')
}
function onInput(value) {
if (!value) {
onClear()
return false
}
window.electron.ipcRenderer.invoke('find-in-page', {
text: value,
findNext: true,
})
}
</script>

<style></style>

0 comments on commit 6dd8244

Please sign in to comment.