Skip to content

Commit

Permalink
Merge pull request #47 from strideynet/kevslashnull/admin-ui
Browse files Browse the repository at this point in the history
Add basic admin UI
  • Loading branch information
strideynet authored Jul 24, 2023
2 parents 9c91cf7 + edbc71e commit 2e4f80f
Show file tree
Hide file tree
Showing 23 changed files with 8,037 additions and 1,275 deletions.
16 changes: 16 additions & 0 deletions web/admin/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module.exports = {
env: {
browser: true,
es2021: true,
node: true,
},
extends: ["eslint:recommended", "@nuxt/eslint-config"],
rules: {
"vue/multi-word-component-names": "off",
"vue/html-self-closing": "off",
"vue/max-attributes-per-line": "off",
"vue/singleline-html-element-content-newline": "off",
"vue/html-indent": "off",
"vue/html-closing-bracket-newline": "off",
},
};
23 changes: 23 additions & 0 deletions web/admin/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Nuxt dev/build outputs
.output
.nuxt
.nitro
.cache
dist

# Node dependencies
node_modules

# Logs
logs
*.log

# Misc
.DS_Store
.fleet
.idea

# Local env files
.env
.env.*
!.env.example
2 changes: 2 additions & 0 deletions web/admin/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
shamefully-hoist=true
strict-peer-dependencies=false
3 changes: 3 additions & 0 deletions web/admin/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"trailingComma": "es5"
}
63 changes: 63 additions & 0 deletions web/admin/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# 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
```

## Development Server

Start the development server on `http://localhost:3000`:

```bash
# npm
npm run dev

# pnpm
pnpm run dev

# yarn
yarn dev
```

## Production

Build the application for production:

```bash
# npm
npm run build

# pnpm
pnpm run build

# yarn
yarn build
```

Locally preview production build:

```bash
# npm
npm run preview

# pnpm
pnpm run preview

# yarn
yarn preview
```

Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information.
70 changes: 70 additions & 0 deletions web/admin/app.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<script setup>
import * as auth from "~/lib/auth";
useHead({
title: "furryli.st Admin",
meta: [{ name: "robots", content: "noindex" }],
link: [
{ rel: "preconnect", href: "https://fonts.googleapis.com" },
{ rel: "preconnect", href: "https://fonts.gstatic.com" },
{
href: "https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap",
rel: "stylesheet",
},
],
bodyAttrs: {
class: "bg-white dark:bg-gray-900 dark:text-white",
},
});
const identifier = ref();
const password = ref();
const error = ref();
const user = await useUser();
async function login() {
error.value = null;
const isSignedIn = await auth
.login(identifier.value, password.value)
.catch((error) => ({ error }));
error.value = !isSignedIn;
}
</script>

<template>
<NuxtPage v-if="user" />
<div v-else class="flex items-center justify-center fixed w-full h-full">
<div
class="mx-auto bg-gray-50 border border-gray-400 dark:border-gray-700 dark:bg-gray-800 py-4 px-5 rounded-lg w-[400px] max-w-[80vw]"
>
<h1 class="text-3xl font-bold mb-4">Login</h1>

<div class="flex flex-col mb-4">
<label class="font-bold mb-1" for="name">Handle</label>
<input
id="name"
v-model="identifier"
class="bg-white dark:bg-gray-900 rounded border border-gray-400 dark:border-gray-700 px-2 py-1"
type="text"
/>
</div>

<div class="flex flex-col mb-4">
<label class="font-bold mb-1" for="password">App password</label>
<input
id="password"
v-model="password"
class="bg-white dark:bg-gray-900 rounded border border-gray-400 dark:border-gray-700 px-2 py-1"
type="password"
/>
</div>

<div class="flex">
<button class="ml-auto px-3 py-2 rounded-lg bg-blue-600" @click="login">
Login
</button>
</div>
</div>
</div>
</template>
35 changes: 35 additions & 0 deletions web/admin/components/core/nav.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<script setup>
import { logout } from "~/lib/auth";
</script>

<template>
<nav
class="flex items-center gap-2 border border-gray-300 dark:border-gray-700 rounded-lg px-4 py-3 mb-5"
>
<nuxt-link href="/" class="mr-1">
<img
class="rounded-lg"
src="/icon-32.webp"
height="32"
width="32"
alt=""
/>
</nuxt-link>
<h1 class="text-xl font-bold">Admin</h1>
<div class="ml-auto flex items-center gap-2">
<img
class="rounded-full"
src="https://cdn.bsky.social/imgproxy/eJpUb3-QB55Yq73mMNdtgroGSVAcbjFB_55EgaNb6HE/rs:fill:1000:1000:1:0/plain/bafkreibhdnzijesikan6bpvmobvhunhtwyvthna32yyyhniosea2hkwa5e@jpeg"
height="32"
width="32"
alt=""
/>
<button
class="text-white bg-gray-700 px-2 py-1 rounded-lg"
@click="logout"
>
Logout
</button>
</div>
</nav>
</template>
31 changes: 31 additions & 0 deletions web/admin/components/shared/avatar.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<script lang="ts" setup>
defineProps<{ url?: string }>();
</script>

<template>
<img
v-if="url"
class="rounded-full"
:src="url"
height="64"
width="64"
alt=""
/>
<svg
v-else
width="64"
height="64"
viewBox="0 0 24 24"
fill="none"
stroke="none"
>
<circle cx="12" cy="12" r="12" fill="#0070ff"></circle>
<circle cx="12" cy="9.5" r="3.5" fill="#fff"></circle>
<path
stroke-linecap="round"
stroke-linejoin="round"
fill="#fff"
d="M 12.058 22.784 C 9.422 22.784 7.007 21.836 5.137 20.262 C 5.667 17.988 8.534 16.25 11.99 16.25 C 15.494 16.25 18.391 18.036 18.864 20.357 C 17.01 21.874 14.64 22.784 12.058 22.784 Z"
></path>
</svg>
</template>
32 changes: 32 additions & 0 deletions web/admin/components/shared/bsky/description.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<script lang="ts" setup>
import { RichText } from "@atproto/api";
import { newAgent } from "~/lib/auth";
const props = defineProps<{ description: string }>();
const segments = ref();
const updateDescription = async () => {
const descriptionRichText = new RichText(
{ text: props.description },
{ cleanNewlines: true }
);
await descriptionRichText.detectFacets(newAgent());
segments.value = [...descriptionRichText.segments()];
};
onMounted(updateDescription);
watch(() => props.description, updateDescription);
</script>
<template>
<div>
<shared-bsky-text
v-for="(segment, index) in segments"
:key="index"
:segment="segment"
/>
<div v-if="!segments" class="whitespace-pre-line">
{{ description }}
</div>
</div>
</template>
25 changes: 25 additions & 0 deletions web/admin/components/shared/bsky/text.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<script lang="ts" setup>
import { RichTextSegment } from "@atproto/api";
defineProps<{ segment: RichTextSegment }>();
</script>

<template>
<nuxt-link
v-if="segment.isLink()"
class="underline hover:no-underline text-blue-500"
:href="segment.link?.uri"
target="_blank"
>
{{ segment.text }}
</nuxt-link>
<nuxt-link
v-else-if="segment.isMention()"
class="underline hover:no-underline text-blue-500"
:href="`https://bsky.app/profile/${segment.mention?.did}`"
target="_blank"
>
{{ segment.text }}
</nuxt-link>
<span v-else class="whitespace-pre-line">{{ segment.text }}</span>
</template>
5 changes: 5 additions & 0 deletions web/admin/components/shared/card.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<template>
<div class="border border-gray-300 dark:border-gray-700 rounded-lg px-4 py-3">
<slot />
</div>
</template>
Loading

1 comment on commit 2e4f80f

@vercel
Copy link

@vercel vercel bot commented on 2e4f80f Jul 24, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.