diff --git a/assets/js/kbar.js b/assets/js/kbar.js index 96a716a..271a68f 100644 --- a/assets/js/kbar.js +++ b/assets/js/kbar.js @@ -1,283 +1,263 @@ -import React from 'react' +import React, {useState, useEffect, useMemo} from 'react' import { - KBarProvider, - KBarPortal, - KBarPositioner, - KBarAnimator, - KBarSearch, - KBarResults, - useMatches, - useRegisterActions, - useKBar + KBarProvider, + KBarPortal, + KBarPositioner, + KBarAnimator, + KBarSearch, + KBarResults, + useMatches, + useRegisterActions, + useKBar, + createAction } from "kbar"; import classNames from 'classnames'; const searchStyle = { - padding: "12px 16px", - fontSize: "16px", - width: "100%", - boxSizing: "border-box", - outline: "none", - border: "none" + padding: "12px 16px", + fontSize: "16px", + width: "100%", + boxSizing: "border-box", + outline: "none", + border: "none" }; const animatorStyle = { - maxWidth: "600px", - width: "100%", - borderRadius: "8px", - overflow: "hidden" + maxWidth: "600px", + width: "100%", + borderRadius: "8px", + overflow: "hidden" }; const groupNameStyle = { - padding: "8px 16px", - fontSize: "10px", - textTransform: "uppercase", - opacity: 0.5, + padding: "8px 16px", + fontSize: "10px", + textTransform: "uppercase", + opacity: 0.5, }; function RenderResults() { - const { results, rootActionId } = useMatches(); + const { results, rootActionId } = useMatches(); - return ( - - typeof item === "string" ? ( -
{item}
- ) : ( - - ) - } - /> - ); + return ( + + typeof item === "string" ? ( +
{item}
+ ) : ( + + ) + } + /> + ); } const ResultItem = React.forwardRef( - ( - { - action, - active, - currentRootActionId, - }, - ref - ) => { - const ancestors = React.useMemo(() => { - if (!currentRootActionId) return action.ancestors; - const index = action.ancestors.findIndex( - (ancestor) => ancestor.id === currentRootActionId - ); - // +1 removes the currentRootAction; e.g. - // if we are on the "Set theme" parent action, - // the UI should not display "Set theme… > Dark" - // but rather just "Dark" - return action.ancestors.slice(index + 1); - }, [action.ancestors, currentRootActionId]); + ( + { + action, + active, + currentRootActionId, + }, + ref + ) => { + const ancestors = React.useMemo(() => { + if (!currentRootActionId) return action.ancestors; + const index = action.ancestors.findIndex( + (ancestor) => ancestor.id === currentRootActionId + ); + // +1 removes the currentRootAction; e.g. + // if we are on the "Set theme" parent action, + // the UI should not display "Set theme… > Dark" + // but rather just "Dark" + return action.ancestors.slice(index + 1); + }, [action.ancestors, currentRootActionId]); - return ( -
-
- {action.icon && action.icon} -
-
- {ancestors.length > 0 && - ancestors.map((ancestor) => ( - - - {ancestor.name} - - - › - - - ))} - {action.name} -
- {action.subtitle && ( - {action.subtitle} - )} -
-
- {action.shortcut?.length ? ( -
- {action.shortcut.map((sc) => ( - - {sc} - - ))} -
- ) : null} -
- ); - } + return ( +
+
+ {action.icon && action.icon} +
+
+ {ancestors.length > 0 && + ancestors.map((ancestor) => ( + + + {ancestor.name} + + + › + + + ))} + {action.name} +
+ {action.subtitle && ( + {action.subtitle} + )} +
+
+ {action.shortcut?.length ? ( +
+ {action.shortcut.map((sc) => ( + + {sc} + + ))} +
+ ) : null} +
+ ); + } ); -const actions = [ - { - id: "user", - name: "User", - shortcut: ["u"], - keywords: "profile", - perform: () => (window.location.pathname = "user"), - }, - { - id: "user.edit", - name: "Edit User", - shortcut: ["u e"], - keywords: "profile edit settings", - perform: () => (window.location.pathname = "user/settings"), - }, - { - id: "admin", - name: "Admin", - shortcut: ["a"], - keywords: "home", - perform: () => (window.location.pathname = "admin"), - }, - { - id: "notes", - name: "Notes", - shortcut: ["n"], - keywords: "posts", - perform: () => (window.location.pathname = "admin/notes"), - }, - { - id: "notes.new", - name: "New Note", - shortcut: ["n n"], - keywords: "create new", - perform: () => (window.location.pathname = "admin/notes/new"), - }, - { - id: "channels", - name: "Channels", - shortcut: ["c"], - keywords: "channels", - perform: () => (window.location.pathname = "admin/channels"), - }, - { - id: "channels.new", - name: "New Channel", - shortcut: ["n c"], - keywords: "create new", - perform: () => (window.location.pathname = "admin/channels/new"), - }, - { - id: "identities", - name: "Identities", - shortcut: ["i"], - keywords: "identities", - perform: () => (window.location.pathname = "admin/identities"), - }, - { - id: "identities.new", - name: "New Identity", - shortcut: ["n i"], - keywords: "create new", - perform: () => (window.location.pathname = "admin/identities/new"), - }, - { - id: "settings", - name: "Settings", - shortcut: ["s"], - keywords: "settings", - perform: () => (window.location.pathname = "admin/settings"), - }, - { - id: "settings.edit", - name: "Edit Settings", - shortcut: ["s e"], - keywords: "settings edit", - perform: () => (window.location.pathname = "admin/settings/edit"), - } +const staticActions = [ + { + id: "user", + name: "User", + shortcut: ["u"], + keywords: "profile", + perform: () => (window.location.pathname = "user"), + }, + { + id: "user.edit", + name: "Edit User", + shortcut: ["u e"], + keywords: "profile edit settings", + perform: () => (window.location.pathname = "user/settings"), + }, + { + id: "admin", + name: "Admin", + shortcut: ["a"], + keywords: "home", + perform: () => (window.location.pathname = "admin"), + }, + { + id: "notes", + name: "Notes", + shortcut: ["n"], + keywords: "posts", + perform: () => (window.location.pathname = "admin/notes"), + }, + { + id: "notes.new", + name: "New Note", + shortcut: ["n n"], + keywords: "create new", + perform: () => (window.location.pathname = "admin/notes/new"), + }, + { + id: "channels", + name: "Channels", + shortcut: ["c"], + keywords: "channels", + perform: () => (window.location.pathname = "admin/channels"), + }, + { + id: "channels.new", + name: "New Channel", + shortcut: ["n c"], + keywords: "create new", + perform: () => (window.location.pathname = "admin/channels/new"), + }, + { + id: "identities", + name: "Identities", + shortcut: ["i"], + keywords: "identities", + perform: () => (window.location.pathname = "admin/identities"), + }, + { + id: "identities.new", + name: "New Identity", + shortcut: ["n i"], + keywords: "create new", + perform: () => (window.location.pathname = "admin/identities/new"), + }, + { + id: "settings", + name: "Settings", + shortcut: ["s"], + keywords: "settings", + perform: () => (window.location.pathname = "admin/settings"), + }, + { + id: "settings.edit", + name: "Edit Settings", + shortcut: ["s e"], + keywords: "settings edit", + perform: () => (window.location.pathname = "admin/settings/edit"), + } ] -const dynamicActionsList = { - id: "public.home", - name: "Go Home", - shortcut: ["x"], - keywords: "public", - perform: () => (window.location.pathname = "/"), -} +function DynamicResultsProvider() { + const [actions, setActions] = useState([]) + const [notes, setNotes] = useState([]) + const [rerender, setRerender] = useState(true) -function DynamicResultsProvider({children}) { - //const [search, setSearch] = React.useState(""); - //useKBar(state => console.log("state")) - /* - const dynamicActions = React.useMemo(() => { - const searchQuery = search - //const results = await getResults(search); - //return results.map(r => createAction(...)); - console.log(searchQuery) - return dynamicActionsInner - }, [search]) - */ - // const {query, search, options} = useKBar((state) => ({ search: state.searchQuery })) - // const dynamicActions = React.useMemo(() =>{ - // return dynamicActionsInner - // }, [search]) + useEffect(() => { + fetch("/api/admin/notes") + .then(resp => resp.json()) + .then(json => setNotes(json.notes)) + }, [rerender]) - const { query } = useKBar(state => ({ query: state.query })) - const [dynamicActions, setDynamicActions] = React.useState([]) + const noteActions = useMemo(() => notes.map(note => createAction({ + id: note.slug, + name: note.name, + keywords: note.channels.map(c => c.name), + perform: () => (window.location.pathname = `/admin/notes/${note.id}`), + })), [notes]) - React.useEffect(() => { - console.log(query) - //fetchUsers(query).then(setUsers) - setDynamicActions(dynamicActionsList) - }, [query]) - - console.log("mount") - - useRegisterActions(dynamicActionsList, [dynamicActions]) - - return ([children]) + useRegisterActions([...staticActions, ...noteActions], [noteActions]) } export default function KBar() { - return ( - - - - - - - - - - - - - ) + return ( + + + + + + + + + + + + ) } \ No newline at end of file diff --git a/lib/chiya/channels/channel.ex b/lib/chiya/channels/channel.ex index 9e390a9..0500e86 100644 --- a/lib/chiya/channels/channel.ex +++ b/lib/chiya/channels/channel.ex @@ -2,6 +2,7 @@ defmodule Chiya.Channels.Channel do use Ecto.Schema import Ecto.Changeset + @derive {Jason.Encoder, only: [:id, :name, :content, :slug, :visibility]} schema "channels" do field :content, :string field :name, :string diff --git a/lib/chiya/notes/note.ex b/lib/chiya/notes/note.ex index b0e6786..27c0e8a 100644 --- a/lib/chiya/notes/note.ex +++ b/lib/chiya/notes/note.ex @@ -2,6 +2,7 @@ defmodule Chiya.Notes.Note do use Ecto.Schema import Ecto.Changeset + @derive {Jason.Encoder, only: [:id, :name, :content, :slug, :channels]} schema "notes" do field :content, :string field :kind, Ecto.Enum, values: [:post, :bookmark] diff --git a/lib/chiya_web/controllers/api_controller.ex b/lib/chiya_web/controllers/api_controller.ex new file mode 100644 index 0000000..7f0cd01 --- /dev/null +++ b/lib/chiya_web/controllers/api_controller.ex @@ -0,0 +1,8 @@ +defmodule ChiyaWeb.ApiController do + use ChiyaWeb, :controller + + def notes(conn, _params) do + notes = Chiya.Notes.list_notes() + json(conn, %{notes: notes}) + end +end \ No newline at end of file diff --git a/lib/chiya_web/router.ex b/lib/chiya_web/router.ex index 717e4eb..8467060 100644 --- a/lib/chiya_web/router.ex +++ b/lib/chiya_web/router.ex @@ -25,9 +25,11 @@ defmodule ChiyaWeb.Router do end # Other scopes may use custom stacks. - # scope "/api", ChiyaWeb do - # pipe_through :api - # end + scope "/api", ChiyaWeb do + pipe_through :api + + get "/admin/notes", ApiController, :notes + end # Enable LiveDashboard and Swoosh mailbox preview in development if Application.compile_env(:chiya, :dev_routes) do