├── .env.example ├── .github ├── FUNDING.yml ├── dependabot.yml └── workflows │ ├── build.yml │ └── release.yml ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── analysis_options.yaml ├── assets ├── alfredhatcog.png ├── google.png └── icon.png ├── bin ├── main.dart ├── main_helpers.dart └── src │ ├── env │ ├── .gitignore │ └── env.dart │ ├── models │ ├── search_result.dart │ ├── search_result.g.dart │ ├── search_result_hierarchy.dart │ ├── search_result_hierarchy.g.dart │ └── user_config_key.dart │ └── services │ └── algolia_search.dart ├── build.sh ├── configure.png ├── demo.gif ├── entitlements.plist ├── info.plist ├── pubspec.lock └── pubspec.yaml /.env.example: -------------------------------------------------------------------------------- 1 | APP_VERSION= 2 | GITHUB_REPOSITORY_URL= 3 | ALGOLIA_SEARCH_INDEX= 4 | ALGOLIA_APPLICATION_ID= 5 | ALGOLIA_SEARCH_ONLY_API_KEY= 6 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: techouse 2 | custom: [ "https://paypal.me/ktusar" ] 3 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "pub" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | - package-ecosystem: "github-actions" 8 | directory: "/" 9 | schedule: 10 | interval: "weekly" -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build package 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | runs-on: 7 | description: 'The runner type' 8 | required: true 9 | type: string 10 | defaults: 11 | run: 12 | shell: bash 13 | env: 14 | PUB_ENVIRONMENT: bot.github 15 | permissions: read-all 16 | 17 | jobs: 18 | publish: 19 | name: "Build" 20 | runs-on: "${{ inputs.runs-on }}" 21 | environment: build 22 | env: 23 | GITHUB_REPOSITORY_URL: ${{ github.server_url }}/${{ github.repository }} 24 | steps: 25 | - uses: dart-lang/setup-dart@v1 26 | with: 27 | sdk: stable 28 | - id: checkout 29 | uses: actions/checkout@v4 30 | - name: Compare version with ref/tag 31 | if: startsWith(github.ref, 'refs/tags/') 32 | id: compare_version_with_tag 33 | run: | 34 | set -e 35 | VERSION=$(awk '/^version: / {print $2}' pubspec.yaml) 36 | TAG=${GITHUB_REF_NAME#v} 37 | if [[ "$VERSION" != "$TAG" ]]; then 38 | echo "Version in pubspec.yaml ($VERSION) does not match tag ($TAG)" 39 | exit 1 40 | fi 41 | echo "VERSION=$VERSION" >> $GITHUB_ENV 42 | - name: Configure .env file 43 | id: generate_env_file 44 | env: 45 | ALGOLIA_SEARCH_INDEX: ${{ vars.ALGOLIA_SEARCH_INDEX }} 46 | ALGOLIA_APPLICATION_ID: ${{ vars.ALGOLIA_APPLICATION_ID }} 47 | ALGOLIA_SEARCH_ONLY_API_KEY: ${{ vars.ALGOLIA_SEARCH_ONLY_API_KEY }} 48 | run: | 49 | set -e 50 | mv .env.example .env 51 | sed -i '' "s#APP_VERSION=.*#APP_VERSION=$VERSION#" .env 52 | sed -i '' "s#GITHUB_REPOSITORY_URL=.*#GITHUB_REPOSITORY_URL=$GITHUB_REPOSITORY_URL#" .env 53 | sed -i '' "s#ALGOLIA_SEARCH_INDEX=.*#ALGOLIA_SEARCH_INDEX=$ALGOLIA_SEARCH_INDEX#" .env 54 | sed -i '' "s#ALGOLIA_APPLICATION_ID=.*#ALGOLIA_APPLICATION_ID=$ALGOLIA_APPLICATION_ID#" .env 55 | sed -i '' "s#ALGOLIA_SEARCH_ONLY_API_KEY=.*#ALGOLIA_SEARCH_ONLY_API_KEY=$ALGOLIA_SEARCH_ONLY_API_KEY#" .env 56 | - name: Configure the info.plist 57 | id: info_plist 58 | run: | 59 | set -e 60 | /usr/libexec/PlistBuddy -c "Set :version $VERSION" info.plist 61 | /usr/libexec/PlistBuddy -c "Set :webaddress $GITHUB_REPOSITORY_URL" info.plist 62 | - name: Install dependencies 63 | id: install_dependencies 64 | run: | 65 | dart pub get 66 | dart pub global activate -sgit https://github.com/techouse/dart_pubspec_licenses_lite 67 | - name: Run Dart code generation 68 | id: generate_code 69 | run: dart run build_runner build --delete-conflicting-outputs 70 | - name: Check formatting 71 | run: dart format --output=none --set-exit-if-changed . 72 | - name: Analyze 73 | run: dart analyze --fatal-infos 74 | - name: Build executable 75 | id: build_executable 76 | run: bash build.sh 77 | - name: Install the Apple certificate 78 | id: install_certificate 79 | env: 80 | BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }} 81 | P12_PASSWORD: ${{ secrets.P12_PASSWORD }} 82 | KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} 83 | run: | 84 | set -e 85 | CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12 86 | KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db 87 | 88 | # import certificate 89 | echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH 90 | 91 | # create temporary keychain 92 | security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH 93 | security set-keychain-settings -lut 21600 $KEYCHAIN_PATH 94 | security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH 95 | 96 | # import certificate to keychain 97 | security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH 98 | security list-keychain -d user -s $KEYCHAIN_PATH 99 | - name: Sign executable 100 | id: sign_executable 101 | env: 102 | BUILD_CERTIFICATE_SHA1: ${{ secrets.BUILD_CERTIFICATE_SHA1 }} 103 | run: | 104 | set -e 105 | BUNDLE_ID=$(/usr/libexec/PlistBuddy -c 'print ":bundleid"' info.plist) 106 | codesign \ 107 | --sign="$BUILD_CERTIFICATE_SHA1" \ 108 | --identifier="$BUNDLE_ID" \ 109 | --deep \ 110 | --force \ 111 | --options=runtime \ 112 | --entitlement="entitlements.plist" \ 113 | --timestamp \ 114 | build/dist/workflow 115 | - name: Verify signature 116 | id: verify_executable_signature 117 | env: 118 | TEAM_ID: ${{ secrets.TEAM_ID }} 119 | run: | 120 | set -e 121 | if [[ $(codesign -dv build/dist/workflow 2>&1 | awk -F= '/TeamIdentifier/{print $2}') != "$TEAM_ID" ]]; then 122 | echo "The TeamIdentifier in the signature does not match the signing TeamIdentifier." 123 | exit 1 124 | fi 125 | - name: Package executable into ZIP archive 126 | id: zip_executable 127 | run: | 128 | set -e 129 | zip -j build/dist/workflow.zip build/dist/workflow 130 | - name: Create notarytool Keychain profile 131 | id: create_keychain_profile 132 | env: 133 | APPLE_ID: ${{ secrets.APPLE_ID }} 134 | TEAM_ID: ${{ secrets.TEAM_ID }} 135 | NOTARYTOOL_PASSWORD: ${{ secrets.NOTARYTOOL_PASSWORD }} 136 | NOTARYTOOL_KEYCHAIN_PROFILE: ${{ vars.NOTARYTOOL_KEYCHAIN_PROFILE }} 137 | run: | 138 | set -e 139 | xcrun notarytool \ 140 | store-credentials "$NOTARYTOOL_KEYCHAIN_PROFILE" \ 141 | --apple-id "$APPLE_ID" \ 142 | --team-id "$TEAM_ID" \ 143 | --password "$NOTARYTOOL_PASSWORD" 144 | - name: Notarize executable 145 | id: notarize_executable 146 | env: 147 | NOTARYTOOL_KEYCHAIN_PROFILE: ${{ vars.NOTARYTOOL_KEYCHAIN_PROFILE }} 148 | run: | 149 | set -e 150 | xcrun notarytool \ 151 | submit build/dist/workflow.zip \ 152 | --keychain-profile "$NOTARYTOOL_KEYCHAIN_PROFILE" \ 153 | --wait 154 | - name: Delete obsolete ZIP archive 155 | id: delete_zip_archive 156 | run: | 157 | set -e 158 | rm -rf build/dist/workflow.zip 159 | - name: Compress artifacts 160 | id: compress_artifacts 161 | env: 162 | WORKFLOW_NAME: ${{ vars.WORKFLOW_NAME }} 163 | working-directory: build/dist 164 | run: | 165 | set -e 166 | ARTIFACT_NAME=${WORKFLOW_NAME}-v${VERSION}-$(uname -m) 167 | echo "ARTIFACT_NAME=$ARTIFACT_NAME" >> $GITHUB_ENV 168 | find . -not -path "./*_cache*" -exec zip --symlinks "../${ARTIFACT_NAME}.zip" {} + 169 | echo "ARTIFACT_PATH=build/${ARTIFACT_NAME}.zip" >> $GITHUB_ENV 170 | - name: Artifact 171 | id: success_artifact 172 | uses: actions/upload-artifact@v4 173 | with: 174 | name: ${{ env.ARTIFACT_NAME }} 175 | path: ${{ env.ARTIFACT_PATH }} 176 | retention-days: 1 177 | - name: Clean up keychain and build directory 178 | id: clean_up 179 | if: ${{ always() }} 180 | run: | 181 | security delete-keychain $RUNNER_TEMP/app-signing.keychain-db 182 | rm -rf $RUNNER_TEMP/build_certificate.p12 183 | rm .env 184 | rm -rf build 185 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release package 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v[0-9]+.[0-9]+.[0-9]+*' 7 | defaults: 8 | run: 9 | shell: bash 10 | env: 11 | PUB_ENVIRONMENT: bot.github 12 | permissions: read-all 13 | 14 | jobs: 15 | build: 16 | name: "Build" 17 | strategy: 18 | matrix: 19 | os: [macos-latest, macos-13] 20 | fail-fast: true 21 | uses: ./.github/workflows/build.yml 22 | with: 23 | runs-on: ${{ matrix.os }} 24 | secrets: inherit 25 | github_release: 26 | name: "Github Release" 27 | needs: build 28 | environment: build 29 | runs-on: ubuntu-latest 30 | permissions: 31 | contents: write 32 | steps: 33 | - uses: actions/checkout@v4 34 | - name: Read pubspec.yaml version 35 | id: read_pubspec_version 36 | run: | 37 | set -e 38 | VERSION=$(yq -r '.version' pubspec.yaml) 39 | echo "VERSION=$VERSION" >> $GITHUB_ENV 40 | - name: Get arm64 artifact 41 | id: download_arm64_artifact 42 | uses: actions/download-artifact@v4 43 | env: 44 | WORKFLOW_NAME: ${{ vars.WORKFLOW_NAME }} 45 | ARCH: arm64 46 | with: 47 | name: ${{ env.WORKFLOW_NAME }}-v${{ env.VERSION }}-${{ env.ARCH }} 48 | path: ${{ runner.temp }}/download 49 | - name: Get x86_64 artifact 50 | id: download_x86_64_artifact 51 | uses: actions/download-artifact@v4 52 | env: 53 | WORKFLOW_NAME: ${{ vars.WORKFLOW_NAME }} 54 | ARCH: x86_64 55 | with: 56 | name: ${{ env.WORKFLOW_NAME }}-v${{ env.VERSION }}-${{ env.ARCH }} 57 | path: ${{ runner.temp }}/download 58 | - name: Unzip artifacts 59 | env: 60 | WORKFLOW_NAME: ${{ vars.WORKFLOW_NAME }} 61 | id: unzip_artifacts 62 | working-directory: ${{ runner.temp }}/download 63 | run: | 64 | set -e 65 | for ARCH in "arm64" "x86_64"; do 66 | mkdir -p $ARCH 67 | unzip -q ${{ env.WORKFLOW_NAME }}-v${{ env.VERSION }}-${ARCH}.zip -d $ARCH 68 | done 69 | - name: Create Alfred Workflow 70 | id: create_alfred_workflow 71 | env: 72 | WORKFLOW_NAME: ${{ vars.WORKFLOW_NAME }} 73 | working-directory: ${{ runner.temp }}/download 74 | run: | 75 | set -e 76 | mv x86_64/workflow arm64/workflow_intel 77 | pushd arm64 78 | find . -not -path "./*_cache*" -exec zip --symlinks "../${WORKFLOW_NAME}-v${VERSION}.alfredworkflow" {} + 79 | popd 80 | - name: Release 81 | id: release_workflow 82 | env: 83 | WORKFLOW_NAME: ${{ vars.WORKFLOW_NAME }} 84 | uses: softprops/action-gh-release@v2 85 | with: 86 | files: ${{ runner.temp }}/download/${{ env.WORKFLOW_NAME }}-v${{ env.VERSION }}.alfredworkflow 87 | - name: Clean up keychain and build directory 88 | id: clean_up 89 | if: ${{ always() }} 90 | run: | 91 | rm -rf $RUNNER_TEMP/download 92 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Files and directories created by pub. 2 | .dart_tool/ 3 | .packages 4 | 5 | # Conventional directory for build output. 6 | build/ 7 | 8 | # IDE specific 9 | .idea/ 10 | 11 | # macOS specific 12 | .DS_Store 13 | 14 | bin/*_cache/ 15 | sign.sh 16 | 17 | .env 18 | prefs.plist 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Klemen Tušar 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Makefile 2 | 3 | help: 4 | @printf "%-20s %s\n" "Target" "Description" 5 | @printf "%-20s %s\n" "------" "-----------" 6 | @make -pqR : 2>/dev/null \ 7 | | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' \ 8 | | sort \ 9 | | egrep -v -e '^[^[:alnum:]]' -e '^$@$$' \ 10 | | xargs -I _ sh -c 'printf "%-20s " _; make _ -nB | (grep -i "^# Help:" || echo "") | tail -1 | sed "s/^# Help: //g"' 11 | 12 | analyze: 13 | @# Help: Analyze the project's Dart code. 14 | dart analyze --fatal-infos 15 | 16 | compile: 17 | @# Help: Compile the executable binary 18 | bash ./build.sh 19 | 20 | check_format: 21 | @# Help: Check the formatting of one or more Dart files. 22 | dart format --output=none --set-exit-if-changed . 23 | 24 | check_outdated: 25 | @# Help: Check which of the project's packages are outdated. 26 | dart pub outdated 27 | 28 | check_style: 29 | @# Help: Analyze the project's Dart code and check the formatting one or more Dart files. 30 | make analyze && make check_format 31 | 32 | clean_code_gen: 33 | @# Help: Remove all generated files. 34 | dart run build_runner clean 35 | 36 | code_gen: 37 | @# Help: Run the build system for Dart code generation and modular compilation. 38 | dart run build_runner build --delete-conflicting-outputs 39 | 40 | code_gen_watcher: 41 | @# Help: Run the build system for Dart code generation and modular compilation as a watcher. 42 | dart run build_runner watch --delete-conflicting-outputs 43 | 44 | format: 45 | @# Help: Format one or more Dart files. 46 | dart format . 47 | 48 | install: 49 | @# Help: Install all the project's packages 50 | dart pub get 51 | 52 | upgrade: 53 | @# Help: Upgrade all the project's packages. 54 | dart pub upgrade 55 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tailwind CSS Docs Workflow for Alfred 2 | 3 | ![GitHub release](https://img.shields.io/github/release/techouse/alfred-tailwindcss-docs.svg) 4 | ![GitHub All Releases](https://img.shields.io/github/downloads/techouse/alfred-tailwindcss-docs/total.svg) 5 | ![GitHub](https://img.shields.io/github/license/techouse/alfred-tailwindcss-docs.svg) 6 | [![GitHub Sponsors](https://img.shields.io/github/sponsors/techouse)](https://github.com/sponsors/techouse) 7 | 8 | 9 | Search the [Tailwind CSS documentation](https://tailwindcss.com/docs/) using [Alfred](https://www.alfredapp.com/). 10 | 11 | ![demo](demo.gif) 12 | 13 | ## Installation 14 | 15 | 1. [Download the latest version](https://github.com/techouse/alfred-tailwindcss-docs/releases/latest) 16 | 2. Install the workflow by double-clicking the `.alfredworkflow` file 17 | 3. You can add the workflow to a category, then click "Import" to finish importing. You'll now see the workflow listed in the left sidebar of your Workflows preferences pane. 18 | 19 | ## Usage 20 | 21 | Just type `twd` followed by your search query. 22 | 23 | ``` 24 | twd background color 25 | ``` 26 | 27 | Either press `⌘Y` to Quick Look the result, or press `` to open it in your web browser. 28 | 29 | ## Changing the Tailwind CSS version to search 30 | 31 | The workflow supports searching the documentation of several versions. To change the branch, configure the Workflow as show in the image below. 32 | 33 | ![configure](configure.png) 34 | 35 | ### Note 36 | 37 | The lightning fast search is powered by [Algolia](https://www.algolia.com) using the _same_ index as the official [Tailwind CSS](https://tailwindcss.com/) website. 38 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:lints/recommended.yaml 2 | 3 | linter: 4 | rules: 5 | avoid_print: true 6 | prefer_single_quotes: true 7 | -------------------------------------------------------------------------------- /assets/alfredhatcog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/techouse/alfred-tailwindcss-docs/0eb9aef2044e76376681e59621a8a9f0894f61d0/assets/alfredhatcog.png -------------------------------------------------------------------------------- /assets/google.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/techouse/alfred-tailwindcss-docs/0eb9aef2044e76376681e59621a8a9f0894f61d0/assets/google.png -------------------------------------------------------------------------------- /assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/techouse/alfred-tailwindcss-docs/0eb9aef2044e76376681e59621a8a9f0894f61d0/assets/icon.png -------------------------------------------------------------------------------- /bin/main.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io' show exitCode, stdout; 2 | 3 | import 'package:alfred_workflow/alfred_workflow.dart'; 4 | import 'package:algoliasearch/src/model/hit.dart'; 5 | import 'package:algoliasearch/src/model/search_response.dart'; 6 | import 'package:args/args.dart' show ArgParser, ArgResults; 7 | import 'package:cli_script/cli_script.dart'; 8 | import 'package:html_unescape/html_unescape.dart' show HtmlUnescape; 9 | 10 | import 'src/env/env.dart' show Env; 11 | import 'src/models/search_result.dart' show SearchResult; 12 | import 'src/models/user_config_key.dart' show UserConfigKey; 13 | import 'src/services/algolia_search.dart' show AlgoliaSearch; 14 | 15 | part 'main_helpers.dart'; 16 | 17 | bool _verbose = false; 18 | bool _update = false; 19 | 20 | void main(List arguments) { 21 | wrapMain(() async { 22 | try { 23 | exitCode = 0; 24 | 25 | _workflow.clearItems(); 26 | 27 | final ArgParser parser = ArgParser() 28 | ..addOption('query', abbr: 'q', defaultsTo: '') 29 | ..addFlag('verbose', abbr: 'v', defaultsTo: false) 30 | ..addFlag('update', abbr: 'u', defaultsTo: false); 31 | final ArgResults args = parser.parse(arguments); 32 | 33 | _update = args['update']; 34 | if (_update) { 35 | stdout.writeln('Updating workflow...'); 36 | 37 | return await _updater.update(); 38 | } 39 | 40 | _verbose = args['verbose']; 41 | 42 | final Map? userDefaults = 43 | await _workflow.getUserDefaults(); 44 | 45 | final AlfredUserConfigurationSelect? tailwindVersion = 46 | userDefaults?[UserConfigKey.tailwindVersion.toString()] 47 | as AlfredUserConfigurationSelect?; 48 | 49 | final AlfredUserConfigurationCheckBox? useFileCache = 50 | userDefaults?[UserConfigKey.useFileCache.toString()] 51 | as AlfredUserConfigurationCheckBox?; 52 | 53 | final AlfredUserConfigurationNumberSlider? fileCacheMaxEntries = 54 | userDefaults?[UserConfigKey.fileCacheMaxEntries.toString()] 55 | as AlfredUserConfigurationNumberSlider?; 56 | 57 | final AlfredUserConfigurationCheckBox? useAlfredCache = 58 | userDefaults?[UserConfigKey.useAlfredCache.toString()] 59 | as AlfredUserConfigurationCheckBox?; 60 | 61 | final AlfredUserConfigurationNumberSlider? cacheTimeToLive = 62 | userDefaults?[UserConfigKey.cacheTtl.toString()] 63 | as AlfredUserConfigurationNumberSlider?; 64 | 65 | if (tailwindVersion == null) { 66 | throw Exception('tailwind_version not set!'); 67 | } 68 | 69 | final List query = 70 | args['query'].replaceAll(RegExp(r'\s+'), ' ').trim().split(' '); 71 | query.removeWhere((str) => str == tailwindVersion.value); 72 | 73 | final String queryString = query.join(' ').trim().toLowerCase(); 74 | 75 | if (_verbose) stdout.writeln('Query: "$queryString"'); 76 | 77 | if (useAlfredCache?.value ?? false) { 78 | _workflow.useAutomaticCache = true; 79 | } else if (useFileCache?.value ?? false) { 80 | _workflow.maxCacheEntries = 81 | fileCacheMaxEntries?.value ?? fileCacheMaxEntries?.defaultValue; 82 | } 83 | 84 | _workflow.cacheTimeToLive = cacheTimeToLive?.value; 85 | 86 | if (queryString.isEmpty) { 87 | _showPlaceholder(); 88 | } else { 89 | if (useFileCache?.value ?? false) { 90 | _workflow.cacheKey = '${queryString}_${tailwindVersion.value}'; 91 | } 92 | if ((await _workflow.getItems()).isEmpty) { 93 | await _performSearch(queryString, version: tailwindVersion.value); 94 | } 95 | } 96 | } on FormatException catch (err) { 97 | exitCode = 2; 98 | _workflow.addItem(AlfredItem(title: err.toString())); 99 | } catch (err) { 100 | exitCode = 1; 101 | _workflow.addItem(AlfredItem(title: err.toString())); 102 | if (_verbose) rethrow; 103 | } finally { 104 | if (!_update) { 105 | if (await _updater.updateAvailable()) { 106 | _workflow.run(addToBeginning: updateItem); 107 | } else { 108 | _workflow.run(); 109 | } 110 | } 111 | } 112 | }); 113 | } 114 | -------------------------------------------------------------------------------- /bin/main_helpers.dart: -------------------------------------------------------------------------------- 1 | part of 'main.dart'; 2 | 3 | final HtmlUnescape _unescape = HtmlUnescape(); 4 | 5 | final AlfredWorkflow _workflow = AlfredWorkflow() 6 | ..disableAlfredSmartResultOrdering = true; 7 | 8 | final AlfredUpdater _updater = AlfredUpdater( 9 | githubRepositoryUrl: Env.githubRepositoryUrl, 10 | currentVersion: Env.appVersion, 11 | updateInterval: Duration(days: 7), 12 | ); 13 | 14 | const updateItem = AlfredItem( 15 | title: 'Auto-Update available!', 16 | subtitle: 'Press to auto-update to a new version of this workflow.', 17 | arg: 'update:workflow', 18 | match: 19 | 'Auto-Update available! Press to auto-update to a new version of this workflow.', 20 | icon: AlfredItemIcon(path: 'alfredhatcog.png'), 21 | valid: true, 22 | ); 23 | 24 | void _showPlaceholder() { 25 | _workflow.addItem( 26 | const AlfredItem( 27 | title: 'Search the Tailwind CSS docs...', 28 | icon: AlfredItemIcon(path: 'icon.png'), 29 | ), 30 | ); 31 | } 32 | 33 | Future _performSearch(String query, {required String version}) async { 34 | try { 35 | final SearchResponse snapshot = await AlgoliaSearch.query( 36 | query, 37 | version: version, 38 | ); 39 | 40 | if ((snapshot.nbHits ?? 0) > 0) { 41 | final AlfredItems items = AlfredItems( 42 | snapshot.hits 43 | .map((Hit hit) => SearchResult.fromJson( 44 | {...hit, 'objectID': hit.objectID})) 45 | .map((SearchResult result) { 46 | final int level = int.tryParse(result.type.substring(3)) ?? 0; 47 | final String? title = result.hierarchy.getLevel(level); 48 | final Map hierarchy = result.hierarchy.toJson() 49 | ..removeWhere((_, value) => value == null); 50 | 51 | return AlfredItem( 52 | uid: result.objectID, 53 | title: title!, 54 | subtitle: level > 0 55 | ? _unescape.convert(hierarchy.values.join(' > ')) 56 | : null, 57 | arg: result.url, 58 | text: AlfredItemText( 59 | largeType: title, 60 | copy: result.url, 61 | ), 62 | quickLookUrl: result.url, 63 | icon: AlfredItemIcon(path: 'icon.png'), 64 | valid: true, 65 | ); 66 | }).toList(), 67 | ); 68 | _workflow.addItems(items.items); 69 | } else { 70 | final Uri url = 71 | Uri.https('www.google.com', '/search', {'q': 'Tailwind CSS $query'}); 72 | 73 | _workflow.addItem( 74 | AlfredItem( 75 | title: 'No matching answers found', 76 | subtitle: 'Shall I try and search Google?', 77 | arg: url.toString(), 78 | text: AlfredItemText( 79 | copy: url.toString(), 80 | ), 81 | quickLookUrl: url.toString(), 82 | icon: AlfredItemIcon(path: 'google.png'), 83 | valid: true, 84 | ), 85 | ); 86 | } 87 | } finally { 88 | AlgoliaSearch.dispose(); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /bin/src/env/.gitignore: -------------------------------------------------------------------------------- 1 | *.g.dart 2 | !.gitignore -------------------------------------------------------------------------------- /bin/src/env/env.dart: -------------------------------------------------------------------------------- 1 | import 'package:envied/envied.dart'; 2 | 3 | part 'env.g.dart'; 4 | 5 | @Envied(path: '.env') 6 | abstract class Env { 7 | @EnviedField(varName: 'APP_VERSION') 8 | static const String appVersion = _Env.appVersion; 9 | 10 | @EnviedField(varName: 'GITHUB_REPOSITORY_URL') 11 | static final Uri githubRepositoryUrl = _Env.githubRepositoryUrl; 12 | 13 | @EnviedField(varName: 'ALGOLIA_APPLICATION_ID', obfuscate: true) 14 | static final String algoliaApplicationId = _Env.algoliaApplicationId; 15 | 16 | @EnviedField(varName: 'ALGOLIA_SEARCH_ONLY_API_KEY', obfuscate: true) 17 | static final String algoliaSearchOnlyApiKey = _Env.algoliaSearchOnlyApiKey; 18 | 19 | @EnviedField(varName: 'ALGOLIA_SEARCH_INDEX', obfuscate: true) 20 | static final String algoliaSearchIndex = _Env.algoliaSearchIndex; 21 | } 22 | -------------------------------------------------------------------------------- /bin/src/models/search_result.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | import 'search_result_hierarchy.dart'; 4 | 5 | part 'search_result.g.dart'; 6 | 7 | @JsonSerializable(explicitToJson: true) 8 | class SearchResult { 9 | const SearchResult({ 10 | required this.objectID, 11 | required this.type, 12 | required this.url, 13 | required this.hierarchy, 14 | this.content, 15 | }); 16 | 17 | final String objectID; 18 | final String type; 19 | final String url; 20 | final SearchResultHierarchy hierarchy; 21 | final String? content; 22 | 23 | static const List attributesToRetrieve = [ 24 | 'hierarchy.lvl0', 25 | 'hierarchy.lvl1', 26 | 'hierarchy.lvl2', 27 | 'hierarchy.lvl3', 28 | 'hierarchy.lvl4', 29 | 'hierarchy.lvl5', 30 | 'hierarchy.lvl6', 31 | 'content', 32 | 'type', 33 | 'url', 34 | ]; 35 | 36 | static const List attributesToSnippet = [ 37 | 'hierarchy.lvl1:10', 38 | 'hierarchy.lvl2:10', 39 | 'hierarchy.lvl3:10', 40 | 'hierarchy.lvl4:10', 41 | 'hierarchy.lvl5:10', 42 | 'hierarchy.lvl6:10', 43 | 'content:10', 44 | ]; 45 | 46 | static const String snippetEllipsisText = '...'; 47 | 48 | factory SearchResult.fromJson(Map json) => 49 | _$SearchResultFromJson(json); 50 | 51 | Map toJson() => _$SearchResultToJson(this); 52 | } 53 | -------------------------------------------------------------------------------- /bin/src/models/search_result.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'search_result.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | SearchResult _$SearchResultFromJson(Map json) => SearchResult( 10 | objectID: json['objectID'] as String, 11 | type: json['type'] as String, 12 | url: json['url'] as String, 13 | hierarchy: SearchResultHierarchy.fromJson( 14 | json['hierarchy'] as Map), 15 | content: json['content'] as String?, 16 | ); 17 | 18 | Map _$SearchResultToJson(SearchResult instance) => 19 | { 20 | 'objectID': instance.objectID, 21 | 'type': instance.type, 22 | 'url': instance.url, 23 | 'hierarchy': instance.hierarchy.toJson(), 24 | 'content': instance.content, 25 | }; 26 | -------------------------------------------------------------------------------- /bin/src/models/search_result_hierarchy.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'search_result_hierarchy.g.dart'; 4 | 5 | @JsonSerializable() 6 | class SearchResultHierarchy { 7 | const SearchResultHierarchy({ 8 | required this.lvl0, 9 | this.lvl1, 10 | this.lvl2, 11 | this.lvl3, 12 | this.lvl4, 13 | this.lvl5, 14 | this.lvl6, 15 | }); 16 | 17 | final String lvl0; 18 | final String? lvl1; 19 | final String? lvl2; 20 | final String? lvl3; 21 | final String? lvl4; 22 | final String? lvl5; 23 | final String? lvl6; 24 | 25 | String? getLevel(int level) { 26 | switch (level) { 27 | case 1: 28 | return lvl1; 29 | case 2: 30 | return lvl2; 31 | case 3: 32 | return lvl3; 33 | case 4: 34 | return lvl4; 35 | case 5: 36 | return lvl5; 37 | case 6: 38 | return lvl6; 39 | default: 40 | return lvl0; 41 | } 42 | } 43 | 44 | factory SearchResultHierarchy.fromJson(Map json) => 45 | _$SearchResultHierarchyFromJson(json); 46 | 47 | Map toJson() => _$SearchResultHierarchyToJson(this) 48 | .map((key, value) => MapEntry(key, value?.toString())); 49 | } 50 | -------------------------------------------------------------------------------- /bin/src/models/search_result_hierarchy.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'search_result_hierarchy.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | SearchResultHierarchy _$SearchResultHierarchyFromJson( 10 | Map json) => 11 | SearchResultHierarchy( 12 | lvl0: json['lvl0'] as String, 13 | lvl1: json['lvl1'] as String?, 14 | lvl2: json['lvl2'] as String?, 15 | lvl3: json['lvl3'] as String?, 16 | lvl4: json['lvl4'] as String?, 17 | lvl5: json['lvl5'] as String?, 18 | lvl6: json['lvl6'] as String?, 19 | ); 20 | 21 | Map _$SearchResultHierarchyToJson( 22 | SearchResultHierarchy instance) => 23 | { 24 | 'lvl0': instance.lvl0, 25 | 'lvl1': instance.lvl1, 26 | 'lvl2': instance.lvl2, 27 | 'lvl3': instance.lvl3, 28 | 'lvl4': instance.lvl4, 29 | 'lvl5': instance.lvl5, 30 | 'lvl6': instance.lvl6, 31 | }; 32 | -------------------------------------------------------------------------------- /bin/src/models/user_config_key.dart: -------------------------------------------------------------------------------- 1 | import 'package:recase/recase.dart'; 2 | 3 | enum UserConfigKey { 4 | tailwindVersion, 5 | useAlfredCache, 6 | useFileCache, 7 | cacheTtl, 8 | fileCacheMaxEntries; 9 | 10 | @override 11 | String toString() => name.snakeCase; 12 | } 13 | -------------------------------------------------------------------------------- /bin/src/services/algolia_search.dart: -------------------------------------------------------------------------------- 1 | import 'package:algoliasearch/algoliasearch_lite.dart'; 2 | 3 | import '../env/env.dart'; 4 | import '../models/search_result.dart'; 5 | 6 | class AlgoliaSearch { 7 | AlgoliaSearch._(); 8 | 9 | static final SearchClient _client = SearchClient( 10 | appId: Env.algoliaApplicationId, 11 | apiKey: Env.algoliaSearchOnlyApiKey, 12 | ); 13 | 14 | static Future query( 15 | String queryString, { 16 | required String version, 17 | }) => 18 | _client.searchIndex( 19 | request: SearchForHits( 20 | indexName: Env.algoliaSearchIndex, 21 | query: queryString, 22 | facetFilters: ['version:$version'], 23 | attributesToRetrieve: SearchResult.attributesToRetrieve, 24 | attributesToSnippet: SearchResult.attributesToSnippet, 25 | snippetEllipsisText: SearchResult.snippetEllipsisText, 26 | distinct: 1, 27 | page: 0, 28 | hitsPerPage: 20, 29 | ), 30 | ); 31 | 32 | static dispose() => _client.dispose(); 33 | } 34 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Function to build header 4 | oss_header() { 5 | first=$(printf '%.s#' {1..78}) 6 | second=$( 7 | printf '##' 8 | printf '%.s ' {1..74} 9 | printf '##' 10 | ) 11 | third=$( 12 | printf '##' 13 | printf '%.s ' {1..27} 14 | printf 'OPEN-SOURCE LICENSES' 15 | printf '%.s ' {1..27} 16 | printf '##' 17 | ) 18 | printf "\n\n%s\n%s\n%s\n%s\n%s\n\n" "$first" "$second" "$third" "$second" "$first" 19 | } 20 | 21 | if [ -d "build/dist" ]; then 22 | rm -rf build/dist 23 | fi 24 | 25 | if [ -d "build/debug_info" ]; then 26 | rm -rf build/debug_info 27 | fi 28 | 29 | mkdir -p build/dist build/debug_info 30 | cp -r info.plist assets/* LICENSE README.md build/dist 31 | 32 | if command -v dart-pubspec-licenses-lite; then 33 | oss_header >>build/dist/LICENSE 34 | dart-pubspec-licenses-lite --pubspec-lock pubspec.lock >>build/dist/LICENSE 35 | else 36 | echo 'Info: Unable to generate OSS LICENSES. Please install https://github.com/techouse/dart_pubspec_licenses_lite' 37 | fi 38 | 39 | dart compile exe bin/main.dart -o build/dist/workflow -S build/debug_info/workflow 40 | -------------------------------------------------------------------------------- /configure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/techouse/alfred-tailwindcss-docs/0eb9aef2044e76376681e59621a8a9f0894f61d0/configure.png -------------------------------------------------------------------------------- /demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/techouse/alfred-tailwindcss-docs/0eb9aef2044e76376681e59621a8a9f0894f61d0/demo.gif -------------------------------------------------------------------------------- /entitlements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.cs.allow-unsigned-executable-memory 6 | 7 | 8 | -------------------------------------------------------------------------------- /info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | bundleid 6 | com.techouse.alfred-tailwindcss-docs 7 | category 8 | Productivity 9 | connections 10 | 11 | 54CB9D8A-3FC3-4570-9CDC-CBE9197102B7 12 | 13 | 14 | destinationuid 15 | 32B3C427-9180-4209-9432-B2890069F63E 16 | modifiers 17 | 0 18 | modifiersubtext 19 | 20 | sourceoutputuid 21 | D850B7E1-B6F7-4A5E-8EF6-522CBF4E0A21 22 | vitoclose 23 | 24 | 25 | 26 | destinationuid 27 | 709668B9-4793-4106-9DFE-A58EF9BFA3EE 28 | modifiers 29 | 0 30 | modifiersubtext 31 | 32 | vitoclose 33 | 34 | 35 | 36 | A6C3EF08-1D63-4571-9A71-253A36551FB4 37 | 38 | 39 | destinationuid 40 | 54CB9D8A-3FC3-4570-9CDC-CBE9197102B7 41 | modifiers 42 | 0 43 | modifiersubtext 44 | 45 | vitoclose 46 | 47 | 48 | 49 | 50 | createdby 51 | Klemen Tušar 52 | description 53 | Search the Tailwind CSS documentation using Alfred 54 | disabled 55 | 56 | name 57 | Tailwind CSS Docs 58 | objects 59 | 60 | 61 | config 62 | 63 | concurrently 64 | 65 | escaping 66 | 102 67 | script 68 | [ "$(uname -m)" = "arm64" ] && ./workflow -u || ./workflow_intel -u 69 | scriptargtype 70 | 1 71 | scriptfile 72 | 73 | type 74 | 0 75 | 76 | type 77 | alfred.workflow.action.script 78 | uid 79 | 32B3C427-9180-4209-9432-B2890069F63E 80 | version 81 | 2 82 | 83 | 84 | config 85 | 86 | alfredfiltersresults 87 | 88 | alfredfiltersresultsmatchmode 89 | 0 90 | argumenttreatemptyqueryasnil 91 | 92 | argumenttrimmode 93 | 0 94 | argumenttype 95 | 0 96 | escaping 97 | 102 98 | keyword 99 | twd 100 | queuedelaycustom 101 | 3 102 | queuedelayimmediatelyinitially 103 | 104 | queuedelaymode 105 | 2 106 | queuemode 107 | 1 108 | runningsubtext 109 | Fetching the documentation ... 110 | script 111 | [ "$(uname -m)" = "arm64" ] && ./workflow -q "{query}" || ./workflow_intel -q "{query}" 112 | scriptargtype 113 | 0 114 | scriptfile 115 | 116 | subtext 117 | Everything you need to know about Tailwind CSS 118 | title 119 | Search the Tailwind CSS documentation 120 | type 121 | 0 122 | withspace 123 | 124 | 125 | type 126 | alfred.workflow.input.scriptfilter 127 | uid 128 | A6C3EF08-1D63-4571-9A71-253A36551FB4 129 | version 130 | 3 131 | 132 | 133 | config 134 | 135 | conditions 136 | 137 | 138 | inputstring 139 | {query} 140 | matchcasesensitive 141 | 142 | matchmode 143 | 0 144 | matchstring 145 | update:workflow 146 | outputlabel 147 | Update Workflow 148 | uid 149 | D850B7E1-B6F7-4A5E-8EF6-522CBF4E0A21 150 | 151 | 152 | elselabel 153 | Open URL 154 | hideelse 155 | 156 | 157 | type 158 | alfred.workflow.utility.conditional 159 | uid 160 | 54CB9D8A-3FC3-4570-9CDC-CBE9197102B7 161 | version 162 | 1 163 | 164 | 165 | config 166 | 167 | browser 168 | 169 | skipqueryencode 170 | 171 | skipvarencode 172 | 173 | spaces 174 | 175 | url 176 | {query} 177 | 178 | type 179 | alfred.workflow.action.openurl 180 | uid 181 | 709668B9-4793-4106-9DFE-A58EF9BFA3EE 182 | version 183 | 1 184 | 185 | 186 | readme 187 | Search the Tailwind CSS documentation using Alfred 188 | uidata 189 | 190 | 32B3C427-9180-4209-9432-B2890069F63E 191 | 192 | xpos 193 | 640 194 | ypos 195 | 115 196 | 197 | 54CB9D8A-3FC3-4570-9CDC-CBE9197102B7 198 | 199 | xpos 200 | 430 201 | ypos 202 | 280 203 | 204 | 709668B9-4793-4106-9DFE-A58EF9BFA3EE 205 | 206 | xpos 207 | 640 208 | ypos 209 | 410 210 | 211 | A6C3EF08-1D63-4571-9A71-253A36551FB4 212 | 213 | xpos 214 | 210 215 | ypos 216 | 260 217 | 218 | 219 | userconfigurationconfig 220 | 221 | 222 | config 223 | 224 | default 225 | v4 226 | pairs 227 | 228 | 229 | 4 230 | v4 231 | 232 | 233 | 3 234 | v3 235 | 236 | 237 | 2 238 | v2 239 | 240 | 241 | 1 242 | v1 243 | 244 | 245 | 0 246 | v0 247 | 248 | 249 | 250 | description 251 | Search the documentation of this Tailwind version 252 | label 253 | Tailwind version 254 | type 255 | popupbutton 256 | variable 257 | tailwind_version 258 | 259 | 260 | config 261 | 262 | default 263 | 264 | required 265 | 266 | text 267 | Enable (Alfred 5.5+ only) 268 | 269 | description 270 | Presents results from previous run when enabled and not expired. Mutually exclusive with Dart Cache. 271 | label 272 | Use Alfred Cache 273 | type 274 | checkbox 275 | variable 276 | use_alfred_cache 277 | 278 | 279 | config 280 | 281 | default 282 | 283 | required 284 | 285 | text 286 | Enable (Recommended for Alfred 5 or older) 287 | 288 | description 289 | Presents results from previous run when enabled and not expired. Mutually exclusive with Alfred Cache. 290 | label 291 | Use File Cache 292 | type 293 | checkbox 294 | variable 295 | use_file_cache 296 | 297 | 298 | config 299 | 300 | defaultvalue 301 | 86400 302 | markercount 303 | 24 304 | maxvalue 305 | 86400 306 | minvalue 307 | 5 308 | onlystoponmarkers 309 | 310 | showmarkers 311 | 312 | 313 | description 314 | Time to live for cached data is defined as a number of seconds between 5 and 86400 (i.e. 24 hours). 315 | label 316 | Cache TTL 317 | type 318 | slider 319 | variable 320 | cache_ttl 321 | 322 | 323 | config 324 | 325 | defaultvalue 326 | 1280 327 | markercount 328 | 8 329 | maxvalue 330 | 2048 331 | minvalue 332 | 256 333 | onlystoponmarkers 334 | 335 | showmarkers 336 | 337 | 338 | description 339 | Maximum File Cache entries 340 | label 341 | Max File Cache 342 | type 343 | slider 344 | variable 345 | file_cache_max_entries 346 | 347 | 348 | version 349 | 350 | webaddress 351 | 352 | 353 | 354 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | _fe_analyzer_shared: 5 | dependency: transitive 6 | description: 7 | name: _fe_analyzer_shared 8 | sha256: dc27559385e905ad30838356c5f5d574014ba39872d732111cd07ac0beff4c57 9 | url: "https://pub.dev" 10 | source: hosted 11 | version: "80.0.0" 12 | alfred_workflow: 13 | dependency: "direct main" 14 | description: 15 | name: alfred_workflow 16 | sha256: ef9787de3b4bdb8cde9be15b9cbca19004f07d389d19126e21afad28a8e23c80 17 | url: "https://pub.dev" 18 | source: hosted 19 | version: "1.1.3" 20 | algolia_client_core: 21 | dependency: transitive 22 | description: 23 | name: algolia_client_core 24 | sha256: "40e5c260f8fd871699118553f52047b724b9fdfc8dbe6b920ac30c6874991782" 25 | url: "https://pub.dev" 26 | source: hosted 27 | version: "1.31.1" 28 | algolia_client_insights: 29 | dependency: transitive 30 | description: 31 | name: algolia_client_insights 32 | sha256: ad302a9d1cbe400f3897d58d947f41e179c0343cd51aa15e8644af0658dc741c 33 | url: "https://pub.dev" 34 | source: hosted 35 | version: "1.31.1" 36 | algolia_client_search: 37 | dependency: transitive 38 | description: 39 | name: algolia_client_search 40 | sha256: "97fe47bf1da0625d0a86beabb2e9a1c5f8b3953fc761e484a509e2dc3b413d96" 41 | url: "https://pub.dev" 42 | source: hosted 43 | version: "1.31.1" 44 | algoliasearch: 45 | dependency: "direct main" 46 | description: 47 | name: algoliasearch 48 | sha256: "2a8a40e9eb83a957a1f25c41d9a9ead7731a5af5fa98d52e3c1614e2dbce6982" 49 | url: "https://pub.dev" 50 | source: hosted 51 | version: "1.30.2" 52 | analyzer: 53 | dependency: transitive 54 | description: 55 | name: analyzer 56 | sha256: "192d1c5b944e7e53b24b5586db760db934b177d4147c42fbca8c8c5f1eb8d11e" 57 | url: "https://pub.dev" 58 | source: hosted 59 | version: "7.3.0" 60 | args: 61 | dependency: "direct main" 62 | description: 63 | name: args 64 | sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 65 | url: "https://pub.dev" 66 | source: hosted 67 | version: "2.7.0" 68 | async: 69 | dependency: transitive 70 | description: 71 | name: async 72 | sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" 73 | url: "https://pub.dev" 74 | source: hosted 75 | version: "2.13.0" 76 | autoequal: 77 | dependency: transitive 78 | description: 79 | name: autoequal 80 | sha256: "186f99b614d8dd5b5756b26b6208d21ab948d7798ecfdf84669fff18eed7aab2" 81 | url: "https://pub.dev" 82 | source: hosted 83 | version: "0.9.1" 84 | boolean_selector: 85 | dependency: transitive 86 | description: 87 | name: boolean_selector 88 | sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" 89 | url: "https://pub.dev" 90 | source: hosted 91 | version: "2.1.2" 92 | build: 93 | dependency: transitive 94 | description: 95 | name: build 96 | sha256: cef23f1eda9b57566c81e2133d196f8e3df48f244b317368d65c5943d91148f0 97 | url: "https://pub.dev" 98 | source: hosted 99 | version: "2.4.2" 100 | build_config: 101 | dependency: transitive 102 | description: 103 | name: build_config 104 | sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33" 105 | url: "https://pub.dev" 106 | source: hosted 107 | version: "1.1.2" 108 | build_daemon: 109 | dependency: transitive 110 | description: 111 | name: build_daemon 112 | sha256: "8e928697a82be082206edb0b9c99c5a4ad6bc31c9e9b8b2f291ae65cd4a25daa" 113 | url: "https://pub.dev" 114 | source: hosted 115 | version: "4.0.4" 116 | build_resolvers: 117 | dependency: transitive 118 | description: 119 | name: build_resolvers 120 | sha256: b9e4fda21d846e192628e7a4f6deda6888c36b5b69ba02ff291a01fd529140f0 121 | url: "https://pub.dev" 122 | source: hosted 123 | version: "2.4.4" 124 | build_runner: 125 | dependency: "direct dev" 126 | description: 127 | name: build_runner 128 | sha256: "058fe9dce1de7d69c4b84fada934df3e0153dd000758c4d65964d0166779aa99" 129 | url: "https://pub.dev" 130 | source: hosted 131 | version: "2.4.15" 132 | build_runner_core: 133 | dependency: transitive 134 | description: 135 | name: build_runner_core 136 | sha256: "22e3aa1c80e0ada3722fe5b63fd43d9c8990759d0a2cf489c8c5d7b2bdebc021" 137 | url: "https://pub.dev" 138 | source: hosted 139 | version: "8.0.0" 140 | built_collection: 141 | dependency: transitive 142 | description: 143 | name: built_collection 144 | sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" 145 | url: "https://pub.dev" 146 | source: hosted 147 | version: "5.1.1" 148 | built_value: 149 | dependency: transitive 150 | description: 151 | name: built_value 152 | sha256: ea90e81dc4a25a043d9bee692d20ed6d1c4a1662a28c03a96417446c093ed6b4 153 | url: "https://pub.dev" 154 | source: hosted 155 | version: "8.9.5" 156 | charcode: 157 | dependency: transitive 158 | description: 159 | name: charcode 160 | sha256: fb0f1107cac15a5ea6ef0a6ef71a807b9e4267c713bb93e00e92d737cc8dbd8a 161 | url: "https://pub.dev" 162 | source: hosted 163 | version: "1.4.0" 164 | checked_yaml: 165 | dependency: transitive 166 | description: 167 | name: checked_yaml 168 | sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff 169 | url: "https://pub.dev" 170 | source: hosted 171 | version: "2.0.3" 172 | cli_script: 173 | dependency: "direct main" 174 | description: 175 | name: cli_script 176 | sha256: "4d4d47dcac7f2e6fb68a6b3e806787b031eeb042bc330ba6dd333ad1e7f83252" 177 | url: "https://pub.dev" 178 | source: hosted 179 | version: "1.0.0" 180 | clock: 181 | dependency: transitive 182 | description: 183 | name: clock 184 | sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b 185 | url: "https://pub.dev" 186 | source: hosted 187 | version: "1.1.2" 188 | code_builder: 189 | dependency: transitive 190 | description: 191 | name: code_builder 192 | sha256: "0ec10bf4a89e4c613960bf1e8b42c64127021740fb21640c29c909826a5eea3e" 193 | url: "https://pub.dev" 194 | source: hosted 195 | version: "4.10.1" 196 | collection: 197 | dependency: "direct main" 198 | description: 199 | name: collection 200 | sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" 201 | url: "https://pub.dev" 202 | source: hosted 203 | version: "1.19.1" 204 | convert: 205 | dependency: transitive 206 | description: 207 | name: convert 208 | sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 209 | url: "https://pub.dev" 210 | source: hosted 211 | version: "3.1.2" 212 | copy_with_extension: 213 | dependency: transitive 214 | description: 215 | name: copy_with_extension 216 | sha256: "0447e5ea09845b275fbeaa7605bc85e74da759788678760b2a6c4e06ca622410" 217 | url: "https://pub.dev" 218 | source: hosted 219 | version: "6.0.1" 220 | crypto: 221 | dependency: transitive 222 | description: 223 | name: crypto 224 | sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" 225 | url: "https://pub.dev" 226 | source: hosted 227 | version: "3.0.6" 228 | dart_style: 229 | dependency: transitive 230 | description: 231 | name: dart_style 232 | sha256: "27eb0ae77836989a3bc541ce55595e8ceee0992807f14511552a898ddd0d88ac" 233 | url: "https://pub.dev" 234 | source: hosted 235 | version: "3.0.1" 236 | dio: 237 | dependency: transitive 238 | description: 239 | name: dio 240 | sha256: "253a18bbd4851fecba42f7343a1df3a9a4c1d31a2c1b37e221086b4fa8c8dbc9" 241 | url: "https://pub.dev" 242 | source: hosted 243 | version: "5.8.0+1" 244 | dio_web_adapter: 245 | dependency: transitive 246 | description: 247 | name: dio_web_adapter 248 | sha256: "7586e476d70caecaf1686d21eee7247ea43ef5c345eab9e0cc3583ff13378d78" 249 | url: "https://pub.dev" 250 | source: hosted 251 | version: "2.1.1" 252 | envied: 253 | dependency: "direct main" 254 | description: 255 | name: envied 256 | sha256: a4e2b1d0caa479b5d61332ae516518c175a6d09328a35a0bc0a53894cc5d7e4d 257 | url: "https://pub.dev" 258 | source: hosted 259 | version: "1.1.1" 260 | envied_generator: 261 | dependency: "direct dev" 262 | description: 263 | name: envied_generator 264 | sha256: "894f6c5eb624c60a1ce6f642b6fd7ec68bc3440aa6f1881837aa9acbbeade0c8" 265 | url: "https://pub.dev" 266 | source: hosted 267 | version: "1.1.1" 268 | equatable: 269 | dependency: transitive 270 | description: 271 | name: equatable 272 | sha256: "567c64b3cb4cf82397aac55f4f0cbd3ca20d77c6c03bedbc4ceaddc08904aef7" 273 | url: "https://pub.dev" 274 | source: hosted 275 | version: "2.0.7" 276 | file: 277 | dependency: transitive 278 | description: 279 | name: file 280 | sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 281 | url: "https://pub.dev" 282 | source: hosted 283 | version: "7.0.1" 284 | fixnum: 285 | dependency: transitive 286 | description: 287 | name: fixnum 288 | sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be 289 | url: "https://pub.dev" 290 | source: hosted 291 | version: "1.1.1" 292 | frontend_server_client: 293 | dependency: transitive 294 | description: 295 | name: frontend_server_client 296 | sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 297 | url: "https://pub.dev" 298 | source: hosted 299 | version: "4.0.0" 300 | glob: 301 | dependency: transitive 302 | description: 303 | name: glob 304 | sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de 305 | url: "https://pub.dev" 306 | source: hosted 307 | version: "2.1.3" 308 | graphs: 309 | dependency: transitive 310 | description: 311 | name: graphs 312 | sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0" 313 | url: "https://pub.dev" 314 | source: hosted 315 | version: "2.3.2" 316 | html_unescape: 317 | dependency: "direct main" 318 | description: 319 | name: html_unescape 320 | sha256: "15362d7a18f19d7b742ef8dcb811f5fd2a2df98db9f80ea393c075189e0b61e3" 321 | url: "https://pub.dev" 322 | source: hosted 323 | version: "2.0.0" 324 | http: 325 | dependency: transitive 326 | description: 327 | name: http 328 | sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f 329 | url: "https://pub.dev" 330 | source: hosted 331 | version: "1.3.0" 332 | http_multi_server: 333 | dependency: transitive 334 | description: 335 | name: http_multi_server 336 | sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8 337 | url: "https://pub.dev" 338 | source: hosted 339 | version: "3.2.2" 340 | http_parser: 341 | dependency: transitive 342 | description: 343 | name: http_parser 344 | sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" 345 | url: "https://pub.dev" 346 | source: hosted 347 | version: "4.1.2" 348 | io: 349 | dependency: transitive 350 | description: 351 | name: io 352 | sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b 353 | url: "https://pub.dev" 354 | source: hosted 355 | version: "1.0.5" 356 | js: 357 | dependency: transitive 358 | description: 359 | name: js 360 | sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc" 361 | url: "https://pub.dev" 362 | source: hosted 363 | version: "0.7.2" 364 | json_annotation: 365 | dependency: "direct main" 366 | description: 367 | name: json_annotation 368 | sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" 369 | url: "https://pub.dev" 370 | source: hosted 371 | version: "4.9.0" 372 | json_serializable: 373 | dependency: "direct dev" 374 | description: 375 | name: json_serializable 376 | sha256: "81f04dee10969f89f604e1249382d46b97a1ccad53872875369622b5bfc9e58a" 377 | url: "https://pub.dev" 378 | source: hosted 379 | version: "6.9.4" 380 | lints: 381 | dependency: "direct dev" 382 | description: 383 | name: lints 384 | sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7 385 | url: "https://pub.dev" 386 | source: hosted 387 | version: "5.1.1" 388 | logging: 389 | dependency: transitive 390 | description: 391 | name: logging 392 | sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 393 | url: "https://pub.dev" 394 | source: hosted 395 | version: "1.3.0" 396 | matcher: 397 | dependency: transitive 398 | description: 399 | name: matcher 400 | sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 401 | url: "https://pub.dev" 402 | source: hosted 403 | version: "0.12.17" 404 | meta: 405 | dependency: transitive 406 | description: 407 | name: meta 408 | sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c 409 | url: "https://pub.dev" 410 | source: hosted 411 | version: "1.16.0" 412 | mime: 413 | dependency: transitive 414 | description: 415 | name: mime 416 | sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" 417 | url: "https://pub.dev" 418 | source: hosted 419 | version: "2.0.0" 420 | package_config: 421 | dependency: transitive 422 | description: 423 | name: package_config 424 | sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc 425 | url: "https://pub.dev" 426 | source: hosted 427 | version: "2.2.0" 428 | path: 429 | dependency: transitive 430 | description: 431 | name: path 432 | sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" 433 | url: "https://pub.dev" 434 | source: hosted 435 | version: "1.9.1" 436 | petitparser: 437 | dependency: transitive 438 | description: 439 | name: petitparser 440 | sha256: "07c8f0b1913bcde1ff0d26e57ace2f3012ccbf2b204e070290dad3bb22797646" 441 | url: "https://pub.dev" 442 | source: hosted 443 | version: "6.1.0" 444 | plist_parser: 445 | dependency: transitive 446 | description: 447 | name: plist_parser 448 | sha256: e2a6f9abfa0c45c0253656b7360abb0dfb84af9937bace74605b93d2aad2bf0c 449 | url: "https://pub.dev" 450 | source: hosted 451 | version: "0.0.11" 452 | pool: 453 | dependency: transitive 454 | description: 455 | name: pool 456 | sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" 457 | url: "https://pub.dev" 458 | source: hosted 459 | version: "1.5.1" 460 | pub_semver: 461 | dependency: transitive 462 | description: 463 | name: pub_semver 464 | sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" 465 | url: "https://pub.dev" 466 | source: hosted 467 | version: "2.2.0" 468 | pubspec_parse: 469 | dependency: transitive 470 | description: 471 | name: pubspec_parse 472 | sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082" 473 | url: "https://pub.dev" 474 | source: hosted 475 | version: "1.5.0" 476 | recase: 477 | dependency: "direct main" 478 | description: 479 | name: recase 480 | sha256: e4eb4ec2dcdee52dcf99cb4ceabaffc631d7424ee55e56f280bc039737f89213 481 | url: "https://pub.dev" 482 | source: hosted 483 | version: "4.1.0" 484 | shelf: 485 | dependency: transitive 486 | description: 487 | name: shelf 488 | sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 489 | url: "https://pub.dev" 490 | source: hosted 491 | version: "1.4.2" 492 | shelf_web_socket: 493 | dependency: transitive 494 | description: 495 | name: shelf_web_socket 496 | sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925" 497 | url: "https://pub.dev" 498 | source: hosted 499 | version: "3.0.0" 500 | source_gen: 501 | dependency: transitive 502 | description: 503 | name: source_gen 504 | sha256: "35c8150ece9e8c8d263337a265153c3329667640850b9304861faea59fc98f6b" 505 | url: "https://pub.dev" 506 | source: hosted 507 | version: "2.0.0" 508 | source_helper: 509 | dependency: transitive 510 | description: 511 | name: source_helper 512 | sha256: "86d247119aedce8e63f4751bd9626fc9613255935558447569ad42f9f5b48b3c" 513 | url: "https://pub.dev" 514 | source: hosted 515 | version: "1.3.5" 516 | source_span: 517 | dependency: transitive 518 | description: 519 | name: source_span 520 | sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" 521 | url: "https://pub.dev" 522 | source: hosted 523 | version: "1.10.1" 524 | sprintf: 525 | dependency: transitive 526 | description: 527 | name: sprintf 528 | sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23" 529 | url: "https://pub.dev" 530 | source: hosted 531 | version: "7.0.0" 532 | stack_trace: 533 | dependency: transitive 534 | description: 535 | name: stack_trace 536 | sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" 537 | url: "https://pub.dev" 538 | source: hosted 539 | version: "1.12.1" 540 | stash: 541 | dependency: transitive 542 | description: 543 | name: stash 544 | sha256: c1482f64dcaa9b2d9eb112106ef018aad49adb284e1ba371c892c2ad9f99fc12 545 | url: "https://pub.dev" 546 | source: hosted 547 | version: "5.2.0" 548 | stash_file: 549 | dependency: transitive 550 | description: 551 | name: stash_file 552 | sha256: f2a68f2e7dcf7ca8f2b617959fca305983d5557355ede43cb15601e9533b495b 553 | url: "https://pub.dev" 554 | source: hosted 555 | version: "5.2.0" 556 | stream_channel: 557 | dependency: transitive 558 | description: 559 | name: stream_channel 560 | sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" 561 | url: "https://pub.dev" 562 | source: hosted 563 | version: "2.1.4" 564 | stream_transform: 565 | dependency: transitive 566 | description: 567 | name: stream_transform 568 | sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871 569 | url: "https://pub.dev" 570 | source: hosted 571 | version: "2.1.1" 572 | string_scanner: 573 | dependency: transitive 574 | description: 575 | name: string_scanner 576 | sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" 577 | url: "https://pub.dev" 578 | source: hosted 579 | version: "1.4.1" 580 | term_glyph: 581 | dependency: transitive 582 | description: 583 | name: term_glyph 584 | sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" 585 | url: "https://pub.dev" 586 | source: hosted 587 | version: "1.2.2" 588 | test_api: 589 | dependency: transitive 590 | description: 591 | name: test_api 592 | sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd 593 | url: "https://pub.dev" 594 | source: hosted 595 | version: "0.7.4" 596 | timing: 597 | dependency: transitive 598 | description: 599 | name: timing 600 | sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe" 601 | url: "https://pub.dev" 602 | source: hosted 603 | version: "1.0.2" 604 | tuple: 605 | dependency: transitive 606 | description: 607 | name: tuple 608 | sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151 609 | url: "https://pub.dev" 610 | source: hosted 611 | version: "2.0.2" 612 | typed_data: 613 | dependency: transitive 614 | description: 615 | name: typed_data 616 | sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 617 | url: "https://pub.dev" 618 | source: hosted 619 | version: "1.4.0" 620 | uuid: 621 | dependency: transitive 622 | description: 623 | name: uuid 624 | sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff 625 | url: "https://pub.dev" 626 | source: hosted 627 | version: "4.5.1" 628 | watcher: 629 | dependency: transitive 630 | description: 631 | name: watcher 632 | sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104" 633 | url: "https://pub.dev" 634 | source: hosted 635 | version: "1.1.1" 636 | web: 637 | dependency: transitive 638 | description: 639 | name: web 640 | sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" 641 | url: "https://pub.dev" 642 | source: hosted 643 | version: "1.1.1" 644 | web_socket: 645 | dependency: transitive 646 | description: 647 | name: web_socket 648 | sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83" 649 | url: "https://pub.dev" 650 | source: hosted 651 | version: "0.1.6" 652 | web_socket_channel: 653 | dependency: transitive 654 | description: 655 | name: web_socket_channel 656 | sha256: "0b8e2457400d8a859b7b2030786835a28a8e80836ef64402abef392ff4f1d0e5" 657 | url: "https://pub.dev" 658 | source: hosted 659 | version: "3.0.2" 660 | xml: 661 | dependency: transitive 662 | description: 663 | name: xml 664 | sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 665 | url: "https://pub.dev" 666 | source: hosted 667 | version: "6.5.0" 668 | yaml: 669 | dependency: transitive 670 | description: 671 | name: yaml 672 | sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce 673 | url: "https://pub.dev" 674 | source: hosted 675 | version: "3.1.3" 676 | sdks: 677 | dart: ">=3.7.0-0 <4.0.0" 678 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: tailwindcss_docs_alfred_workflow 2 | description: Search the Tailwind CSS documentation using Alfred 3 | 4 | # Prevent accidental publishing to pub.dev. 5 | publish_to: 'none' 6 | 7 | version: 2.3.3 8 | 9 | environment: 10 | sdk: ^3.4.0 11 | 12 | dependencies: 13 | alfred_workflow: ^1.1.3 14 | algoliasearch: ^1.30.2 15 | args: ^2.7.0 16 | cli_script: ^1.0.0 17 | collection: ^1.19.1 18 | envied: ^1.1.1 19 | html_unescape: ^2.0.0 20 | json_annotation: ^4.9.0 21 | recase: ^4.1.0 22 | 23 | dev_dependencies: 24 | build_runner: ^2.4.15 25 | envied_generator: ^1.1.1 26 | json_serializable: ^6.9.4 27 | lints: ^5.1.1 28 | --------------------------------------------------------------------------------