mirror of
https://github.com/hay-kot/homebox.git
synced 2024-12-18 13:06:32 +00:00
feat: link implementation (#100)
* link implementation * add docs for links * use btn instead of badge
This commit is contained in:
parent
97a34475c8
commit
2d34557f69
9 changed files with 120 additions and 6 deletions
|
@ -61,11 +61,13 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk
|
||||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||||
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
|
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
|
||||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
|
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||||
github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI=
|
github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI=
|
||||||
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||||
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
|
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
|
||||||
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
|
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
|
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
@ -75,6 +77,8 @@ github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||||
github.com/rs/zerolog v1.28.0 h1:MirSo27VyNi7RJYP3078AA1+Cyzd2GB66qy3aUHvsWY=
|
github.com/rs/zerolog v1.28.0 h1:MirSo27VyNi7RJYP3078AA1+Cyzd2GB66qy3aUHvsWY=
|
||||||
github.com/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0=
|
github.com/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0=
|
||||||
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
|
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
|
||||||
|
github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU=
|
||||||
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
|
|
@ -13,7 +13,7 @@ docker run --name=homebox \
|
||||||
|
|
||||||
## Docker-Compose
|
## Docker-Compose
|
||||||
|
|
||||||
```yml
|
```yaml
|
||||||
version: "3.4"
|
version: "3.4"
|
||||||
|
|
||||||
services:
|
services:
|
||||||
|
|
16
docs/docs/tips-tricks.md
Normal file
16
docs/docs/tips-tricks.md
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
# Tips and Tricks
|
||||||
|
|
||||||
|
## Custom Fields
|
||||||
|
|
||||||
|
Custom fields are a great way to add any extra information to your item. The following types are supported:
|
||||||
|
|
||||||
|
- [x] Text
|
||||||
|
- [ ] Integer (Future)
|
||||||
|
- [ ] Boolean (Future)
|
||||||
|
- [ ] Timestamp (Future)
|
||||||
|
|
||||||
|
Custom fields are appended to the main details section of your item.
|
||||||
|
|
||||||
|
!!! tip
|
||||||
|
Homebox Custom Fields also have special support for URLs. Provide a URL (`https://google.com`) and it will be automatically converted to a clickable link in the UI. Optionally, you can also use markdown syntax to add a custom text to the button. `[Google](https://google.com)`
|
||||||
|
|
|
@ -47,5 +47,6 @@ markdown_extensions:
|
||||||
nav:
|
nav:
|
||||||
- Home: index.md
|
- Home: index.md
|
||||||
- Quick Start: quick-start.md
|
- Quick Start: quick-start.md
|
||||||
|
- Tips and Tricks: tips-tricks.md
|
||||||
- Importing Data: import-csv.md
|
- Importing Data: import-csv.md
|
||||||
- Building The Binary: build.md
|
- Building The Binary: build.md
|
||||||
|
|
|
@ -9,6 +9,14 @@
|
||||||
<slot :name="detail.slot || detail.name" v-bind="{ detail }">
|
<slot :name="detail.slot || detail.name" v-bind="{ detail }">
|
||||||
<DateTime v-if="detail.type == 'date'" :date="detail.text" />
|
<DateTime v-if="detail.type == 'date'" :date="detail.text" />
|
||||||
<Currency v-else-if="detail.type == 'currency'" :amount="detail.text" />
|
<Currency v-else-if="detail.type == 'currency'" :amount="detail.text" />
|
||||||
|
<template v-else-if="detail.type === 'link'">
|
||||||
|
<div class="tooltip tooltip-primary tooltip-right" :data-tip="detail.href">
|
||||||
|
<a class="btn btn-primary btn-xs" :href="detail.href" target="_blank">
|
||||||
|
<Icon name="mdi-open-in-new" class="mr-2 swap-on"></Icon>
|
||||||
|
{{ detail.text }}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
{{ detail.text }}
|
{{ detail.text }}
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -15,7 +15,13 @@ type CurrencyDetail = BaseDetail & {
|
||||||
text: string;
|
text: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type CustomDetail = DateDetail | CurrencyDetail;
|
type LinkDetail = BaseDetail & {
|
||||||
|
type: "link";
|
||||||
|
text: string;
|
||||||
|
href: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CustomDetail = DateDetail | CurrencyDetail | LinkDetail;
|
||||||
|
|
||||||
export type Detail = BaseDetail & {
|
export type Detail = BaseDetail & {
|
||||||
text: StringLike;
|
text: StringLike;
|
||||||
|
|
32
frontend/composables/utils.test.ts
Normal file
32
frontend/composables/utils.test.ts
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
import { describe, expect, test } from "vitest";
|
||||||
|
import { maybeUrl } from "./utils";
|
||||||
|
|
||||||
|
describe("maybeURL works as expected", () => {
|
||||||
|
test("basic valid URL case", () => {
|
||||||
|
const result = maybeUrl("https://example.com");
|
||||||
|
expect(result.isUrl).toBe(true);
|
||||||
|
expect(result.url).toBe("https://example.com");
|
||||||
|
expect(result.text).toBe("Link");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("special URL syntax", () => {
|
||||||
|
const result = maybeUrl("[My Text](http://example.com)");
|
||||||
|
expect(result.isUrl).toBe(true);
|
||||||
|
expect(result.url).toBe("http://example.com");
|
||||||
|
expect(result.text).toBe("My Text");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("not a url", () => {
|
||||||
|
const result = maybeUrl("not a url");
|
||||||
|
expect(result.isUrl).toBe(false);
|
||||||
|
expect(result.url).toBe("");
|
||||||
|
expect(result.text).toBe("");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("malformed special syntax", () => {
|
||||||
|
const result = maybeUrl("[My Text(http://example.com)");
|
||||||
|
expect(result.isUrl).toBe(false);
|
||||||
|
expect(result.url).toBe("");
|
||||||
|
expect(result.text).toBe("");
|
||||||
|
});
|
||||||
|
});
|
|
@ -33,3 +33,35 @@ export function fmtCurrency(value: number | string, currency = "USD", locale = "
|
||||||
});
|
});
|
||||||
return formatter.format(value);
|
return formatter.format(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type MaybeUrlResult = {
|
||||||
|
isUrl: boolean;
|
||||||
|
url: string;
|
||||||
|
text: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function maybeUrl(str: string): MaybeUrlResult {
|
||||||
|
const result: MaybeUrlResult = {
|
||||||
|
isUrl: str.startsWith("http://") || str.startsWith("https://"),
|
||||||
|
url: "",
|
||||||
|
text: "",
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!result.isUrl && !str.startsWith("[")) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str.startsWith("[")) {
|
||||||
|
const match = str.match(/\[(.*)\]\((.*)\)/);
|
||||||
|
if (match && match.length === 3) {
|
||||||
|
result.isUrl = true;
|
||||||
|
result.text = match[1];
|
||||||
|
result.url = match[2];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result.url = str;
|
||||||
|
result.text = "Link";
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
|
@ -96,10 +96,25 @@
|
||||||
name: "Notes",
|
name: "Notes",
|
||||||
text: item.value?.notes,
|
text: item.value?.notes,
|
||||||
},
|
},
|
||||||
...item.value.fields.map(field => ({
|
...item.value.fields.map(field => {
|
||||||
name: field.name,
|
/**
|
||||||
text: field.textValue,
|
* Support Special URL Syntax
|
||||||
})),
|
*/
|
||||||
|
const url = maybeUrl(field.textValue);
|
||||||
|
if (url.isUrl) {
|
||||||
|
return {
|
||||||
|
name: field.name,
|
||||||
|
text: url.text,
|
||||||
|
type: "link",
|
||||||
|
href: url.url,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: field.name,
|
||||||
|
text: field.textValue,
|
||||||
|
};
|
||||||
|
}),
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue