Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add <FileTree> component #1308

Merged
merged 46 commits into from
Mar 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
4dd1abb
feat: add basic file tree rehype processor
HiDeoo Dec 20, 2023
584bd15
feat: add basic file tree component
HiDeoo Dec 20, 2023
677f82a
feat: add basic file icon support
HiDeoo Dec 21, 2023
9f9a894
feat: folder icon
HiDeoo Dec 21, 2023
e425274
feat: file icon
HiDeoo Dec 21, 2023
39e5e20
feat: port old icons and add new ones
HiDeoo Dec 22, 2023
64a0a2b
refactor: simplify partial definitions
HiDeoo Dec 22, 2023
79c35d3
chore: add demo page
HiDeoo Dec 22, 2023
b3fe1c9
feat: add localized directory label
HiDeoo Dec 22, 2023
a24c273
feat: validation
HiDeoo Dec 22, 2023
120114d
test: add file tree tests
HiDeoo Dec 22, 2023
df57a49
docs: update demo
HiDeoo Dec 22, 2023
1502dc7
refactor: tweak error messsages
HiDeoo Dec 22, 2023
289b6df
docs: add file tree component documentation
HiDeoo Dec 22, 2023
e8c5c4b
docs: update i18n ui strings
HiDeoo Dec 22, 2023
1ff9298
docs: replace file tree component
HiDeoo Dec 22, 2023
c782abd
refactor: component name
HiDeoo Dec 22, 2023
068b937
chore: add changesets
HiDeoo Dec 22, 2023
93a654d
Merge branch 'main' into hd-file-tree
HiDeoo Jan 15, 2024
4aecb0c
Merge branch 'main' into hd-file-tree
HiDeoo Feb 15, 2024
a69c63e
feat: add file icons generator package
HiDeoo Feb 20, 2024
8406573
docs: revert docs file tree component replacements
HiDeoo Feb 20, 2024
7e91fb8
Merge branch 'main' into hd-file-tree
HiDeoo Feb 20, 2024
1e4d5f9
chore: update icons changeset
HiDeoo Feb 20, 2024
23f6727
Merge branch 'main' into hd-file-tree
HiDeoo Feb 23, 2024
e9b281d
chore: clean file icons generator `package.json` file
HiDeoo Feb 23, 2024
8f267eb
chore: ignore file icons generator in changeset configuration
HiDeoo Feb 23, 2024
cc6ecd9
fix: add `fileTree.directory` ui string for `zh-TW`
HiDeoo Feb 23, 2024
8e9ffda
feat: prefix all Seti icons with `seti:`
HiDeoo Feb 23, 2024
71ef005
feat: make Seti repo branch configurable
HiDeoo Feb 23, 2024
a941780
fix: improve file tree component errors wording
HiDeoo Feb 23, 2024
df1d7cd
fix: udpate astro icon
HiDeoo Feb 23, 2024
d93f1a3
docs: move components icon section to the bottom of the page
HiDeoo Feb 23, 2024
64d0310
fix: add any point wrapping to icons list in the docs
HiDeoo Feb 23, 2024
f3dec10
chore: update changesets
HiDeoo Feb 23, 2024
0fbbe3f
fix: add prefix support to aliases
HiDeoo Feb 26, 2024
bdb3824
chore: slim down changeset
HiDeoo Feb 26, 2024
60e79b2
docs: apply suggested improvements
HiDeoo Feb 26, 2024
666ea8b
Merge branch 'main' into hd-file-tree
HiDeoo Feb 26, 2024
bf14d2e
fix: update error snapshots
HiDeoo Feb 26, 2024
3d3e4ce
feat: add `mdx` icon and mapping
HiDeoo Feb 27, 2024
783b9ee
feat: add Markdown backticks in error messages
HiDeoo Feb 27, 2024
d35bdf2
fix: update file tree validation error documentation anchor
HiDeoo Feb 27, 2024
311b109
chore: remove file tree demo page
HiDeoo Feb 27, 2024
d9dfc9f
refactor: use rehype in fragment mode
HiDeoo Feb 27, 2024
9e881ec
Merge branch 'main' into hd-file-tree
delucis Mar 1, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"access": "public",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": ["starlight-docs", "@example/*"],
"ignore": ["starlight-docs", "@example/*", "starlight-file-icons-generator"],
"___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": {
"onlyUpdatePeerDependentsWhenOutOfRange": true
}
Expand Down
5 changes: 5 additions & 0 deletions .changeset/hot-paws-work.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@astrojs/starlight': minor
---

Adds `<FileTree>` component to display the structure of a directory.
5 changes: 5 additions & 0 deletions .changeset/mighty-adults-help.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@astrojs/starlight': minor
---

Adds 144 new file-type icons from the [Seti UI icon set](https://github.com/jesseweed/seti-ui#current-icons), available with the `seti:` prefix, e.g. `seti:javascript`.
5 changes: 5 additions & 0 deletions .changeset/smart-planets-flow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@astrojs/starlight': minor
---

Adds 5 new icons: `astro`, `biome`, `bun`, `mdx`, and `pnpm`.
1 change: 1 addition & 0 deletions docs/src/components/icons-list.astro
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ const icons = Object.keys(Icons) as (keyof typeof Icons)[];
font-size: var(--sl-text-sm);
gap: 0.25rem;
margin: 0;
overflow-wrap: anywhere;
padding: 0.75rem;
background: none;
}
Expand Down
103 changes: 76 additions & 27 deletions docs/src/content/docs/guides/components.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -233,33 +233,6 @@ Other content is also supported in asides.
Starlight also provides a custom syntax for rendering asides in Markdown and MDX as an alternative to the `<Aside>` component.
See the [“Authoring Content in Markdown”](/guides/authoring-content/#asides) guide for details of the custom syntax.

### Icon

import { Icon } from '@astrojs/starlight/components';
import IconsList from '~/components/icons-list.astro';

Starlight provides a set of common icons that you can display in your content using the `<Icon>` component.

Each `<Icon>` requires a [`name`](#all-icons) and can optionally include a `label`, `size`, and `color` attribute.

```mdx
# src/content/docs/example.mdx

import { Icon } from '@astrojs/starlight/components';

<Icon name="star" color="goldenrod" size="2rem" />
```

The code above generates the following on the page:

<Icon name="star" color="goldenrod" size="2rem" />

#### All icons

A list of all available icons is shown below with their associated names. Click an icon to copy the component code for it.

<IconsList />

### Code

Use the `<Code>` component to render syntax highlighted code when using a [Markdown code block](/guides/authoring-content/#code-blocks) is not possible, for example, to render data coming from external sources like files, databases, or APIs.
Expand Down Expand Up @@ -305,3 +278,79 @@ The code above generates the following on the page:
import importedCode from '/src/env.d.ts?raw';

<Code code={importedCode} lang="ts" title="src/env.d.ts" />

### File Tree

Use the `<FileTree>` component to display the structure of a directory with file icons and collapsible sub-directories.

Specify the structure of your files and directories with an [unordered Markdown list](https://www.markdownguide.org/basic-syntax/#unordered-lists) inside `<FileTree>`.
Create a sub-directory using a nested list or add a `/` to the end of a list item to render it as a directory without specific content.

The following syntax can be used to customize the appearance of the file tree:

- Highlight a file or directory by making its name bold, e.g. `**README.md**`.
- Add a comment to a file or directory by adding more text after the name.
- Add placeholder files and directories by using either `...` or `…` as the name.

```mdx
# src/content/docs/example.mdx

import { FileTree } from '@astrojs/starlight/components';

<FileTree>

- astro.config.mjs an **important** file
- package.json
- README.md
- src
- components
- **Header.astro**
- …
- pages/

</FileTree>
```

The above code generates the following on the page:

import { FileTree } from '@astrojs/starlight/components';

<FileTree>

- astro.config.mjs an **important** file
- package.json
- README.md
- src
- components
- **Header.astro**
- …
- pages/

</FileTree>

### Icon

import { Icon } from '@astrojs/starlight/components';
import IconsList from '~/components/icons-list.astro';

Starlight provides a set of common icons that you can display in your content using the `<Icon>` component.

Each `<Icon>` requires a [`name`](#all-icons) and can optionally include a `label`, `size`, and `color` attribute.

```mdx
# src/content/docs/example.mdx

import { Icon } from '@astrojs/starlight/components';

<Icon name="star" color="goldenrod" size="2rem" />
```

The code above generates the following on the page:

<Icon name="star" color="goldenrod" size="2rem" />

#### All icons

A list of all available icons is shown below with their associated names. Click an icon to copy the component code for it.

<IconsList />
3 changes: 2 additions & 1 deletion docs/src/content/docs/guides/i18n.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,8 @@ You can provide translations for additional languages you support — or overrid
"aside.note": "Note",
"aside.tip": "Tip",
"aside.caution": "Caution",
"aside.danger": "Danger"
"aside.danger": "Danger",
"fileTree.directory": "Directory"
}
```

Expand Down
93 changes: 93 additions & 0 deletions packages/file-icons-generator/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import type { Definitions } from '../starlight/user-components/rehype-file-tree';

export const seti = {
/** The GitHub repository containing the Seti UI theme using the `username/repo` format. */
repo: 'jesseweed/seti-ui',
/** The repository branch to use. */
branch: 'master',
/** The path to the icon mapping file in the repository. */
mapping: 'styles/components/icons/mapping.less',
/** The path to the icon font file in the repository. */
font: 'styles/_fonts/seti/seti.woff',
/**
* Some Seti UI icons share identical SVG for multiple icons. When converted to a font, identical
* SVGs will be saved as one unique glyph with its name being the first icon encountered. The
* other names are lost in the process and only their associated unicode character will be kept.
* As we want to access icons by their name, we need to manually map the names of identical SVGs
* to the icon name that is embedded in the font glyph.
* Note that when this happens, an error will be thrown indicating which icon is affected.
*/
aliases: {
coffee: 'cjsx',
html_erb: 'html',
less: 'json',
},
/**
* Seti UI icons can be overriden to use another Seti UI icon.
* The key is the icon name to override and the value is the Seti icon name to use instead.
* The reason to support aliasing to another Seti UI icon is that some Seti UI icons can be
* almost identical. For example, the `npm_ignored` icon used for `npm-debug.log` files is
* identical to the `npm` icon except the npm logo is shifted 1px to the right. There is no need
* to provide a separate icon for this case and we can just use the `npm` icon instead.
*/
overrides: {
ejs: 'html',
go: 'go2',
npm_ignored: 'npm',
},
/**
* Allows for renaming Seti UI icons to another name.
* For example, the Visual Studio Code icon used for Go is named `go2` and this is not the name
* we want to expose to the user.
* Note that renaming an icon happens after overrides are applied.
*/
renames: {
go2: 'go',
},
/**
* A list of Seti UI icons to ignore.
* Each entry should be commented with the reason why the icon is ignored.
*/
ignores: [
// The ReasonML SVG icon contains a path issue that makes it render a plain square instead of a
// square with the "RE" letters when converted to a font.
// This is also an issue in Visual Studio Code but considering that in Starlight, all the icons
// are also available with the `<Icon>` component, it's better to ignore it for now instead of
// providing an icon with no meaning.
delucis marked this conversation as resolved.
Show resolved Hide resolved
'reasonml',
],
};

export const starlight = {
/** The path of the generated file in the Starlight package directory. */
output: 'user-components/file-tree-icons.ts',
/** A prefix to add to the Seti icon names. */
prefix: 'seti:',
/**
* The Starlight `<Icon>` component viewBox size.
* @see {@link file://../starlight/user-components/Icon.astro}
*/
iconViewBoxSize: 24,
/**
* Extra definitions for the `<FileTree>` component that add mappings using built-in Starlight
* icons.
*/
definitions: {
files: {
'astro.config.js': 'astro',
'astro.config.mjs': 'astro',
'astro.config.cjs': 'astro',
'astro.config.ts': 'astro',
'pnpm-debug.log': 'pnpm',
'pnpm-lock.yaml': 'pnpm',
'pnpm-workspace.yaml': 'pnpm',
'biome.json': 'biome',
'bun.lockb': 'bun',
},
extensions: {
'.astro': 'astro',
'.mdx': 'mdx',
},
partials: {},
} satisfies Definitions,
};
24 changes: 24 additions & 0 deletions packages/file-icons-generator/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { writeDefinitionsAndSVGs } from './utils/file';
import { getIconSvgPaths } from './utils/font';
import { fetchFont, fetchMapping, parseMapping } from './utils/seti';

/**
* Script generating definitions used by the Starlight `<FileTree>` component and associated SVGs.
*
* To do so, it fetches the Seti UI icon mapping file and font from GitHub, parses the mapping to
* generate the definitions and a list of icons to extract as SVGs, and finally extracts the SVGs
* from the font and writes the definitions and SVGs to the Starlight package in a file ready to be
* consumed by Starlight.
*
* @see {@link file://./config.ts} for the configuration used by this script.
* @see {@link file://../starlight/user-components/file-tree-icons.ts} for the generated file.
* @see {@link https://opentype.js.org/glyph-inspector.html} for a font glyph inspector.
*/

const mapping = await fetchMapping();
const { definitions, icons } = parseMapping(mapping);

const font = await fetchFont();
const svgPaths = getIconSvgPaths(icons, definitions, font);

await writeDefinitionsAndSVGs(definitions, svgPaths);
18 changes: 18 additions & 0 deletions packages/file-icons-generator/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "starlight-file-icons-generator",
"version": "0.1.0",
"description": "Generates Starlight file icons based on the Seti UI theme",
"private": true,
"scripts": {
"build": "tsx ."
},
"license": "MIT",
"dependencies": {
"opentype.js": "^1.3.4",
"tsx": "^4.7.1"
},
delucis marked this conversation as resolved.
Show resolved Hide resolved
"devDependencies": {
"@types/opentype.js": "^1.3.8"
},
"type": "module"
}
81 changes: 81 additions & 0 deletions packages/file-icons-generator/utils/file.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { spawn } from 'node:child_process';
import fs from 'node:fs/promises';
import path from 'node:path';
import { starlight } from '../config';
import type { Definitions } from '../../starlight/user-components/rehype-file-tree';

const copyrightNotice = `/**
* Based on https://github.com/elviswolcott/seti-icons which
* is derived from https://github.com/jesseweed/seti-ui/
*
* Copyright (c) 2014 Jesse Weed
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/`;

const generatedFileHeader = `/**
* This file was generated by the \`file-icons-generator\` package.
* Do not edit this file directly as it will be overwritten.
*/`;

/** Write the generated definitions and SVGs to the Starlight package. */
export async function writeDefinitionsAndSVGs(
definitions: Definitions,
svgPaths: Record<string, string>
) {
const content = `${generatedFileHeader}

import type { Definitions } from './rehype-file-tree.ts';

${copyrightNotice}
export const definitions: Definitions = ${JSON.stringify(definitions)};

export const FileIcons = ${JSON.stringify(svgPaths)};
`;

const filePath = path.join('..', 'starlight', starlight.output);

await fs.writeFile(filePath, content);

await prettifyFile(path.resolve(filePath));
}

/** Run Prettier on a generated file. */
function prettifyFile(filePath: string) {
return new Promise<void>((resolve, reject) => {
const child = spawn('pnpm', ['prettier', '-w', filePath], {
cwd: '../..',
stdio: [],
});

const error = new Error('Failed to run Prettier on the generated file.');

child.on('error', () => reject(error));
child.on('close', (code) => {
if (code !== 0) {
reject(error);

return;
}

resolve();
});
});
}
Loading
Loading