inital
24
.gitignore
vendored
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
# Nuxt dev/build outputs
|
||||||
|
.output
|
||||||
|
.data
|
||||||
|
.nuxt
|
||||||
|
.nitro
|
||||||
|
.cache
|
||||||
|
dist
|
||||||
|
|
||||||
|
# Node dependencies
|
||||||
|
node_modules
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# Misc
|
||||||
|
.DS_Store
|
||||||
|
.fleet
|
||||||
|
.idea
|
||||||
|
|
||||||
|
# Local env files
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
75
README.md
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
# Nuxt 3 Minimal Starter
|
||||||
|
|
||||||
|
Look at the [Nuxt 3 documentation](https://nuxt.com/docs/getting-started/introduction) to learn more.
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
Make sure to install the dependencies:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# npm
|
||||||
|
npm install
|
||||||
|
|
||||||
|
# pnpm
|
||||||
|
pnpm install
|
||||||
|
|
||||||
|
# yarn
|
||||||
|
yarn install
|
||||||
|
|
||||||
|
# bun
|
||||||
|
bun install
|
||||||
|
```
|
||||||
|
|
||||||
|
## Development Server
|
||||||
|
|
||||||
|
Start the development server on `http://localhost:3000`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# npm
|
||||||
|
npm run dev
|
||||||
|
|
||||||
|
# pnpm
|
||||||
|
pnpm run dev
|
||||||
|
|
||||||
|
# yarn
|
||||||
|
yarn dev
|
||||||
|
|
||||||
|
# bun
|
||||||
|
bun run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
## Production
|
||||||
|
|
||||||
|
Build the application for production:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# npm
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
# pnpm
|
||||||
|
pnpm run build
|
||||||
|
|
||||||
|
# yarn
|
||||||
|
yarn build
|
||||||
|
|
||||||
|
# bun
|
||||||
|
bun run build
|
||||||
|
```
|
||||||
|
|
||||||
|
Locally preview production build:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# npm
|
||||||
|
npm run preview
|
||||||
|
|
||||||
|
# pnpm
|
||||||
|
pnpm run preview
|
||||||
|
|
||||||
|
# yarn
|
||||||
|
yarn preview
|
||||||
|
|
||||||
|
# bun
|
||||||
|
bun run preview
|
||||||
|
```
|
||||||
|
|
||||||
|
Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information.
|
176
app.vue
Normal file
|
@ -0,0 +1,176 @@
|
||||||
|
<template>
|
||||||
|
<div class="bg" @keydown.down.prevent="selectNext" @keydown.up.prevent="selectPrevious"
|
||||||
|
@keydown.enter.prevent="pasteSelectedItem" tabindex="0">
|
||||||
|
<input v-model="searchQuery" @input="searchHistory" autocorrect="off" autocapitalize="off" spellcheck="false"
|
||||||
|
class="search" type="text" placeholder="Type to filter entries...">
|
||||||
|
<div class="bottom-bar">
|
||||||
|
<div class="left">
|
||||||
|
<img src="/Logo.svg" alt="">
|
||||||
|
<p>Clipboard Manager</p>
|
||||||
|
</div>
|
||||||
|
<div class="right">
|
||||||
|
<div class="paste" @click="pasteSelectedItem">
|
||||||
|
<p>Paste</p>
|
||||||
|
<img src="/enter.svg" alt="">
|
||||||
|
</div>
|
||||||
|
<div class="divider"></div>
|
||||||
|
<div class="actions">
|
||||||
|
<p>Actions</p>
|
||||||
|
<div>
|
||||||
|
<img v-if="os == 'windows' || os == 'linux'" src="/ctrl.svg" alt="">
|
||||||
|
<img v-if="os == 'macos'" src="/cmd.svg" alt="">
|
||||||
|
<img src="/k.svg" alt="">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<OverlayScrollbarsComponent class="results" ref="resultsContainer"
|
||||||
|
:options="{ scrollbars: { autoHide: 'scroll' } }">
|
||||||
|
<div v-for="(item, index) in filteredHistory" :key="item.id"
|
||||||
|
:class="['result clothoid-corner', { 'selected': index === selectedIndex }]" @click="selectItem(index)"
|
||||||
|
:ref="el => { if (index === selectedIndex) selectedElement = el }">
|
||||||
|
<FileIcon />
|
||||||
|
{{ truncateContent(item.content) }}
|
||||||
|
</div>
|
||||||
|
</OverlayScrollbarsComponent>
|
||||||
|
<div class="content">
|
||||||
|
{{ filteredHistory[selectedIndex]?.content || '' }}
|
||||||
|
</div>
|
||||||
|
<Noise />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed, onMounted, watch, nextTick } from 'vue';
|
||||||
|
import Database from '@tauri-apps/plugin-sql';
|
||||||
|
import { register, unregister, isRegistered } from '@tauri-apps/plugin-global-shortcut';
|
||||||
|
import { writeText } from '@tauri-apps/plugin-clipboard-manager';
|
||||||
|
import { OverlayScrollbarsComponent } from "overlayscrollbars-vue";
|
||||||
|
import 'overlayscrollbars/overlayscrollbars.css';
|
||||||
|
import { app, window } from '@tauri-apps/api';
|
||||||
|
import { platform } from '@tauri-apps/plugin-os';
|
||||||
|
import { invoke } from '@tauri-apps/api/core';
|
||||||
|
import { enable, isEnabled } from "@tauri-apps/plugin-autostart";
|
||||||
|
|
||||||
|
const history = ref([]);
|
||||||
|
const searchQuery = ref('');
|
||||||
|
const selectedIndex = ref(0);
|
||||||
|
const isVisible = ref(false);
|
||||||
|
const resultsContainer = ref(null);
|
||||||
|
const selectedElement = ref(null);
|
||||||
|
const os = platform();
|
||||||
|
|
||||||
|
const filteredHistory = computed(() => {
|
||||||
|
if (!searchQuery.value) return history.value;
|
||||||
|
return history.value
|
||||||
|
.filter(item => item.content.toLowerCase().includes(searchQuery.value.toLowerCase()))
|
||||||
|
.sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp));
|
||||||
|
});
|
||||||
|
|
||||||
|
const searchHistory = () => {
|
||||||
|
selectedIndex.value = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
const selectNext = () => {
|
||||||
|
if (selectedIndex.value < filteredHistory.value.length - 1) {
|
||||||
|
selectedIndex.value++;
|
||||||
|
scrollToSelectedItem();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const selectPrevious = () => {
|
||||||
|
if (selectedIndex.value > 0) {
|
||||||
|
selectedIndex.value--;
|
||||||
|
scrollToSelectedItem();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const scrollToSelectedItem = () => {
|
||||||
|
nextTick(() => {
|
||||||
|
if (selectedElement.value && resultsContainer.value) {
|
||||||
|
const osInstance = resultsContainer.value.osInstance();
|
||||||
|
const { viewport } = osInstance.elements();
|
||||||
|
const element = selectedElement.value;
|
||||||
|
|
||||||
|
const viewportRect = viewport.getBoundingClientRect();
|
||||||
|
const elementRect = element.getBoundingClientRect();
|
||||||
|
|
||||||
|
const isAbove = elementRect.top < viewportRect.top;
|
||||||
|
const isBelow = elementRect.bottom > viewportRect.bottom - 48;
|
||||||
|
|
||||||
|
if (isAbove || isBelow) {
|
||||||
|
let scrollOffset;
|
||||||
|
|
||||||
|
if (isAbove && selectedIndex.value === 0) {
|
||||||
|
scrollOffset = elementRect.top - viewportRect.top - 14;
|
||||||
|
} else if (isAbove) {
|
||||||
|
scrollOffset = elementRect.top - viewportRect.top - 8;
|
||||||
|
} else {
|
||||||
|
scrollOffset = elementRect.bottom - viewportRect.bottom + 48;
|
||||||
|
}
|
||||||
|
|
||||||
|
viewport.scrollBy({
|
||||||
|
top: scrollOffset,
|
||||||
|
behavior: 'smooth'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const selectItem = (index) => {
|
||||||
|
selectedIndex.value = index;
|
||||||
|
scrollToSelectedItem();
|
||||||
|
};
|
||||||
|
|
||||||
|
const pasteSelectedItem = async () => {
|
||||||
|
const selectedItem = filteredHistory.value[selectedIndex.value];
|
||||||
|
if (selectedItem) {
|
||||||
|
await writeText(selectedItem.content);
|
||||||
|
isVisible.value = false;
|
||||||
|
await app.hide();
|
||||||
|
await window.getCurrent().hide();
|
||||||
|
await window.getCurrent().setFocus();
|
||||||
|
await invoke('simulate_paste');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const truncateContent = (content) => {
|
||||||
|
const maxWidth = 284;
|
||||||
|
const charWidth = 9;
|
||||||
|
const maxChars = Math.floor(maxWidth / charWidth);
|
||||||
|
return content.length > maxChars ? content.slice(0, maxChars - 3) + '...' : content;
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
const db = await Database.load('sqlite:data.db');
|
||||||
|
history.value = await db.select('SELECT * FROM history ORDER BY timestamp DESC');
|
||||||
|
|
||||||
|
if (await isRegistered("MetaLeft+V")) {
|
||||||
|
await unregister("MetaLeft+V")
|
||||||
|
}
|
||||||
|
|
||||||
|
await register('MetaLeft+V', (event) => {
|
||||||
|
if (event.state === "MetaLeft+V") {
|
||||||
|
if (isVisible.value == true) {
|
||||||
|
app.hide()
|
||||||
|
isVisible.value = false;
|
||||||
|
} else {
|
||||||
|
app.show()
|
||||||
|
isVisible.value = true;
|
||||||
|
selectedIndex.value = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!await isEnabled()) {
|
||||||
|
await enable()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(selectedIndex, scrollToSelectedItem);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import '~/assets/css/style.scss';
|
||||||
|
</style>
|
287
assets/css/style.scss
Normal file
|
@ -0,0 +1,287 @@
|
||||||
|
$primary: #2E2D2B;
|
||||||
|
$accent: #FEB453;
|
||||||
|
$divider: #ffffff0d;
|
||||||
|
|
||||||
|
$text: #E5DFD5;
|
||||||
|
$text2: #ADA9A1;
|
||||||
|
$mutedtext: #78756F;
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: SFRoundedRegular;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("~/assets/fonts/SFRoundedRegular.otf") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: SFRoundedMedium;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("~/assets/fonts/SFRoundedMedium.otf") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: SFRoundedSemiBold;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("~/assets/fonts/SFRoundedSemiBold.otf") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: SFMonoRegular;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("~/assets/fonts/SFMonoRegular.otf") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
color: $text;
|
||||||
|
text-decoration: none;
|
||||||
|
font-family: SFRoundedRegular;
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
scrollbar-width: thin;
|
||||||
|
user-select: none;
|
||||||
|
|
||||||
|
--os-handle-bg: #ADA9A1;
|
||||||
|
--os-handle-bg-hover: #78756F;
|
||||||
|
--os-handle-bg-active: #78756F;
|
||||||
|
}
|
||||||
|
|
||||||
|
html,
|
||||||
|
body,
|
||||||
|
#__nuxt {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg {
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
background-color: $primary;
|
||||||
|
border: 1px solid $divider;
|
||||||
|
border-radius: 12px;
|
||||||
|
z-index: -1;
|
||||||
|
position: fixed;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search {
|
||||||
|
width: 100%;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
height: 54px;
|
||||||
|
background-color: transparent;
|
||||||
|
outline: none;
|
||||||
|
border: none;
|
||||||
|
font-size: 18px;
|
||||||
|
color: $mutedtext;
|
||||||
|
padding-inline: 16px;
|
||||||
|
border-bottom: 1px solid $divider;
|
||||||
|
font-family: SFRoundedMedium;
|
||||||
|
}
|
||||||
|
|
||||||
|
.results {
|
||||||
|
position: absolute;
|
||||||
|
width: 284px;
|
||||||
|
top: 53px;
|
||||||
|
left: 0;
|
||||||
|
height: calc(100vh - 55px);
|
||||||
|
border-right: 1px solid $divider;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding-inline: 8px;
|
||||||
|
padding-top: 14px;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
|
||||||
|
.result {
|
||||||
|
height: 40px;
|
||||||
|
font-size: 14px;
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
padding: 12px;
|
||||||
|
padding-left: 12px;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result {
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&.selected {
|
||||||
|
background-color: $divider;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
position: fixed;
|
||||||
|
top: 53px;
|
||||||
|
left: 284px;
|
||||||
|
padding: 10px;
|
||||||
|
padding-inline: 14px;
|
||||||
|
font-family: SFMonoRegular;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom-bar {
|
||||||
|
height: 40px;
|
||||||
|
width: calc(100vw - 2px);
|
||||||
|
backdrop-filter: blur(18px);
|
||||||
|
background-color: rgba(46, 45, 43, 0.8);
|
||||||
|
position: fixed;
|
||||||
|
bottom: 1px;
|
||||||
|
left: 1px;
|
||||||
|
z-index: 100;
|
||||||
|
border-radius: 0 0 10px 10px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding-inline: 12px;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 14px;
|
||||||
|
|
||||||
|
p {
|
||||||
|
color: $text2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.left {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.paste p {
|
||||||
|
color: $text;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions div {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider {
|
||||||
|
width: 2px;
|
||||||
|
height: 12px;
|
||||||
|
background-color: $divider;
|
||||||
|
margin-left: 8px;
|
||||||
|
margin-right: 4px;
|
||||||
|
transition: all .2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.paste,
|
||||||
|
.actions {
|
||||||
|
padding: 4px;
|
||||||
|
padding-left: 8px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
border-radius: 6px;
|
||||||
|
background-color: transparent;
|
||||||
|
transition: all .2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.paste:hover,
|
||||||
|
.actions:hover {
|
||||||
|
background-color: $divider;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover .paste:hover~.divider,
|
||||||
|
&:hover .actions:hover~.divider {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.clothoid-corner {
|
||||||
|
clip-path: polygon(13.890123px 0px,
|
||||||
|
calc(100% - 13.890123px) 0px,
|
||||||
|
calc(100% - 12.723414px) 0.004211px,
|
||||||
|
calc(100% - 11.556933px) 0.025635px,
|
||||||
|
calc(100% - 10.391895px) 0.085062px,
|
||||||
|
calc(100% - 9.231074px) 0.199291px,
|
||||||
|
calc(100% - 8.079275px) 0.382298px,
|
||||||
|
calc(100% - 6.947448px) 0.662609px,
|
||||||
|
calc(100% - 5.844179px) 1.039291px,
|
||||||
|
calc(100% - 4.793324px) 1.542842px,
|
||||||
|
calc(100% - 3.811369px) 2.169728px,
|
||||||
|
calc(100% - 2.926417px) 2.926417px,
|
||||||
|
calc(100% - 2.169728px) 3.811369px,
|
||||||
|
calc(100% - 1.542842px) 4.793324px,
|
||||||
|
calc(100% - 1.039291px) 5.844179px,
|
||||||
|
calc(100% - 0.662609px) 6.947448px,
|
||||||
|
calc(100% - 0.382298px) 8.079275px,
|
||||||
|
calc(100% - 0.199291px) 9.231074px,
|
||||||
|
calc(100% - 0.085062px) 10.391895px,
|
||||||
|
calc(100% - 0.025635px) 11.556933px,
|
||||||
|
calc(100% - 0.004211px) 12.723414px,
|
||||||
|
100% 13.890123px,
|
||||||
|
100% calc(100% - 13.890123px),
|
||||||
|
calc(100% - 0.004211px) calc(100% - 12.723414px),
|
||||||
|
calc(100% - 0.025635px) calc(100% - 11.556933px),
|
||||||
|
calc(100% - 0.085062px) calc(100% - 10.391895px),
|
||||||
|
calc(100% - 0.199291px) calc(100% - 9.231074px),
|
||||||
|
calc(100% - 0.382298px) calc(100% - 8.079275px),
|
||||||
|
calc(100% - 0.662609px) calc(100% - 6.947448px),
|
||||||
|
calc(100% - 1.039291px) calc(100% - 5.844179px),
|
||||||
|
calc(100% - 1.542842px) calc(100% - 4.793324px),
|
||||||
|
calc(100% - 2.169728px) calc(100% - 3.811369px),
|
||||||
|
calc(100% - 2.926417px) calc(100% - 2.926417px),
|
||||||
|
calc(100% - 3.811369px) calc(100% - 2.169728px),
|
||||||
|
calc(100% - 4.793324px) calc(100% - 1.542842px),
|
||||||
|
calc(100% - 5.844179px) calc(100% - 1.039291px),
|
||||||
|
calc(100% - 6.947448px) calc(100% - 0.662609px),
|
||||||
|
calc(100% - 8.079275px) calc(100% - 0.382298px),
|
||||||
|
calc(100% - 9.231074px) calc(100% - 0.199291px),
|
||||||
|
calc(100% - 10.391895px) calc(100% - 0.085062px),
|
||||||
|
calc(100% - 11.556933px) calc(100% - 0.025635px),
|
||||||
|
calc(100% - 12.723414px) calc(100% - 0.004211px),
|
||||||
|
calc(100% - 13.890123px) 100%,
|
||||||
|
13.890123px 100%,
|
||||||
|
12.723414px calc(100% - 0.004211px),
|
||||||
|
11.556933px calc(100% - 0.025635px),
|
||||||
|
10.391895px calc(100% - 0.085062px),
|
||||||
|
9.231074px calc(100% - 0.199291px),
|
||||||
|
8.079275px calc(100% - 0.382298px),
|
||||||
|
6.947448px calc(100% - 0.662609px),
|
||||||
|
5.844179px calc(100% - 1.039291px),
|
||||||
|
4.793324px calc(100% - 1.542842px),
|
||||||
|
3.811369px calc(100% - 2.169728px),
|
||||||
|
2.926417px calc(100% - 2.926417px),
|
||||||
|
2.169728px calc(100% - 3.811369px),
|
||||||
|
1.542842px calc(100% - 4.793324px),
|
||||||
|
1.039291px calc(100% - 5.844179px),
|
||||||
|
0.662609px calc(100% - 6.947448px),
|
||||||
|
0.382298px calc(100% - 8.079275px),
|
||||||
|
0.199291px calc(100% - 9.231074px),
|
||||||
|
0.085062px calc(100% - 10.391895px),
|
||||||
|
0.025635px calc(100% - 11.556933px),
|
||||||
|
0.004211px calc(100% - 12.723414px),
|
||||||
|
0px calc(100% - 13.890123px),
|
||||||
|
0px 13.890123px,
|
||||||
|
0.004211px 12.723414px,
|
||||||
|
0.025635px 11.556933px,
|
||||||
|
0.085062px 10.391895px,
|
||||||
|
0.199291px 9.231074px,
|
||||||
|
0.382298px 8.079275px,
|
||||||
|
0.662609px 6.947448px,
|
||||||
|
1.039291px 5.844179px,
|
||||||
|
1.542842px 4.793324px,
|
||||||
|
2.169728px 3.811369px,
|
||||||
|
2.926417px 2.926417px,
|
||||||
|
3.811369px 2.169728px,
|
||||||
|
4.793324px 1.542842px,
|
||||||
|
5.844179px 1.039291px,
|
||||||
|
6.947448px 0.662609px,
|
||||||
|
8.079275px 0.382298px,
|
||||||
|
9.231074px 0.199291px,
|
||||||
|
10.391895px 0.085062px,
|
||||||
|
11.556933px 0.025635px,
|
||||||
|
12.723414px 0.004211px,
|
||||||
|
13.890123px 0px);
|
||||||
|
}
|
BIN
assets/fonts/SFMonoRegular.otf
Normal file
BIN
assets/fonts/SFRoundedMedium.otf
Normal file
BIN
assets/fonts/SFRoundedRegular.otf
Normal file
BIN
assets/fonts/SFRoundedSemiBold.otf
Normal file
BIN
bun.lockb
Normal file
3
components/FileIcon.vue
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<template>
|
||||||
|
<img src="/file.svg" alt="">
|
||||||
|
</template>
|
21
components/Noise.vue
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<template>
|
||||||
|
<div class="noise"></div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.noise {
|
||||||
|
position: absolute;
|
||||||
|
overflow: hidden;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
pointer-events: none;
|
||||||
|
user-select: none;
|
||||||
|
z-index: 0;
|
||||||
|
background-image: url('/noise.png');
|
||||||
|
background-repeat: repeat;
|
||||||
|
image-rendering: pixelated;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
</style>
|
6
nuxt.config.ts
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
// https://nuxt.com/docs/api/configuration/nuxt-config
|
||||||
|
export default defineNuxtConfig({
|
||||||
|
devtools: { enabled: false },
|
||||||
|
compatibilityDate: "2024-07-04",
|
||||||
|
ssr: false
|
||||||
|
})
|
26
package.json
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"name": "nuxt-app",
|
||||||
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"build": "nuxt build",
|
||||||
|
"dev": "tauri dev",
|
||||||
|
"generate": "nuxt generate",
|
||||||
|
"preview": "nuxt preview",
|
||||||
|
"postinstall": "nuxt prepare"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@tauri-apps/api": "^2.0.0-beta.14",
|
||||||
|
"@tauri-apps/cli": "^2.0.0-beta.21",
|
||||||
|
"@tauri-apps/plugin-autostart": "^2.0.0-beta.6",
|
||||||
|
"@tauri-apps/plugin-clipboard-manager": "^2.1.0-beta.4",
|
||||||
|
"@tauri-apps/plugin-global-shortcut": "^2.0.0-beta.6",
|
||||||
|
"@tauri-apps/plugin-os": "^2.0.0-beta.6",
|
||||||
|
"@tauri-apps/plugin-sql": "^2.0.0-beta.6",
|
||||||
|
"nuxt": "^3.12.3",
|
||||||
|
"overlayscrollbars": "^2.9.2",
|
||||||
|
"overlayscrollbars-vue": "^0.5.9",
|
||||||
|
"sass": "^1.77.6",
|
||||||
|
"vue": "latest"
|
||||||
|
}
|
||||||
|
}
|
14
public/Logo.svg
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<svg width="18px" height="18px" viewBox="0 0 18 18" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<path d="M0 0L10 0L10 16L0 16L0 0Z" id="path_1" />
|
||||||
|
</defs>
|
||||||
|
<g id="Logo">
|
||||||
|
<path d="M9 0L9 0C11.9197 0 13.3795 0 14.3219 0.347674Q14.894 0.558746 15.4077 0.887528Q15.9213 1.21631 16.3525 1.64752Q16.7837 2.07874 17.1125 2.59235Q17.4413 3.10595 17.6523 3.67809C18 4.6205 18 6.08033 18 9L18 9C18 11.9197 18 13.3795 17.6523 14.3219Q17.4413 14.894 17.1125 15.4077Q16.7837 15.9213 16.3525 16.3525Q15.9213 16.7837 15.4077 17.1125Q14.894 17.4413 14.3219 17.6523C13.3795 18 11.9197 18 9 18L9 18C6.08033 18 4.6205 18 3.67809 17.6523Q3.10595 17.4413 2.59235 17.1125Q2.07874 16.7837 1.64752 16.3525Q1.21631 15.9213 0.887528 15.4077Q0.558746 14.894 0.347674 14.3219C0 13.3795 0 11.9197 0 9L0 9C0 6.08033 0 4.6205 0.347674 3.67809Q0.558746 3.10595 0.887528 2.59235Q1.21631 2.07874 1.64752 1.64752Q2.07874 1.21631 2.59235 0.887527Q3.10596 0.558745 3.67809 0.347673C4.6205 0 6.08033 0 9 0Z" id="Rectangle" fill="#FEB453" stroke="none" />
|
||||||
|
<g id="C" clip-path="url(#clip_1)" transform="translate(4 -1)">
|
||||||
|
<g transform="translate(0.828125, 2.8945312)" id="C" fill="#2E2D2B">
|
||||||
|
<path d="M4.35938 11.5664C5.92969 11.5664 7.08398 10.9043 7.62891 9.76172C7.72266 9.56836 7.76953 9.39844 7.76953 9.2168C7.76953 8.87109 7.52344 8.625 7.16602 8.625C6.87891 8.625 6.70898 8.75391 6.56836 9.06445C6.17578 9.97852 5.38477 10.418 4.35352 10.418C2.80078 10.418 1.81641 9.16992 1.81641 7.19531C1.81641 5.23828 2.8125 3.97852 4.34766 3.97852C5.32031 3.97852 6.15234 4.48242 6.54492 5.42578C6.69141 5.76563 6.89648 5.91797 7.20703 5.91797C7.55859 5.91797 7.79297 5.68945 7.79297 5.33789C7.79297 5.17969 7.75195 5.00391 7.66992 4.83398C7.14258 3.58594 5.90039 2.83008 4.34766 2.83008C1.98633 2.83008 0.474609 4.51758 0.474609 7.19531C0.474609 9.89063 1.96875 11.5664 4.35938 11.5664Z" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2 KiB |
18
public/cmd.svg
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<svg width="24px" height="20px" viewBox="0 0 24 20" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<path d="M0 0L24 0L24 20L0 20L0 0Z" id="path_1" />
|
||||||
|
<clipPath id="clip_1">
|
||||||
|
<use xlink:href="#path_1" clip-rule="evenodd" fill-rule="evenodd" transform="translate(0, -2.133523)" />
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
<g id="cmd">
|
||||||
|
<path d="M-751 -2016L-751 -2016L-751 -1996L-775 -1996L-775 -2016L-751 -2016Z" id="cmd" fill="none" stroke="none" />
|
||||||
|
<path d="M12 0L17.6 0C19.8402 0 20.9603 0 21.816 0.435974Q22.3804 0.723593 22.8284 1.17157Q23.2764 1.61955 23.564 2.18404C24 3.03969 24 4.15979 24 6.4L24 13.6C24 15.8402 24 16.9603 23.564 17.816Q23.2764 18.3804 22.8284 18.8284Q22.3804 19.2764 21.816 19.564C20.9603 20 19.8402 20 17.6 20L6.4 20C4.15979 20 3.03969 20 2.18404 19.564Q1.61955 19.2764 1.17157 18.8284Q0.723594 18.3804 0.435974 17.816C0 16.9603 0 15.8402 0 13.6L0 6.4C0 4.15979 0 3.03969 0.435974 2.18404Q0.723594 1.61955 1.17157 1.17157Q1.61955 0.723594 2.18404 0.435974C3.03969 0 4.15979 0 6.4 0L12 0Z" id="Rectangle" fill="#FFFFFF" fill-opacity="0.050980393" stroke="none" />
|
||||||
|
<g id="⌘" clip-path="url(#clip_1)" transform="translate(0 2.133523)">
|
||||||
|
<g transform="translate(5.5692472, 0)" id="⌘" fill="#E5DFD5">
|
||||||
|
<path d="M3.55007 12.8061Q2.98224 12.8061 2.51598 12.5268Q2.04972 12.2475 1.77042 11.7789Q1.49112 11.3104 1.49112 10.7472Q1.49112 10.1747 1.77042 9.70614Q2.04972 9.23757 2.51598 8.95827Q2.98224 8.67898 3.55007 8.67898L4.5657 8.67898L4.5657 7.04474L3.55007 7.04474Q2.98224 7.04474 2.51598 6.76775Q2.04972 6.49077 1.77042 6.02219Q1.49112 5.55362 1.49112 4.98579Q1.49112 4.41797 1.77042 3.9494Q2.04972 3.48082 2.51598 3.20383Q2.98224 2.92685 3.55007 2.92684Q4.1179 2.92684 4.58647 3.20383Q5.05504 3.48082 5.33434 3.9494Q5.61364 4.41797 5.61364 4.98579L5.61364 5.99219L7.25249 5.99219L7.25249 4.98579Q7.25249 4.41797 7.52947 3.9494Q7.80646 3.48082 8.27504 3.20383Q8.74361 2.92685 9.31144 2.92684Q9.87926 2.92684 10.3455 3.20383Q10.8118 3.48082 11.0888 3.9494Q11.3658 4.41797 11.3658 4.98579Q11.3658 5.55362 11.0888 6.02219Q10.8118 6.49077 10.3455 6.76775Q9.87926 7.04474 9.31144 7.04474L8.30043 7.04474L8.30043 8.67898L9.31144 8.67898Q9.87926 8.67898 10.3455 8.95827Q10.8118 9.23757 11.0888 9.70614Q11.3658 10.1747 11.3658 10.7472Q11.3658 11.3104 11.0888 11.7789Q10.8118 12.2475 10.3455 12.5268Q9.87926 12.8061 9.31144 12.8061Q8.74361 12.8061 8.27504 12.5268Q7.80646 12.2475 7.52947 11.7789Q7.25249 11.3104 7.25249 10.7472L7.25249 9.73153L5.61364 9.73153L5.61364 10.7472Q5.61364 11.3104 5.33434 11.7789Q5.05504 12.2475 4.58647 12.5268Q4.1179 12.8061 3.55007 12.8061ZM3.55007 11.7536Q3.97017 11.7536 4.26563 11.4604Q4.56108 11.1673 4.5657 10.7472L4.5657 9.73153L3.55007 9.73153Q3.12997 9.73615 2.83452 10.0293Q2.53906 10.3224 2.53906 10.7472Q2.53906 11.1673 2.83452 11.4604Q3.12997 11.7536 3.55007 11.7536ZM9.31144 11.7536Q9.72692 11.7536 10.0224 11.4604Q10.3178 11.1673 10.3178 10.7472Q10.3178 10.3224 10.0224 10.0293Q9.72692 9.73615 9.31144 9.73153L8.30043 9.73153L8.30043 10.7472Q8.29581 11.1673 8.59357 11.4604Q8.89133 11.7536 9.31144 11.7536ZM3.55007 5.99219L4.5657 5.99219L4.5657 4.98579Q4.56108 4.56569 4.26563 4.27255Q3.97017 3.9794 3.55007 3.9794Q3.12997 3.9794 2.83452 4.27255Q2.53906 4.56569 2.53906 4.98579Q2.53906 5.40589 2.83452 5.70135Q3.12997 5.9968 3.55007 5.99219ZM8.30043 5.99219L9.31144 5.99219Q9.72692 5.9968 10.0224 5.70135Q10.3178 5.40589 10.3178 4.98579Q10.3178 4.56569 10.0224 4.27255Q9.72692 3.9794 9.31144 3.9794Q8.89133 3.9794 8.59357 4.27255Q8.29581 4.56569 8.30043 4.98579L8.30043 5.99219ZM5.61364 8.67898L7.25249 8.67898L7.25249 7.04474L5.61364 7.04474L5.61364 8.67898Z" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.7 KiB |
8
public/ctrl.svg
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<svg width="24px" height="20px" viewBox="0 0 24 20" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g id="Ctrl" fill-opacity="1">
|
||||||
|
<path d="M-751 -2016L-751 -2016L-751 -1996L-775 -1996L-775 -2016L-751 -2016Z" id="Ctrl" fill="none" stroke="none" />
|
||||||
|
<path d="M12 0L17.6 0C19.8402 0 20.9603 0 21.816 0.435974Q22.3804 0.723593 22.8284 1.17157Q23.2764 1.61955 23.564 2.18404C24 3.03969 24 4.15979 24 6.4L24 13.6C24 15.8402 24 16.9603 23.564 17.816Q23.2764 18.3804 22.8284 18.8284Q22.3804 19.2764 21.816 19.564C20.9603 20 19.8402 20 17.6 20L6.4 20C4.15979 20 3.03969 20 2.18404 19.564Q1.61955 19.2764 1.17157 18.8284Q0.723594 18.3804 0.435974 17.816C0 16.9603 0 15.8402 0 13.6L0 6.4C0 4.15979 0 3.03969 0.435974 2.18404Q0.723594 1.61955 1.17157 1.17157Q1.61955 0.723594 2.18404 0.435974C3.03969 0 4.15979 0 6.4 0L12 0Z" id="Rectangle" fill="#FFFFFF" fill-opacity="0.050980393" stroke="none" />
|
||||||
|
<path d="M7.97095 9.00977L12 5L16 9.00977" id="Vector" fill="none" fill-rule="evenodd" stroke="#E5E0D5" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
9
public/enter.svg
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<svg width="24px" height="20px" viewBox="0 0 24 20" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g id="Enter" fill-opacity="1">
|
||||||
|
<path d="M-659 -2016L-659 -2016L-659 -1996L-683 -1996L-683 -2016L-659 -2016Z" id="Enter" fill="none" stroke="none" />
|
||||||
|
<path d="M12 0L17.6 0C19.8402 0 20.9603 0 21.816 0.435974Q22.3804 0.723593 22.8284 1.17157Q23.2764 1.61955 23.564 2.18404C24 3.03969 24 4.15979 24 6.4L24 13.6C24 15.8402 24 16.9603 23.564 17.816Q23.2764 18.3804 22.8284 18.8284Q22.3804 19.2764 21.816 19.564C20.9603 20 19.8402 20 17.6 20L6.4 20C4.15979 20 3.03969 20 2.18404 19.564Q1.61955 19.2764 1.17157 18.8284Q0.723594 18.3804 0.435974 17.816C0 16.9603 0 15.8402 0 13.6L0 6.4C0 4.15979 0 3.03969 0.435974 2.18404Q0.723594 1.61955 1.17157 1.17157Q1.61955 0.723594 2.18404 0.435974C3.03969 0 4.15979 0 6.4 0L12 0Z" id="Rectangle" fill="#FFFFFF" fill-opacity="0.050980393" stroke="none" />
|
||||||
|
<path d="M16.0597 5.48914L16.0597 10.5L7.5 10.5" id="Vector" fill="none" fill-rule="evenodd" stroke="#E5DFD5" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
||||||
|
<path d="M9.5 8.5L9.5 12.5035L7 10.5L9.5 8.5Z" id="Vector" fill="#E5DFD5" fill-rule="evenodd" stroke="#E5DFD5" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
BIN
public/favicon.ico
Normal file
After Width: | Height: | Size: 4.2 KiB |
28
public/file.svg
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<svg width="14px" height="18px" viewBox="0 0 14 18" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<path
|
||||||
|
d="M2.99805 0L8 0L14 6L14 15.002Q14 15.1492 13.9856 15.2958Q13.9711 15.4424 13.9424 15.5868Q13.9137 15.7313 13.8709 15.8722Q13.8282 16.0132 13.7718 16.1493Q13.7154 16.2853 13.646 16.4152Q13.5766 16.5451 13.4947 16.6676Q13.4129 16.79 13.3195 16.9039Q13.226 17.0177 13.1219 17.1219Q13.0177 17.226 12.9039 17.3195Q12.79 17.4129 12.6676 17.4947Q12.5451 17.5766 12.4152 17.646Q12.2853 17.7154 12.1493 17.7718Q12.0132 17.8282 11.8722 17.8709Q11.7313 17.9137 11.5868 17.9424Q11.4424 17.9711 11.2958 17.9856Q11.1492 18 11.002 18L2.99805 18Q2.85076 18 2.70419 17.9856Q2.55761 17.9711 2.41316 17.9424Q2.2687 17.9137 2.12776 17.8709Q1.98682 17.8281 1.85074 17.7718Q1.71467 17.7154 1.58478 17.646Q1.45488 17.5766 1.33242 17.4947Q1.20996 17.4129 1.09611 17.3195Q0.982254 17.226 0.878108 17.1219Q0.773962 17.0177 0.680525 16.9039Q0.587089 16.79 0.505262 16.6676Q0.423435 16.5451 0.354006 16.4152Q0.284576 16.2853 0.228213 16.1493Q0.171849 16.0132 0.129095 15.8722Q0.0863404 15.7313 0.0576066 15.5868Q0.0288728 15.4424 0.0144364 15.2958Q0 15.1492 0 15.002L0 2.99805Q0 2.85076 0.0144364 2.70419Q0.0288728 2.55761 0.0576066 2.41316Q0.0863404 2.2687 0.129095 2.12776Q0.171849 1.98682 0.228213 1.85074Q0.284576 1.71467 0.354006 1.58478Q0.423435 1.45488 0.505262 1.33242Q0.587089 1.20996 0.680525 1.09611Q0.773962 0.982254 0.878108 0.878108Q0.982254 0.773962 1.09611 0.680525Q1.20996 0.587089 1.33242 0.505262Q1.45488 0.423435 1.58478 0.354006Q1.71467 0.284576 1.85074 0.228213Q1.98682 0.171849 2.12776 0.129095Q2.2687 0.0863404 2.41316 0.0576066Q2.55761 0.0288728 2.70419 0.0144364Q2.85076 0 2.99805 0Z"
|
||||||
|
id="path_1" />
|
||||||
|
<path d="M7 1.61429e-06L7.99999 0L14 6L14 8L7 8L7 1.61429e-06Z" id="path_2" />
|
||||||
|
<clipPath id="clip_1">
|
||||||
|
<use xlink:href="#path_1" />
|
||||||
|
</clipPath>
|
||||||
|
<clipPath id="clip_2">
|
||||||
|
<use xlink:href="#path_2" />
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
<g id="File" fill-opacity="1">
|
||||||
|
<path d="M-135 -1664L-135 -1664L-135 -1646L-149 -1646L-149 -1664L-135 -1664Z" id="File" fill="none" stroke="none" />
|
||||||
|
<g id="Rectangle">
|
||||||
|
<g clip-path="url(#clip_1)">
|
||||||
|
<use xlink:href="#path_1" fill="none" stroke="#E5DFD5" stroke-width="4" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g id="Rectangle">
|
||||||
|
<g clip-path="url(#clip_2)">
|
||||||
|
<use xlink:href="#path_2" fill="none" stroke="#E5DFD5" stroke-width="4" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.5 KiB |
12
public/k.svg
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<svg width="24px" height="20px" viewBox="0 0 24 20" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g id="K" fill-opacity="1">
|
||||||
|
<path d="M-751 -2016L-751 -2016L-751 -1996L-775 -1996L-775 -2016L-751 -2016Z" id="K" fill="none" stroke="none" />
|
||||||
|
<path d="M12 0L17.6 0C19.8402 0 20.9603 0 21.816 0.435974Q22.3804 0.723593 22.8284 1.17157Q23.2764 1.61955 23.564 2.18404C24 3.03969 24 4.15979 24 6.4L24 13.6C24 15.8402 24 16.9603 23.564 17.816Q23.2764 18.3804 22.8284 18.8284Q22.3804 19.2764 21.816 19.564C20.9603 20 19.8402 20 17.6 20L6.4 20C4.15979 20 3.03969 20 2.18404 19.564Q1.61955 19.2764 1.17157 18.8284Q0.723594 18.3804 0.435974 17.816C0 16.9603 0 15.8402 0 13.6L0 6.4C0 4.15979 0 3.03969 0.435974 2.18404Q0.723594 1.61955 1.17157 1.17157Q1.61955 0.723594 2.18404 0.435974C3.03969 0 4.15979 0 6.4 0L12 0Z" id="Rectangle" fill="#FFFFFF" fill-opacity="0.050980393" stroke="none" />
|
||||||
|
<g id="K" transform="translate(8 0)">
|
||||||
|
<g transform="translate(0, 2.8945312)" id="K" fill="#E5E0D5">
|
||||||
|
<path d="M1.5 11.5254C1.97461 11.5254 2.25586 11.2383 2.25586 10.7402L2.25586 8.70703L3.13477 7.77539L5.87695 11.127C6.11133 11.4199 6.31641 11.5313 6.61523 11.5313C7.02539 11.5313 7.3418 11.2148 7.3418 10.8047C7.3418 10.6055 7.25391 10.3945 7.04883 10.1426L4.25391 6.76172L6.79688 4.10742C6.97266 3.91992 7.04297 3.76172 7.04297 3.55664C7.04297 3.16992 6.74414 2.86523 6.33984 2.86523C6.09375 2.86523 5.91211 2.95898 5.70703 3.18164L2.30859 6.84961L2.25586 6.84961L2.25586 3.65625C2.25586 3.1582 1.97461 2.87109 1.5 2.87109C1.03125 2.87109 0.744141 3.1582 0.744141 3.65625L0.744141 10.7402C0.744141 11.2383 1.03125 11.5254 1.5 11.5254Z" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.7 KiB |
BIN
public/noise.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
3
server/tsconfig.json
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"extends": "../.nuxt/tsconfig.server.json"
|
||||||
|
}
|
4
src-tauri/.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
# Generated by Cargo
|
||||||
|
# will have compiled files and executables
|
||||||
|
/target/
|
||||||
|
/gen/schemas
|
5595
src-tauri/Cargo.lock
generated
Normal file
33
src-tauri/Cargo.toml
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
[package]
|
||||||
|
name = "app"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "A Tauri App"
|
||||||
|
authors = ["you"]
|
||||||
|
license = ""
|
||||||
|
repository = ""
|
||||||
|
edition = "2021"
|
||||||
|
rust-version = "1.70"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "app_lib"
|
||||||
|
crate-type = ["staticlib", "cdylib", "rlib"]
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
tauri-build = { version = "2.0.0-beta.18", features = [] }
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
tauri = { version = "2.0.0-beta.23", features = ["unstable"] }
|
||||||
|
tauri-plugin-clipboard-manager = "2.1.0-beta.5"
|
||||||
|
tauri-plugin-window-state = "2.0.0-beta.10"
|
||||||
|
tauri-plugin-sql = {version = "2.0.0-beta.8", features = ["sqlite"] }
|
||||||
|
tauri-plugin-global-shortcut = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
|
||||||
|
tauri-plugin-autostart = "2.0.0-beta.8"
|
||||||
|
sqlx = { version = "0.7.4", features = ["runtime-tokio-native-tls", "sqlite"] }
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
tokio = { version = "1.0", features = ["full"] }
|
||||||
|
serde_json = "1.0"
|
||||||
|
rdev = "0.5.3"
|
||||||
|
rand = "0.8"
|
||||||
|
tauri-plugin-os = "2.0.0-beta.7"
|
3
src-tauri/build.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
fn main() {
|
||||||
|
tauri_build::build()
|
||||||
|
}
|
42
src-tauri/capabilities/default.json
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
{
|
||||||
|
"$schema": "../gen/schemas/desktop-schema.json",
|
||||||
|
"identifier": "default",
|
||||||
|
"description": "enables the default permissions",
|
||||||
|
"windows": [
|
||||||
|
"main"
|
||||||
|
],
|
||||||
|
"permissions": [
|
||||||
|
"path:default",
|
||||||
|
"event:default",
|
||||||
|
"window:default",
|
||||||
|
"webview:default",
|
||||||
|
"app:default",
|
||||||
|
"resources:default",
|
||||||
|
"image:default",
|
||||||
|
"menu:default",
|
||||||
|
"tray:default",
|
||||||
|
"clipboard-manager:default",
|
||||||
|
"clipboard-manager:allow-read-text",
|
||||||
|
"clipboard-manager:allow-write-text",
|
||||||
|
"clipboard-manager:allow-read-image",
|
||||||
|
"clipboard-manager:allow-write-html",
|
||||||
|
"clipboard-manager:allow-write-image",
|
||||||
|
"sql:allow-load",
|
||||||
|
"sql:allow-select",
|
||||||
|
"sql:allow-execute",
|
||||||
|
"global-shortcut:default",
|
||||||
|
"global-shortcut:allow-is-registered",
|
||||||
|
"global-shortcut:allow-register",
|
||||||
|
"global-shortcut:allow-unregister",
|
||||||
|
"global-shortcut:allow-unregister-all",
|
||||||
|
"autostart:allow-enable",
|
||||||
|
"autostart:allow-disable",
|
||||||
|
"autostart:allow-is-enabled",
|
||||||
|
"os:allow-os-type",
|
||||||
|
"app:allow-app-hide",
|
||||||
|
"app:allow-app-show",
|
||||||
|
"window:allow-hide",
|
||||||
|
"window:allow-show",
|
||||||
|
"window:allow-set-focus"
|
||||||
|
]
|
||||||
|
}
|
BIN
src-tauri/icons/128x128.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
src-tauri/icons/128x128@2x.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
src-tauri/icons/32x32.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
src-tauri/icons/Square107x107Logo.png
Normal file
After Width: | Height: | Size: 9 KiB |
BIN
src-tauri/icons/Square142x142Logo.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
src-tauri/icons/Square150x150Logo.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
src-tauri/icons/Square284x284Logo.png
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
src-tauri/icons/Square30x30Logo.png
Normal file
After Width: | Height: | Size: 2 KiB |
BIN
src-tauri/icons/Square310x310Logo.png
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
src-tauri/icons/Square44x44Logo.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
src-tauri/icons/Square71x71Logo.png
Normal file
After Width: | Height: | Size: 5.9 KiB |
BIN
src-tauri/icons/Square89x89Logo.png
Normal file
After Width: | Height: | Size: 7.4 KiB |
BIN
src-tauri/icons/StoreLogo.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
src-tauri/icons/icon.icns
Normal file
BIN
src-tauri/icons/icon.ico
Normal file
After Width: | Height: | Size: 37 KiB |
BIN
src-tauri/icons/icon.png
Normal file
After Width: | Height: | Size: 49 KiB |
133
src-tauri/src/lib.rs
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
use rand::distributions::Alphanumeric;
|
||||||
|
use rand::{thread_rng, Rng};
|
||||||
|
use rdev::{listen, EventType, Key};
|
||||||
|
use sqlx::{sqlite::SqlitePoolOptions, SqlitePool};
|
||||||
|
use std::fs;
|
||||||
|
use std::sync::mpsc;
|
||||||
|
use tauri::Manager;
|
||||||
|
use tauri_plugin_autostart::MacosLauncher;
|
||||||
|
use tauri_plugin_window_state::{AppHandleExt, StateFlags, WindowExt};
|
||||||
|
use tokio::runtime::Runtime;
|
||||||
|
|
||||||
|
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||||
|
pub fn run() {
|
||||||
|
let (tx, rx) = mpsc::channel();
|
||||||
|
|
||||||
|
tauri::Builder::default()
|
||||||
|
.plugin(tauri_plugin_os::init())
|
||||||
|
.plugin(tauri_plugin_autostart::init(MacosLauncher::LaunchAgent, Some(vec![])))
|
||||||
|
.plugin(tauri_plugin_global_shortcut::Builder::new().build())
|
||||||
|
.plugin(tauri_plugin_clipboard_manager::init())
|
||||||
|
.plugin(tauri_plugin_window_state::Builder::default().build())
|
||||||
|
.plugin(tauri_plugin_sql::Builder::default().build())
|
||||||
|
.setup(|app| {
|
||||||
|
let app_handle = app.handle().clone();
|
||||||
|
|
||||||
|
let rt = Runtime::new().expect("Failed to create Tokio runtime");
|
||||||
|
|
||||||
|
let app_data_dir = app.path().app_data_dir().unwrap();
|
||||||
|
fs::create_dir_all(&app_data_dir).expect("Failed to create app data directory");
|
||||||
|
|
||||||
|
let db_path = app_data_dir.join("data.db");
|
||||||
|
let is_new_db = !db_path.exists();
|
||||||
|
if is_new_db {
|
||||||
|
fs::File::create(&db_path).expect("Failed to create database file");
|
||||||
|
}
|
||||||
|
|
||||||
|
let db_url = format!("sqlite:{}", db_path.to_str().unwrap());
|
||||||
|
let pool = rt.block_on(async {
|
||||||
|
SqlitePoolOptions::new()
|
||||||
|
.max_connections(5)
|
||||||
|
.connect(&db_url)
|
||||||
|
.await
|
||||||
|
.expect("Failed to create pool")
|
||||||
|
});
|
||||||
|
|
||||||
|
rt.block_on(async {
|
||||||
|
sqlx::query(
|
||||||
|
"CREATE TABLE IF NOT EXISTS history (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
content TEXT NOT NULL,
|
||||||
|
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||||
|
)"
|
||||||
|
)
|
||||||
|
.execute(&pool)
|
||||||
|
.await
|
||||||
|
.expect("Failed to create table");
|
||||||
|
|
||||||
|
if is_new_db {
|
||||||
|
let id: String = thread_rng()
|
||||||
|
.sample_iter(&Alphanumeric)
|
||||||
|
.take(16)
|
||||||
|
.map(char::from)
|
||||||
|
.collect();
|
||||||
|
sqlx::query("INSERT INTO history (id, content) VALUES (?, ?)")
|
||||||
|
.bind(id)
|
||||||
|
.bind("Welcome to your clipboard history!")
|
||||||
|
.execute(&pool)
|
||||||
|
.await
|
||||||
|
.expect("Failed to insert welcome message");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.manage(pool);
|
||||||
|
app.manage(rt);
|
||||||
|
|
||||||
|
if let Some(window) = app.get_window("main") {
|
||||||
|
let _ = window.restore_state(StateFlags::POSITION);
|
||||||
|
window.show().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
listen(move |event| match event.event_type {
|
||||||
|
EventType::KeyPress(Key::ControlLeft | Key::ControlRight) => {
|
||||||
|
let _ = tx.send(true);
|
||||||
|
}
|
||||||
|
EventType::KeyRelease(Key::KeyC) => {
|
||||||
|
if rx.try_recv().is_ok() {
|
||||||
|
match app_handle.clipboard().read_text() {
|
||||||
|
Ok(content) => {
|
||||||
|
let pool = app_handle.state::<SqlitePool>();
|
||||||
|
let rt = app_handle.state::<Runtime>();
|
||||||
|
rt.block_on(async {
|
||||||
|
let exists = sqlx::query_scalar::<_, bool>("SELECT EXISTS(SELECT 1 FROM history WHERE content = ?)")
|
||||||
|
.bind(&content)
|
||||||
|
.fetch_one(&*pool)
|
||||||
|
.await
|
||||||
|
.unwrap_or(false);
|
||||||
|
|
||||||
|
if !exists {
|
||||||
|
let id: String = thread_rng()
|
||||||
|
.sample_iter(&Alphanumeric)
|
||||||
|
.take(16)
|
||||||
|
.map(char::from)
|
||||||
|
.collect();
|
||||||
|
let _ = sqlx::query("INSERT INTO history (id, content) VALUES (?, ?)")
|
||||||
|
.bind(id)
|
||||||
|
.bind(content)
|
||||||
|
.execute(&*pool)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
Err(e) => eprintln!("Error reading clipboard: {:?}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
.on_window_event(|app, event| match event {
|
||||||
|
tauri::WindowEvent::CloseRequested { .. }
|
||||||
|
| tauri::WindowEvent::Destroyed
|
||||||
|
| tauri::WindowEvent::Focused(false) => {
|
||||||
|
let _ = AppHandleExt::save_window_state(app.app_handle(), StateFlags::POSITION);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
})
|
||||||
|
.run(tauri::generate_context!())
|
||||||
|
.expect("error while running tauri application");
|
||||||
|
}
|
6
src-tauri/src/main.rs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
|
||||||
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
app_lib::run();
|
||||||
|
}
|
48
src-tauri/tauri.conf.json
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
{
|
||||||
|
"productName": "Clipboard Manager",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"identifier": "net.pandadev.clipboard-manager",
|
||||||
|
"build": {
|
||||||
|
"frontendDist": "../dist",
|
||||||
|
"devUrl": "http://localhost:3000",
|
||||||
|
"beforeDevCommand": "pnpm nuxt dev",
|
||||||
|
"beforeBuildCommand": "pnpm nuxt generate"
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"windows": [
|
||||||
|
{
|
||||||
|
"title": "Clipboard Manager",
|
||||||
|
"titleBarStyle": "Overlay",
|
||||||
|
"fullscreen": false,
|
||||||
|
"resizable": false,
|
||||||
|
"height": 474,
|
||||||
|
"width": 750,
|
||||||
|
"minHeight": 474,
|
||||||
|
"maxHeight": 474,
|
||||||
|
"minWidth": 750,
|
||||||
|
"maxWidth": 750,
|
||||||
|
"decorations": false,
|
||||||
|
"center": true,
|
||||||
|
"shadow": false,
|
||||||
|
"transparent": true,
|
||||||
|
"visible": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"security": {
|
||||||
|
"csp": null
|
||||||
|
},
|
||||||
|
"withGlobalTauri": true
|
||||||
|
},
|
||||||
|
"bundle": {
|
||||||
|
"active": true,
|
||||||
|
"targets": "all",
|
||||||
|
"icon": [
|
||||||
|
"icons/32x32.png",
|
||||||
|
"icons/128x128.png",
|
||||||
|
"icons/128x128@2x.png",
|
||||||
|
"icons/icon.icns",
|
||||||
|
"icons/icon.ico"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"$schema": "../node_modules/@tauri-apps/cli/schema.json"
|
||||||
|
}
|
4
tsconfig.json
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
// https://nuxt.com/docs/guide/concepts/typescript
|
||||||
|
"extends": "./.nuxt/tsconfig.json"
|
||||||
|
}
|