feat(app): implement basic function
General - 配置界面支持配置对象存储桶 - 快捷键进入截图 - 一键上传截图 & 复制截图链接 MacOS - 状态栏指示器和应用图标
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
# Vue 3 + TypeScript + Vite
|
||||
|
||||
This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue
|
||||
3 `<script setup>` SFCs, check out
|
||||
the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
|
||||
|
||||
## Recommended IDE Setup
|
||||
|
||||
- [VS Code](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar)
|
||||
|
||||
## Type Support For `.vue` Imports in TS
|
||||
|
||||
Since TypeScript cannot handle type information for `.vue` imports, they are shimmed to be a generic Vue component type
|
||||
by default. In most cases this is fine if you don't really care about component prop types outside of templates.
|
||||
However, if you wish to get actual prop types in `.vue` imports (for example to get props validation when using
|
||||
manual `h(...)` calls), you can enable Volar's Take Over mode by following these steps:
|
||||
|
||||
1. Run `Extensions: Show Built-in Extensions` from VS Code's command palette, look
|
||||
for `TypeScript and JavaScript Language Features`, then right click and select `Disable (Workspace)`. By default,
|
||||
Take Over mode will enable itself if the default TypeScript extension is disabled.
|
||||
2. Reload the VS Code window by running `Developer: Reload Window` from the command palette.
|
||||
|
||||
You can learn more about Take Over mode [here](https://github.com/johnsoncodehk/volar/discussions/471).
|
||||
@@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||
<title>SnapGo</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script src="./src/main.ts" type="module"></script>
|
||||
</body>
|
||||
</html>
|
||||
Generated
+1071
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "frontend",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vue-tsc --noEmit && vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"vue": "^3.2.37"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^3.0.3",
|
||||
"typescript": "^4.6.4",
|
||||
"vite": "^3.0.7",
|
||||
"vue-tsc": "^1.8.27",
|
||||
"@babel/types": "^7.18.10"
|
||||
}
|
||||
}
|
||||
Executable
+1
@@ -0,0 +1 @@
|
||||
bb7ffb87329c9ad4990374471d4ce9a4
|
||||
@@ -0,0 +1,299 @@
|
||||
<script setup lang="ts">
|
||||
/*
|
||||
* App shell — switches between two distinct UI modes that share the same
|
||||
* Wails window:
|
||||
*
|
||||
* • "settings" : full settings UI (self-drawn title bar + sidebar + form).
|
||||
* Self-drawn because the window is now Frameless to make
|
||||
* the overlay paint edge-to-edge.
|
||||
* • "overlay" : Snipaste-style region picker that fills the whole
|
||||
* primary display.
|
||||
*
|
||||
* The Go side resizes/positions/flag-flips the window for each mode and
|
||||
* emits a `capture:overlay` event with the screenshot payload so the
|
||||
* frontend knows when (and what) to render.
|
||||
*/
|
||||
import { onMounted, onUnmounted, ref } from 'vue'
|
||||
import SettingsView from './views/SettingsView.vue'
|
||||
import Toast from './components/Toast.vue'
|
||||
import CaptureOverlay from './views/CaptureOverlay.vue'
|
||||
import { EventsOn, EventsOff } from '../wailsjs/runtime/runtime'
|
||||
import {
|
||||
RetryRegisterHotkey,
|
||||
ConfirmRegion,
|
||||
CancelRegion,
|
||||
} from '../wailsjs/go/main/App'
|
||||
|
||||
type HotkeyStatus =
|
||||
| { state: 'unknown' }
|
||||
| { state: 'ok'; spec: string }
|
||||
| { state: 'error'; reason: string }
|
||||
const hotkeyStatus = ref<HotkeyStatus>({ state: 'unknown' })
|
||||
|
||||
type Mode = 'settings' | 'overlay'
|
||||
const mode = ref<Mode>('settings')
|
||||
|
||||
interface OverlayPayload {
|
||||
cssWidth: number
|
||||
cssHeight: number
|
||||
scale: number
|
||||
}
|
||||
const overlayPayload = ref<OverlayPayload | null>(null)
|
||||
|
||||
const capturing = ref(false)
|
||||
|
||||
const toast = ref<{ kind: 'success' | 'error'; text: string } | null>(null)
|
||||
let toastTimer: number | undefined
|
||||
|
||||
function showToast(kind: 'success' | 'error', text: string) {
|
||||
toast.value = { kind, text }
|
||||
window.clearTimeout(toastTimer)
|
||||
toastTimer = window.setTimeout(() => {
|
||||
toast.value = null
|
||||
}, 3000)
|
||||
}
|
||||
|
||||
async function retryHotkey() {
|
||||
try {
|
||||
await RetryRegisterHotkey()
|
||||
} catch {
|
||||
/* Surfaced via hotkey:error */
|
||||
}
|
||||
}
|
||||
|
||||
async function onOverlayConfirm(rect: {
|
||||
x: number
|
||||
y: number
|
||||
w: number
|
||||
h: number
|
||||
}) {
|
||||
// Optimistically swap back so the window does not visually lag the
|
||||
// Go-side hide. If upload fails, the toast surfaces the reason.
|
||||
mode.value = 'settings'
|
||||
overlayPayload.value = null
|
||||
try {
|
||||
await ConfirmRegion(rect)
|
||||
} catch {
|
||||
/* Surfaced via upload:failure */
|
||||
}
|
||||
}
|
||||
|
||||
async function onOverlayCancel() {
|
||||
mode.value = 'settings'
|
||||
overlayPayload.value = null
|
||||
try {
|
||||
await CancelRegion()
|
||||
} catch {
|
||||
/* Best-effort */
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
EventsOn('capture:start', () => {
|
||||
capturing.value = true
|
||||
})
|
||||
EventsOn('capture:end', () => {
|
||||
capturing.value = false
|
||||
})
|
||||
EventsOn('capture:cancelled', () => {
|
||||
capturing.value = false
|
||||
})
|
||||
EventsOn('capture:overlay', (payload: OverlayPayload) => {
|
||||
overlayPayload.value = payload
|
||||
mode.value = 'overlay'
|
||||
capturing.value = false
|
||||
})
|
||||
EventsOn('upload:success', (url: string) => {
|
||||
showToast('success', `Copied: ${url}`)
|
||||
})
|
||||
EventsOn('upload:failure', (reason: string) => {
|
||||
showToast('error', reason)
|
||||
})
|
||||
EventsOn('hotkey:ready', (spec: string) => {
|
||||
hotkeyStatus.value = { state: 'ok', spec }
|
||||
})
|
||||
EventsOn('hotkey:error', (reason: string) => {
|
||||
hotkeyStatus.value = { state: 'error', reason }
|
||||
})
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
EventsOff('capture:start')
|
||||
EventsOff('capture:end')
|
||||
EventsOff('capture:cancelled')
|
||||
EventsOff('capture:overlay')
|
||||
EventsOff('upload:success')
|
||||
EventsOff('upload:failure')
|
||||
EventsOff('hotkey:ready')
|
||||
EventsOff('hotkey:error')
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- Overlay mode: full-screen Snipaste-style picker. -->
|
||||
<CaptureOverlay
|
||||
v-if="mode === 'overlay' && overlayPayload"
|
||||
:width="overlayPayload.cssWidth"
|
||||
:height="overlayPayload.cssHeight"
|
||||
@confirm="onOverlayConfirm"
|
||||
@cancel="onOverlayCancel"
|
||||
/>
|
||||
|
||||
<!-- Settings mode: standard desktop window; macOS title bar is native. -->
|
||||
<div v-else class="app-root">
|
||||
<div v-if="hotkeyStatus.state === 'error'" class="permission-banner">
|
||||
<div>
|
||||
<strong>Global hotkey is not active.</strong>
|
||||
Reason: {{ hotkeyStatus.reason }}
|
||||
<br />
|
||||
On macOS open
|
||||
<em>System Settings → Privacy & Security → Accessibility</em>,
|
||||
enable <strong>SnapGo</strong>, then click "Retry".
|
||||
</div>
|
||||
<button class="btn" @click="retryHotkey">Retry</button>
|
||||
</div>
|
||||
|
||||
<main class="main">
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-item active"><span class="dot" /> Settings</div>
|
||||
</aside>
|
||||
<section class="content">
|
||||
<SettingsView />
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<Toast v-if="toast" :kind="toast.kind" :text="toast.text" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.app-root {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background: #f6f7fa;
|
||||
color: #111827;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.status-pill {
|
||||
font-size: 11px;
|
||||
padding: 3px 9px;
|
||||
border-radius: 999px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.status-pill.ok {
|
||||
color: #047857;
|
||||
background: rgba(16, 185, 129, 0.12);
|
||||
}
|
||||
.status-pill.err {
|
||||
color: #b91c1c;
|
||||
background: rgba(239, 68, 68, 0.14);
|
||||
cursor: help;
|
||||
}
|
||||
.status-pill.muted {
|
||||
color: #6b7280;
|
||||
background: rgba(107, 114, 128, 0.14);
|
||||
}
|
||||
|
||||
.permission-banner {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: flex-start;
|
||||
margin: 12px 16px 0;
|
||||
padding: 10px 14px;
|
||||
background: #fff7ed;
|
||||
border: 1px solid #fdba74;
|
||||
border-radius: 8px;
|
||||
color: #7c2d12;
|
||||
font-size: 12px;
|
||||
line-height: 1.55;
|
||||
}
|
||||
.permission-banner em {
|
||||
font-style: normal;
|
||||
background: rgba(124, 45, 18, 0.08);
|
||||
padding: 0 4px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.permission-banner .btn {
|
||||
flex: 0 0 auto;
|
||||
border: 1px solid #fdba74;
|
||||
background: #fff;
|
||||
color: #7c2d12;
|
||||
border-radius: 6px;
|
||||
padding: 6px 12px;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.permission-banner .btn:hover {
|
||||
background: #fed7aa;
|
||||
}
|
||||
|
||||
.main {
|
||||
flex: 1;
|
||||
display: grid;
|
||||
grid-template-columns: 180px 1fr;
|
||||
min-height: 0;
|
||||
}
|
||||
.sidebar {
|
||||
border-right: 1px solid #e5e7eb;
|
||||
padding: 14px 8px;
|
||||
background: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
.sidebar-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 7px 12px;
|
||||
border-radius: 6px;
|
||||
font-size: 13px;
|
||||
color: #374151;
|
||||
cursor: default;
|
||||
}
|
||||
.sidebar-item.active {
|
||||
background: rgba(59, 130, 246, 0.12);
|
||||
color: #1d4ed8;
|
||||
font-weight: 500;
|
||||
}
|
||||
.sidebar-item .dot {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background: currentColor;
|
||||
}
|
||||
.content {
|
||||
overflow-y: auto;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.app-root {
|
||||
background: #1c1d22;
|
||||
color: #e5e7eb;
|
||||
}
|
||||
.titlebar {
|
||||
background: rgba(28, 29, 34, 0.7);
|
||||
border-bottom-color: #2c2f36;
|
||||
}
|
||||
.titlebar-title {
|
||||
color: #f3f4f6;
|
||||
}
|
||||
.sidebar {
|
||||
background: rgba(0, 0, 0, 0.15);
|
||||
border-right-color: #2c2f36;
|
||||
}
|
||||
.sidebar-item {
|
||||
color: #d1d5db;
|
||||
}
|
||||
.sidebar-item.active {
|
||||
background: rgba(59, 130, 246, 0.18);
|
||||
color: #93c5fd;
|
||||
}
|
||||
.permission-banner {
|
||||
background: rgba(120, 53, 15, 0.3);
|
||||
border-color: rgba(253, 186, 116, 0.4);
|
||||
color: #fed7aa;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,93 @@
|
||||
Copyright 2016 The Nunito Project Authors (contact@sansoxygen.com),
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 136 KiB |
@@ -0,0 +1,48 @@
|
||||
<script setup lang="ts">
|
||||
/*
|
||||
* Toast — bottom-right transient notification used for upload success /
|
||||
* failure messages. Self-managed lifecycle is owned by the parent App.vue,
|
||||
* which simply hides this component after a delay.
|
||||
*/
|
||||
defineProps<{
|
||||
kind: 'success' | 'error'
|
||||
text: string
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="toast" :class="kind">{{ text }}</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.toast {
|
||||
position: fixed;
|
||||
right: 18px;
|
||||
bottom: 18px;
|
||||
max-width: 380px;
|
||||
padding: 10px 14px;
|
||||
border-radius: 6px;
|
||||
font-size: 12.5px;
|
||||
color: #fff;
|
||||
box-shadow: 0 8px 24px rgba(15, 23, 42, 0.18);
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
animation: toast-in 0.18s ease-out;
|
||||
}
|
||||
.toast.success {
|
||||
background: #10b981;
|
||||
}
|
||||
.toast.error {
|
||||
background: #ef4444;
|
||||
}
|
||||
@keyframes toast-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(8px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,5 @@
|
||||
import {createApp} from 'vue'
|
||||
import App from './App.vue'
|
||||
import './style.css';
|
||||
|
||||
createApp(App).mount('#app')
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Global styles for SnapGo.
|
||||
*
|
||||
* Design rationale:
|
||||
* - The native window/webview is transparent so the capture overlay can show
|
||||
* the live desktop through its selection cut-out.
|
||||
* - SettingsView remains opaque because App.vue paints `.app-root` across
|
||||
* the whole window.
|
||||
*/
|
||||
:root {
|
||||
color-scheme: light dark;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text",
|
||||
"Segoe UI Variable", "Inter", sans-serif;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
background: transparent;
|
||||
color: #111827;
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
html,
|
||||
body {
|
||||
background: transparent;
|
||||
color: #e5e7eb;
|
||||
}
|
||||
}
|
||||
|
||||
#app {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
button {
|
||||
font-family: inherit;
|
||||
}
|
||||
@@ -0,0 +1,314 @@
|
||||
<script setup lang="ts">
|
||||
/*
|
||||
* CaptureOverlay — Snipaste-style region picker.
|
||||
*
|
||||
* Three layers, painted in order:
|
||||
* 1. Dark mask + selection : a single SVG that draws a 0.4 alpha
|
||||
* black rectangle over the whole screen
|
||||
* with the selection cut out via fill-rule
|
||||
* evenodd. The Wails window itself is
|
||||
* transparent, so the cut-out shows the live
|
||||
* desktop rather than a stale screenshot.
|
||||
* 2. Toolbar : floats just outside the bottom-right of
|
||||
* the selection rectangle (Snipaste rule).
|
||||
*
|
||||
* Interaction model (kept minimal per user choice):
|
||||
* • If no selection yet: mousedown drags out a new rectangle.
|
||||
* • If selection exists: mousedown INSIDE moves it; OUTSIDE re-drags.
|
||||
* • Esc / Cancel button → emit('cancel')
|
||||
* • Enter / Upload button → emit('confirm', rect)
|
||||
*/
|
||||
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
||||
|
||||
interface Props {
|
||||
/** Logical (CSS) width of the primary display. */
|
||||
width: number
|
||||
/** Logical (CSS) height of the primary display. */
|
||||
height: number
|
||||
}
|
||||
const props = defineProps<Props>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'confirm', rect: { x: number; y: number; w: number; h: number }): void
|
||||
(e: 'cancel'): void
|
||||
}>()
|
||||
|
||||
// Selection rect stored in CSS pixels. null = nothing selected yet.
|
||||
interface Rect {
|
||||
x: number
|
||||
y: number
|
||||
w: number
|
||||
h: number
|
||||
}
|
||||
const rect = ref<Rect | null>(null)
|
||||
|
||||
// Drag state machine.
|
||||
type DragMode = 'idle' | 'creating' | 'moving'
|
||||
const dragMode = ref<DragMode>('idle')
|
||||
// For 'creating': the anchor where mousedown started.
|
||||
// For 'moving' : the mouse offset relative to the rect's top-left.
|
||||
const dragAnchor = ref({ x: 0, y: 0 })
|
||||
|
||||
// SVG path for "the entire screen with the selection rect cut out".
|
||||
// We rely on fill-rule:evenodd to subtract the inner rectangle.
|
||||
const maskPath = computed(() => {
|
||||
const outer = `M0 0 H${props.width} V${props.height} H0 Z`
|
||||
if (!rect.value) return outer
|
||||
const r = rect.value
|
||||
// Inner rect drawn in the OPPOSITE winding order so evenodd cuts it.
|
||||
const inner = `M${r.x} ${r.y} H${r.x + r.w} V${r.y + r.h} H${r.x} Z`
|
||||
return outer + ' ' + inner
|
||||
})
|
||||
|
||||
// Toolbar placement: anchor to bottom-right of the selection, but shove
|
||||
// it to the inside top-right if the selection is too close to the screen
|
||||
// edge to keep the buttons visible.
|
||||
const TOOLBAR_W = 220
|
||||
const TOOLBAR_H = 40
|
||||
const GAP = 8
|
||||
const toolbarPos = computed(() => {
|
||||
if (!rect.value) return null
|
||||
const r = rect.value
|
||||
let x = r.x + r.w - TOOLBAR_W
|
||||
let y = r.y + r.h + GAP
|
||||
if (y + TOOLBAR_H > props.height) {
|
||||
// No room below: put it inside the selection's bottom-right.
|
||||
y = r.y + r.h - TOOLBAR_H - GAP
|
||||
}
|
||||
if (x < 0) x = 0
|
||||
if (x + TOOLBAR_W > props.width) x = props.width - TOOLBAR_W
|
||||
return { x, y }
|
||||
})
|
||||
|
||||
const insideRect = (px: number, py: number, r: Rect | null) => {
|
||||
if (!r) return false
|
||||
return px >= r.x && px <= r.x + r.w && py >= r.y && py <= r.y + r.h
|
||||
}
|
||||
|
||||
function onMouseDown(e: MouseEvent) {
|
||||
if (e.button !== 0) return
|
||||
const px = e.clientX
|
||||
const py = e.clientY
|
||||
if (rect.value && insideRect(px, py, rect.value)) {
|
||||
// Move existing selection.
|
||||
dragMode.value = 'moving'
|
||||
dragAnchor.value = { x: px - rect.value.x, y: py - rect.value.y }
|
||||
} else {
|
||||
// Start a new selection.
|
||||
dragMode.value = 'creating'
|
||||
dragAnchor.value = { x: px, y: py }
|
||||
rect.value = { x: px, y: py, w: 0, h: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
function onMouseMove(e: MouseEvent) {
|
||||
if (dragMode.value === 'idle') return
|
||||
const px = e.clientX
|
||||
const py = e.clientY
|
||||
if (dragMode.value === 'creating') {
|
||||
const ax = dragAnchor.value.x
|
||||
const ay = dragAnchor.value.y
|
||||
rect.value = {
|
||||
x: Math.min(ax, px),
|
||||
y: Math.min(ay, py),
|
||||
w: Math.abs(px - ax),
|
||||
h: Math.abs(py - ay),
|
||||
}
|
||||
} else if (dragMode.value === 'moving' && rect.value) {
|
||||
let nx = px - dragAnchor.value.x
|
||||
let ny = py - dragAnchor.value.y
|
||||
// Clamp inside the screen so the selection cannot be dragged off-canvas.
|
||||
nx = Math.max(0, Math.min(nx, props.width - rect.value.w))
|
||||
ny = Math.max(0, Math.min(ny, props.height - rect.value.h))
|
||||
rect.value = { ...rect.value, x: nx, y: ny }
|
||||
}
|
||||
}
|
||||
|
||||
function onMouseUp() {
|
||||
if (dragMode.value === 'creating' && rect.value) {
|
||||
// Discard zero/tiny selections — the user probably clicked accidentally.
|
||||
if (rect.value.w < 4 || rect.value.h < 4) {
|
||||
rect.value = null
|
||||
}
|
||||
}
|
||||
dragMode.value = 'idle'
|
||||
}
|
||||
|
||||
function onConfirm() {
|
||||
if (!rect.value) return
|
||||
emit('confirm', { ...rect.value })
|
||||
}
|
||||
|
||||
function onCancel() {
|
||||
emit('cancel')
|
||||
}
|
||||
|
||||
function onKeydown(e: KeyboardEvent) {
|
||||
if (e.key === 'Escape') {
|
||||
e.preventDefault()
|
||||
onCancel()
|
||||
} else if (e.key === 'Enter' && rect.value) {
|
||||
e.preventDefault()
|
||||
onConfirm()
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
window.addEventListener('keydown', onKeydown)
|
||||
})
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('keydown', onKeydown)
|
||||
})
|
||||
|
||||
// Selection size pill (Snipaste shows "WxH" near the top-left of selection).
|
||||
const sizeLabel = computed(() => {
|
||||
if (!rect.value) return ''
|
||||
return `${Math.round(rect.value.w)} × ${Math.round(rect.value.h)}`
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="overlay-root"
|
||||
:style="{ width: width + 'px', height: height + 'px' }"
|
||||
@mousedown="onMouseDown"
|
||||
@mousemove="onMouseMove"
|
||||
@mouseup="onMouseUp"
|
||||
@contextmenu.prevent="onCancel"
|
||||
>
|
||||
<!-- Layer 1: mask with selection cut out over the live desktop -->
|
||||
<svg
|
||||
class="mask"
|
||||
:width="width"
|
||||
:height="height"
|
||||
:viewBox="`0 0 ${width} ${height}`"
|
||||
preserveAspectRatio="none"
|
||||
>
|
||||
<path :d="maskPath" fill="rgba(0,0,0,0.45)" fill-rule="evenodd" />
|
||||
<!-- Selection border, drawn separately so it stays crisp. -->
|
||||
<rect
|
||||
v-if="rect"
|
||||
:x="rect.x"
|
||||
:y="rect.y"
|
||||
:width="rect.w"
|
||||
:height="rect.h"
|
||||
fill="none"
|
||||
stroke="#3b82f6"
|
||||
stroke-width="1.5"
|
||||
vector-effect="non-scaling-stroke"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
<!-- Layer 3a: size readout floating above the selection -->
|
||||
<div
|
||||
v-if="rect && rect.w > 0 && rect.h > 0"
|
||||
class="size-pill"
|
||||
:style="{
|
||||
left: rect.x + 'px',
|
||||
top: Math.max(0, rect.y - 26) + 'px',
|
||||
}"
|
||||
>
|
||||
{{ sizeLabel }}
|
||||
</div>
|
||||
|
||||
<!-- Layer 3b: action toolbar -->
|
||||
<div
|
||||
v-if="toolbarPos && rect && rect.w >= 4 && rect.h >= 4"
|
||||
class="toolbar"
|
||||
:style="{ left: toolbarPos.x + 'px', top: toolbarPos.y + 'px' }"
|
||||
@mousedown.stop
|
||||
>
|
||||
<button class="btn cancel" @click="onCancel" title="Esc">Cancel</button>
|
||||
<button class="btn primary" @click="onConfirm" title="Enter">
|
||||
Upload & copy
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Hint shown before the user has dragged anything. -->
|
||||
<div v-if="!rect" class="hint">
|
||||
Drag to select an area · Esc to cancel
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.overlay-root {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
user-select: none;
|
||||
cursor: crosshair;
|
||||
background: transparent;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.mask {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.size-pill {
|
||||
position: absolute;
|
||||
padding: 2px 8px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
color: #fff;
|
||||
background: rgba(15, 23, 42, 0.78);
|
||||
border-radius: 4px;
|
||||
pointer-events: none;
|
||||
font-variant-numeric: tabular-nums;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
|
||||
.toolbar {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
align-items: center;
|
||||
padding: 4px;
|
||||
background: rgba(28, 28, 32, 0.94);
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 6px 22px rgba(0, 0, 0, 0.4);
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.btn {
|
||||
border: 0;
|
||||
border-radius: 5px;
|
||||
padding: 6px 12px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
transition: background-color 120ms ease;
|
||||
}
|
||||
.btn.cancel {
|
||||
background: transparent;
|
||||
color: #d1d5db;
|
||||
}
|
||||
.btn.cancel:hover {
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
.btn.primary {
|
||||
background: #3b82f6;
|
||||
color: #fff;
|
||||
}
|
||||
.btn.primary:hover {
|
||||
background: #2563eb;
|
||||
}
|
||||
|
||||
.hint {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 24px;
|
||||
transform: translateX(-50%);
|
||||
padding: 6px 14px;
|
||||
font-size: 12px;
|
||||
color: #f3f4f6;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
border-radius: 999px;
|
||||
pointer-events: none;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,374 @@
|
||||
<script setup lang="ts">
|
||||
/*
|
||||
* SettingsView — the home screen of SnapGo before the user triggers a
|
||||
* capture. It exposes:
|
||||
* 1. Hotkey configuration
|
||||
* 2. S3-compatible OSS configuration
|
||||
* 3. Manual capture button (useful when developing or when the global
|
||||
* hotkey conflicts with another app)
|
||||
*
|
||||
* State flow: load() pulls config from Go on mount, save() pushes back.
|
||||
*/
|
||||
import { onMounted, ref } from 'vue'
|
||||
import {
|
||||
GetConfig,
|
||||
SaveConfig,
|
||||
TestConnection,
|
||||
CaptureNow,
|
||||
} from '../../wailsjs/go/main/App'
|
||||
|
||||
interface S3Config {
|
||||
endpoint: string
|
||||
region: string
|
||||
bucket: string
|
||||
accessKeyId: string
|
||||
secretAccessKey: string
|
||||
pathPrefix: string
|
||||
publicUrlBase: string
|
||||
usePathStyle: boolean
|
||||
}
|
||||
|
||||
interface AppConfig {
|
||||
hotkey: string
|
||||
s3: S3Config
|
||||
}
|
||||
|
||||
const config = ref<AppConfig>({
|
||||
hotkey: 'cmd+shift+a',
|
||||
s3: {
|
||||
endpoint: '',
|
||||
region: 'us-east-1',
|
||||
bucket: '',
|
||||
accessKeyId: '',
|
||||
secretAccessKey: '',
|
||||
pathPrefix: 'snapgo/',
|
||||
publicUrlBase: '',
|
||||
usePathStyle: true,
|
||||
},
|
||||
})
|
||||
|
||||
const saving = ref(false)
|
||||
const testing = ref(false)
|
||||
const message = ref<{ kind: 'ok' | 'err'; text: string } | null>(null)
|
||||
|
||||
function flash(kind: 'ok' | 'err', text: string) {
|
||||
message.value = { kind, text }
|
||||
window.setTimeout(() => {
|
||||
if (message.value?.text === text) message.value = null
|
||||
}, 4000)
|
||||
}
|
||||
|
||||
async function load() {
|
||||
const cfg = await GetConfig()
|
||||
if (cfg) {
|
||||
config.value = cfg as unknown as AppConfig
|
||||
}
|
||||
}
|
||||
|
||||
async function save() {
|
||||
saving.value = true
|
||||
try {
|
||||
await SaveConfig(config.value as any)
|
||||
flash('ok', 'Settings saved')
|
||||
} catch (err: any) {
|
||||
flash('err', `Save failed: ${err?.message ?? err}`)
|
||||
} finally {
|
||||
saving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function test() {
|
||||
testing.value = true
|
||||
try {
|
||||
await TestConnection(config.value.s3 as any)
|
||||
flash('ok', 'S3 connection OK — bucket is writable')
|
||||
} catch (err: any) {
|
||||
flash('err', `Test failed: ${err?.message ?? err}`)
|
||||
} finally {
|
||||
testing.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function manualCapture() {
|
||||
await CaptureNow()
|
||||
}
|
||||
|
||||
onMounted(load)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="settings">
|
||||
<header class="hero">
|
||||
<div>
|
||||
<h1>SnapGo</h1>
|
||||
<p class="subtitle">
|
||||
Press <kbd>{{ config.hotkey }}</kbd> anywhere to capture, upload, and
|
||||
copy the URL to your clipboard.
|
||||
</p>
|
||||
</div>
|
||||
<button class="btn primary" @click="manualCapture">Capture now</button>
|
||||
</header>
|
||||
|
||||
<section class="card">
|
||||
<h2>Shortcut</h2>
|
||||
<label class="field">
|
||||
<span>Global hotkey</span>
|
||||
<input
|
||||
v-model="config.hotkey"
|
||||
placeholder="cmd+shift+a"
|
||||
spellcheck="false"
|
||||
/>
|
||||
</label>
|
||||
<p class="hint">
|
||||
Tokens (case-insensitive, "+"-separated): cmd / ctrl / option / shift +
|
||||
a–z or 0–9. Example: <code>cmd+shift+a</code>.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="card">
|
||||
<h2>S3-compatible storage</h2>
|
||||
<div class="grid">
|
||||
<label class="field">
|
||||
<span>Endpoint *</span>
|
||||
<input
|
||||
v-model="config.s3.endpoint"
|
||||
placeholder="https://s3.us-east-005.backblazeb2.com"
|
||||
/>
|
||||
</label>
|
||||
<label class="field">
|
||||
<span>Region</span>
|
||||
<input v-model="config.s3.region" placeholder="us-east-1 / auto" />
|
||||
</label>
|
||||
<label class="field">
|
||||
<span>Bucket *</span>
|
||||
<input v-model="config.s3.bucket" placeholder="my-screenshots" />
|
||||
</label>
|
||||
<label class="field">
|
||||
<span>Access Key ID *</span>
|
||||
<input v-model="config.s3.accessKeyId" />
|
||||
</label>
|
||||
<label class="field">
|
||||
<span>Secret Access Key *</span>
|
||||
<input v-model="config.s3.secretAccessKey" type="password" />
|
||||
</label>
|
||||
<label class="field">
|
||||
<span>Path prefix</span>
|
||||
<input v-model="config.s3.pathPrefix" placeholder="snapgo/" />
|
||||
</label>
|
||||
<label class="field full">
|
||||
<span>Public URL base (optional, e.g. CDN)</span>
|
||||
<input
|
||||
v-model="config.s3.publicUrlBase"
|
||||
placeholder="https://cdn.example.com/screenshots"
|
||||
/>
|
||||
</label>
|
||||
<label class="field checkbox">
|
||||
<input type="checkbox" v-model="config.s3.usePathStyle" />
|
||||
<span
|
||||
>Use path-style addressing (recommended for MinIO, R2, custom
|
||||
domains)</span
|
||||
>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<button class="btn" :disabled="testing" @click="test">
|
||||
{{ testing ? 'Testing…' : 'Test connection' }}
|
||||
</button>
|
||||
<button class="btn primary" :disabled="saving" @click="save">
|
||||
{{ saving ? 'Saving…' : 'Save' }}
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<transition name="fade">
|
||||
<div
|
||||
v-if="message"
|
||||
class="banner"
|
||||
:class="message.kind === 'ok' ? 'ok' : 'err'"
|
||||
>
|
||||
{{ message.text }}
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.settings {
|
||||
max-width: 760px;
|
||||
margin: 0 auto;
|
||||
padding: 28px 32px 60px;
|
||||
color: #1f2937;
|
||||
}
|
||||
.hero {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
.hero h1 {
|
||||
margin: 0 0 6px;
|
||||
font-size: 24px;
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
.subtitle {
|
||||
margin: 0;
|
||||
color: #6b7280;
|
||||
font-size: 13px;
|
||||
}
|
||||
kbd {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
||||
background: #f3f4f6;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 4px;
|
||||
padding: 1px 6px;
|
||||
font-size: 12px;
|
||||
}
|
||||
.card {
|
||||
background: #ffffff;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 8px;
|
||||
padding: 18px 20px;
|
||||
margin-bottom: 18px;
|
||||
box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
|
||||
}
|
||||
.card h2 {
|
||||
margin: 0 0 12px;
|
||||
font-size: 14px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
color: #6b7280;
|
||||
}
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 12px 16px;
|
||||
}
|
||||
.field {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
font-size: 13px;
|
||||
}
|
||||
.field.full {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
.field span {
|
||||
color: #374151;
|
||||
font-weight: 500;
|
||||
}
|
||||
.field input[type='text'],
|
||||
.field input:not([type='checkbox']) {
|
||||
border: 1px solid #d1d5db;
|
||||
border-radius: 6px;
|
||||
padding: 7px 10px;
|
||||
font-size: 13px;
|
||||
background: #fff;
|
||||
color: inherit;
|
||||
outline: none;
|
||||
transition: border-color 0.15s, box-shadow 0.15s;
|
||||
}
|
||||
.field input:focus {
|
||||
border-color: #3b82f6;
|
||||
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.18);
|
||||
}
|
||||
.field.checkbox {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
.hint {
|
||||
margin: 8px 0 0;
|
||||
font-size: 12px;
|
||||
color: #6b7280;
|
||||
}
|
||||
.hint code {
|
||||
background: #f3f4f6;
|
||||
padding: 1px 6px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
.btn {
|
||||
border: 1px solid #d1d5db;
|
||||
background: #fff;
|
||||
border-radius: 6px;
|
||||
padding: 7px 14px;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
transition: background 0.15s, border-color 0.15s, color 0.15s;
|
||||
}
|
||||
.btn:hover:not(:disabled) {
|
||||
border-color: #9ca3af;
|
||||
background: #f9fafb;
|
||||
}
|
||||
.btn.primary {
|
||||
background: #3b82f6;
|
||||
border-color: #3b82f6;
|
||||
color: #fff;
|
||||
}
|
||||
.btn.primary:hover:not(:disabled) {
|
||||
background: #2563eb;
|
||||
border-color: #2563eb;
|
||||
}
|
||||
.btn:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.banner {
|
||||
position: fixed;
|
||||
bottom: 18px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
padding: 8px 14px;
|
||||
border-radius: 6px;
|
||||
font-size: 13px;
|
||||
box-shadow: 0 6px 24px rgba(15, 23, 42, 0.18);
|
||||
}
|
||||
.banner.ok {
|
||||
background: #10b981;
|
||||
color: #fff;
|
||||
}
|
||||
.banner.err {
|
||||
background: #ef4444;
|
||||
color: #fff;
|
||||
}
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
.fade-enter-from,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.settings {
|
||||
color: #e5e7eb;
|
||||
}
|
||||
.card {
|
||||
background: #1f2937;
|
||||
border-color: #374151;
|
||||
}
|
||||
.field input {
|
||||
background: #111827;
|
||||
border-color: #374151;
|
||||
color: #e5e7eb;
|
||||
}
|
||||
.btn {
|
||||
background: #1f2937;
|
||||
border-color: #374151;
|
||||
color: #e5e7eb;
|
||||
}
|
||||
.btn:hover:not(:disabled) {
|
||||
background: #374151;
|
||||
}
|
||||
.subtitle {
|
||||
color: #9ca3af;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
declare module '*.vue' {
|
||||
import type {DefineComponent} from 'vue'
|
||||
const component: DefineComponent<{}, {}, any>
|
||||
export default component
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"strict": true,
|
||||
"jsx": "preserve",
|
||||
"sourceMap": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"esModuleInterop": true,
|
||||
"lib": [
|
||||
"ESNext",
|
||||
"DOM"
|
||||
],
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.d.ts",
|
||||
"src/**/*.tsx",
|
||||
"src/**/*.vue"
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.node.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": [
|
||||
"vite.config.ts"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import {defineConfig} from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [vue()]
|
||||
})
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
import {main} from '../models';
|
||||
import {domain} from '../models';
|
||||
|
||||
export function CancelNativeRegion():Promise<void>;
|
||||
|
||||
export function CancelRegion():Promise<void>;
|
||||
|
||||
export function CaptureNow():Promise<void>;
|
||||
|
||||
export function ConfirmNativeRegion(arg1:main.RegionRect):Promise<void>;
|
||||
|
||||
export function ConfirmRegion(arg1:main.RegionRect):Promise<void>;
|
||||
|
||||
export function GetConfig():Promise<domain.AppConfig>;
|
||||
|
||||
export function QuitApp():Promise<void>;
|
||||
|
||||
export function RetryRegisterHotkey():Promise<void>;
|
||||
|
||||
export function SaveConfig(arg1:domain.AppConfig):Promise<void>;
|
||||
|
||||
export function ShowWindow():Promise<void>;
|
||||
|
||||
export function TestConnection(arg1:domain.S3Config):Promise<void>;
|
||||
Executable
+47
@@ -0,0 +1,47 @@
|
||||
// @ts-check
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
export function CancelNativeRegion() {
|
||||
return window['go']['main']['App']['CancelNativeRegion']();
|
||||
}
|
||||
|
||||
export function CancelRegion() {
|
||||
return window['go']['main']['App']['CancelRegion']();
|
||||
}
|
||||
|
||||
export function CaptureNow() {
|
||||
return window['go']['main']['App']['CaptureNow']();
|
||||
}
|
||||
|
||||
export function ConfirmNativeRegion(arg1) {
|
||||
return window['go']['main']['App']['ConfirmNativeRegion'](arg1);
|
||||
}
|
||||
|
||||
export function ConfirmRegion(arg1) {
|
||||
return window['go']['main']['App']['ConfirmRegion'](arg1);
|
||||
}
|
||||
|
||||
export function GetConfig() {
|
||||
return window['go']['main']['App']['GetConfig']();
|
||||
}
|
||||
|
||||
export function QuitApp() {
|
||||
return window['go']['main']['App']['QuitApp']();
|
||||
}
|
||||
|
||||
export function RetryRegisterHotkey() {
|
||||
return window['go']['main']['App']['RetryRegisterHotkey']();
|
||||
}
|
||||
|
||||
export function SaveConfig(arg1) {
|
||||
return window['go']['main']['App']['SaveConfig'](arg1);
|
||||
}
|
||||
|
||||
export function ShowWindow() {
|
||||
return window['go']['main']['App']['ShowWindow']();
|
||||
}
|
||||
|
||||
export function TestConnection(arg1) {
|
||||
return window['go']['main']['App']['TestConnection'](arg1);
|
||||
}
|
||||
Executable
+86
@@ -0,0 +1,86 @@
|
||||
export namespace domain {
|
||||
|
||||
export class S3Config {
|
||||
endpoint: string;
|
||||
region: string;
|
||||
bucket: string;
|
||||
accessKeyId: string;
|
||||
secretAccessKey: string;
|
||||
pathPrefix: string;
|
||||
publicUrlBase: string;
|
||||
usePathStyle: boolean;
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
return new S3Config(source);
|
||||
}
|
||||
|
||||
constructor(source: any = {}) {
|
||||
if ('string' === typeof source) source = JSON.parse(source);
|
||||
this.endpoint = source["endpoint"];
|
||||
this.region = source["region"];
|
||||
this.bucket = source["bucket"];
|
||||
this.accessKeyId = source["accessKeyId"];
|
||||
this.secretAccessKey = source["secretAccessKey"];
|
||||
this.pathPrefix = source["pathPrefix"];
|
||||
this.publicUrlBase = source["publicUrlBase"];
|
||||
this.usePathStyle = source["usePathStyle"];
|
||||
}
|
||||
}
|
||||
export class AppConfig {
|
||||
hotkey: string;
|
||||
s3: S3Config;
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
return new AppConfig(source);
|
||||
}
|
||||
|
||||
constructor(source: any = {}) {
|
||||
if ('string' === typeof source) source = JSON.parse(source);
|
||||
this.hotkey = source["hotkey"];
|
||||
this.s3 = this.convertValues(source["s3"], S3Config);
|
||||
}
|
||||
|
||||
convertValues(a: any, classs: any, asMap: boolean = false): any {
|
||||
if (!a) {
|
||||
return a;
|
||||
}
|
||||
if (a.slice && a.map) {
|
||||
return (a as any[]).map(elem => this.convertValues(elem, classs));
|
||||
} else if ("object" === typeof a) {
|
||||
if (asMap) {
|
||||
for (const key of Object.keys(a)) {
|
||||
a[key] = new classs(a[key]);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
return new classs(a);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export namespace main {
|
||||
|
||||
export class RegionRect {
|
||||
x: number;
|
||||
y: number;
|
||||
w: number;
|
||||
h: number;
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
return new RegionRect(source);
|
||||
}
|
||||
|
||||
constructor(source: any = {}) {
|
||||
if ('string' === typeof source) source = JSON.parse(source);
|
||||
this.x = source["x"];
|
||||
this.y = source["y"];
|
||||
this.w = source["w"];
|
||||
this.h = source["h"];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "@wailsapp/runtime",
|
||||
"version": "2.0.0",
|
||||
"description": "Wails Javascript runtime library",
|
||||
"main": "runtime.js",
|
||||
"types": "runtime.d.ts",
|
||||
"scripts": {
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/wailsapp/wails.git"
|
||||
},
|
||||
"keywords": [
|
||||
"Wails",
|
||||
"Javascript",
|
||||
"Go"
|
||||
],
|
||||
"author": "Lea Anthony <lea.anthony@gmail.com>",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/wailsapp/wails/issues"
|
||||
},
|
||||
"homepage": "https://github.com/wailsapp/wails#readme"
|
||||
}
|
||||
+330
@@ -0,0 +1,330 @@
|
||||
/*
|
||||
_ __ _ __
|
||||
| | / /___ _(_) /____
|
||||
| | /| / / __ `/ / / ___/
|
||||
| |/ |/ / /_/ / / (__ )
|
||||
|__/|__/\__,_/_/_/____/
|
||||
The electron alternative for Go
|
||||
(c) Lea Anthony 2019-present
|
||||
*/
|
||||
|
||||
export interface Position {
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
export interface Size {
|
||||
w: number;
|
||||
h: number;
|
||||
}
|
||||
|
||||
export interface Screen {
|
||||
isCurrent: boolean;
|
||||
isPrimary: boolean;
|
||||
width : number
|
||||
height : number
|
||||
}
|
||||
|
||||
// Environment information such as platform, buildtype, ...
|
||||
export interface EnvironmentInfo {
|
||||
buildType: string;
|
||||
platform: string;
|
||||
arch: string;
|
||||
}
|
||||
|
||||
// [EventsEmit](https://wails.io/docs/reference/runtime/events#eventsemit)
|
||||
// emits the given event. Optional data may be passed with the event.
|
||||
// This will trigger any event listeners.
|
||||
export function EventsEmit(eventName: string, ...data: any): void;
|
||||
|
||||
// [EventsOn](https://wails.io/docs/reference/runtime/events#eventson) sets up a listener for the given event name.
|
||||
export function EventsOn(eventName: string, callback: (...data: any) => void): () => void;
|
||||
|
||||
// [EventsOnMultiple](https://wails.io/docs/reference/runtime/events#eventsonmultiple)
|
||||
// sets up a listener for the given event name, but will only trigger a given number times.
|
||||
export function EventsOnMultiple(eventName: string, callback: (...data: any) => void, maxCallbacks: number): () => void;
|
||||
|
||||
// [EventsOnce](https://wails.io/docs/reference/runtime/events#eventsonce)
|
||||
// sets up a listener for the given event name, but will only trigger once.
|
||||
export function EventsOnce(eventName: string, callback: (...data: any) => void): () => void;
|
||||
|
||||
// [EventsOff](https://wails.io/docs/reference/runtime/events#eventsoff)
|
||||
// unregisters the listener for the given event name.
|
||||
export function EventsOff(eventName: string, ...additionalEventNames: string[]): void;
|
||||
|
||||
// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall)
|
||||
// unregisters all listeners.
|
||||
export function EventsOffAll(): void;
|
||||
|
||||
// [LogPrint](https://wails.io/docs/reference/runtime/log#logprint)
|
||||
// logs the given message as a raw message
|
||||
export function LogPrint(message: string): void;
|
||||
|
||||
// [LogTrace](https://wails.io/docs/reference/runtime/log#logtrace)
|
||||
// logs the given message at the `trace` log level.
|
||||
export function LogTrace(message: string): void;
|
||||
|
||||
// [LogDebug](https://wails.io/docs/reference/runtime/log#logdebug)
|
||||
// logs the given message at the `debug` log level.
|
||||
export function LogDebug(message: string): void;
|
||||
|
||||
// [LogError](https://wails.io/docs/reference/runtime/log#logerror)
|
||||
// logs the given message at the `error` log level.
|
||||
export function LogError(message: string): void;
|
||||
|
||||
// [LogFatal](https://wails.io/docs/reference/runtime/log#logfatal)
|
||||
// logs the given message at the `fatal` log level.
|
||||
// The application will quit after calling this method.
|
||||
export function LogFatal(message: string): void;
|
||||
|
||||
// [LogInfo](https://wails.io/docs/reference/runtime/log#loginfo)
|
||||
// logs the given message at the `info` log level.
|
||||
export function LogInfo(message: string): void;
|
||||
|
||||
// [LogWarning](https://wails.io/docs/reference/runtime/log#logwarning)
|
||||
// logs the given message at the `warning` log level.
|
||||
export function LogWarning(message: string): void;
|
||||
|
||||
// [WindowReload](https://wails.io/docs/reference/runtime/window#windowreload)
|
||||
// Forces a reload by the main application as well as connected browsers.
|
||||
export function WindowReload(): void;
|
||||
|
||||
// [WindowReloadApp](https://wails.io/docs/reference/runtime/window#windowreloadapp)
|
||||
// Reloads the application frontend.
|
||||
export function WindowReloadApp(): void;
|
||||
|
||||
// [WindowSetAlwaysOnTop](https://wails.io/docs/reference/runtime/window#windowsetalwaysontop)
|
||||
// Sets the window AlwaysOnTop or not on top.
|
||||
export function WindowSetAlwaysOnTop(b: boolean): void;
|
||||
|
||||
// [WindowSetSystemDefaultTheme](https://wails.io/docs/next/reference/runtime/window#windowsetsystemdefaulttheme)
|
||||
// *Windows only*
|
||||
// Sets window theme to system default (dark/light).
|
||||
export function WindowSetSystemDefaultTheme(): void;
|
||||
|
||||
// [WindowSetLightTheme](https://wails.io/docs/next/reference/runtime/window#windowsetlighttheme)
|
||||
// *Windows only*
|
||||
// Sets window to light theme.
|
||||
export function WindowSetLightTheme(): void;
|
||||
|
||||
// [WindowSetDarkTheme](https://wails.io/docs/next/reference/runtime/window#windowsetdarktheme)
|
||||
// *Windows only*
|
||||
// Sets window to dark theme.
|
||||
export function WindowSetDarkTheme(): void;
|
||||
|
||||
// [WindowCenter](https://wails.io/docs/reference/runtime/window#windowcenter)
|
||||
// Centers the window on the monitor the window is currently on.
|
||||
export function WindowCenter(): void;
|
||||
|
||||
// [WindowSetTitle](https://wails.io/docs/reference/runtime/window#windowsettitle)
|
||||
// Sets the text in the window title bar.
|
||||
export function WindowSetTitle(title: string): void;
|
||||
|
||||
// [WindowFullscreen](https://wails.io/docs/reference/runtime/window#windowfullscreen)
|
||||
// Makes the window full screen.
|
||||
export function WindowFullscreen(): void;
|
||||
|
||||
// [WindowUnfullscreen](https://wails.io/docs/reference/runtime/window#windowunfullscreen)
|
||||
// Restores the previous window dimensions and position prior to full screen.
|
||||
export function WindowUnfullscreen(): void;
|
||||
|
||||
// [WindowIsFullscreen](https://wails.io/docs/reference/runtime/window#windowisfullscreen)
|
||||
// Returns the state of the window, i.e. whether the window is in full screen mode or not.
|
||||
export function WindowIsFullscreen(): Promise<boolean>;
|
||||
|
||||
// [WindowSetSize](https://wails.io/docs/reference/runtime/window#windowsetsize)
|
||||
// Sets the width and height of the window.
|
||||
export function WindowSetSize(width: number, height: number): void;
|
||||
|
||||
// [WindowGetSize](https://wails.io/docs/reference/runtime/window#windowgetsize)
|
||||
// Gets the width and height of the window.
|
||||
export function WindowGetSize(): Promise<Size>;
|
||||
|
||||
// [WindowSetMaxSize](https://wails.io/docs/reference/runtime/window#windowsetmaxsize)
|
||||
// Sets the maximum window size. Will resize the window if the window is currently larger than the given dimensions.
|
||||
// Setting a size of 0,0 will disable this constraint.
|
||||
export function WindowSetMaxSize(width: number, height: number): void;
|
||||
|
||||
// [WindowSetMinSize](https://wails.io/docs/reference/runtime/window#windowsetminsize)
|
||||
// Sets the minimum window size. Will resize the window if the window is currently smaller than the given dimensions.
|
||||
// Setting a size of 0,0 will disable this constraint.
|
||||
export function WindowSetMinSize(width: number, height: number): void;
|
||||
|
||||
// [WindowSetPosition](https://wails.io/docs/reference/runtime/window#windowsetposition)
|
||||
// Sets the window position relative to the monitor the window is currently on.
|
||||
export function WindowSetPosition(x: number, y: number): void;
|
||||
|
||||
// [WindowGetPosition](https://wails.io/docs/reference/runtime/window#windowgetposition)
|
||||
// Gets the window position relative to the monitor the window is currently on.
|
||||
export function WindowGetPosition(): Promise<Position>;
|
||||
|
||||
// [WindowHide](https://wails.io/docs/reference/runtime/window#windowhide)
|
||||
// Hides the window.
|
||||
export function WindowHide(): void;
|
||||
|
||||
// [WindowShow](https://wails.io/docs/reference/runtime/window#windowshow)
|
||||
// Shows the window, if it is currently hidden.
|
||||
export function WindowShow(): void;
|
||||
|
||||
// [WindowMaximise](https://wails.io/docs/reference/runtime/window#windowmaximise)
|
||||
// Maximises the window to fill the screen.
|
||||
export function WindowMaximise(): void;
|
||||
|
||||
// [WindowToggleMaximise](https://wails.io/docs/reference/runtime/window#windowtogglemaximise)
|
||||
// Toggles between Maximised and UnMaximised.
|
||||
export function WindowToggleMaximise(): void;
|
||||
|
||||
// [WindowUnmaximise](https://wails.io/docs/reference/runtime/window#windowunmaximise)
|
||||
// Restores the window to the dimensions and position prior to maximising.
|
||||
export function WindowUnmaximise(): void;
|
||||
|
||||
// [WindowIsMaximised](https://wails.io/docs/reference/runtime/window#windowismaximised)
|
||||
// Returns the state of the window, i.e. whether the window is maximised or not.
|
||||
export function WindowIsMaximised(): Promise<boolean>;
|
||||
|
||||
// [WindowMinimise](https://wails.io/docs/reference/runtime/window#windowminimise)
|
||||
// Minimises the window.
|
||||
export function WindowMinimise(): void;
|
||||
|
||||
// [WindowUnminimise](https://wails.io/docs/reference/runtime/window#windowunminimise)
|
||||
// Restores the window to the dimensions and position prior to minimising.
|
||||
export function WindowUnminimise(): void;
|
||||
|
||||
// [WindowIsMinimised](https://wails.io/docs/reference/runtime/window#windowisminimised)
|
||||
// Returns the state of the window, i.e. whether the window is minimised or not.
|
||||
export function WindowIsMinimised(): Promise<boolean>;
|
||||
|
||||
// [WindowIsNormal](https://wails.io/docs/reference/runtime/window#windowisnormal)
|
||||
// Returns the state of the window, i.e. whether the window is normal or not.
|
||||
export function WindowIsNormal(): Promise<boolean>;
|
||||
|
||||
// [WindowSetBackgroundColour](https://wails.io/docs/reference/runtime/window#windowsetbackgroundcolour)
|
||||
// Sets the background colour of the window to the given RGBA colour definition. This colour will show through for all transparent pixels.
|
||||
export function WindowSetBackgroundColour(R: number, G: number, B: number, A: number): void;
|
||||
|
||||
// [ScreenGetAll](https://wails.io/docs/reference/runtime/window#screengetall)
|
||||
// Gets the all screens. Call this anew each time you want to refresh data from the underlying windowing system.
|
||||
export function ScreenGetAll(): Promise<Screen[]>;
|
||||
|
||||
// [BrowserOpenURL](https://wails.io/docs/reference/runtime/browser#browseropenurl)
|
||||
// Opens the given URL in the system browser.
|
||||
export function BrowserOpenURL(url: string): void;
|
||||
|
||||
// [Environment](https://wails.io/docs/reference/runtime/intro#environment)
|
||||
// Returns information about the environment
|
||||
export function Environment(): Promise<EnvironmentInfo>;
|
||||
|
||||
// [Quit](https://wails.io/docs/reference/runtime/intro#quit)
|
||||
// Quits the application.
|
||||
export function Quit(): void;
|
||||
|
||||
// [Hide](https://wails.io/docs/reference/runtime/intro#hide)
|
||||
// Hides the application.
|
||||
export function Hide(): void;
|
||||
|
||||
// [Show](https://wails.io/docs/reference/runtime/intro#show)
|
||||
// Shows the application.
|
||||
export function Show(): void;
|
||||
|
||||
// [ClipboardGetText](https://wails.io/docs/reference/runtime/clipboard#clipboardgettext)
|
||||
// Returns the current text stored on clipboard
|
||||
export function ClipboardGetText(): Promise<string>;
|
||||
|
||||
// [ClipboardSetText](https://wails.io/docs/reference/runtime/clipboard#clipboardsettext)
|
||||
// Sets a text on the clipboard
|
||||
export function ClipboardSetText(text: string): Promise<boolean>;
|
||||
|
||||
// [OnFileDrop](https://wails.io/docs/reference/runtime/draganddrop#onfiledrop)
|
||||
// OnFileDrop listens to drag and drop events and calls the callback with the coordinates of the drop and an array of path strings.
|
||||
export function OnFileDrop(callback: (x: number, y: number ,paths: string[]) => void, useDropTarget: boolean) :void
|
||||
|
||||
// [OnFileDropOff](https://wails.io/docs/reference/runtime/draganddrop#dragandddropoff)
|
||||
// OnFileDropOff removes the drag and drop listeners and handlers.
|
||||
export function OnFileDropOff() :void
|
||||
|
||||
// Check if the file path resolver is available
|
||||
export function CanResolveFilePaths(): boolean;
|
||||
|
||||
// Resolves file paths for an array of files
|
||||
export function ResolveFilePaths(files: File[]): void
|
||||
|
||||
// Notification types
|
||||
export interface NotificationOptions {
|
||||
id: string;
|
||||
title: string;
|
||||
subtitle?: string; // macOS and Linux only
|
||||
body?: string;
|
||||
categoryId?: string;
|
||||
data?: { [key: string]: any };
|
||||
}
|
||||
|
||||
export interface NotificationAction {
|
||||
id?: string;
|
||||
title?: string;
|
||||
destructive?: boolean; // macOS-specific
|
||||
}
|
||||
|
||||
export interface NotificationCategory {
|
||||
id?: string;
|
||||
actions?: NotificationAction[];
|
||||
hasReplyField?: boolean;
|
||||
replyPlaceholder?: string;
|
||||
replyButtonTitle?: string;
|
||||
}
|
||||
|
||||
// [InitializeNotifications](https://wails.io/docs/reference/runtime/notification#initializenotifications)
|
||||
// Initializes the notification service for the application.
|
||||
// This must be called before sending any notifications.
|
||||
export function InitializeNotifications(): Promise<void>;
|
||||
|
||||
// [CleanupNotifications](https://wails.io/docs/reference/runtime/notification#cleanupnotifications)
|
||||
// Cleans up notification resources and releases any held connections.
|
||||
export function CleanupNotifications(): Promise<void>;
|
||||
|
||||
// [IsNotificationAvailable](https://wails.io/docs/reference/runtime/notification#isnotificationavailable)
|
||||
// Checks if notifications are available on the current platform.
|
||||
export function IsNotificationAvailable(): Promise<boolean>;
|
||||
|
||||
// [RequestNotificationAuthorization](https://wails.io/docs/reference/runtime/notification#requestnotificationauthorization)
|
||||
// Requests notification authorization from the user (macOS only).
|
||||
export function RequestNotificationAuthorization(): Promise<boolean>;
|
||||
|
||||
// [CheckNotificationAuthorization](https://wails.io/docs/reference/runtime/notification#checknotificationauthorization)
|
||||
// Checks the current notification authorization status (macOS only).
|
||||
export function CheckNotificationAuthorization(): Promise<boolean>;
|
||||
|
||||
// [SendNotification](https://wails.io/docs/reference/runtime/notification#sendnotification)
|
||||
// Sends a basic notification with the given options.
|
||||
export function SendNotification(options: NotificationOptions): Promise<void>;
|
||||
|
||||
// [SendNotificationWithActions](https://wails.io/docs/reference/runtime/notification#sendnotificationwithactions)
|
||||
// Sends a notification with action buttons. Requires a registered category.
|
||||
export function SendNotificationWithActions(options: NotificationOptions): Promise<void>;
|
||||
|
||||
// [RegisterNotificationCategory](https://wails.io/docs/reference/runtime/notification#registernotificationcategory)
|
||||
// Registers a notification category that can be used with SendNotificationWithActions.
|
||||
export function RegisterNotificationCategory(category: NotificationCategory): Promise<void>;
|
||||
|
||||
// [RemoveNotificationCategory](https://wails.io/docs/reference/runtime/notification#removenotificationcategory)
|
||||
// Removes a previously registered notification category.
|
||||
export function RemoveNotificationCategory(categoryId: string): Promise<void>;
|
||||
|
||||
// [RemoveAllPendingNotifications](https://wails.io/docs/reference/runtime/notification#removeallpendingnotifications)
|
||||
// Removes all pending notifications from the notification center.
|
||||
export function RemoveAllPendingNotifications(): Promise<void>;
|
||||
|
||||
// [RemovePendingNotification](https://wails.io/docs/reference/runtime/notification#removependingnotification)
|
||||
// Removes a specific pending notification by its identifier.
|
||||
export function RemovePendingNotification(identifier: string): Promise<void>;
|
||||
|
||||
// [RemoveAllDeliveredNotifications](https://wails.io/docs/reference/runtime/notification#removealldeliverednotifications)
|
||||
// Removes all delivered notifications from the notification center.
|
||||
export function RemoveAllDeliveredNotifications(): Promise<void>;
|
||||
|
||||
// [RemoveDeliveredNotification](https://wails.io/docs/reference/runtime/notification#removedeliverednotification)
|
||||
// Removes a specific delivered notification by its identifier.
|
||||
export function RemoveDeliveredNotification(identifier: string): Promise<void>;
|
||||
|
||||
// [RemoveNotification](https://wails.io/docs/reference/runtime/notification#removenotification)
|
||||
// Removes a notification by its identifier (cross-platform convenience function).
|
||||
export function RemoveNotification(identifier: string): Promise<void>;
|
||||
@@ -0,0 +1,298 @@
|
||||
/*
|
||||
_ __ _ __
|
||||
| | / /___ _(_) /____
|
||||
| | /| / / __ `/ / / ___/
|
||||
| |/ |/ / /_/ / / (__ )
|
||||
|__/|__/\__,_/_/_/____/
|
||||
The electron alternative for Go
|
||||
(c) Lea Anthony 2019-present
|
||||
*/
|
||||
|
||||
export function LogPrint(message) {
|
||||
window.runtime.LogPrint(message);
|
||||
}
|
||||
|
||||
export function LogTrace(message) {
|
||||
window.runtime.LogTrace(message);
|
||||
}
|
||||
|
||||
export function LogDebug(message) {
|
||||
window.runtime.LogDebug(message);
|
||||
}
|
||||
|
||||
export function LogInfo(message) {
|
||||
window.runtime.LogInfo(message);
|
||||
}
|
||||
|
||||
export function LogWarning(message) {
|
||||
window.runtime.LogWarning(message);
|
||||
}
|
||||
|
||||
export function LogError(message) {
|
||||
window.runtime.LogError(message);
|
||||
}
|
||||
|
||||
export function LogFatal(message) {
|
||||
window.runtime.LogFatal(message);
|
||||
}
|
||||
|
||||
export function EventsOnMultiple(eventName, callback, maxCallbacks) {
|
||||
return window.runtime.EventsOnMultiple(eventName, callback, maxCallbacks);
|
||||
}
|
||||
|
||||
export function EventsOn(eventName, callback) {
|
||||
return EventsOnMultiple(eventName, callback, -1);
|
||||
}
|
||||
|
||||
export function EventsOff(eventName, ...additionalEventNames) {
|
||||
return window.runtime.EventsOff(eventName, ...additionalEventNames);
|
||||
}
|
||||
|
||||
export function EventsOffAll() {
|
||||
return window.runtime.EventsOffAll();
|
||||
}
|
||||
|
||||
export function EventsOnce(eventName, callback) {
|
||||
return EventsOnMultiple(eventName, callback, 1);
|
||||
}
|
||||
|
||||
export function EventsEmit(eventName) {
|
||||
let args = [eventName].slice.call(arguments);
|
||||
return window.runtime.EventsEmit.apply(null, args);
|
||||
}
|
||||
|
||||
export function WindowReload() {
|
||||
window.runtime.WindowReload();
|
||||
}
|
||||
|
||||
export function WindowReloadApp() {
|
||||
window.runtime.WindowReloadApp();
|
||||
}
|
||||
|
||||
export function WindowSetAlwaysOnTop(b) {
|
||||
window.runtime.WindowSetAlwaysOnTop(b);
|
||||
}
|
||||
|
||||
export function WindowSetSystemDefaultTheme() {
|
||||
window.runtime.WindowSetSystemDefaultTheme();
|
||||
}
|
||||
|
||||
export function WindowSetLightTheme() {
|
||||
window.runtime.WindowSetLightTheme();
|
||||
}
|
||||
|
||||
export function WindowSetDarkTheme() {
|
||||
window.runtime.WindowSetDarkTheme();
|
||||
}
|
||||
|
||||
export function WindowCenter() {
|
||||
window.runtime.WindowCenter();
|
||||
}
|
||||
|
||||
export function WindowSetTitle(title) {
|
||||
window.runtime.WindowSetTitle(title);
|
||||
}
|
||||
|
||||
export function WindowFullscreen() {
|
||||
window.runtime.WindowFullscreen();
|
||||
}
|
||||
|
||||
export function WindowUnfullscreen() {
|
||||
window.runtime.WindowUnfullscreen();
|
||||
}
|
||||
|
||||
export function WindowIsFullscreen() {
|
||||
return window.runtime.WindowIsFullscreen();
|
||||
}
|
||||
|
||||
export function WindowGetSize() {
|
||||
return window.runtime.WindowGetSize();
|
||||
}
|
||||
|
||||
export function WindowSetSize(width, height) {
|
||||
window.runtime.WindowSetSize(width, height);
|
||||
}
|
||||
|
||||
export function WindowSetMaxSize(width, height) {
|
||||
window.runtime.WindowSetMaxSize(width, height);
|
||||
}
|
||||
|
||||
export function WindowSetMinSize(width, height) {
|
||||
window.runtime.WindowSetMinSize(width, height);
|
||||
}
|
||||
|
||||
export function WindowSetPosition(x, y) {
|
||||
window.runtime.WindowSetPosition(x, y);
|
||||
}
|
||||
|
||||
export function WindowGetPosition() {
|
||||
return window.runtime.WindowGetPosition();
|
||||
}
|
||||
|
||||
export function WindowHide() {
|
||||
window.runtime.WindowHide();
|
||||
}
|
||||
|
||||
export function WindowShow() {
|
||||
window.runtime.WindowShow();
|
||||
}
|
||||
|
||||
export function WindowMaximise() {
|
||||
window.runtime.WindowMaximise();
|
||||
}
|
||||
|
||||
export function WindowToggleMaximise() {
|
||||
window.runtime.WindowToggleMaximise();
|
||||
}
|
||||
|
||||
export function WindowUnmaximise() {
|
||||
window.runtime.WindowUnmaximise();
|
||||
}
|
||||
|
||||
export function WindowIsMaximised() {
|
||||
return window.runtime.WindowIsMaximised();
|
||||
}
|
||||
|
||||
export function WindowMinimise() {
|
||||
window.runtime.WindowMinimise();
|
||||
}
|
||||
|
||||
export function WindowUnminimise() {
|
||||
window.runtime.WindowUnminimise();
|
||||
}
|
||||
|
||||
export function WindowSetBackgroundColour(R, G, B, A) {
|
||||
window.runtime.WindowSetBackgroundColour(R, G, B, A);
|
||||
}
|
||||
|
||||
export function ScreenGetAll() {
|
||||
return window.runtime.ScreenGetAll();
|
||||
}
|
||||
|
||||
export function WindowIsMinimised() {
|
||||
return window.runtime.WindowIsMinimised();
|
||||
}
|
||||
|
||||
export function WindowIsNormal() {
|
||||
return window.runtime.WindowIsNormal();
|
||||
}
|
||||
|
||||
export function BrowserOpenURL(url) {
|
||||
window.runtime.BrowserOpenURL(url);
|
||||
}
|
||||
|
||||
export function Environment() {
|
||||
return window.runtime.Environment();
|
||||
}
|
||||
|
||||
export function Quit() {
|
||||
window.runtime.Quit();
|
||||
}
|
||||
|
||||
export function Hide() {
|
||||
window.runtime.Hide();
|
||||
}
|
||||
|
||||
export function Show() {
|
||||
window.runtime.Show();
|
||||
}
|
||||
|
||||
export function ClipboardGetText() {
|
||||
return window.runtime.ClipboardGetText();
|
||||
}
|
||||
|
||||
export function ClipboardSetText(text) {
|
||||
return window.runtime.ClipboardSetText(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for OnFileDrop returns a slice of file path strings when a drop is finished.
|
||||
*
|
||||
* @export
|
||||
* @callback OnFileDropCallback
|
||||
* @param {number} x - x coordinate of the drop
|
||||
* @param {number} y - y coordinate of the drop
|
||||
* @param {string[]} paths - A list of file paths.
|
||||
*/
|
||||
|
||||
/**
|
||||
* OnFileDrop listens to drag and drop events and calls the callback with the coordinates of the drop and an array of path strings.
|
||||
*
|
||||
* @export
|
||||
* @param {OnFileDropCallback} callback - Callback for OnFileDrop returns a slice of file path strings when a drop is finished.
|
||||
* @param {boolean} [useDropTarget=true] - Only call the callback when the drop finished on an element that has the drop target style. (--wails-drop-target)
|
||||
*/
|
||||
export function OnFileDrop(callback, useDropTarget) {
|
||||
return window.runtime.OnFileDrop(callback, useDropTarget);
|
||||
}
|
||||
|
||||
/**
|
||||
* OnFileDropOff removes the drag and drop listeners and handlers.
|
||||
*/
|
||||
export function OnFileDropOff() {
|
||||
return window.runtime.OnFileDropOff();
|
||||
}
|
||||
|
||||
export function CanResolveFilePaths() {
|
||||
return window.runtime.CanResolveFilePaths();
|
||||
}
|
||||
|
||||
export function ResolveFilePaths(files) {
|
||||
return window.runtime.ResolveFilePaths(files);
|
||||
}
|
||||
|
||||
export function InitializeNotifications() {
|
||||
return window.runtime.InitializeNotifications();
|
||||
}
|
||||
|
||||
export function CleanupNotifications() {
|
||||
return window.runtime.CleanupNotifications();
|
||||
}
|
||||
|
||||
export function IsNotificationAvailable() {
|
||||
return window.runtime.IsNotificationAvailable();
|
||||
}
|
||||
|
||||
export function RequestNotificationAuthorization() {
|
||||
return window.runtime.RequestNotificationAuthorization();
|
||||
}
|
||||
|
||||
export function CheckNotificationAuthorization() {
|
||||
return window.runtime.CheckNotificationAuthorization();
|
||||
}
|
||||
|
||||
export function SendNotification(options) {
|
||||
return window.runtime.SendNotification(options);
|
||||
}
|
||||
|
||||
export function SendNotificationWithActions(options) {
|
||||
return window.runtime.SendNotificationWithActions(options);
|
||||
}
|
||||
|
||||
export function RegisterNotificationCategory(category) {
|
||||
return window.runtime.RegisterNotificationCategory(category);
|
||||
}
|
||||
|
||||
export function RemoveNotificationCategory(categoryId) {
|
||||
return window.runtime.RemoveNotificationCategory(categoryId);
|
||||
}
|
||||
|
||||
export function RemoveAllPendingNotifications() {
|
||||
return window.runtime.RemoveAllPendingNotifications();
|
||||
}
|
||||
|
||||
export function RemovePendingNotification(identifier) {
|
||||
return window.runtime.RemovePendingNotification(identifier);
|
||||
}
|
||||
|
||||
export function RemoveAllDeliveredNotifications() {
|
||||
return window.runtime.RemoveAllDeliveredNotifications();
|
||||
}
|
||||
|
||||
export function RemoveDeliveredNotification(identifier) {
|
||||
return window.runtime.RemoveDeliveredNotification(identifier);
|
||||
}
|
||||
|
||||
export function RemoveNotification(identifier) {
|
||||
return window.runtime.RemoveNotification(identifier);
|
||||
}
|
||||
Reference in New Issue
Block a user