├── .formatter.exs ├── .github ├── FUNDING.yml ├── dependabot.yml └── workflows │ └── elixir.yml ├── .gitignore ├── .tool-versions ├── CHANGELOG.md ├── README.md ├── lib ├── phoenix_better_table.ex └── phoenix_better_table.html.heex ├── mix.exs ├── mix.lock ├── static └── phoenix-better-table.gif └── test ├── phoenix_better_table_test.exs ├── support └── table_helpers.ex └── test_helper.exs /.formatter.exs: -------------------------------------------------------------------------------- 1 | # Used by "mix format" 2 | [ 3 | inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] 4 | ] 5 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [mwhitworth] 4 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | updates: 4 | - package-ecosystem: mix 5 | directory: "/" 6 | schedule: 7 | interval: monthly 8 | open-pull-requests-limit: 99 9 | insecure-external-code-execution: allow 10 | -------------------------------------------------------------------------------- /.github/workflows/elixir.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. 2 | # They are provided by a third-party and are governed by 3 | # separate terms of service, privacy policy, and support 4 | # documentation. 5 | 6 | name: Elixir CI 7 | 8 | on: 9 | push: 10 | branches: [ "master" ] 11 | pull_request: 12 | branches: [ "master" ] 13 | 14 | permissions: 15 | contents: read 16 | 17 | jobs: 18 | build: 19 | 20 | name: Build and test 21 | runs-on: ubuntu-latest 22 | 23 | steps: 24 | - uses: actions/checkout@v3 25 | - name: Set up Elixir 26 | uses: erlef/setup-beam@61e01a43a562a89bfc54c7f9a378ff67b03e4a21 # v1.16.0 27 | with: 28 | elixir-version: '1.15.2' # [Required] Define the Elixir version 29 | otp-version: '26.0' # [Required] Define the Erlang/OTP version 30 | - name: Restore dependencies cache 31 | uses: actions/cache@v3 32 | with: 33 | path: deps 34 | key: ${{ runner.os }}-mix-${{ hashFiles('**/mix.lock') }} 35 | restore-keys: ${{ runner.os }}-mix- 36 | - name: Install dependencies 37 | run: mix deps.get 38 | - name: Run CI 39 | run: mix ci 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where third-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | # Ignore package tarball (built via "mix hex.build"). 23 | phoenix_better_table-*.tar 24 | 25 | # Temporary files, for example, from tests. 26 | /tmp/ 27 | -------------------------------------------------------------------------------- /.tool-versions: -------------------------------------------------------------------------------- 1 | elixir 1.15.5 2 | erlang 26.0.2 3 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 0.5.0 (2024-05-26) 4 | 5 | ### New features 6 | 7 | * optional filter slot to customize filter display (#39) 8 | * optional sort slot to customize sort display (#40) 9 | 10 | ### Fixes 11 | 12 | * ensure rows is a list before processing (#38) 13 | * dependency upgrades (#31, #32) 14 | * add FUNDING.yml (#33) 15 | 16 | ## 0.4.3 (2024-03-12) 17 | 18 | * add styling options to table header and body (#26) 19 | * dependency upgrades (#23) 20 | * documentation updates (#17, #18) 21 | * migrate to Github Actions (#24) 22 | 23 | ## 0.4.2 (2024-02-08) 24 | 25 | * support Phoenix LiveView from 0.18.0 (#15) 26 | 27 | ## 0.4.1 (2024-01-14) 28 | 29 | * allow a filter function that generates text to be passed (#12) 30 | 31 | ## 0.4.0 (2024-01-14) 32 | 33 | * basic filtering support (#10, #11) 34 | * basic CI setup (#9) 35 | * bump dependencies (#8) 36 | 37 | ## 0.3.0 (2024-01-13) 38 | 39 | * custom sorter function for column (#5) 40 | * pin Phoenix LiveView to earlier dependency (#3) 41 | 42 | ## 0.2.0 (2023-11-22) 43 | 44 | * optional custom render function for column (#2) 45 | 46 | ## 0.1.0 (2023-11-18) 47 | 48 | initial release 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PhoenixBetterTable 2 | 3 | PhoenixBetterTable is a Phoenix Live Component that presents a filterable and sortable table component given table metadata and rows. 4 | 5 | ## Why? 6 | 7 | It is designed to fill the space between `
5 | <%= Map.get(header, :label, header.id) %> 6 | <%= if Map.get(header, :sort, true) do %> 7 | <%= if @sort_control do %> 8 | <%= render_slot(@sort_control, {column_sort_order(@sort, header.id), header.id, @myself}) %> 9 | <% else %> 10 | <.sort_control direction={column_sort_order(@sort, header.id)} phx-click="sort" phx-value-header={header.id} phx-target={@myself} /> 11 | <% end %> 12 | <% end %> 13 | 14 | <%= if @filter_control do %> 15 | <%= render_slot(@filter_control, {Map.has_key?(@filter, header.id), header.id, @myself}) %> 16 | <% else %> 17 | <.filter_control active?={Map.has_key?(@filter, header.id)} phx-click="filter_toggle" phx-value-header={header.id} phx-target={@myself} /> 18 | <% end %> 19 | | 20 |
---|
23 | 24 | | 25 |
31 | <%= if Map.has_key?(header, :render) do %> 32 | <%= @engine_module.component( 33 | header.render, 34 | [value: row[header.id]], 35 | {__ENV__.module, __ENV__.function, __ENV__.file, __ENV__.line}) %> 36 | <% else %> 37 | <%= row[header.id] %> 38 | <% end %> 39 | | 40 |