Skip to content

Commit c2119df

Browse files
committed
Merge branch 'develop'
1 parent 21e415d commit c2119df

22 files changed

+474
-383
lines changed

README.md

Lines changed: 29 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,55 @@
1-
# Qua
1+
![qua](./logo.png)
22

3-
Open source QDA software running on Vue + Nuxt.js + Supabase and a little bit of Tailwind CSS.
3+
![Nuxt](https://img.shields.io/badge/Nuxt-%23010113?style=for-the-badge&logo=nuxtdotjs)
4+
![Vue](https://img.shields.io/badge/Vue-%23191A22?style=for-the-badge&logo=vuedotjs)
5+
![Supabase](https://img.shields.io/badge/Supabase-%230E0E10?style=for-the-badge&logo=supabase)
46

5-
If you are going to develop this project yourself, you will need to create a `.env` file in the root of the project with the following content:
6-
7-
```bash
8-
SUPABASE_URL=https://your-supabase-url.supabase.co
9-
SUPABASE_KEY=your-supabase-key
10-
```
7+
Open source QDA software, because I don't want to pay for one and I got tired of using excel.
118

129
That should do it for now...more to come.
1310

14-
## Setup
11+
# running locally
1512

16-
Make sure to install the dependencies:
17-
18-
```bash
19-
# npm
20-
npm install
21-
22-
# pnpm
23-
pnpm install
24-
25-
# yarn
26-
yarn install
13+
If you are going to develop this project yourself, you will need to create a `.env` file in the root of the project with the following content:
2714

28-
# bun
29-
bun install
15+
```
16+
SUPABASE_URL=https://your-supabase-url.supabase.co (replace with your supabase url)
17+
SUPABASE_KEY=your-supabase-key (replace with your supabase key)
18+
BASE_URL=http://localhost:3000 (replace with your local development url)
19+
SUPABASE_AUTH_GITHUB_CLIENT_ID=your-github-client-id (optional if using github auth)
20+
SUPABASE_AUTH_GITHUB_CLIENT_SECRET=your-github-client-secret (optional if using github auth)
21+
LOCAL_DEV=true (optional if you will be resetting your database often)
3022
```
3123

32-
## Development Server
24+
The `LOCAL_DEV` variable was created to handle local Supabase storage. When initializing the local Supabase instance, there is currently no way to popultate objects in the `files` storage bucket. This flag points the application to use data from the `public/samples/` directory instead of fetching a signed url from the Supabase storage endpoint. Keep this in mind if you plan to upload data locally as the data will not be able to be accessed. Reference the [FileViewerPanel](./components/FileViewerPanel.vue) component for this implementation.
3325

34-
Start the development server on `http://localhost:3000`:
26+
## Supabase
3527

36-
```bash
37-
# npm
38-
npm run dev
28+
This project takes advantage of [Supabase](https://supabase.com/) for authentication, database, and storage for now. You have two options for setting up Supabase:
3929

40-
# pnpm
41-
pnpm run dev
30+
1) Create a project on [Supabase](https://supabase.com/) and use the provided URL and key in your `.env` file. All data will be stored in your Supabase project on their servers. **TODO: Need to add information on how to set up the database schema.**
31+
2) Run a local instance of Supabase using [Supabase CLI](https://supabase.com/docs/guides/cli/local-development). Grab the URL and key from the CLI output and use them in your `.env` file. All data will be stored locally on your machine. This is recommended for development as this repo contains migrations and seed information in [./supabase](./supabase/). **Not recommended for long term usage as you may lose your data if you are not careful. Instead, use the Supabase Platform resources to ensure your data is backed up, i.e. option 1.** (Requires Docker)
4232

43-
# yarn
44-
yarn dev
45-
46-
# bun
47-
bun run dev
48-
```
33+
Once you have set up Supabase, you can start the application locally.
4934

50-
## Production
35+
## running the app
5136

52-
Build the application for production:
37+
Make sure to install the dependencies:
5338

5439
```bash
5540
# npm
56-
npm run build
57-
58-
# pnpm
59-
pnpm run build
60-
61-
# yarn
62-
yarn build
63-
64-
# bun
65-
bun run build
41+
npm install
6642
```
6743

68-
Locally preview production build:
44+
Start the development server on `http://localhost:3000`:
6945

7046
```bash
7147
# npm
72-
npm run preview
73-
74-
# pnpm
75-
pnpm run preview
48+
npm run dev
49+
```
7650

77-
# yarn
78-
yarn preview
51+
You may want to change the host to `127.0.0.1` if `localhost` is acting slow for you.
7952

80-
# bun
81-
bun run preview
82-
```
53+
## production / deployment
8354

84-
Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information.
55+
Check out the [Nuxt deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information on building and deploying. This project is currently configured for client-side-rendering (CSR) only so you can serve it or deploy it on any static hosting provider.

components/AppHeader.vue

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,6 @@ const logout = async () => {
2525
<div class="tooltip">projects</div>
2626
</NuxtLink>
2727
</div>
28-
<div v-if="loggedIn" class="link-btn">
29-
<NuxtLink to="/dashboard">
30-
<Icon name="fa6-solid:chart-line" />
31-
<div class="tooltip">dashboard</div>
32-
</NuxtLink>
33-
</div>
3428
</div>
3529
<span v-if="projectStore.currentProject && loggedIn" class="splitter" />
3630
<div
@@ -52,18 +46,6 @@ const logout = async () => {
5246
<div class="tooltip">codebook</div>
5347
</NuxtLink>
5448
</div>
55-
<div class="link-btn">
56-
<NuxtLink to="/graph">
57-
<Icon name="fa6-solid:circle-nodes" />
58-
<div class="tooltip">graph</div>
59-
</NuxtLink>
60-
</div>
61-
<div class="link-btn">
62-
<NuxtLink to="/export">
63-
<Icon name="fa6-solid:file-export" />
64-
<div class="tooltip">export</div>
65-
</NuxtLink>
66-
</div>
6749
</div>
6850
<div class="spacer" />
6951
<div class="right-links links">

components/CodePanel.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ const parsedCodes = computed(() => {
5454
codes.value.forEach((c) => {
5555
const newCode = { ...c }
5656
if (newCode.group) {
57-
newCode.codes = []
57+
newCode.children = []
5858
}
5959
codeMap.set(newCode.id, newCode)
6060
})
@@ -64,7 +64,7 @@ const parsedCodes = computed(() => {
6464
if (newCode.parent) {
6565
const parent = codeMap.get(newCode.parent)
6666
if (parent) {
67-
parent.codes.push(newCode)
67+
parent.children.push(newCode)
6868
}
6969
} else {
7070
rootItems.push(newCode)
@@ -262,7 +262,7 @@ async function handleEditSubmit() {
262262
263263
async function handleDeleteSubmit() {
264264
if (contextMenuCode.value.group) {
265-
if (contextMenuCode.value.codes.length > 0) {
265+
if (contextMenuCode.value.children.length > 0) {
266266
alert('The group must be empty first before deleting')
267267
showDeleteModal.value = false
268268
return

components/CodePanelItem.vue

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ function onDrop(e, code) {
4646
4747
function getAllChildren(code) {
4848
let children = []
49-
if (code.group && code.codes.length > 0) {
50-
for (const c of code.codes) {
49+
if (code.group && code.children.length > 0) {
50+
for (const c of code.children) {
5151
children.push(c)
5252
if (c.group) {
5353
children = children.concat(getAllChildren(c))
@@ -95,7 +95,7 @@ function getAllChildren(code) {
9595
{{ code.code }}
9696
</div>
9797
<div
98-
v-if="code.group && code.codes.length > 0"
98+
v-if="code.group && code.children.length > 0"
9999
class="child-colors"
100100
>
101101
<div
@@ -109,14 +109,14 @@ function getAllChildren(code) {
109109
</div>
110110
</div>
111111
<div
112-
v-if="code.group && code.codes.length > 0 && groupOpen"
112+
v-if="code.group && code.children.length > 0 && groupOpen"
113113
class="children-container"
114114
>
115115
<span class="left-bar" :style="{ left: `${10 + level * 15}px` }" />
116116
<div class="children">
117117
<div v-if="groupOpen" class="children">
118118
<CodePanelItem
119-
v-for="c in code.codes"
119+
v-for="c in code.children"
120120
:key="c.id"
121121
v-model:dragged-code="draggedCode"
122122
v-model:drop-target="dropTarget"

components/CodesTab.vue

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,6 @@ const elementWidth = computed(() => {
2020
return props.width / (props.columns + 1)
2121
})
2222
23-
// function getCodesChildren(codes) {
24-
// const children = []
25-
// for (const code of codes) {
26-
// if (!code.group) {
27-
// children.push(code)
28-
// } else if (code.group) {
29-
// children.push(...getCodesChildren(code.codes))
30-
// }
31-
// }
32-
// return children
33-
// }
34-
3523
function getCodesGroupsByLevel(codes) {
3624
const groupsByLevelMap = new Map()
3725
let groups = codes.filter((code) => code.group)
@@ -40,7 +28,7 @@ function getCodesGroupsByLevel(codes) {
4028
while (groups.length > 0) {
4129
groupsByLevelMap.set(level, groups.length)
4230
for (const group of groups) {
43-
nextLevelGroups.push(...group.codes.filter((code) => code.group))
31+
nextLevelGroups.push(...group.children.filter((code) => code.group))
4432
}
4533
groups = nextLevelGroups
4634
nextLevelGroups = []

components/CodesTabGroup.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ const props = defineProps({
5050
</div>
5151
<div v-if="code.group" class="children">
5252
<CodesTabGroup
53-
v-for="(c, i) in code.codes"
53+
v-for="(c, i) in code.children"
5454
:key="c.id"
5555
:code="c"
5656
:depth="depth + 1"

components/DraggableContainer.vue

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<script setup>
2+
const selectedItems = ref([])
3+
const draggedItems = ref([])
4+
const dropTarget = ref(null)
5+
6+
const emit = defineEmits(['onDrop', 'onContextMenu'])
7+
8+
provide('selectedItems', selectedItems)
9+
provide('draggedItems', draggedItems)
10+
provide('dropTarget', dropTarget)
11+
12+
const isDragOver = computed(() => dropTarget.value === 'root')
13+
14+
function onDropRoot(event) {
15+
if (draggedItems.value.length > 0) {
16+
emit('onDrop', { items: draggedItems.value, target: 'root' })
17+
draggedItems.value = []
18+
dropTarget.value = null
19+
}
20+
}
21+
22+
watch(dropTarget, (value) => {
23+
if (value !== null) {
24+
}
25+
})
26+
27+
window.addEventListener('drop', (e) => e.preventDefault())
28+
window.addEventListener('dragover', (e) => e.preventDefault())
29+
30+
onBeforeUnmount(() => {
31+
window.removeEventListener('drop', (e) => e.preventDefault())
32+
window.removeEventListener('dragover', (e) => e.preventDefault())
33+
})
34+
35+
function handleContextMenu(event) {
36+
emit('onContextMenu', { event, target: 'root' })
37+
}
38+
39+
function onDragEnter(event) {
40+
event.preventDefault()
41+
dropTarget.value = 'root'
42+
}
43+
44+
function onDragLeave(event) {
45+
event.preventDefault()
46+
if (dropTarget.value === 'root') {
47+
dropTarget.value = null
48+
}
49+
}
50+
</script>
51+
52+
<template>
53+
<div
54+
class="flex flex-col w-full h-full"
55+
@drop.prevent="onDropRoot"
56+
@contextmenu.prevent="handleContextMenu"
57+
@dragover.prevent
58+
>
59+
<slot></slot>
60+
<div
61+
:class="['grow', { 'bg-sub-alt': isDragOver }]"
62+
@dragenter="onDragEnter"
63+
@dragleave="onDragLeave"
64+
/>
65+
</div>
66+
</template>
67+
68+
<style scoped>
69+
70+
</style>

0 commit comments

Comments
 (0)