mirror of
https://github.com/sourcegraph/sourcegraph.git
synced 2026-02-06 17:51:57 +00:00
feat(search/svelte): Support more file icons (#63181)
Closes SRCH-452
Until this commit both the React and Svelte apps have used the same code
to determine the correct file icon. That code however still held
separate logic for the two apps with the result that our file icon set
for the Svelte app was a lot smaller.
This commit separates the logic and now makes use of `unplugin-icons` in
the Svelte app.
I tried to use `unplugin-icons` in the React so that the code could
continued to be shared but I couldn't get it to work.
Note that I didn't use the exact same icons as in the React app. I
wanted to minimize the number of different icon sets we are using.
## Test plan
Builds without error, manual testing.
This commit is contained in:
parent
378977912f
commit
1c28f460ae
@ -82,7 +82,10 @@ BUILD_DEPS = [
|
||||
":node_modules/@graphql-codegen/typescript",
|
||||
":node_modules/@graphql-codegen/typescript-operations",
|
||||
":node_modules/@graphql-tools/utils",
|
||||
":node_modules/@iconify-json/devicon-plain",
|
||||
":node_modules/@iconify-json/lucide",
|
||||
":node_modules/@iconify-json/ph",
|
||||
":node_modules/@iconify-json/simple-icons",
|
||||
":node_modules/@melt-ui/svelte",
|
||||
":node_modules/@sentry/sveltekit",
|
||||
":node_modules/@sourcegraph/branded",
|
||||
|
||||
@ -31,7 +31,10 @@
|
||||
"@graphql-codegen/typescript-operations": "^4.0.1",
|
||||
"@graphql-tools/utils": "^10.0.11",
|
||||
"@graphql-typed-document-node/core": "^3.2.0",
|
||||
"@iconify-json/devicon-plain": "^1.1.42",
|
||||
"@iconify-json/lucide": "^1.1.188",
|
||||
"@iconify-json/ph": "^1.1.13",
|
||||
"@iconify-json/simple-icons": "^1.1.104",
|
||||
"@playwright/test": "1.42.1",
|
||||
"@storybook/addon-essentials": "^8.0.5",
|
||||
"@storybook/addon-interactions": "^7.2.0",
|
||||
|
||||
77
client/web-sveltekit/src/auto-imports.d.ts
vendored
77
client/web-sveltekit/src/auto-imports.d.ts
vendored
@ -5,6 +5,7 @@
|
||||
// Generated by unplugin-auto-import
|
||||
export {}
|
||||
declare global {
|
||||
const IDeviconPlainJava: typeof import('~icons/devicon-plain/java')['default']
|
||||
const ILucideArrowDownFromLine: typeof import('~icons/lucide/arrow-down-from-line')['default']
|
||||
const ILucideArrowLeftFromLine: typeof import('~icons/lucide/arrow-left-from-line')['default']
|
||||
const ILucideArrowRightFromLine: typeof import('~icons/lucide/arrow-right-from-line')['default']
|
||||
@ -13,7 +14,13 @@ declare global {
|
||||
const ILucideChevronLast: typeof import('~icons/lucide/chevron-last')['default']
|
||||
const ILucideChevronLeft: typeof import('~icons/lucide/chevron-left')['default']
|
||||
const ILucideChevronRight: typeof import('~icons/lucide/chevron-right')['default']
|
||||
const ILucideDatabase: typeof import('~icons/lucide/database')['default']
|
||||
const ILucideEarth: typeof import('~icons/lucide/earth')['default']
|
||||
const ILucideEllipsis: typeof import('~icons/lucide/ellipsis')['default']
|
||||
const ILucideFileCode: typeof import('~icons/lucide/file-code')['default']
|
||||
const ILucideFileJson: typeof import('~icons/lucide/file-json')['default']
|
||||
const ILucideFileTerminal: typeof import('~icons/lucide/file-terminal')['default']
|
||||
const ILucideFileText: typeof import('~icons/lucide/file-text')['default']
|
||||
const ILucideFolder: typeof import('~icons/lucide/folder')['default']
|
||||
const ILucideGitCompareArrows: typeof import('~icons/lucide/git-compare-arrows')['default']
|
||||
const ILucideGitMerge: typeof import('~icons/lucide/git-merge')['default']
|
||||
@ -23,7 +30,77 @@ declare global {
|
||||
const ILucidePanelLeftClose: typeof import('~icons/lucide/panel-left-close')['default']
|
||||
const ILucidePanelLeftOpen: typeof import('~icons/lucide/panel-left-open')['default']
|
||||
const ILucideRegex: typeof import('~icons/lucide/regex')['default']
|
||||
const ILucideSettings: typeof import('~icons/lucide/settings')['default']
|
||||
const ILucideSetttings: typeof import('~icons/lucide/setttings')['default']
|
||||
const ILucideSquareSlash: typeof import('~icons/lucide/square-slash')['default']
|
||||
const ILucideStar: typeof import('~icons/lucide/star')['default']
|
||||
const ILucideX: typeof import('~icons/lucide/x')['default']
|
||||
const IPhFileJpgLight: typeof import('~icons/ph/file-jpg-light')['default']
|
||||
const IPhFilePngLight: typeof import('~icons/ph/file-png-light')['default']
|
||||
const IPhGifFill: typeof import('~icons/ph/gif-fill')['default']
|
||||
const IPhJpgLight: typeof import('~icons/ph/jpg-light')['default']
|
||||
const IPhPngLight: typeof import('~icons/ph/png-light')['default']
|
||||
const IPhPnglight: typeof import('~icons/ph/pnglight')['default']
|
||||
const IPhosphorPngLight: typeof import('~icons/ph/osphor-png-light')['default']
|
||||
const IPhosphorePngLight: typeof import('~icons/ph/osphore-png-light')['default']
|
||||
const ISimpleIconsApachegroovy: typeof import('~icons/simple-icons/apachegroovy')['default']
|
||||
const ISimpleIconsC: typeof import('~icons/simple-icons/c')['default']
|
||||
const ISimpleIconsCSS3: typeof import('~icons/simple-icons/c-s-s3')['default']
|
||||
const ISimpleIconsClojure: typeof import('~icons/simple-icons/clojure')['default']
|
||||
const ISimpleIconsCmake: typeof import('~icons/simple-icons/cmake')['default']
|
||||
const ISimpleIconsCoffeescript: typeof import('~icons/simple-icons/coffeescript')['default']
|
||||
const ISimpleIconsCplusplus: typeof import('~icons/simple-icons/cplusplus')['default']
|
||||
const ISimpleIconsCrystal: typeof import('~icons/simple-icons/crystal')['default']
|
||||
const ISimpleIconsCsharp: typeof import('~icons/simple-icons/csharp')['default']
|
||||
const ISimpleIconsCss3: typeof import('~icons/simple-icons/css3')['default']
|
||||
const ISimpleIconsD: typeof import('~icons/simple-icons/d')['default']
|
||||
const ISimpleIconsDart: typeof import('~icons/simple-icons/dart')['default']
|
||||
const ISimpleIconsDocker: typeof import('~icons/simple-icons/docker')['default']
|
||||
const ISimpleIconsEditorconfig: typeof import('~icons/simple-icons/editorconfig')['default']
|
||||
const ISimpleIconsElixir: typeof import('~icons/simple-icons/elixir')['default']
|
||||
const ISimpleIconsElm: typeof import('~icons/simple-icons/elm')['default']
|
||||
const ISimpleIconsErlang: typeof import('~icons/simple-icons/erlang')['default']
|
||||
const ISimpleIconsFortran: typeof import('~icons/simple-icons/fortran')['default']
|
||||
const ISimpleIconsFsharp: typeof import('~icons/simple-icons/fsharp')['default']
|
||||
const ISimpleIconsGit: typeof import('~icons/simple-icons/git')['default']
|
||||
const ISimpleIconsGnuemacs: typeof import('~icons/simple-icons/gnuemacs')['default']
|
||||
const ISimpleIconsGo: typeof import('~icons/simple-icons/go')['default']
|
||||
const ISimpleIconsGraphql: typeof import('~icons/simple-icons/graphql')['default']
|
||||
const ISimpleIconsHaskell: typeof import('~icons/simple-icons/haskell')['default']
|
||||
const ISimpleIconsHtml5: typeof import('~icons/simple-icons/html5')['default']
|
||||
const ISimpleIconsJavascript: typeof import('~icons/simple-icons/javascript')['default']
|
||||
const ISimpleIconsJinja: typeof import('~icons/simple-icons/jinja')['default']
|
||||
const ISimpleIconsJpeg: typeof import('~icons/simple-icons/jpeg')['default']
|
||||
const ISimpleIconsJulia: typeof import('~icons/simple-icons/julia')['default']
|
||||
const ISimpleIconsKotlin: typeof import('~icons/simple-icons/kotlin')['default']
|
||||
const ISimpleIconsLlvm: typeof import('~icons/simple-icons/llvm')['default']
|
||||
const ISimpleIconsLua: typeof import('~icons/simple-icons/lua')['default']
|
||||
const ISimpleIconsMarkdown: typeof import('~icons/simple-icons/markdown')['default']
|
||||
const ISimpleIconsNginx: typeof import('~icons/simple-icons/nginx')['default']
|
||||
const ISimpleIconsNim: typeof import('~icons/simple-icons/nim')['default']
|
||||
const ISimpleIconsNixos: typeof import('~icons/simple-icons/nixos')['default']
|
||||
const ISimpleIconsNpm: typeof import('~icons/simple-icons/npm')['default']
|
||||
const ISimpleIconsOcaml: typeof import('~icons/simple-icons/ocaml')['default']
|
||||
const ISimpleIconsPerl: typeof import('~icons/simple-icons/perl')['default']
|
||||
const ISimpleIconsPhp: typeof import('~icons/simple-icons/php')['default']
|
||||
const ISimpleIconsPurescript: typeof import('~icons/simple-icons/purescript')['default']
|
||||
const ISimpleIconsPython: typeof import('~icons/simple-icons/python')['default']
|
||||
const ISimpleIconsR: typeof import('~icons/simple-icons/r')['default']
|
||||
const ISimpleIconsRuby: typeof import('~icons/simple-icons/ruby')['default']
|
||||
const ISimpleIconsRust: typeof import('~icons/simple-icons/rust')['default']
|
||||
const ISimpleIconsSass: typeof import('~icons/simple-icons/sass')['default']
|
||||
const ISimpleIconsScala: typeof import('~icons/simple-icons/scala')['default']
|
||||
const ISimpleIconsSvelte: typeof import('~icons/simple-icons/svelte')['default']
|
||||
const ISimpleIconsSvg: typeof import('~icons/simple-icons/svg')['default']
|
||||
const ISimpleIconsSwift: typeof import('~icons/simple-icons/swift')['default']
|
||||
const ISimpleIconsTerraform: typeof import('~icons/simple-icons/terraform')['default']
|
||||
const ISimpleIconsToml: typeof import('~icons/simple-icons/toml')['default']
|
||||
const ISimpleIconsTypescript: typeof import('~icons/simple-icons/typescript')['default']
|
||||
const ISimpleIconsUnrealengine: typeof import('~icons/simple-icons/unrealengine')['default']
|
||||
const ISimpleIconsVim: typeof import('~icons/simple-icons/vim')['default']
|
||||
const ISimpleIconsVisualbasic: typeof import('~icons/simple-icons/visualbasic')['default']
|
||||
const ISimpleIconsVuedotjs: typeof import('~icons/simple-icons/vuedotjs')['default']
|
||||
const ISimpleIconsWebassembly: typeof import('~icons/simple-icons/webassembly')['default']
|
||||
const ISimpleIconsWolframmathematica: typeof import('~icons/simple-icons/wolframmathematica')['default']
|
||||
const ISimpleIconsZig: typeof import('~icons/simple-icons/zig')['default']
|
||||
}
|
||||
|
||||
@ -30,4 +30,4 @@
|
||||
export let inline: boolean = false
|
||||
</script>
|
||||
|
||||
<svelte:component this={icon} class="{style.icon} {inline ? style.iconInline : ''}" />
|
||||
<svelte:component this={icon} class="{style.icon} {inline ? style.iconInline : ''}" {...$$restProps} />
|
||||
|
||||
@ -1,15 +1,18 @@
|
||||
<script lang="ts">
|
||||
import { mdiFileCodeOutline } from '@mdi/js'
|
||||
import type { ComponentProps } from 'svelte'
|
||||
|
||||
import { getFileIconInfo } from '$lib/wildcard'
|
||||
import FileIcon from './repo/FileIcon.svelte'
|
||||
|
||||
import Icon from './Icon.svelte'
|
||||
type $$Props = {
|
||||
language: string
|
||||
} & Omit<ComponentProps<FileIcon>, 'file'>
|
||||
|
||||
export let language: string
|
||||
|
||||
$: icon = getFileIconInfo('', language)?.svg
|
||||
$: svgPath = icon?.path ?? mdiFileCodeOutline
|
||||
$: svgColor = icon?.color
|
||||
</script>
|
||||
|
||||
<Icon {svgPath} --color={svgColor} {...$$restProps} />
|
||||
<!--
|
||||
This component abstracts from FileIcon specifics when we only have the language available.
|
||||
This allows us to use the same fallback logic.
|
||||
-->
|
||||
|
||||
<FileIcon file={{ name: '', languages: [language] }} {...$$restProps} />
|
||||
|
||||
@ -1,16 +1,21 @@
|
||||
<script lang="ts">
|
||||
import { getFileIconInfo } from '$lib/wildcard'
|
||||
import type { ComponentProps } from 'svelte'
|
||||
|
||||
import Icon2 from '$lib/Icon2.svelte'
|
||||
import { getFileIconInfo, DEFAULT_ICON_COLOR } from '$lib/wildcard'
|
||||
|
||||
import { FileIcon_GitBlob } from './FileIcon.gql'
|
||||
import Icon from '$lib/Icon.svelte'
|
||||
import { mdiFileCodeOutline } from '@mdi/js'
|
||||
|
||||
type $$Props = {
|
||||
file: FileIcon_GitBlob | null
|
||||
} & Omit<ComponentProps<Icon2>, 'icon'>
|
||||
|
||||
export let file: FileIcon_GitBlob | null
|
||||
export let inline = false
|
||||
|
||||
$: icon = (file && getFileIconInfo(file.name, file.languages.at(0) ?? '')?.svg) || {
|
||||
path: mdiFileCodeOutline,
|
||||
color: 'var(--gray-05)',
|
||||
$: icon = (file && getFileIconInfo(file.name, file.languages.at(0) ?? '')) ?? {
|
||||
icon: ILucideFileCode,
|
||||
color: DEFAULT_ICON_COLOR,
|
||||
}
|
||||
</script>
|
||||
|
||||
<Icon svgPath={icon.path} {inline} aria-hidden --color={icon.color} />
|
||||
<Icon2 icon={icon.icon} aria-hidden style="color: {icon.color}" {...$$restProps} />
|
||||
|
||||
@ -156,7 +156,7 @@
|
||||
onFilterSelect={handleFilterSelect}
|
||||
>
|
||||
<svelte:fragment slot="label" let:label>
|
||||
<LanguageIcon class="icon" language={label} inline />
|
||||
<LanguageIcon language={label} inline />
|
||||
{label}
|
||||
</svelte:fragment>
|
||||
</Section>
|
||||
|
||||
@ -15,4 +15,4 @@ export { default as Input } from './Input.svelte'
|
||||
export { default as PanelGroup } from './resizable-panel/PanelGroup.svelte'
|
||||
export { default as Panel } from './resizable-panel/Panel.svelte'
|
||||
export { default as PanelResizeHandle } from './resizable-panel/PanelResizeHandle.svelte'
|
||||
export { getFileIconInfo } from '@sourcegraph/wildcard/src/components/Icon'
|
||||
export { getFileIconInfo, DEFAULT_ICON_COLOR } from './language-icons'
|
||||
|
||||
152
client/web-sveltekit/src/lib/wildcard/language-icons.ts
Normal file
152
client/web-sveltekit/src/lib/wildcard/language-icons.ts
Normal file
@ -0,0 +1,152 @@
|
||||
import type { ComponentType, SvelteComponent } from 'svelte'
|
||||
import type { SvelteHTMLElements } from 'svelte/elements'
|
||||
|
||||
interface LanguageIcon {
|
||||
icon: ComponentType<SvelteComponent<SvelteHTMLElements['svg']>>
|
||||
color: string
|
||||
}
|
||||
|
||||
const BLUE = 'var(--blue)'
|
||||
const PINK = 'var(--pink)'
|
||||
const YELLOW = 'var(--yellow)'
|
||||
const RED = 'var(--red)'
|
||||
const GREEN = 'var(--green)'
|
||||
const CYAN = 'var(--blue)'
|
||||
const GRAY = 'var(--gray-05)'
|
||||
export const DEFAULT_ICON_COLOR = GRAY
|
||||
|
||||
/**
|
||||
* The keys of this map must be present in the list of `languageFilter.ALL_LANGUAGES`.
|
||||
*
|
||||
* This map is deliberately not public, use {@link getFileIconInfo} instead.
|
||||
*
|
||||
* See FIXME(id: language-detection) for context on why this map uses the
|
||||
* language as the key instead of something simpler like a file extension.
|
||||
*/
|
||||
export const FILE_ICONS_BY_LANGUAGE: Map<string, LanguageIcon> = new Map([
|
||||
['Bash', { icon: ILucideFileTerminal, color: DEFAULT_ICON_COLOR }],
|
||||
['BASIC', { icon: ISimpleIconsVisualbasic, color: DEFAULT_ICON_COLOR }],
|
||||
['C', { icon: ISimpleIconsC, color: BLUE }],
|
||||
['C++', { icon: ISimpleIconsCplusplus, color: BLUE }],
|
||||
['C#', { icon: ISimpleIconsCsharp, color: BLUE }],
|
||||
['Clojure', { icon: ISimpleIconsClojure, color: BLUE }],
|
||||
['CMake', { icon: ISimpleIconsCmake, color: DEFAULT_ICON_COLOR }],
|
||||
['CoffeeScript', { icon: ISimpleIconsCoffeescript, color: DEFAULT_ICON_COLOR }],
|
||||
|
||||
// TODO: Decide icon for CSV?
|
||||
['Crystal', { icon: ISimpleIconsCrystal, color: BLUE }],
|
||||
['CSS', { icon: ISimpleIconsCss3, color: BLUE }],
|
||||
['D', { icon: ISimpleIconsD, color: RED }],
|
||||
['Dart', { icon: ISimpleIconsDart, color: BLUE }],
|
||||
['Dockerfile', { icon: ISimpleIconsDocker, color: BLUE }],
|
||||
['EditorConfig', { icon: ISimpleIconsEditorconfig, color: DEFAULT_ICON_COLOR }],
|
||||
['Elixir', { icon: ISimpleIconsElixir, color: BLUE }],
|
||||
['Elm', { icon: ISimpleIconsElm, color: BLUE }],
|
||||
['Emacs Lisp', { icon: ISimpleIconsGnuemacs, color: DEFAULT_ICON_COLOR }],
|
||||
['Erlang', { icon: ISimpleIconsErlang, color: BLUE }],
|
||||
['Fortran', { icon: ISimpleIconsFortran, color: DEFAULT_ICON_COLOR }],
|
||||
['Fortran Free Form', { icon: ISimpleIconsFortran, color: DEFAULT_ICON_COLOR }],
|
||||
['F#', { icon: ISimpleIconsFsharp, color: BLUE }],
|
||||
['Git Attributes', { icon: ISimpleIconsGit, color: RED }],
|
||||
['Go', { icon: ISimpleIconsGo, color: BLUE }],
|
||||
['Go Module', { icon: ISimpleIconsGo, color: PINK }],
|
||||
['Go Checksums', { icon: ISimpleIconsGo, color: PINK }],
|
||||
['Groovy', { icon: ISimpleIconsApachegroovy, color: BLUE }],
|
||||
['GraphQL', { icon: ISimpleIconsGraphql, color: PINK }],
|
||||
['Haskell', { icon: ISimpleIconsHaskell, color: BLUE }],
|
||||
['HTML', { icon: ISimpleIconsHtml5, color: BLUE }],
|
||||
['HTML+ECR', { icon: ISimpleIconsCrystal, color: BLUE }],
|
||||
['HTML+EEX', { icon: ISimpleIconsElixir, color: BLUE }],
|
||||
['HTML+ERB', { icon: ISimpleIconsRuby, color: BLUE }],
|
||||
['HTML+PHP', { icon: ISimpleIconsPhp, color: BLUE }],
|
||||
['HTML+Razor', { icon: ISimpleIconsCsharp, color: BLUE }],
|
||||
['Ignore List', { icon: ILucideSettings, color: DEFAULT_ICON_COLOR }],
|
||||
['Java', { icon: IDeviconPlainJava, color: DEFAULT_ICON_COLOR }],
|
||||
['JavaScript', { icon: ISimpleIconsJavascript, color: YELLOW }],
|
||||
['Jinja', { icon: ISimpleIconsJinja, color: DEFAULT_ICON_COLOR }],
|
||||
['JSON with Comments', { icon: ILucideFileJson, color: DEFAULT_ICON_COLOR }],
|
||||
['JSON', { icon: ILucideFileJson, color: DEFAULT_ICON_COLOR }],
|
||||
['JSON5', { icon: ILucideFileJson, color: DEFAULT_ICON_COLOR }],
|
||||
['JSONLD', { icon: ILucideFileJson, color: DEFAULT_ICON_COLOR }],
|
||||
['Julia', { icon: ISimpleIconsJulia, color: DEFAULT_ICON_COLOR }],
|
||||
['Kotlin', { icon: ISimpleIconsKotlin, color: GREEN }],
|
||||
['LLVM', { icon: ISimpleIconsLlvm, color: GRAY }],
|
||||
['Lua', { icon: ISimpleIconsLua, color: BLUE }],
|
||||
['Markdown', { icon: ISimpleIconsMarkdown, color: BLUE }],
|
||||
['Mathematica', { icon: ISimpleIconsWolframmathematica, color: RED }],
|
||||
|
||||
// https://github.com/NCAR/ncl, not tweag/nickel
|
||||
['NCL', { icon: ILucideEarth, color: DEFAULT_ICON_COLOR }],
|
||||
['Nginx', { icon: ISimpleIconsNginx, color: DEFAULT_ICON_COLOR }],
|
||||
['Nim', { icon: ISimpleIconsNim, color: YELLOW }],
|
||||
['Nix', { icon: ISimpleIconsNixos, color: GRAY }],
|
||||
['NPM Config', { icon: ISimpleIconsNpm, color: RED }],
|
||||
|
||||
// Missing an icon for Objective-C
|
||||
['OCaml', { icon: ISimpleIconsOcaml, color: YELLOW }],
|
||||
['PHP', { icon: ISimpleIconsPhp, color: CYAN }],
|
||||
['Perl', { icon: ISimpleIconsPerl, color: DEFAULT_ICON_COLOR }],
|
||||
['PLpgSQL', { icon: ILucideDatabase, color: BLUE }],
|
||||
['PowerShell', { icon: ILucideFileTerminal, color: DEFAULT_ICON_COLOR }],
|
||||
|
||||
// Missing icon for Protobuf
|
||||
['PureScript', { icon: ISimpleIconsPurescript, color: DEFAULT_ICON_COLOR }],
|
||||
['Python', { icon: ISimpleIconsPython, color: BLUE }],
|
||||
['R', { icon: ISimpleIconsR, color: RED }],
|
||||
['Ruby', { icon: ISimpleIconsRuby, color: RED }],
|
||||
['Rust', { icon: ISimpleIconsRust, color: DEFAULT_ICON_COLOR }],
|
||||
['Scala', { icon: ISimpleIconsScala, color: RED }],
|
||||
['Sass', { icon: ISimpleIconsSass, color: PINK }],
|
||||
['SCSS', { icon: ISimpleIconsSass, color: PINK }],
|
||||
['SQL', { icon: ILucideDatabase, color: BLUE }],
|
||||
|
||||
// Missing icon for Starlark
|
||||
['Svelte', { icon: ISimpleIconsSvelte, color: RED }],
|
||||
['SVG', { icon: ISimpleIconsSvg, color: YELLOW }],
|
||||
['Swift', { icon: ISimpleIconsSwift, color: BLUE }],
|
||||
['Terraform', { icon: ISimpleIconsTerraform, color: BLUE }],
|
||||
['TSX', { icon: ISimpleIconsTypescript, color: BLUE }],
|
||||
['TypeScript', { icon: ISimpleIconsTypescript, color: BLUE }],
|
||||
['Text', { icon: ILucideFileText, color: DEFAULT_ICON_COLOR }],
|
||||
|
||||
// Missing icon for Thrift
|
||||
['TOML', { icon: ISimpleIconsToml, color: DEFAULT_ICON_COLOR }],
|
||||
['UnrealScript', { icon: ISimpleIconsUnrealengine, color: DEFAULT_ICON_COLOR }],
|
||||
['VBA', { icon: ISimpleIconsVisualbasic, color: BLUE }],
|
||||
['VBScript', { icon: ISimpleIconsVisualbasic, color: BLUE }],
|
||||
['Vim Script', { icon: ISimpleIconsVim, color: DEFAULT_ICON_COLOR }],
|
||||
['Vue', { icon: ISimpleIconsVuedotjs, color: GREEN }],
|
||||
['WebAssembly', { icon: ISimpleIconsWebassembly, color: BLUE }],
|
||||
['XML', { icon: ILucideSettings, color: DEFAULT_ICON_COLOR }],
|
||||
['YAML', { icon: ILucideSettings, color: DEFAULT_ICON_COLOR }],
|
||||
['Zig', { icon: ISimpleIconsZig, color: YELLOW }],
|
||||
])
|
||||
|
||||
/**
|
||||
* DO NOT add any extensions here for which there are multiple different
|
||||
* file formats in practice which use the same extensions.
|
||||
*
|
||||
* For programming languages, update {@link FILE_ICONS_BY_LANGUAGE}.
|
||||
*/
|
||||
const BINARY_FILE_ICONS_BY_EXTENSION: Map<string, LanguageIcon> = new Map([
|
||||
['gif', { icon: IPhGifFill, color: DEFAULT_ICON_COLOR }],
|
||||
['giff', { icon: IPhGifFill, color: DEFAULT_ICON_COLOR }],
|
||||
['jpg', { icon: IPhFileJpgLight, color: YELLOW }],
|
||||
['jpeg', { icon: IPhFileJpgLight, color: YELLOW }],
|
||||
['png', { icon: IPhFilePngLight, color: DEFAULT_ICON_COLOR }],
|
||||
])
|
||||
|
||||
/**
|
||||
*
|
||||
* See FIXME(id: language-detection) for context on why this takes a
|
||||
* languages argument instead of directly using the file extension
|
||||
* for determining the language.
|
||||
*
|
||||
* @param path The path of the file (or just its name).
|
||||
* @param language Alias to the file language name.
|
||||
* @returns undefined if the language is not a known language.
|
||||
*/
|
||||
export function getFileIconInfo(path: string, language: string): LanguageIcon | undefined {
|
||||
const extension = path.split('.').at(-1) ?? ''
|
||||
return BINARY_FILE_ICONS_BY_EXTENSION.get(extension) ?? FILE_ICONS_BY_LANGUAGE.get(language)
|
||||
}
|
||||
@ -565,6 +565,7 @@ ts_project(
|
||||
"//:node_modules/js-cookie",
|
||||
"//:node_modules/mdi-react",
|
||||
"//:node_modules/react",
|
||||
"//:node_modules/react-icons",
|
||||
"//:node_modules/rxjs",
|
||||
"//:node_modules/sinon",
|
||||
"//:node_modules/vitest",
|
||||
|
||||
@ -24,8 +24,8 @@ export const LanguageIcon: FC<LanguageIconProps> = props => {
|
||||
if (fileIcon) {
|
||||
return (
|
||||
<Icon
|
||||
as={fileIcon.react.icon}
|
||||
className={classNames(styles.icon, fileIcon.react.className, className)}
|
||||
as={fileIcon.icon}
|
||||
className={classNames(styles.icon, fileIcon.className, className)}
|
||||
aria-hidden={true}
|
||||
/>
|
||||
)
|
||||
|
||||
@ -1,50 +1,35 @@
|
||||
import { mdiFileCodeOutline, mdiFilePngBox, mdiLanguageJavascript } from '@mdi/js'
|
||||
import { PiFilePngLight } from 'react-icons/pi'
|
||||
import { SiJavascript } from 'react-icons/si'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import { getFileIconInfo } from './language-icons'
|
||||
|
||||
describe('getFileIconInfo', () => {
|
||||
const tests: {
|
||||
name: string
|
||||
file: string
|
||||
language: string
|
||||
expectedSvgPath: string | undefined
|
||||
expectedIsTest: boolean
|
||||
}[] = [
|
||||
const tests = [
|
||||
{
|
||||
name: 'check that png works',
|
||||
file: 'myfile.png',
|
||||
language: '',
|
||||
expectedSvgPath: mdiFilePngBox,
|
||||
expectedIsTest: false,
|
||||
expectedIcon: PiFilePngLight,
|
||||
},
|
||||
{
|
||||
name: 'works with simple file name',
|
||||
file: 'my-file.js',
|
||||
language: 'JavaScript',
|
||||
expectedSvgPath: mdiLanguageJavascript,
|
||||
expectedIsTest: false,
|
||||
},
|
||||
{
|
||||
name: 'check fallback behavior',
|
||||
file: 'placeholder',
|
||||
language: 'Vim Script',
|
||||
expectedSvgPath: mdiFileCodeOutline,
|
||||
expectedIsTest: false,
|
||||
expectedIcon: SiJavascript,
|
||||
},
|
||||
{
|
||||
name: 'check unknown language',
|
||||
file: 'my-file.test.unknown',
|
||||
language: 'Unknown',
|
||||
expectedSvgPath: undefined,
|
||||
expectedIsTest: true,
|
||||
expectedIcon: undefined,
|
||||
},
|
||||
]
|
||||
|
||||
for (const t of tests) {
|
||||
it(t.name, () => {
|
||||
const iconInfo = getFileIconInfo(t.file, t.language)
|
||||
expect(iconInfo?.svg.path).toBe(t.expectedSvgPath)
|
||||
expect(iconInfo?.icon).toBe(t.expectedIcon)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
@ -1,57 +1,5 @@
|
||||
import type { ComponentType } from 'react'
|
||||
|
||||
// TODO(id: md-icons-and-react-icons)
|
||||
//
|
||||
// We're using react-icons for the React version of the web app
|
||||
// since it has a large number of icons. However, those aren't
|
||||
// usable in SvelteKit as the icons are React components.
|
||||
//
|
||||
// So we also use Material Design icons which are exposed as SVGs.
|
||||
// However, this has two drawbacks:
|
||||
// - It has many fewer languages compared to react-icons.
|
||||
// - A future version of Material Design icons will remove programming
|
||||
// language and file type icons.
|
||||
// https://github.com/Templarian/MaterialDesign/issues/6602
|
||||
//
|
||||
// It would be valuable to explore other icon libraries that can
|
||||
// be used both by React and SvelteKit or make our own.
|
||||
import {
|
||||
mdiCodeJson,
|
||||
mdiCog,
|
||||
mdiConsole,
|
||||
mdiDocker,
|
||||
mdiEarth,
|
||||
mdiFileCodeOutline,
|
||||
mdiFileGifBox,
|
||||
mdiFileJpgBox,
|
||||
mdiFilePngBox,
|
||||
mdiGit,
|
||||
mdiGraphql,
|
||||
mdiLanguageC,
|
||||
mdiLanguageCpp,
|
||||
mdiLanguageCsharp,
|
||||
mdiLanguageCss3,
|
||||
mdiLanguageGo,
|
||||
mdiLanguageHaskell,
|
||||
mdiLanguageHtml5,
|
||||
mdiLanguageJava,
|
||||
mdiLanguageJavascript,
|
||||
mdiLanguageKotlin,
|
||||
mdiLanguageLua,
|
||||
mdiLanguageMarkdown,
|
||||
mdiLanguagePhp,
|
||||
mdiLanguagePython,
|
||||
mdiLanguageR,
|
||||
mdiLanguageRuby,
|
||||
mdiLanguageRust,
|
||||
mdiLanguageSwift,
|
||||
mdiLanguageTypescript,
|
||||
mdiNix,
|
||||
mdiNpm,
|
||||
mdiSass,
|
||||
mdiSvg,
|
||||
mdiText,
|
||||
} from '@mdi/js'
|
||||
import { CiSettings, CiTextAlignLeft } from 'react-icons/ci'
|
||||
import { FaCss3Alt, FaSass, FaVuejs } from 'react-icons/fa'
|
||||
import { GoDatabase, GoTerminal } from 'react-icons/go'
|
||||
@ -123,21 +71,11 @@ import styles from './LanguageIcon.module.scss'
|
||||
|
||||
export type CustomIcon = ComponentType<{ className?: string }>
|
||||
|
||||
export interface ReactIcon {
|
||||
export interface IconInfo {
|
||||
icon: CustomIcon
|
||||
className: string
|
||||
}
|
||||
|
||||
export interface SvgIcon {
|
||||
path: string
|
||||
color: string
|
||||
}
|
||||
|
||||
interface UnifiedIcon {
|
||||
react: ReactIcon
|
||||
svg?: SvgIcon['path']
|
||||
}
|
||||
|
||||
/**
|
||||
* The keys of this map must be present in the list of `languageFilter.ALL_LANGUAGES`.
|
||||
*
|
||||
@ -146,133 +84,119 @@ interface UnifiedIcon {
|
||||
* See FIXME(id: language-detection) for context on why this map uses the
|
||||
* language as the key instead of something simpler like a file extension.
|
||||
*/
|
||||
export const FILE_ICONS_BY_LANGUAGE: Map<string, UnifiedIcon> = new Map([
|
||||
['Bash', { react: { icon: GoTerminal, className: styles.defaultIcon }, svg: mdiConsole }],
|
||||
['BASIC', { react: { icon: SiVisualbasic, className: styles.defaultIcon } }],
|
||||
['C', { react: { icon: SiC, className: styles.blue }, svg: mdiLanguageC }],
|
||||
['C++', { react: { icon: SiCplusplus, className: styles.blue }, svg: mdiLanguageCpp }],
|
||||
['C#', { react: { icon: SiCsharp, className: styles.blue }, svg: mdiLanguageCsharp }],
|
||||
['Clojure', { react: { icon: SiClojure, className: styles.blue } }],
|
||||
['CMake', { react: { icon: SiCmake, className: styles.defaultIcon } }],
|
||||
['CoffeeScript', { react: { icon: SiCoffeescript, className: styles.defaultIcon } }],
|
||||
export const FILE_ICONS_BY_LANGUAGE: Map<string, IconInfo> = new Map([
|
||||
['Bash', { icon: GoTerminal, className: styles.defaultIcon }],
|
||||
['BASIC', { icon: SiVisualbasic, className: styles.defaultIcon }],
|
||||
['C', { icon: SiC, className: styles.blue }],
|
||||
['C++', { icon: SiCplusplus, className: styles.blue }],
|
||||
['C#', { icon: SiCsharp, className: styles.blue }],
|
||||
['Clojure', { icon: SiClojure, className: styles.blue }],
|
||||
['CMake', { icon: SiCmake, className: styles.defaultIcon }],
|
||||
['CoffeeScript', { icon: SiCoffeescript, className: styles.defaultIcon }],
|
||||
|
||||
// TODO: Decide icon for CSV?
|
||||
['Crystal', { react: { icon: SiCrystal, className: styles.blue } }],
|
||||
['CSS', { react: { icon: FaCss3Alt, className: styles.blue }, svg: mdiLanguageCss3 }],
|
||||
['D', { react: { icon: SiD, className: styles.red } }],
|
||||
['Dart', { react: { icon: SiDart, className: styles.blue } }],
|
||||
['Dockerfile', { react: { icon: SiDocker, className: styles.blue }, svg: mdiDocker }],
|
||||
['EditorConfig', { react: { icon: SiEditorconfig, className: styles.defaultIcon } }],
|
||||
['Elixir', { react: { icon: SiElixir, className: styles.blue } }],
|
||||
['Elm', { react: { icon: SiElm, className: styles.blue } }],
|
||||
['Emacs Lisp', { react: { icon: SiGnuemacs, className: styles.defaultIcon } }],
|
||||
['Erlang', { react: { icon: SiErlang, className: styles.blue } }],
|
||||
['Fortran', { react: { icon: SiFortran, className: styles.defaultIcon } }],
|
||||
['Fortran Free Form', { react: { icon: SiFortran, className: styles.defaultIcon } }],
|
||||
['F#', { react: { icon: SiFsharp, className: styles.blue } }],
|
||||
['Git Attributes', { react: { icon: SiGit, className: styles.red }, svg: mdiGit }],
|
||||
['Go', { react: { icon: SiGo, className: styles.blue }, svg: mdiLanguageGo }],
|
||||
['Go Module', { react: { icon: SiGo, className: styles.pink }, svg: mdiLanguageGo }],
|
||||
['Go Checksums', { react: { icon: SiGo, className: styles.pink }, svg: mdiLanguageGo }],
|
||||
['Groovy', { react: { icon: SiApachegroovy, className: styles.blue } }],
|
||||
['GraphQL', { react: { icon: SiGraphql, className: styles.pink }, svg: mdiGraphql }],
|
||||
['Haskell', { react: { icon: SiHaskell, className: styles.blue }, svg: mdiLanguageHaskell }],
|
||||
['HTML', { react: { icon: SiHtml5, className: styles.blue }, svg: mdiLanguageHtml5 }],
|
||||
['HTML+ECR', { react: { icon: SiCrystal, className: styles.blue } }],
|
||||
['HTML+EEX', { react: { icon: SiElixir, className: styles.blue } }],
|
||||
['HTML+ERB', { react: { icon: SiRuby, className: styles.blue } }],
|
||||
['HTML+PHP', { react: { icon: SiPhp, className: styles.blue } }],
|
||||
['HTML+Razor', { react: { icon: SiCsharp, className: styles.blue } }],
|
||||
['Ignore List', { react: { icon: CiSettings, className: styles.defaultIcon }, svg: mdiCog }],
|
||||
['Java', { react: { icon: GrJava, className: styles.defaultIcon }, svg: mdiLanguageJava }],
|
||||
['JavaScript', { react: { icon: SiJavascript, className: styles.yellow }, svg: mdiLanguageJavascript }],
|
||||
['Jinja', { react: { icon: SiJinja, className: styles.defaultIcon } }],
|
||||
['JSON with Comments', { react: { icon: VscJson, className: styles.defaultIcon } }],
|
||||
['JSON', { react: { icon: VscJson, className: styles.defaultIcon }, svg: mdiCodeJson }],
|
||||
['JSON5', { react: { icon: VscJson, className: styles.defaultIcon }, svg: mdiCodeJson }],
|
||||
['JSONLD', { react: { icon: VscJson, className: styles.defaultIcon }, svg: mdiCodeJson }],
|
||||
['Julia', { react: { icon: SiJulia, className: styles.defaultIcon } }],
|
||||
['Kotlin', { react: { icon: SiKotlin, className: styles.green }, svg: mdiLanguageKotlin }],
|
||||
['LLVM', { react: { icon: SiLlvm, className: styles.gray } }],
|
||||
['Lua', { react: { icon: SiLua, className: styles.blue }, svg: mdiLanguageLua }],
|
||||
['Markdown', { react: { icon: SiMarkdown, className: styles.blue }, svg: mdiLanguageMarkdown }],
|
||||
['Mathematica', { react: { icon: SiWolframmathematica, className: styles.red } }],
|
||||
['Crystal', { icon: SiCrystal, className: styles.blue }],
|
||||
['CSS', { icon: FaCss3Alt, className: styles.blue }],
|
||||
['D', { icon: SiD, className: styles.red }],
|
||||
['Dart', { icon: SiDart, className: styles.blue }],
|
||||
['Dockerfile', { icon: SiDocker, className: styles.blue }],
|
||||
['EditorConfig', { icon: SiEditorconfig, className: styles.defaultIcon }],
|
||||
['Elixir', { icon: SiElixir, className: styles.blue }],
|
||||
['Elm', { icon: SiElm, className: styles.blue }],
|
||||
['Emacs Lisp', { icon: SiGnuemacs, className: styles.defaultIcon }],
|
||||
['Erlang', { icon: SiErlang, className: styles.blue }],
|
||||
['Fortran', { icon: SiFortran, className: styles.defaultIcon }],
|
||||
['Fortran Free Form', { icon: SiFortran, className: styles.defaultIcon }],
|
||||
['F#', { icon: SiFsharp, className: styles.blue }],
|
||||
['Git Attributes', { icon: SiGit, className: styles.red }],
|
||||
['Go', { icon: SiGo, className: styles.blue }],
|
||||
['Go Module', { icon: SiGo, className: styles.pink }],
|
||||
['Go Checksums', { icon: SiGo, className: styles.pink }],
|
||||
['Groovy', { icon: SiApachegroovy, className: styles.blue }],
|
||||
['GraphQL', { icon: SiGraphql, className: styles.pink }],
|
||||
['Haskell', { icon: SiHaskell, className: styles.blue }],
|
||||
['HTML', { icon: SiHtml5, className: styles.blue }],
|
||||
['HTML+ECR', { icon: SiCrystal, className: styles.blue }],
|
||||
['HTML+EEX', { icon: SiElixir, className: styles.blue }],
|
||||
['HTML+ERB', { icon: SiRuby, className: styles.blue }],
|
||||
['HTML+PHP', { icon: SiPhp, className: styles.blue }],
|
||||
['HTML+Razor', { icon: SiCsharp, className: styles.blue }],
|
||||
['Ignore List', { icon: CiSettings, className: styles.defaultIcon }],
|
||||
['Java', { icon: GrJava, className: styles.defaultIcon }],
|
||||
['JavaScript', { icon: SiJavascript, className: styles.yellow }],
|
||||
['Jinja', { icon: SiJinja, className: styles.defaultIcon }],
|
||||
['JSON with Comments', { icon: VscJson, className: styles.defaultIcon }],
|
||||
['JSON', { icon: VscJson, className: styles.defaultIcon }],
|
||||
['JSON5', { icon: VscJson, className: styles.defaultIcon }],
|
||||
['JSONLD', { icon: VscJson, className: styles.defaultIcon }],
|
||||
['Julia', { icon: SiJulia, className: styles.defaultIcon }],
|
||||
['Kotlin', { icon: SiKotlin, className: styles.green }],
|
||||
['LLVM', { icon: SiLlvm, className: styles.gray }],
|
||||
['Lua', { icon: SiLua, className: styles.blue }],
|
||||
['Markdown', { icon: SiMarkdown, className: styles.blue }],
|
||||
['Mathematica', { icon: SiWolframmathematica, className: styles.red }],
|
||||
|
||||
// https://github.com/NCAR/ncl, not tweag/nickel
|
||||
['NCL', { react: { icon: ImEarth, className: styles.defaultIcon }, svg: mdiEarth }],
|
||||
['Nginx', { react: { icon: SiNginx, className: styles.defaultIcon } }],
|
||||
['Nim', { react: { icon: SiNim, className: styles.yellow } }],
|
||||
['Nix', { react: { icon: SiNixos, className: styles.gray }, svg: mdiNix }],
|
||||
['NPM Config', { react: { icon: SiNpm, className: styles.red }, svg: mdiNpm }],
|
||||
['NCL', { icon: ImEarth, className: styles.defaultIcon }],
|
||||
['Nginx', { icon: SiNginx, className: styles.defaultIcon }],
|
||||
['Nim', { icon: SiNim, className: styles.yellow }],
|
||||
['Nix', { icon: SiNixos, className: styles.gray }],
|
||||
['NPM Config', { icon: SiNpm, className: styles.red }],
|
||||
|
||||
// Missing an icon for Objective-C
|
||||
['OCaml', { react: { icon: SiOcaml, className: styles.yellow } }],
|
||||
['PHP', { react: { icon: SiPhp, className: styles.cyan }, svg: mdiLanguagePhp }],
|
||||
['Perl', { react: { icon: SiPerl, className: styles.defaultIcon } }],
|
||||
['PLpgSQL', { react: { icon: GoDatabase, className: styles.blue } }],
|
||||
['PowerShell', { react: { icon: GoTerminal, className: styles.defaultIcon }, svg: mdiConsole }],
|
||||
['OCaml', { icon: SiOcaml, className: styles.yellow }],
|
||||
['PHP', { icon: SiPhp, className: styles.cyan }],
|
||||
['Perl', { icon: SiPerl, className: styles.defaultIcon }],
|
||||
['PLpgSQL', { icon: GoDatabase, className: styles.blue }],
|
||||
['PowerShell', { icon: GoTerminal, className: styles.defaultIcon }],
|
||||
|
||||
// Missing icon for Protobuf
|
||||
['PureScript', { react: { icon: SiPurescript, className: styles.defaultIcon } }],
|
||||
['Python', { react: { icon: SiPython, className: styles.blue }, svg: mdiLanguagePython }],
|
||||
['R', { react: { icon: SiR, className: styles.red }, svg: mdiLanguageR }],
|
||||
['Ruby', { react: { icon: SiRuby, className: styles.red }, svg: mdiLanguageRuby }],
|
||||
['Rust', { react: { icon: SiRust, className: styles.defaultIcon }, svg: mdiLanguageRust }],
|
||||
['Scala', { react: { icon: SiScala, className: styles.red } }],
|
||||
['Sass', { react: { icon: FaSass, className: styles.pink }, svg: mdiSass }],
|
||||
['SCSS', { react: { icon: FaSass, className: styles.pink } }],
|
||||
['SQL', { react: { icon: GoDatabase, className: styles.blue } }],
|
||||
['PureScript', { icon: SiPurescript, className: styles.defaultIcon }],
|
||||
['Python', { icon: SiPython, className: styles.blue }],
|
||||
['R', { icon: SiR, className: styles.red }],
|
||||
['Ruby', { icon: SiRuby, className: styles.red }],
|
||||
['Rust', { icon: SiRust, className: styles.defaultIcon }],
|
||||
['Scala', { icon: SiScala, className: styles.red }],
|
||||
['Sass', { icon: FaSass, className: styles.pink }],
|
||||
['SCSS', { icon: FaSass, className: styles.pink }],
|
||||
['SQL', { icon: GoDatabase, className: styles.blue }],
|
||||
|
||||
// Missing icon for Starlark
|
||||
['Svelte', { react: { icon: SiSvelte, className: styles.red } }],
|
||||
['SVG', { react: { icon: SiSvg, className: styles.yellow }, svg: mdiSvg }],
|
||||
['Swift', { react: { icon: SiSwift, className: styles.blue }, svg: mdiLanguageSwift }],
|
||||
['Terraform', { react: { icon: SiTerraform, className: styles.blue } }],
|
||||
['TSX', { react: { icon: SiTypescript, className: styles.blue }, svg: mdiLanguageTypescript }],
|
||||
['TypeScript', { react: { icon: SiTypescript, className: styles.blue }, svg: mdiLanguageTypescript }],
|
||||
['Text', { react: { icon: CiTextAlignLeft, className: styles.defaultIcon }, svg: mdiText }],
|
||||
['Svelte', { icon: SiSvelte, className: styles.red }],
|
||||
['SVG', { icon: SiSvg, className: styles.yellow }],
|
||||
['Swift', { icon: SiSwift, className: styles.blue }],
|
||||
['Terraform', { icon: SiTerraform, className: styles.blue }],
|
||||
['TSX', { icon: SiTypescript, className: styles.blue }],
|
||||
['TypeScript', { icon: SiTypescript, className: styles.blue }],
|
||||
['Text', { icon: CiTextAlignLeft, className: styles.defaultIcon }],
|
||||
|
||||
// Missing icon for Thrift
|
||||
['TOML', { react: { icon: SiToml, className: styles.defaultIcon } }],
|
||||
['UnrealScript', { react: { icon: SiUnrealengine, className: styles.defaultIcon } }],
|
||||
['VBA', { react: { icon: SiVisualbasic, className: styles.blue } }],
|
||||
['VBScript', { react: { icon: SiVisualbasic, className: styles.blue } }],
|
||||
['Vim Script', { react: { icon: SiVim, className: styles.defaultIcon } }],
|
||||
['Vue', { react: { icon: FaVuejs, className: styles.green } }],
|
||||
['WebAssembly', { react: { icon: SiWebassembly, className: styles.blue } }],
|
||||
['XML', { react: { icon: CiSettings, className: styles.defaultIcon }, svg: mdiCog }],
|
||||
['YAML', { react: { icon: CiSettings, className: styles.defaultIcon }, svg: mdiCog }],
|
||||
['Zig', { react: { icon: SiZig, className: styles.yellow } }],
|
||||
['TOML', { icon: SiToml, className: styles.defaultIcon }],
|
||||
['UnrealScript', { icon: SiUnrealengine, className: styles.defaultIcon }],
|
||||
['VBA', { icon: SiVisualbasic, className: styles.blue }],
|
||||
['VBScript', { icon: SiVisualbasic, className: styles.blue }],
|
||||
['Vim Script', { icon: SiVim, className: styles.defaultIcon }],
|
||||
['Vue', { icon: FaVuejs, className: styles.green }],
|
||||
['WebAssembly', { icon: SiWebassembly, className: styles.blue }],
|
||||
['XML', { icon: CiSettings, className: styles.defaultIcon }],
|
||||
['YAML', { icon: CiSettings, className: styles.defaultIcon }],
|
||||
['Zig', { icon: SiZig, className: styles.yellow }],
|
||||
])
|
||||
|
||||
export interface BinaryFileIcon {
|
||||
react: ReactIcon
|
||||
svg: string
|
||||
}
|
||||
|
||||
/**
|
||||
* DO NOT add any extensions here for which there are multiple different
|
||||
* file formats in practice which use the same extensions.
|
||||
*
|
||||
* For programming languages, update {@link FILE_ICONS_BY_LANGUAGE}.
|
||||
*/
|
||||
const BINARY_FILE_ICONS_BY_EXTENSION: Map<string, BinaryFileIcon> = new Map([
|
||||
['gif', { react: { icon: MdGif, className: styles.defaultIcon }, svg: mdiFileGifBox }],
|
||||
['giff', { react: { icon: MdGif, className: styles.defaultIcon }, svg: mdiFileGifBox }],
|
||||
['jpg', { react: { icon: SiJpeg, className: styles.yellow }, svg: mdiFileJpgBox }],
|
||||
['jpeg', { react: { icon: SiJpeg, className: styles.yellow }, svg: mdiFileJpgBox }],
|
||||
['png', { react: { icon: PiFilePngLight, className: styles.defaultIcon }, svg: mdiFilePngBox }],
|
||||
const BINARY_FILE_ICONS_BY_EXTENSION: Map<string, IconInfo> = new Map([
|
||||
['gif', { icon: MdGif, className: styles.defaultIcon }],
|
||||
['giff', { icon: MdGif, className: styles.defaultIcon }],
|
||||
['jpg', { icon: SiJpeg, className: styles.yellow }],
|
||||
['jpeg', { icon: SiJpeg, className: styles.yellow }],
|
||||
['png', { icon: PiFilePngLight, className: styles.defaultIcon }],
|
||||
])
|
||||
|
||||
// See TODO(id: md-icons-and-react-icons) for context
|
||||
export interface IconInfo {
|
||||
// For use in the React webapp
|
||||
react: ReactIcon
|
||||
|
||||
// For use in the SvelteKit rewrite
|
||||
svg: SvgIcon
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* See FIXME(id: language-detection) for context on why this takes a
|
||||
@ -285,58 +209,5 @@ export interface IconInfo {
|
||||
*/
|
||||
export function getFileIconInfo(path: string, language: string): IconInfo | undefined {
|
||||
const extension = path.split('.').at(-1) ?? ''
|
||||
const icon1 = BINARY_FILE_ICONS_BY_EXTENSION.get(extension)
|
||||
|
||||
if (icon1 !== undefined) {
|
||||
return {
|
||||
react: icon1.react,
|
||||
svg: { path: icon1.svg, color: classNameToColor(icon1.react.className) },
|
||||
}
|
||||
}
|
||||
|
||||
const icon2 = FILE_ICONS_BY_LANGUAGE.get(language)
|
||||
|
||||
if (icon2 !== undefined) {
|
||||
return {
|
||||
react: icon2.react,
|
||||
svg: { path: icon2.svg ?? mdiFileCodeOutline, color: classNameToColor(icon2.react.className) },
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
const BLUE = 'var(--blue)'
|
||||
const PINK = 'var(--pink)'
|
||||
const YELLOW = 'var(--yellow)'
|
||||
const RED = 'var(--red)'
|
||||
const GREEN = 'var(--green)'
|
||||
const CYAN = 'var(--blue)'
|
||||
const GRAY = 'var(--gray-05)'
|
||||
|
||||
function classNameToColor(name: string): string {
|
||||
switch (name) {
|
||||
case styles.blue: {
|
||||
return BLUE
|
||||
}
|
||||
case styles.red: {
|
||||
return RED
|
||||
}
|
||||
case styles.yellow: {
|
||||
return YELLOW
|
||||
}
|
||||
case styles.pink: {
|
||||
return PINK
|
||||
}
|
||||
case styles.green: {
|
||||
return GREEN
|
||||
}
|
||||
case styles.cyan: {
|
||||
return CYAN
|
||||
}
|
||||
case styles.gray:
|
||||
default: {
|
||||
return GRAY
|
||||
}
|
||||
}
|
||||
return BINARY_FILE_ICONS_BY_EXTENSION.get(extension) ?? FILE_ICONS_BY_LANGUAGE.get(language)
|
||||
}
|
||||
|
||||
@ -1639,9 +1639,18 @@ importers:
|
||||
'@graphql-typed-document-node/core':
|
||||
specifier: ^3.2.0
|
||||
version: 3.2.0(graphql@15.4.0)
|
||||
'@iconify-json/devicon-plain':
|
||||
specifier: ^1.1.42
|
||||
version: 1.1.42
|
||||
'@iconify-json/lucide':
|
||||
specifier: ^1.1.188
|
||||
version: 1.1.188
|
||||
'@iconify-json/ph':
|
||||
specifier: ^1.1.13
|
||||
version: 1.1.13
|
||||
'@iconify-json/simple-icons':
|
||||
specifier: ^1.1.104
|
||||
version: 1.1.104
|
||||
'@playwright/test':
|
||||
specifier: 1.42.1
|
||||
version: 1.42.1
|
||||
@ -5508,12 +5517,30 @@ packages:
|
||||
resolution: {integrity: sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==}
|
||||
dev: true
|
||||
|
||||
/@iconify-json/devicon-plain@1.1.42:
|
||||
resolution: {integrity: sha512-NGCuw6BHn8lpjbVVa4XvYnprhWZ6IWkr6O19b69ySpDyi8QF3lh/Pe5As7C6eAG1KsblxQFqwcztgILOOmZqAA==}
|
||||
dependencies:
|
||||
'@iconify/types': 2.0.0
|
||||
dev: true
|
||||
|
||||
/@iconify-json/lucide@1.1.188:
|
||||
resolution: {integrity: sha512-yJNoU7vX11OvdeSKBiAvmbk/etAq2HPCZQkZX1U687NZhn8dTfx1PfyNhPxtJilrd288XGDKK+NQgygcZ+Ho4g==}
|
||||
dependencies:
|
||||
'@iconify/types': 2.0.0
|
||||
dev: true
|
||||
|
||||
/@iconify-json/ph@1.1.13:
|
||||
resolution: {integrity: sha512-xtM4JJ63HCKj09WRqrBswXiHrpliBlqboWSZH8odcmqYXbvIFceU9/Til4V+MQr6+MoUC+KB72cxhky2+A6r/g==}
|
||||
dependencies:
|
||||
'@iconify/types': 2.0.0
|
||||
dev: true
|
||||
|
||||
/@iconify-json/simple-icons@1.1.104:
|
||||
resolution: {integrity: sha512-986r56QHsIqa84MdGpV+tUJVhJjDXFb1OfFJZKMDiuQOi0CacK5QsM3if5RNjmT9WhrQtm5uTRHy4/4u7Cb9oQ==}
|
||||
dependencies:
|
||||
'@iconify/types': 2.0.0
|
||||
dev: true
|
||||
|
||||
/@iconify/types@2.0.0:
|
||||
resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==}
|
||||
dev: true
|
||||
|
||||
Loading…
Reference in New Issue
Block a user