diff --git a/README.md b/README.md index eef7334..3c7d289 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Taskfile ([taskfile.sh](https://taskfile.sh)) -A `./Taskfile` is a task runner in plain and easy [Bash](https://nl.wikipedia.org/wiki/Bash). It adds a list of -available tasks to your project. +A `./Taskfile` is a task runner in plain and easy [Bash](). It adds a +list of available tasks to your project. Generate your own Taskfile at [taskfile.sh](https://taskfile.sh). @@ -14,81 +14,21 @@ Generate your own Taskfile at [taskfile.sh](https://taskfile.sh). - Very easy to use - Automate your most common tasks (updating, starting, building, etc...) - Easy to understand and maintain -- Automatically generated list of available task +- Automatically generated list of available tasks -# How does it work? +## Documentation -Taskfiles are simple bash scripts, but an easy-to-read function format. There are some things that we need to explain -for our Taskfile setup. It all starts with a `Taskfile`. Download your `Taskfile` from -[taskfile.sh](https://taskfile.sh) and save it. Make sure the Taskfile is executable: `chmod +x ./Taskfile`. You can now -run `./Taskfile` in your terminal. - -## Tasks - -A task is defined by creating a function that starts with `task:`. This defines a task that can be triggered by running -the `./Taskfile`. Right next to the task, you should add a task definition with two hashes. This will let the -`task:help` function know that you're writing the task function definition. So an example task will look like the -following: - -```shell -function task:example { ## Show some example text - title "Example" - echo "This is an example task." -} -``` - -In a task you can call other functions, and run all tooling you desire. Now running `./Taskfile example` will execute -the new task. - -## Sections - -To group multiple tasks, sections can be created in your Taskfile. A section is created by creating a comment line with -a double hashtag like so: - -```shell -## Project section -``` - -Lines with only a single `#` will not appear as section in `task:help` and can be seen as plain comments. - -## Help command - -Running `./Taskfile help`, the `task:help` function is triggered. This task will list all available sections and tasks -using the double `##` comments you've learned about above. Now it's clear how you can run any other task! - -# Auto-completion - -Autocompletion works when you use `zsh` and `oh-my-zsh`. Create the following file in your oh-my-zsh directory -`~/.oh-my-zsh/completions/_task.zsh`: - -```shell -#compdef task - -_task() { - local -a commands - local tasks=$(task comp_targets) - - while IFS= read -r line; do - if [[ -n "$line" ]]; then - commands+=("$line") - fi - done <<< "$tasks" - - _describe -t commands 'task commands' commands -} - -_task "$@" -``` - -Now after running `task shorthand`, your `task` commands will get autocompleted. +- [How does it work](/docs/how-does-it-work.md) +- [Auto completion](/docs/auto-completion.md) +- [SubTaskfiles](/docs/sub-taskfiles.md) # Credits This Taskfile setup is based on [Adrian Cooney's Taskfile](https://github.com/adriancooney/Taskfile) and is widely -adopted by [Enrise](https://enrise.com) in our modified flavour. +adopted by [Enrise](https://enrise.com) in our modified flavor. # Contributors A big thanks to all the contributors of Taskfile! -![contirubtor avatars](https://contrib.rocks/image?repo=enrise/taskfile) +![contributor avatars](https://contrib.rocks/image?repo=enrise/taskfile) diff --git a/dev/linting/eslint.config.mjs b/dev/linting/eslint.config.mjs index 6f698a5..b96b125 100644 --- a/dev/linting/eslint.config.mjs +++ b/dev/linting/eslint.config.mjs @@ -63,6 +63,6 @@ export default [ }, }, { - ignores: ['.next/', 'out/'], + ignores: ['.next/', 'out/', 'next-env.d.ts'], }, ]; diff --git a/docs/auto-completion.md b/docs/auto-completion.md new file mode 100644 index 0000000..7ba3027 --- /dev/null +++ b/docs/auto-completion.md @@ -0,0 +1,25 @@ +# Auto-completion + +Autocompletion works when you use `zsh` and `oh-my-zsh`. Create the following file in your oh-my-zsh directory +`~/.oh-my-zsh/completions/_task.zsh`: + +```shell +#compdef task + +_task() { + local -a commands + local tasks=$(task comp_targets) + + while IFS= read -r line; do + if [[ -n "$line" ]]; then + commands+=("$line") + fi + done <<< "$tasks" + + _describe -t commands 'task commands' commands +} + +_task "$@" +``` + +Now after running `task shorthand`, your `task` commands will get autocompleted. diff --git a/docs/how-does-it-work.md b/docs/how-does-it-work.md new file mode 100644 index 0000000..77a0cce --- /dev/null +++ b/docs/how-does-it-work.md @@ -0,0 +1,39 @@ +# How does it work? + +Taskfiles are simple bash scripts, but an easy-to-read function format. There are some things that we need to explain +for our Taskfile setup. It all starts with a `Taskfile`. Download your `Taskfile` from +[taskfile.sh](https://taskfile.sh) and save it. Make sure the Taskfile is executable: `chmod +x ./Taskfile`. You can now +run `./Taskfile` in your terminal. + +## Tasks + +A task is defined by creating a function that starts with `task:`. This defines a task that can be triggered by running +the `./Taskfile`. Right next to the task, you should add a task definition with two hashes. This will let the +`task:help` function know that you're writing the task function definition. So an example task will look like the +following: + +```shell +function task:example { ## Show some example text + title "Example" + echo "This is an example task." +} +``` + +In a task you can call other functions, and run all tooling you desire. Now running `./Taskfile example` will execute +the new task. + +## Sections + +To group multiple tasks, sections can be created in your Taskfile. A section is created by creating a comment line with +a double hashtag like so: + +```shell +## Project section +``` + +Lines with only a single `#` will not appear as section in `task:help` and can be seen as plain comments. + +## Help command + +Running `./Taskfile help`, the `task:help` function is triggered. This task will list all available sections and tasks +using the double `##` comments you've learned about above. Now it's clear how you can run any other task! diff --git a/docs/sub-taskfiles.md b/docs/sub-taskfiles.md new file mode 100644 index 0000000..a64a4b1 --- /dev/null +++ b/docs/sub-taskfiles.md @@ -0,0 +1,55 @@ +# SubTaskfiles + +SubTaskfiles allow you to divide your tasks across multiple files while still calling them from a single entrypoint (a +familiar, regular Taskfile). + +Use them to split off groups of tasks that can be logically grouped together, like for specific use-cases or because +they are rarely used. For example: git-hooks, frontend- / backend-specific tasks, tasks for (infrequently occurring) +procedures, CI-only tasks, etc. + +Tasks in SubTaskfiles are never called directly, but "via" a task in the root Taskfile, like this: +`Usage: ./Taskfile foo ` + +## How + +Put this in the root Taskfile: + +```shell +function task:foo { ## bar + SUBTASKFILE_DIR="./path/to/subtaskfile/" + SUBTASKFILE_TASK="foo" + TASKFILE_FILE="$SUBTASKFILE_DIR/SubTaskfile" + + source "$TASKFILE_FILE" + + task:"${@-help}" +} + +# Optional: use proxy-tasks like this for tasks you want to run straight from the root Taskfile +function task:baz { ## Call `foo baz` directly + task:foo baz +} +``` + +Create a file named `SubTaskfile` in a relevant location. It should only contain the tasks and sections you think useful +for that location (as utility stuff like `task:help`, `BLUE` env vars, `file:ensure`, etc. are provided by the root +Taskfile). This is a full example (with a few README specific explanations marked by `###`): + +```shell +#!/usr/bin/env bash +### Adding `#!/usr/bin/env bash` is optional but recommended, as it hints editors etc. what syntax highlighting to use. + +### When you refer to files in the SubTaskfile's directory, you need prefix them with $SUBTASKFILE_DIR +function task:call-script { ## Call a script + "$SUBTASKFILE_DIR/some-script.sh" +} + +# ========================================================= +# SubTaskfile helper +# ========================================================= + +### Optional, but without this, you can only run `./Taskfile foo` to get help output +function task:_help { ## Show all available tasks + task:help +} +``` diff --git a/src/app/docs/auto-completion/page.tsx b/src/app/docs/auto-completion/page.tsx new file mode 100644 index 0000000..3257ad7 --- /dev/null +++ b/src/app/docs/auto-completion/page.tsx @@ -0,0 +1,14 @@ +import { Metadata } from 'next'; +import Content from '@/components/Content'; + +import markdown from '@/../docs/auto-completion.md'; + +export const generateMetadata = (): Metadata => ({ + title: 'Auto completion • taskfile.sh', + description: + 'Quickly kick start your project by moving all your development commands to one easy to understand and maintain place.', +}); + +export default function Page() { + return ; +} diff --git a/src/app/docs/how-does-it-work/page.tsx b/src/app/docs/how-does-it-work/page.tsx new file mode 100644 index 0000000..e95dea1 --- /dev/null +++ b/src/app/docs/how-does-it-work/page.tsx @@ -0,0 +1,14 @@ +import { Metadata } from 'next'; +import Content from '@/components/Content'; + +import markdown from '@/../docs/how-does-it-work.md'; + +export const generateMetadata = (): Metadata => ({ + title: 'How does it work? • taskfile.sh', + description: + 'Quickly kick start your project by moving all your development commands to one easy to understand and maintain place.', +}); + +export default function Page() { + return ; +} diff --git a/src/app/about/page.tsx b/src/app/docs/page.tsx similarity index 90% rename from src/app/about/page.tsx rename to src/app/docs/page.tsx index 9eb34e0..2639cc0 100644 --- a/src/app/about/page.tsx +++ b/src/app/docs/page.tsx @@ -4,7 +4,7 @@ import Content from '@/components/Content'; import readme from '@/../README.md'; export const generateMetadata = (): Metadata => ({ - title: 'Information • taskfile.sh', + title: 'Documentation • taskfile.sh', description: 'Quickly kick start your project by moving all your development commands to one easy to understand and maintain place.', }); diff --git a/src/app/docs/sub-taskfiles/page.tsx b/src/app/docs/sub-taskfiles/page.tsx new file mode 100644 index 0000000..f851d21 --- /dev/null +++ b/src/app/docs/sub-taskfiles/page.tsx @@ -0,0 +1,14 @@ +import { Metadata } from 'next'; +import Content from '@/components/Content'; + +import markdown from '@/../docs/sub-taskfiles.md'; + +export const generateMetadata = (): Metadata => ({ + title: 'SubTaskfiles • taskfile.sh', + description: + 'Quickly kick start your project by moving all your development commands to one easy to understand and maintain place.', +}); + +export default function Page() { + return ; +} diff --git a/src/app/globals.scss b/src/app/globals.scss index a90e5f9..30eb559 100644 --- a/src/app/globals.scss +++ b/src/app/globals.scss @@ -8,12 +8,12 @@ } body { - background: #ff00cc; /* fallback for old browsers */ - background: -webkit-linear-gradient(to left, #ff00cc, #333399); /* Chrome 10-25, Safari 5.1-6 */ + background: $color-yellow-50; /* fallback for old browsers */ background: linear-gradient( - to left, - #ff00cc, - #333399 + 220deg, + $color-yellow-50, + $color-purple-50, + $color-black ); /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */ font-family: var(--font-text), sans-serif; } @@ -25,7 +25,7 @@ pre { } a { - color: $color-blue-50; + color: $color-purple-50; text-decoration: none; } diff --git a/src/components/Content/Content.tsx b/src/components/Content/Content.tsx index 50b873b..89d3c99 100644 --- a/src/components/Content/Content.tsx +++ b/src/components/Content/Content.tsx @@ -1,35 +1,79 @@ +'use client'; + import { ReactElement } from 'react'; import styles from './content.module.scss'; import Window from '@/components/Window'; import Markdown from 'markdown-to-jsx'; import { highlighter } from '@/components/Generator/GeneredTaskfile/Highlighter'; +import Link from 'next/link'; +import { usePathname } from 'next/navigation'; +import SaveFile from '@/components/Generator/GeneredTaskfile/SaveFile'; + +const links = [ + { href: '/docs', label: 'About Taskfile' }, + { href: '/docs/how-does-it-work', label: 'How does it work?' }, + { href: '/docs/auto-completion', label: 'Auto completion' }, + { href: '/docs/sub-taskfiles', label: 'SubTaskfiles' }, +]; type WindowProps = { content: string; }; -const Content = ({ content }: WindowProps): ReactElement => ( -
- -
{highlighter(original.children.props.children)}
, - img: ({ alt, src }) => {alt}, - a: ({ href, props, children }) => ( - - {children} - - ), - }, - }} - > - {content} -
-
-
-); +const Content = ({ content }: WindowProps): ReactElement => { + const path = usePathname(); + + return ( +
+
+ +
+ {links.map(({ href, label }) => ( + + {label} + + ))} +
+
+
+ + ( +
+									
+									{highlighter(original.children.props.children)}
+								
+ ), + img: ({ alt, src }) => {alt}, + a: ({ href, props, children }) => { + if (href.includes('.md')) { + const target = href.replace('.md', ''); + + return ( + + {children} + + ); + } + + return ( + + {children} + + ); + }, + }, + }} + > + {content} +
+
+
+ ); +}; export default Content; diff --git a/src/components/Content/content.module.scss b/src/components/Content/content.module.scss index 83124a9..2764aa8 100644 --- a/src/components/Content/content.module.scss +++ b/src/components/Content/content.module.scss @@ -1,45 +1,101 @@ @use 'mixins/from-size' as *; +@use 'variables/color' as *; .container { + display: flex; + gap: 1rem; + flex-direction: column; padding: 1rem; margin: 0 auto; width: 100%; - max-width: 54rem; + max-width: 80rem; line-height: 150%; + justify-content: start; @include from(small) { padding: 2rem; + gap: 2rem; } @include from(medium) { padding: 4rem; + gap: 4rem; + } + + @include from(large) { + flex-direction: row; + } +} + +.menu { + width: 100%; + min-height: 1rem; + + @include from(large) { + width: 20rem; + flex-shrink: 0; + flex-grow: 0; + } + + .menuWindow { + min-height: 1rem; + } +} + +.links { + display: flex; + flex-direction: column; + gap: 0.5rem; + + a { + display: block; + padding: 0.5rem 1rem; + background: #f0f0f0; + font-weight: 'semi-bold'; + border-radius: 0.5rem; + color: #000; + transition: background 0.2s; + + &:hover, + &.active { + background: $color-purple-10; + text-decoration: none; + } } } .content { display: flex; flex-direction: column; - gap: 1rem; + gap: 1.5rem; ul { padding-left: 2rem; } pre { + position: relative; padding: 1rem; font-size: 0.8rem; background: rgba(16, 0, 31, 0.87); border-radius: 0.5rem; + overflow: hidden; + min-height: 6rem; } code { - background: #e0e0e0; - color: #202020; + background: rgba(16, 0, 31, 0.87); + color: $color-white; padding: 0.2rem; - border-radius: 0.2rem; + border-radius: 0.3rem; } } +.content .preSave { + top: 1rem; +} + .image { max-width: 100%; + border-radius: 0.5rem; } diff --git a/src/components/Desktop/Desktop.tsx b/src/components/Desktop/Desktop.tsx index 568974c..fa8853f 100644 --- a/src/components/Desktop/Desktop.tsx +++ b/src/components/Desktop/Desktop.tsx @@ -22,8 +22,8 @@ const Desktop = ({ children }: DesktopProps): ReactElement => { Generate your Taskfile - - About Taskfiles + + Documentation diff --git a/src/components/Form/Checkbox/checkbox.module.css b/src/components/Form/Checkbox/checkbox.module.css index f76864b..7876e48 100644 --- a/src/components/Form/Checkbox/checkbox.module.css +++ b/src/components/Form/Checkbox/checkbox.module.css @@ -61,6 +61,10 @@ transform: translateY(-50%) scale(1); } +.checkbox input:checked + span { + background: #a1e1aa76; +} + .label { user-select: none; } diff --git a/src/components/Generator/Generator.tsx b/src/components/Generator/Generator.tsx index c0d97a8..a73c7ff 100644 --- a/src/components/Generator/Generator.tsx +++ b/src/components/Generator/Generator.tsx @@ -9,6 +9,7 @@ import Settings from './Settings'; import GeneratedTaskfile from './GeneredTaskfile'; import Form from '@/components/Form'; import { Font } from './GeneredTaskfile/buildHeader'; +import SubTaskfile from './GeneredTaskfile/addons/subTaskfile/SubTaskfile'; export type GeneratorSettings = { project: string; @@ -17,6 +18,7 @@ export type GeneratorSettings = { developmentProxy: boolean; checkoutGitRequest: 'none' | 'github' | 'gitlab'; configureGitHooks: boolean; + subTaskfile: boolean; fileUtilities: boolean; appUtilities: boolean; }; @@ -32,14 +34,23 @@ const Generator = (): ReactElement => { }, }); + const hasSubTaskfile = form.watch('subTaskfile'); + return (
{})}> - - - +
+ + + + {hasSubTaskfile && ( + + + + )} +
); }; diff --git a/src/components/Generator/GeneredTaskfile/SaveFile/SaveFile.tsx b/src/components/Generator/GeneredTaskfile/SaveFile/SaveFile.tsx index baeb701..a85eafc 100644 --- a/src/components/Generator/GeneredTaskfile/SaveFile/SaveFile.tsx +++ b/src/components/Generator/GeneredTaskfile/SaveFile/SaveFile.tsx @@ -6,9 +6,10 @@ import styles from './save-file.module.scss'; type SaveFileProps = { content: string; + className?: string; }; -const SaveFile = ({ content }: SaveFileProps): ReactElement => { +const SaveFile = ({ content, className = '' }: SaveFileProps): ReactElement => { const [isCopied, setCopied] = useState(false); const copyToClipboard = (): void => { @@ -29,7 +30,7 @@ const SaveFile = ({ content }: SaveFileProps): ReactElement => { }; return ( -
+