Update how tags are rendered to allow for custom styling (#1179)
* Updated how tags are rendered to allow for custom styling via space-styles * Wrapped the existing span for a tag with an anchor element <a> to improve ux for screen readers * Added data-tag-name attribute to tags so that given a tag `#my-tag` it will have the attribute `data-tag-name="my-tag"` added to the new `<a>` element wrapper allowing for end users to target tags for styling with a css selector such as `.sb-hashtag[data-tag-name="my-tag"]{...}` * Updated Docspull/1183/head
parent
a56db78194
commit
2020e85a6f
|
@ -584,15 +584,13 @@ const NakedURL = regexParser(
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const Hashtag = regexParser(
|
const Hashtag = regexParser({
|
||||||
{
|
|
||||||
firstCharCode: 35, // #
|
firstCharCode: 35, // #
|
||||||
regex: new RegExp(`^${tagRegex.source}`),
|
regex: new RegExp(`^${tagRegex.source}`),
|
||||||
nodeType: "Hashtag",
|
nodeType: "Hashtag",
|
||||||
className: "sb-hashtag",
|
className: "sb-hashtag-text",
|
||||||
tag: ct.HashtagTag,
|
tag: ct.HashtagTag,
|
||||||
},
|
});
|
||||||
);
|
|
||||||
|
|
||||||
const TaskDeadline = regexParser({
|
const TaskDeadline = regexParser({
|
||||||
firstCharCode: 55357, // 📅
|
firstCharCode: 55357, // 📅
|
||||||
|
|
|
@ -14,6 +14,7 @@ import {
|
||||||
import { Fragment, renderHtml, type Tag } from "./html_render.ts";
|
import { Fragment, renderHtml, type Tag } from "./html_render.ts";
|
||||||
import { isLocalPath } from "@silverbulletmd/silverbullet/lib/resolve";
|
import { isLocalPath } from "@silverbulletmd/silverbullet/lib/resolve";
|
||||||
import type { PageMeta } from "@silverbulletmd/silverbullet/types";
|
import type { PageMeta } from "@silverbulletmd/silverbullet/types";
|
||||||
|
import * as TagConstants from "../../plugs/index/constants.ts";
|
||||||
|
|
||||||
export type MarkdownRenderOptions = {
|
export type MarkdownRenderOptions = {
|
||||||
failOnUnknown?: true;
|
failOnUnknown?: true;
|
||||||
|
@ -335,15 +336,18 @@ function render(
|
||||||
body: url,
|
body: url,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case "Hashtag":
|
case "Hashtag": {
|
||||||
|
const tagText: string = t.children![0].text!;
|
||||||
return {
|
return {
|
||||||
name: "span",
|
name: "a",
|
||||||
attrs: {
|
attrs: {
|
||||||
class: "hashtag",
|
class: "hashtag sb-hashtag",
|
||||||
|
"data-tag-name": tagText.replace("#", ""),
|
||||||
|
href: `/${TagConstants.tagPrefix}${tagText.replace("#", "")}`,
|
||||||
},
|
},
|
||||||
body: t.children![0].text!,
|
body: tagText,
|
||||||
};
|
};
|
||||||
|
}
|
||||||
case "Task": {
|
case "Task": {
|
||||||
let externalTaskRef = "";
|
let externalTaskRef = "";
|
||||||
collectNodesOfType(t, "WikiLinkPage").forEach((wikilink) => {
|
collectNodesOfType(t, "WikiLinkPage").forEach((wikilink) => {
|
||||||
|
|
|
@ -15,6 +15,7 @@ import { fencedCodePlugin } from "./fenced_code.ts";
|
||||||
import { frontmatterPlugin } from "./frontmatter.ts";
|
import { frontmatterPlugin } from "./frontmatter.ts";
|
||||||
import { cleanEscapePlugin } from "./escapes.ts";
|
import { cleanEscapePlugin } from "./escapes.ts";
|
||||||
import { luaDirectivePlugin } from "./lua_directive.ts";
|
import { luaDirectivePlugin } from "./lua_directive.ts";
|
||||||
|
import { hashtagPlugin } from "./hashtag.ts";
|
||||||
|
|
||||||
export function cleanModePlugins(client: Client) {
|
export function cleanModePlugins(client: Client) {
|
||||||
return [
|
return [
|
||||||
|
@ -46,5 +47,6 @@ export function cleanModePlugins(client: Client) {
|
||||||
cleanCommandLinkPlugin(client),
|
cleanCommandLinkPlugin(client),
|
||||||
cleanEscapePlugin(),
|
cleanEscapePlugin(),
|
||||||
luaDirectivePlugin(client),
|
luaDirectivePlugin(client),
|
||||||
|
hashtagPlugin(),
|
||||||
] as Extension[];
|
] as Extension[];
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
import { syntaxTree } from "@codemirror/language";
|
||||||
|
import { Decoration } from "@codemirror/view";
|
||||||
|
import { decoratorStateField } from "./util.ts";
|
||||||
|
import * as Constants from "../../plugs/index/constants.ts";
|
||||||
|
import { extractHashtag } from "../../plug-api/lib/tags.ts";
|
||||||
|
|
||||||
|
export function hashtagPlugin() {
|
||||||
|
return decoratorStateField((state) => {
|
||||||
|
const widgets: any[] = [];
|
||||||
|
|
||||||
|
syntaxTree(state).iterate({
|
||||||
|
enter: ({ type, from, to }) => {
|
||||||
|
if (type.name !== "Hashtag") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tag = state.sliceDoc(from, to);
|
||||||
|
|
||||||
|
if (tag.length === 1) {
|
||||||
|
// Invalid Hashtag, a length of 1 means its just #
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tagName = extractHashtag(tag);
|
||||||
|
|
||||||
|
// Wrap the tag in html anchor element
|
||||||
|
widgets.push(
|
||||||
|
Decoration.mark({
|
||||||
|
tagName: "a",
|
||||||
|
class: "sb-hashtag",
|
||||||
|
attributes: {
|
||||||
|
href: `/${Constants.tagPrefix}${tagName}`,
|
||||||
|
rel: "tag",
|
||||||
|
"data-tag-name": tagName,
|
||||||
|
},
|
||||||
|
}).range(from, to),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return Decoration.set(widgets, true);
|
||||||
|
});
|
||||||
|
}
|
|
@ -97,7 +97,7 @@ export function hideHeaderMarkPlugin() {
|
||||||
widgets.push(
|
widgets.push(
|
||||||
Decoration.mark({
|
Decoration.mark({
|
||||||
tagName: "span",
|
tagName: "span",
|
||||||
class: "sb-hashtag",
|
class: "sb-hashtag-text",
|
||||||
}).range(from, from + 1),
|
}).range(from, from + 1),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ export default function highlightStyles() {
|
||||||
{ tag: t.processingInstruction, class: "sb-meta" },
|
{ tag: t.processingInstruction, class: "sb-meta" },
|
||||||
{ tag: t.punctuation, class: "sb-punctuation" },
|
{ tag: t.punctuation, class: "sb-punctuation" },
|
||||||
{ tag: ct.HorizontalRuleTag, class: "sb-hr" },
|
{ tag: ct.HorizontalRuleTag, class: "sb-hr" },
|
||||||
{ tag: ct.HashtagTag, class: "sb-hashtag" },
|
{ tag: ct.HashtagTag, class: "sb-hashtag-text" },
|
||||||
{ tag: ct.NakedURLTag, class: "sb-naked-url" },
|
{ tag: ct.NakedURLTag, class: "sb-naked-url" },
|
||||||
{ tag: ct.TaskDeadlineTag, class: "sb-task-deadline" },
|
{ tag: ct.TaskDeadlineTag, class: "sb-task-deadline" },
|
||||||
{ tag: ct.NamedAnchorTag, class: "sb-named-anchor" },
|
{ tag: ct.NamedAnchorTag, class: "sb-named-anchor" },
|
||||||
|
|
|
@ -57,7 +57,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a header only contains a tag, it's likely a line containging "#" which may turn into a hashtag, so style it as such instead of a header
|
// If a header only contains a tag, it's likely a line containging "#" which may turn into a hashtag, so style it as such instead of a header
|
||||||
.sb-line-h1:has(> span.sb-hashtag:only-child) {
|
.sb-line-h1:has(> a.sb-hashtag:only-child) {
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
|
@ -276,6 +276,10 @@
|
||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a.sb-hashtag {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
.sb-strikethrough {
|
.sb-strikethrough {
|
||||||
text-decoration: line-through;
|
text-decoration: line-through;
|
||||||
|
|
||||||
|
|
|
@ -22,9 +22,32 @@ Beside these, any number of additional tag-specific and custom [[Attributes]] ca
|
||||||
# Tags
|
# Tags
|
||||||
Every object has a main `tag`, which signifies the type of object being described. In addition, any number of additional tags can be assigned as well via the `tags` attribute. You can use either the main `tag` or any of the `tags` as query sources in [[Live Queries]] — examples below.
|
Every object has a main `tag`, which signifies the type of object being described. In addition, any number of additional tags can be assigned as well via the `tags` attribute. You can use either the main `tag` or any of the `tags` as query sources in [[Live Queries]] — examples below.
|
||||||
|
|
||||||
Here are the currently built-in tags:
|
## Styling
|
||||||
|
You can add custom styles to a tag by leveraging the `data-tag-name` attribute, [CSS Attribute Selectors](https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors) and custom [[Speace Style]]'s. Every tag gets an attribute added to it called `data-tag-name` that is set to the tag name with the `#` symbol stripped out. So given the tag #my-cool-tag the `data-tag-name` attribute would look like:
|
||||||
|
`data-tag-name="my-cool-tag"`.
|
||||||
|
This allows us to do things like change the color of the #my-cool-tag to have a purple background, limegreen text and bold font by adding the following [[Space Style]]:
|
||||||
|
```css
|
||||||
|
.sb-hashtag[data-tag-name="my-cool-tag"] {
|
||||||
|
background: purple;
|
||||||
|
color: limegreen;
|
||||||
|
font-weight: bolder;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Additionally tags written using angle brackets, such as...
|
||||||
|
#<my cool tag>
|
||||||
|
...can be styled via [[Space Style]] like this:
|
||||||
|
```css
|
||||||
|
.sb-hashtag[data-tag-name="my cool tag"] {
|
||||||
|
background: purple;
|
||||||
|
color: limegreen;
|
||||||
|
font-weight: bolder;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## page
|
|
||||||
|
## Built-in tags
|
||||||
|
|
||||||
|
### page
|
||||||
Every page in your space is available via the `page` tag. You can attach _additional_ tags to a page, by either specifying them in the `tags` attribute [[Frontmatter]], or by putting additional [[Tags]] in a stand alone paragraph with no other (textual) content in them, for instance check the very first line of this page that says `#level/intermediate`.
|
Every page in your space is available via the `page` tag. You can attach _additional_ tags to a page, by either specifying them in the `tags` attribute [[Frontmatter]], or by putting additional [[Tags]] in a stand alone paragraph with no other (textual) content in them, for instance check the very first line of this page that says `#level/intermediate`.
|
||||||
|
|
||||||
In addition to `ref` and `tags`, the `page` tag defines a bunch of additional attributes as can be seen in this example query:
|
In addition to `ref` and `tags`, the `page` tag defines a bunch of additional attributes as can be seen in this example query:
|
||||||
|
@ -39,7 +62,7 @@ Note that you can also query this page using the `level/intermediate` directly:
|
||||||
level/intermediate
|
level/intermediate
|
||||||
```
|
```
|
||||||
|
|
||||||
## aspiring-page
|
### aspiring-page
|
||||||
[[Aspiring Pages]] are pages that are linked to, but not yet created.
|
[[Aspiring Pages]] are pages that are linked to, but not yet created.
|
||||||
|
|
||||||
```query
|
```query
|
||||||
|
@ -47,7 +70,7 @@ aspiring-page
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## table
|
### table
|
||||||
Markdown table rows are indexed using the `table` tag, any additional tags can be added using [[Tags]] in any of its cells.
|
Markdown table rows are indexed using the `table` tag, any additional tags can be added using [[Tags]] in any of its cells.
|
||||||
|
|
||||||
| Title | Description Text |
|
| Title | Description Text |
|
||||||
|
@ -62,7 +85,7 @@ table
|
||||||
|
|
||||||
Table headers will be normalized by converting them to lowercase and replacing all non alphanumeric characters with `_`.
|
Table headers will be normalized by converting them to lowercase and replacing all non alphanumeric characters with `_`.
|
||||||
|
|
||||||
## item
|
### item
|
||||||
List items (both bullet point and numbered items) are indexed with the `item` tag, and additional tags can be added using [[Tags]].
|
List items (both bullet point and numbered items) are indexed with the `item` tag, and additional tags can be added using [[Tags]].
|
||||||
|
|
||||||
Here is an example of a #quote item using a custom [[Attributes|attribute]]:
|
Here is an example of a #quote item using a custom [[Attributes|attribute]]:
|
||||||
|
@ -108,7 +131,7 @@ upnext render [[Library/Core/Query/Task]]
|
||||||
Similar to [[#item]], `task` objects have a `parent` attribute when nested (pointing to their parent `item`), and inherit their ancestor’s tags in `itags`.
|
Similar to [[#item]], `task` objects have a `parent` attribute when nested (pointing to their parent `item`), and inherit their ancestor’s tags in `itags`.
|
||||||
|
|
||||||
|
|
||||||
## taskstate
|
### taskstate
|
||||||
[[Plugs/Tasks]] support the default `x` and ` ` states (done and not done), but custom states as well. Custom states used across your space are kept in `taskstate`:
|
[[Plugs/Tasks]] support the default `x` and ` ` states (done and not done), but custom states as well. Custom states used across your space are kept in `taskstate`:
|
||||||
|
|
||||||
* [NOT STARTED] Task 1
|
* [NOT STARTED] Task 1
|
||||||
|
@ -150,7 +173,7 @@ Which then becomes queriable via the `person` tag:
|
||||||
person
|
person
|
||||||
```
|
```
|
||||||
|
|
||||||
## link
|
### link
|
||||||
All page _links_ are tagged with `link`. You cannot attach additional tags to links. The main two attributes of a link are:
|
All page _links_ are tagged with `link`. You cannot attach additional tags to links. The main two attributes of a link are:
|
||||||
|
|
||||||
* `toPage` the page the link is linking _to_
|
* `toPage` the page the link is linking _to_
|
||||||
|
@ -166,7 +189,7 @@ Here is a query that shows some links that appear in this particular page:
|
||||||
link where page = @page.name limit 5
|
link where page = @page.name limit 5
|
||||||
```
|
```
|
||||||
|
|
||||||
## anchor
|
### anchor
|
||||||
[[Markdown/Anchors]] use the $myanchor notation to allow deeplinking into a page and are also indexed and queryable. It is not possible to attach additional tags to an anchor.
|
[[Markdown/Anchors]] use the $myanchor notation to allow deeplinking into a page and are also indexed and queryable. It is not possible to attach additional tags to an anchor.
|
||||||
|
|
||||||
Here is an example query:
|
Here is an example query:
|
||||||
|
@ -175,7 +198,7 @@ Here is an example query:
|
||||||
anchor where page = @page.name
|
anchor where page = @page.name
|
||||||
```
|
```
|
||||||
|
|
||||||
## header
|
### header
|
||||||
Headers (lines starting with `#`, `##` etc.) are indexed as well and queriable.
|
Headers (lines starting with `#`, `##` etc.) are indexed as well and queriable.
|
||||||
|
|
||||||
```query
|
```query
|
||||||
|
@ -183,7 +206,7 @@ header where page = @page.name limit 3
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## tag
|
### tag
|
||||||
The ultimate meta tag is _tag_ itself, which indexes for all tags used, in which page they appear and what their “parent tag” is (the context of the tag: either `page`, `item` or `task`).
|
The ultimate meta tag is _tag_ itself, which indexes for all tags used, in which page they appear and what their “parent tag” is (the context of the tag: either `page`, `item` or `task`).
|
||||||
|
|
||||||
Here are the tags used/defined in this page:
|
Here are the tags used/defined in this page:
|
||||||
|
@ -192,7 +215,7 @@ Here are the tags used/defined in this page:
|
||||||
tag where page = @page.name select name, parent
|
tag where page = @page.name select name, parent
|
||||||
```
|
```
|
||||||
|
|
||||||
## space-config
|
### space-config
|
||||||
This stores all configuration picked up as part of [[Space Config]]
|
This stores all configuration picked up as part of [[Space Config]]
|
||||||
|
|
||||||
```query
|
```query
|
||||||
|
@ -200,16 +223,16 @@ space-config select key
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
# System tags
|
## System tags
|
||||||
The following tags are technically implemented a bit differently than the rest, but they are still available to be queried.
|
The following tags are technically implemented a bit differently than the rest, but they are still available to be queried.
|
||||||
|
|
||||||
## command
|
### command
|
||||||
Enables querying of all [[Commands]] available in SilverBullet as well as their assigned keyboard shortcuts.
|
Enables querying of all [[Commands]] available in SilverBullet as well as their assigned keyboard shortcuts.
|
||||||
```query
|
```query
|
||||||
command order by name limit 5
|
command order by name limit 5
|
||||||
```
|
```
|
||||||
|
|
||||||
## syscall
|
### syscall
|
||||||
Enables querying of all [[PlugOS]] syscalls enabled in your space. Mostly useful in the context of [[Plugs]] and [[Space Script]] development.
|
Enables querying of all [[PlugOS]] syscalls enabled in your space. Mostly useful in the context of [[Plugs]] and [[Space Script]] development.
|
||||||
|
|
||||||
```query
|
```query
|
||||||
|
|
|
@ -69,6 +69,26 @@ button {
|
||||||
button:hover {
|
button:hover {
|
||||||
/* box-shadow: #121212 0 0 0 3px, transparent 0 0 0 0; */
|
/* box-shadow: #121212 0 0 0 3px, transparent 0 0 0 0; */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Add custom styling to a specific tag
|
||||||
|
--> Example Tag: #my-cool-tag */
|
||||||
|
.sb-hashtag[data-tag-name="my-cool-tag"] {
|
||||||
|
background: purple;
|
||||||
|
color: limegreen;
|
||||||
|
font-weight: bolder;
|
||||||
|
}
|
||||||
|
/* --> Example Tag with angle brackets: #<my cool tag> */
|
||||||
|
.sb-hashtag[data-tag-name="my cool tag"] {
|
||||||
|
background: purple;
|
||||||
|
color: limegreen;
|
||||||
|
font-weight: bolder;
|
||||||
|
}
|
||||||
|
/* Custom Styling to all tags
|
||||||
|
.sb-hashtag[data-tag-name] {
|
||||||
|
background: yellow;
|
||||||
|
color: goldenrod;
|
||||||
|
border: 2px dashed goldenrod; */
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Another example can be found in [[Page Decorations#Use case: pimp my page]]
|
Another example can be found in [[Page Decorations#Use case: pimp my page]]
|
||||||
|
|
Loading…
Reference in New Issue