Skip to content

Commit

Permalink
feat: support custom pwa manifest
Browse files Browse the repository at this point in the history
  • Loading branch information
zmh-program committed Mar 12, 2024
1 parent 5366fb7 commit 3335e81
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 10 deletions.
2 changes: 2 additions & 0 deletions app/src/admin/api/system.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export type GeneralState = {
backend: string;
docs: string;
file: string;
pwa_manifest: string;
};

export type MailState = {
Expand Down Expand Up @@ -117,6 +118,7 @@ export const initialSystemState: SystemProps = {
backend: "",
docs: "",
file: "",
pwa_manifest: "",
},
site: {
relay_plan: false,
Expand Down
4 changes: 4 additions & 0 deletions app/src/assets/globals.less
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@
--assistant-border-hover: hsla(218, 100%, 64%, .25);
--assistant-shadow: hsla(218, 100%, 64%, .05);
}

[type='text']:focus, input:where(:not([type])):focus, [type='email']:focus, [type='url']:focus, [type='password']:focus, [type='number']:focus, [type='date']:focus, [type='datetime-local']:focus, [type='month']:focus, [type='search']:focus, [type='tel']:focus, [type='time']:focus, [type='week']:focus, [multiple]:focus, textarea:focus, select:focus {
@apply border-border;
}
}

* {
Expand Down
4 changes: 4 additions & 0 deletions app/src/assets/ui.less
Original file line number Diff line number Diff line change
Expand Up @@ -371,3 +371,7 @@ input[type="number"] {
.text-common {
color: hsl(var(--text)) !important;
}

.error-border {
border-color: hsl(var(--destructive)) !important;
}
37 changes: 34 additions & 3 deletions app/src/components/EditorProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { useTranslation } from "react-i18next";
import "@/assets/common/editor.less";
import { Textarea } from "./ui/textarea.tsx";
import Markdown from "./Markdown.tsx";
import React, { useEffect, useRef, useState } from "react";
import React, { useEffect, useMemo, useRef, useState } from "react";
import { Toggle } from "./ui/toggle.tsx";
import { mobile } from "@/utils/device.ts";
import { Button } from "./ui/button.tsx";
Expand All @@ -23,6 +23,8 @@ type RichEditorProps = {
onChange: (value: string) => void;
maxLength?: number;

formatter?: (value: string) => string;
isInvalid?: (value: string) => boolean;
title?: string;

open?: boolean;
Expand All @@ -38,7 +40,9 @@ function RichEditor({
value,
onChange,
maxLength,
formatter,
submittable,
isInvalid,
onSubmit,
setOpen,
closeOnSubmit,
Expand All @@ -48,6 +52,13 @@ function RichEditor({
const [openPreview, setOpenPreview] = useState(!mobile);
const [openInput, setOpenInput] = useState(true);

const formattedValue = useMemo(() => {
return formatter ? formatter(value) : value;
}, [value, formatter]);
const invalid = useMemo(() => {
return isInvalid ? isInvalid(value) : false;
}, [value, isInvalid]);

const handler = () => {
if (!input.current) return;
const target = input.current as HTMLElement;
Expand Down Expand Up @@ -133,15 +144,18 @@ function RichEditor({
<Textarea
placeholder={t("chat.placeholder-raw")}
value={value}
className={`editor-input`}
className={cn(
`editor-input transition-all`,
invalid && `error-border`,
)}
id={`editor`}
maxLength={maxLength}
onChange={(e) => onChange(e.target.value)}
ref={input}
/>
)}
{openPreview && (
<Markdown className={`editor-preview`} children={value} />
<Markdown className={`editor-preview`} children={formattedValue} />
)}
</div>
</div>
Expand Down Expand Up @@ -198,3 +212,20 @@ function EditorProvider(props: RichEditorProps) {
}

export default EditorProvider;

export function JSONEditorProvider({ ...props }: RichEditorProps) {
return (
<EditorProvider
{...props}
formatter={(value) => `\`\`\`json\n${value}\n\`\`\``}
isInvalid={(value) => {
try {
JSON.parse(value);
return false;
} catch (e) {
return true;
}
}}
/>
);
}
17 changes: 16 additions & 1 deletion app/src/routes/admin/System.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ import {
} from "@/components/ui/dialog.tsx";
import { DialogTitle } from "@radix-ui/react-dialog";
import Require from "@/components/Require.tsx";
import { Loader2, Settings2 } from "lucide-react";
import { Loader2, PencilLine, Settings2 } from "lucide-react";
import { FlexibleTextarea } from "@/components/ui/textarea.tsx";
import Tips from "@/components/Tips.tsx";
import { cn } from "@/components/ui/lib/utils.ts";
Expand All @@ -54,6 +54,7 @@ import { allGroups } from "@/utils/groups.ts";
import { useChannelModels } from "@/admin/hook.tsx";
import { useSelector } from "react-redux";
import { selectSupportModels } from "@/store/chat.ts";
import { JSONEditorProvider } from "@/components/EditorProvider.tsx";

type CompProps<T> = {
data: T;
Expand Down Expand Up @@ -222,6 +223,20 @@ function General({ data, dispatch, onChange }: CompProps<GeneralState>) {
/>
</ParagraphItem>
<ParagraphDescription>{t("admin.system.fileTip")}</ParagraphDescription>
<ParagraphItem>
<Label>PWA Manifest</Label>
<JSONEditorProvider
value={data.pwa_manifest ?? ""}
onChange={(value) =>
dispatch({ type: "update:general.pwa_manifest", value })
}
>
<Button variant={`outline`}>
<PencilLine className={`h-4 w-4 mr-1`} />
{t("edit")}
</Button>
</JSONEditorProvider>
</ParagraphItem>
<ParagraphFooter>
<div className={`grow`} />
<RootDialog />
Expand Down
16 changes: 11 additions & 5 deletions channel/system.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,12 @@ type ApiInfo struct {
}

type generalState struct {
Title string `json:"title" mapstructure:"title"`
Logo string `json:"logo" mapstructure:"logo"`
Backend string `json:"backend" mapstructure:"backend"`
File string `json:"file" mapstructure:"file"`
Docs string `json:"docs" mapstructure:"docs"`
Title string `json:"title" mapstructure:"title"`
Logo string `json:"logo" mapstructure:"logo"`
Backend string `json:"backend" mapstructure:"backend"`
File string `json:"file" mapstructure:"file"`
Docs string `json:"docs" mapstructure:"docs"`
PWAManifest string `json:"pwa_manifest" mapstructure:"pwamanifest"`
}

type siteState struct {
Expand Down Expand Up @@ -98,6 +99,10 @@ func (c *SystemConfig) Load() {

globals.CacheAcceptedExpire = c.GetCacheAcceptedExpire()
globals.CacheAcceptedSize = c.GetCacheAcceptedSize()

if c.General.PWAManifest == "" {
c.General.PWAManifest = utils.ReadPWAManifest()
}
}

func (c *SystemConfig) SaveConfig() error {
Expand Down Expand Up @@ -133,6 +138,7 @@ func (c *SystemConfig) UpdateConfig(data *SystemConfig) error {
c.Common = data.Common

utils.ApplySeo(c.General.Title, c.General.Logo)
utils.ApplyPWAManifest(c.General.PWAManifest)

return c.SaveConfig()
}
Expand Down
52 changes: 51 additions & 1 deletion utils/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,51 @@ func ApplySeo(title, icon string) {
globals.Info("[service] seo optimization applied to index.cache.html")
}

func ApplyPWAManifest(content string) {
// pwa manifest rewrite (site.webmanifest -> site.cache.webmanifest)

if !viper.GetBool("serve_static") {
return
}

if len(content) == 0 {
// read from site.webmanifest if not provided

var err error
content, err = ReadFile("./app/dist/site.webmanifest")
if err != nil {
globals.Warn(fmt.Sprintf("[service] failed to read site.webmanifest: %s", err.Error()))
return
}
}

if err := WriteFile("./app/dist/site.cache.webmanifest", content, true); err != nil {
globals.Warn(fmt.Sprintf("[service] failed to write site.cache.webmanifest: %s", err.Error()))
}

globals.Info("[service] pwa manifest applied to site.cache.webmanifest")
}

func ReadPWAManifest() (content string) {
// read site.cache.webmanifest content or site.webmanifest if not found

if !viper.GetBool("serve_static") {
return
}

if text, err := ReadFile("./app/dist/site.cache.webmanifest"); err == nil && len(text) > 0 {
return text
}

if text, err := ReadFile("./app/dist/site.webmanifest"); err != nil {
globals.Warn(fmt.Sprintf("[service] failed to read site.webmanifest: %s", err.Error()))
} else {
content = text
}

return
}

func RegisterStaticRoute(engine *gin.Engine) {
// static files are in ~/app/dist

Expand All @@ -92,11 +137,16 @@ func RegisterStaticRoute(engine *gin.Engine) {
}

ApplySeo(viper.GetString("system.general.title"), viper.GetString("system.general.logo"))
ApplyPWAManifest(viper.GetString("system.general.pwamanifest"))

// serve / -> index.cache.html
engine.GET("/", func(c *gin.Context) {
c.File("./app/dist/index.cache.html")
})

engine.GET("/site.webmanifest", func(c *gin.Context) {
c.File("./app/dist/site.cache.webmanifest")
})

engine.Use(static.Serve("/", static.LocalFile("./app/dist", true)))
engine.NoRoute(func(c *gin.Context) {
c.File("./app/dist/index.cache.html")
Expand Down

0 comments on commit 3335e81

Please sign in to comment.