├── .formatter.exs ├── .github ├── CODEOWNERS ├── dependabot.yml └── workflows │ ├── ci.yml │ ├── v3.yml │ └── v4.yml ├── .gitignore ├── .tool-versions ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── UPGRADING.md ├── assets ├── .nvmrc ├── css │ ├── base.sass │ ├── base │ │ ├── components │ │ │ ├── _account-info.sass │ │ │ ├── _nav.sass │ │ │ └── _table.sass │ │ ├── globals │ │ │ └── _global.sass │ │ └── settings │ │ │ └── _grid.sass │ ├── shared │ │ ├── bourbon │ │ │ ├── _bourbon.scss │ │ │ ├── helpers │ │ │ │ ├── _buttons-list.scss │ │ │ │ ├── _scales.scss │ │ │ │ └── _text-inputs-list.scss │ │ │ ├── library │ │ │ │ ├── _border-color.scss │ │ │ │ ├── _border-radius.scss │ │ │ │ ├── _border-style.scss │ │ │ │ ├── _border-width.scss │ │ │ │ ├── _buttons.scss │ │ │ │ ├── _clearfix.scss │ │ │ │ ├── _contrast-switch.scss │ │ │ │ ├── _ellipsis.scss │ │ │ │ ├── _font-face.scss │ │ │ │ ├── _font-stacks.scss │ │ │ │ ├── _hide-text.scss │ │ │ │ ├── _hide-visually.scss │ │ │ │ ├── _margin.scss │ │ │ │ ├── _modular-scale.scss │ │ │ │ ├── _overflow-wrap.scss │ │ │ │ ├── _padding.scss │ │ │ │ ├── _position.scss │ │ │ │ ├── _prefixer.scss │ │ │ │ ├── _shade.scss │ │ │ │ ├── _size.scss │ │ │ │ ├── _strip-unit.scss │ │ │ │ ├── _text-inputs.scss │ │ │ │ ├── _timing-functions.scss │ │ │ │ ├── _tint.scss │ │ │ │ ├── _triangle.scss │ │ │ │ └── _value-prefixer.scss │ │ │ ├── settings │ │ │ │ └── _settings.scss │ │ │ ├── utilities │ │ │ │ ├── _assign-inputs.scss │ │ │ │ ├── _compact-shorthand.scss │ │ │ │ ├── _contrast-ratio.scss │ │ │ │ ├── _directional-property.scss │ │ │ │ ├── _fetch-bourbon-setting.scss │ │ │ │ ├── _font-source-declaration.scss │ │ │ │ ├── _gamma.scss │ │ │ │ ├── _lightness.scss │ │ │ │ └── _unpack-shorthand.scss │ │ │ └── validators │ │ │ │ ├── _contains-falsy.scss │ │ │ │ ├── _contains.scss │ │ │ │ ├── _is-color.scss │ │ │ │ ├── _is-length.scss │ │ │ │ ├── _is-number.scss │ │ │ │ └── _is-size.scss │ │ ├── flex-grid │ │ │ ├── README.md │ │ │ ├── _fg_breakpoint.scss │ │ │ ├── _fg_grid.scss │ │ │ └── _flex-grid.sass │ │ ├── reset │ │ │ └── _reset.scss │ │ └── settings │ │ │ ├── _colors.sass │ │ │ └── _fonts.sass │ ├── theme.sass │ └── theme │ │ ├── _extends │ │ ├── _buttons.sass │ │ ├── _label.sass │ │ ├── _select-input.sass │ │ ├── _text-input.sass │ │ └── _typography.sass │ │ ├── components │ │ ├── _account-info.sass │ │ ├── _datepicker.sass │ │ ├── _filters.sass │ │ ├── _flash-messages.sass │ │ ├── _form.sass │ │ ├── _header-and-content.sass │ │ ├── _nav.sass │ │ ├── _pagination.sass │ │ ├── _panel.sass │ │ ├── _table.sass │ │ └── _toolbar.sass │ │ ├── globals │ │ └── _global.sass │ │ ├── pages │ │ ├── _edit.sass │ │ ├── _index.sass │ │ ├── _new.sass │ │ └── _show.sass │ │ └── settings │ │ └── _grid.sass ├── images │ ├── down-arrow.png │ └── torch-logo.png ├── js │ └── torch.js ├── package-lock.json ├── package.json └── static │ └── images │ ├── down-arrow.png │ └── torch-logo.png ├── bin ├── coverage ├── release ├── setup └── test ├── config ├── .credo.exs └── config.exs ├── coveralls.json ├── lib ├── gettext.ex ├── mix │ ├── tasks │ │ ├── torch.gen.html.ex │ │ ├── torch.install.ex │ │ └── torch.uninstall.ex │ └── torch.ex ├── torch.ex └── torch │ ├── component.ex │ ├── config.ex │ ├── helpers.ex │ ├── i18n.ex │ ├── i18n │ └── backend.ex │ ├── pagination.ex │ └── views │ ├── filter_view.ex │ ├── flash_view.ex │ ├── page_view.ex │ ├── pagination_view.ex │ └── table_view.ex ├── mix.exs ├── mix.lock ├── priv ├── gettext │ ├── de │ │ └── LC_MESSAGES │ │ │ └── default.po │ ├── default.pot │ ├── en │ │ └── LC_MESSAGES │ │ │ └── default.po │ ├── es │ │ └── LC_MESSAGES │ │ │ └── default.po │ ├── ja │ │ └── LC_MESSAGES │ │ │ └── default.po │ ├── pt_BR │ │ └── LC_MESSAGES │ │ │ └── default.po │ ├── ru │ │ └── LC_MESSAGES │ │ │ └── default.po │ └── vi │ │ └── LC_MESSAGES │ │ └── default.po ├── static │ ├── base.css │ ├── base.css.map │ ├── down-arrow.e17911d3.png │ ├── theme.css │ ├── theme.css.map │ ├── torch-logo.a963df87.png │ ├── torch.js │ ├── torch.js.LICENSE.txt │ └── torch.js.map └── templates │ ├── phx.gen.context │ ├── _grid.sass │ ├── access_no_schema.ex │ ├── context.ex │ ├── context_test.exs │ ├── schema_access.ex │ └── test_cases.exs │ ├── phx.gen.html │ ├── controller.ex │ ├── controller_test.exs │ ├── edit.html.heex │ ├── edit_1_7_0.html.heex │ ├── html.ex │ ├── index.html.heex │ ├── new.html.heex │ ├── new_1_7_0.html.heex │ ├── resource_form.html.heex │ └── show.html.heex │ └── torch.install │ └── layout.html.heex └── test ├── mix ├── tasks │ ├── torch.gen.html_test.exs │ ├── torch.install_test.exs │ └── torch.uninstall_test.exs └── test_helper.exs ├── support ├── apps │ └── phx1_7 │ │ ├── .formatter.exs │ │ ├── .gitignore │ │ ├── README.md │ │ ├── assets │ │ ├── css │ │ │ └── app.css │ │ ├── js │ │ │ └── app.js │ │ ├── tailwind.config.js │ │ └── vendor │ │ │ └── topbar.js │ │ ├── bin │ │ └── test │ │ ├── config │ │ ├── config.exs │ │ ├── dev.exs │ │ ├── prod.exs │ │ ├── runtime.exs │ │ └── test.exs │ │ ├── lib │ │ ├── phx1_7.ex │ │ ├── phx1_7 │ │ │ ├── application.ex │ │ │ ├── mailer.ex │ │ │ └── repo.ex │ │ ├── phx1_7_web.ex │ │ └── phx1_7_web │ │ │ ├── components │ │ │ ├── core_components.ex │ │ │ ├── layouts.ex │ │ │ └── layouts │ │ │ │ ├── app.html.heex │ │ │ │ └── root.html.heex │ │ │ ├── controllers │ │ │ ├── error_html.ex │ │ │ ├── error_json.ex │ │ │ ├── page_controller.ex │ │ │ ├── page_html.ex │ │ │ └── page_html │ │ │ │ └── home.html.heex │ │ │ ├── endpoint.ex │ │ │ ├── gettext.ex │ │ │ ├── router.ex │ │ │ ├── router.ex.orig │ │ │ └── telemetry.ex │ │ ├── mix.exs │ │ ├── mix.lock │ │ ├── priv │ │ ├── gettext │ │ │ ├── en │ │ │ │ └── LC_MESSAGES │ │ │ │ │ └── errors.po │ │ │ └── errors.pot │ │ ├── repo │ │ │ ├── migrations │ │ │ │ └── .formatter.exs │ │ │ └── seeds.exs │ │ └── static │ │ │ ├── favicon.ico │ │ │ └── robots.txt │ │ └── test │ │ ├── phx1_7_web │ │ └── controllers │ │ │ ├── error_html_test.exs │ │ │ ├── error_json_test.exs │ │ │ └── page_controller_test.exs │ │ ├── support │ │ ├── conn_case.ex │ │ └── data_case.ex │ │ └── test_helper.exs ├── cases │ └── mix_case.ex └── patches │ ├── install-route.diff │ └── install-torch.diff └── torch ├── helpers_test.exs ├── i18n_test.exs ├── pagination_test.exs ├── test_helper.exs ├── torch_test.exs └── views ├── filter_view_test.exs ├── flash_view_test.exs ├── page_view_test.exs ├── pagination_view_test.exs └── table_view_test.exs /.formatter.exs: -------------------------------------------------------------------------------- 1 | # Used by "mix format" 2 | [ 3 | inputs: ["mix.exs", "{config,lib}/**/*.{ex,exs}", "test/{mix,torch}/**/*.{ex,exs}"], 4 | locals_without_parens: [ 5 | # Phoenix 6 | plug: 2, 7 | plug: 1, 8 | pipe_through: 1, 9 | get: 3, 10 | post: 3, 11 | patch: 3, 12 | put: 3, 13 | forward: 3 14 | ] 15 | ] 16 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | @cpjolicoeur 2 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: mix 4 | directory: "/" 5 | schedule: 6 | interval: weekly 7 | open-pull-requests-limit: 10 8 | reviewers: 9 | - cpjolicoeur 10 | ignore: 11 | - dependency-name: phoenix 12 | versions: 13 | - ">= 1.4.a, < 1.5" 14 | - dependency-name: phoenix_html 15 | versions: 16 | - ">= 2.14.a, < 2.15" 17 | - dependency-name: timex 18 | versions: 19 | - 3.6.4 20 | - 3.7.3 21 | - package-ecosystem: npm 22 | directory: "/assets" 23 | schedule: 24 | interval: weekly 25 | - package-ecosystem: "github-actions" 26 | directory: "/" 27 | schedule: 28 | interval: "weekly" 29 | -------------------------------------------------------------------------------- /.github/workflows/v3.yml: -------------------------------------------------------------------------------- 1 | name: Torch v3 CI 2 | 3 | on: 4 | pull_request: 5 | branches: [v1, v2, v3] 6 | types: [opened, edited, reopened, synchronize] 7 | push: 8 | branches: [v3] 9 | tags: 10 | - v[1-3].[0-9]+.[0-9]+ 11 | 12 | jobs: 13 | mix_test: 14 | name: mix test (Elixir ${{matrix.elixir}} | OTP ${{matrix.otp}}) 15 | runs-on: ubuntu-latest 16 | 17 | strategy: 18 | fail-fast: false 19 | matrix: 20 | include: 21 | - elixir: 1.10.x 22 | otp: 21.3.8.21 23 | - elixir: 1.10.x 24 | otp: 22.3.4.16 25 | - elixir: 1.10.x 26 | otp: 23.2.7 27 | warnings_as_errors: true 28 | static_analysis: false 29 | - elixir: 1.11.x 30 | otp: 21.3.8.21 31 | - elixir: 1.11.x 32 | otp: 22.3.4.16 33 | - elixir: 1.11.x 34 | otp: 23.2.7 35 | warnings_as_errors: true 36 | static_analysis: false 37 | - elixir: 1.12.x 38 | otp: 22.x 39 | - elixir: 1.12.x 40 | otp: 23.x 41 | - elixir: 1.12.x 42 | otp: 24.x 43 | 44 | services: 45 | db: 46 | image: postgres:10.1-alpine 47 | env: 48 | POSTGRES_USER: postgres 49 | POSTGRES_DB: example_test 50 | POSTGRES_PASSWORD: "" 51 | ports: ["5432:5432"] 52 | options: >- 53 | --health-cmd pg_isready 54 | --health-interval 10s 55 | --health-timeout 5s 56 | --health-retries 5 57 | 58 | env: 59 | MIX_ENV: test 60 | DATABASE_POSTGRESQL_USERNAME: postgres 61 | PGHOST: postgres 62 | PGUSER: postgres 63 | 64 | steps: 65 | - uses: actions/checkout@v4 66 | - uses: actions/setup-node@v4 67 | with: 68 | node-version: '14' 69 | cache: 'npm' 70 | cache-dependency-path: assets/package-lock.json 71 | - uses: erlef/setup-elixir@v1 72 | with: 73 | otp-version: ${{matrix.otp}} 74 | elixir-version: ${{matrix.elixir}} 75 | - name: Get Deps cache 76 | uses: actions/cache@v4 77 | with: 78 | path: deps/ 79 | key: deps-${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-${{ hashFiles('**/mix.lock') }} 80 | - name: Get BUILD cache 81 | uses: actions/cache@v4 82 | with: 83 | path: _build/test/ 84 | key: build-${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-${{ hashFiles('**/mix.lock') }} 85 | - name: Cache build artifacts 86 | uses: actions/cache@v4 87 | with: 88 | path: | 89 | $HOME/.hex 90 | $HOME/.mix 91 | key: artifacts-${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-${{ hashFiles('**/mix.lock') }} 92 | - name: Install Deps 93 | run: | 94 | mix local.hex --force 95 | mix local.rebar --force 96 | mix deps.get --only test 97 | - run: mix compile --warnings-as-errors 98 | if: matrix.warnings_as_errors 99 | - name: Run tests 100 | run: bin/setup 101 | - name: coveralls 102 | run: mix coveralls.github 103 | env: 104 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 105 | - run: mix dialyzer --halt-exist-status 106 | if: matrix.static_analysis 107 | -------------------------------------------------------------------------------- /.github/workflows/v4.yml: -------------------------------------------------------------------------------- 1 | name: Torch v4 CI 2 | 3 | on: 4 | pull_request: 5 | branches: [v4] 6 | types: [opened, edited, reopened, synchronize] 7 | push: 8 | branches: [v4] 9 | tags: 10 | - v4.[0-9]+.[0-9]+ 11 | 12 | jobs: 13 | mix_test: 14 | name: mix test (Elixir ${{matrix.elixir}} | OTP ${{matrix.otp}}) 15 | runs-on: ubuntu-22.04 16 | 17 | strategy: 18 | fail-fast: false 19 | matrix: 20 | include: 21 | - elixir: 1.12.x 22 | otp: 22.x 23 | - elixir: 1.13.x 24 | otp: 22.x 25 | - elixir: 1.12.x 26 | otp: 23.x 27 | - elixir: 1.13.x 28 | otp: 23.x 29 | - elixir: 1.12.x 30 | otp: 24.x 31 | - elixir: 1.13.x 32 | otp: 24.x 33 | - elixir: 1.14.x 34 | otp: 23.x 35 | - elixir: 1.14.x 36 | otp: 24.x 37 | - elixir: 1.14.x 38 | otp: 25.x 39 | 40 | services: 41 | db: 42 | image: postgres:latest 43 | env: 44 | POSTGRES_DB: example_test 45 | POSTGRES_USER: postgres 46 | POSTGRES_PASSWORD: postgres 47 | ports: ["5432:5432"] 48 | options: >- 49 | --health-cmd pg_isready 50 | --health-interval 10s 51 | --health-timeout 5s 52 | --health-retries 5 53 | 54 | env: 55 | MIX_ENV: test 56 | DATABASE_POSTGRESQL_USERNAME: postgres 57 | DATABASE_POSTGRESQL_PASSWORD: postgres 58 | PGHOST: postgres 59 | PGUSER: postgres 60 | ImageOS: ubuntu22 # run on ubuntu-22.04 (which supports Erlang/OTP 24.2-27) 61 | 62 | steps: 63 | - uses: actions/checkout@v4 64 | - uses: actions/setup-node@v4 65 | with: 66 | node-version: "14" 67 | cache: "npm" 68 | cache-dependency-path: assets/package-lock.json 69 | - uses: erlef/setup-beam@v1 70 | with: 71 | otp-version: ${{matrix.otp}} 72 | elixir-version: ${{matrix.elixir}} 73 | - name: Get Deps cache 74 | uses: actions/cache@v4 75 | with: 76 | path: deps/ 77 | key: deps-${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-${{ hashFiles('**/mix.lock') }} 78 | - name: Get BUILD cache 79 | uses: actions/cache@v4 80 | with: 81 | path: _build/test/ 82 | key: build-${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-${{ hashFiles('**/mix.lock') }} 83 | - name: Cache build artifacts 84 | uses: actions/cache@v4 85 | with: 86 | path: | 87 | $HOME/.hex 88 | $HOME/.mix 89 | key: artifacts-${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-${{ hashFiles('**/mix.lock') }} 90 | - name: Install Deps 91 | run: | 92 | mix local.hex --force 93 | mix local.rebar --force 94 | mix deps.get --only test 95 | - run: mix compile --warnings-as-errors 96 | if: matrix.warnings_as_errors 97 | - name: Run tests 98 | run: bin/setup 99 | - name: coveralls 100 | run: mix coveralls.github 101 | env: 102 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 103 | - run: mix dialyzer --halt-exist-status 104 | if: matrix.static_analysis 105 | -------------------------------------------------------------------------------- /.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 3rd-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 | torch-*.tar 24 | 25 | .elixir_ls/* 26 | node_modules/ 27 | .DS_Store 28 | assets/.parcel-cache 29 | 30 | .dir-locals.el 31 | .env 32 | 33 | # Translation .mo files 34 | /priv/gettext/*/LC_MESSAGES/*.mo 35 | 36 | shell.nix 37 | 38 | test/support/apps/phx1_3 39 | test/support/apps/phx1_4 40 | test/support/apps/phx1_5 41 | test/support/apps/phx1_6* 42 | test/support/apps/phx1_7_torch_v4 43 | -------------------------------------------------------------------------------- /.tool-versions: -------------------------------------------------------------------------------- 1 | elixir 1.16.3-otp-26 2 | erlang 26.2.5 3 | nodejs lts-hydrogen 4 | python 2.7.18 5 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at craig@mojotech.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Original work Copyright (c) 2016 Infinite Red, Inc. 4 | Modifed work Copyright (c) 2019 MojoTech, LLC. 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /UPGRADING.md: -------------------------------------------------------------------------------- 1 | # Upgrading 2 | 3 | ### Torch v4 to Torch v5 4 | 5 | Torch v5 **IS NOT ** fully backwards compatible with Torch v4. Due to Phoenix 1.7 dropping the inclusion 6 | of `Phoenix.View` in the core SDK, the way the templates are created, and the content of the templates 7 | generated by Torch have changed significantly. 8 | 9 | There is no automatic upgrade path for existing files that were generated with previous versions of Torch. 10 | If you encounter issues using Torch v5 with existing templates, you can either continue to use Torch v4, 11 | or manually update your existing Torch templates to the new unified function component style 12 | provided by `Torch.Component`. 13 | 14 | Templates that were generated with Torch v4 _should_ still funtion, if you manaully included `:phoenix_view` 15 | in your projects mix dependencies, but your results may vary. For templates generated with Torch v4, you 16 | would also need to make the manual updates described below in the "Torch v3 to Torch v4" section. 17 | 18 | #### Slime support dropped 19 | 20 | Torch v5 has dropped support for Slime templates. Only heex templates 21 | are now supported. 22 | 23 | ### Torch v3 to Torch v4 24 | 25 | Torch v4 **IS NOT** fully backwards compatible with Torch v3. In particular, the templates have changed 26 | in a manner that affect the generated DOM and CSS rules used. 27 | 28 | To manually update your existing templates to the new v4 DOM do the following: 29 | 30 | #### show.html.* 31 | 32 | * `
` becomes `
` 33 | * `` list for model properties becomes `
...
` 34 | 35 | #### form.html.* 36 | 37 | Inside `
40 | <%= label %> 41 | <%= input %> 42 | <%= error %> 43 |
44 | 45 | becomes: 46 | 47 |
48 | <%= label %> 49 |
50 | <%= input %> 51 | <%= error %> 52 |
53 |
54 | 55 | 56 | Another option to "upgrade" is to just generate new templates again via the Torch v4 generators. Run the same 57 | generator commands as the first time and overwrite your existing files. Then resolve any customization previously 58 | made to your Torch v3 templates by re-applying those change to the newly generated Torch v4 templates. 59 | -------------------------------------------------------------------------------- /assets/.nvmrc: -------------------------------------------------------------------------------- 1 | lts/fermium 2 | -------------------------------------------------------------------------------- /assets/css/base.sass: -------------------------------------------------------------------------------- 1 | // setup & base 2 | @import 'shared/bourbon/bourbon' 3 | @import 'shared/reset/reset' 4 | @import 'base/settings/grid' 5 | @import 'shared/flex-grid/flex-grid' 6 | @import "~pikaday/scss/pikaday.scss" 7 | 8 | // global styles 9 | @import 'shared/settings/colors' 10 | @import 'shared/settings/fonts' 11 | @import 'base/settings/grid' 12 | @import 'base/globals/global' 13 | @import 'base/components/account-info' 14 | @import 'base/components/nav' 15 | -------------------------------------------------------------------------------- /assets/css/base/components/_account-info.sass: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mojotech/torch/26ac2f942d7ab89cf2cd27caa01d3b11340540f8/assets/css/base/components/_account-info.sass -------------------------------------------------------------------------------- /assets/css/base/components/_nav.sass: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mojotech/torch/26ac2f942d7ab89cf2cd27caa01d3b11340540f8/assets/css/base/components/_nav.sass -------------------------------------------------------------------------------- /assets/css/base/components/_table.sass: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mojotech/torch/26ac2f942d7ab89cf2cd27caa01d3b11340540f8/assets/css/base/components/_table.sass -------------------------------------------------------------------------------- /assets/css/base/globals/_global.sass: -------------------------------------------------------------------------------- 1 | html 2 | background: $gallery-gray 3 | font-family: $helvetica-neue 4 | font-weight: normal 5 | min-height: 100vh 6 | 7 | body 8 | min-height: 100vh 9 | 10 | a 11 | text-decoration: none 12 | 13 | .torch-container 14 | flex: 1 15 | margin: 0 auto 16 | padding-right: 15px 17 | padding-left: 15px 18 | -------------------------------------------------------------------------------- /assets/css/base/settings/_grid.sass: -------------------------------------------------------------------------------- 1 | // default grid 2 | $fg_gutter: 36 3 | $fg_padding: 0 -------------------------------------------------------------------------------- /assets/css/shared/bourbon/_bourbon.scss: -------------------------------------------------------------------------------- 1 | // Bourbon 5.0.0 2 | // http://bourbon.io 3 | // Copyright 2011-2018 thoughtbot, inc. 4 | // MIT License 5 | 6 | @import "helpers/buttons-list"; 7 | @import "helpers/scales"; 8 | @import "helpers/text-inputs-list"; 9 | 10 | @import "settings/settings"; 11 | 12 | @import "validators/contains"; 13 | @import "validators/contains-falsy"; 14 | @import "validators/is-color"; 15 | @import "validators/is-length"; 16 | @import "validators/is-number"; 17 | @import "validators/is-size"; 18 | 19 | @import "utilities/assign-inputs"; 20 | @import "utilities/compact-shorthand"; 21 | @import "utilities/directional-property"; 22 | @import "utilities/fetch-bourbon-setting"; 23 | @import "utilities/font-source-declaration"; 24 | @import "utilities/gamma"; 25 | @import "utilities/lightness"; 26 | @import "utilities/contrast-ratio"; 27 | @import "utilities/unpack-shorthand"; 28 | 29 | @import "library/border-color"; 30 | @import "library/border-radius"; 31 | @import "library/border-style"; 32 | @import "library/border-width"; 33 | @import "library/buttons"; 34 | @import "library/clearfix"; 35 | @import "library/contrast-switch"; 36 | @import "library/ellipsis"; 37 | @import "library/font-face"; 38 | @import "library/font-stacks"; 39 | @import "library/hide-text"; 40 | @import "library/hide-visually"; 41 | @import "library/margin"; 42 | @import "library/modular-scale"; 43 | @import "library/overflow-wrap"; 44 | @import "library/padding"; 45 | @import "library/position"; 46 | @import "library/prefixer"; 47 | @import "library/shade"; 48 | @import "library/size"; 49 | @import "library/strip-unit"; 50 | @import "library/text-inputs"; 51 | @import "library/timing-functions"; 52 | @import "library/tint"; 53 | @import "library/triangle"; 54 | @import "library/value-prefixer"; 55 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/helpers/_buttons-list.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// A list of all HTML button elements. 4 | /// 5 | /// @type list 6 | /// 7 | /// @access private 8 | 9 | $_buttons-list: ( 10 | "button", 11 | "[type='button']", 12 | "[type='reset']", 13 | "[type='submit']", 14 | ); 15 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/helpers/_scales.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | //// 4 | /// Pre-defined scales for use with the `modular-scale` function. 5 | /// 6 | /// @type number (unitless) 7 | /// 8 | /// @see {function} modular-scale 9 | //// 10 | 11 | $minor-second: 1.067; 12 | $major-second: 1.125; 13 | $minor-third: 1.2; 14 | $major-third: 1.25; 15 | $perfect-fourth: 1.333; 16 | $augmented-fourth: 1.414; 17 | $perfect-fifth: 1.5; 18 | $minor-sixth: 1.6; 19 | $golden: 1.618; 20 | $major-sixth: 1.667; 21 | $minor-seventh: 1.778; 22 | $major-seventh: 1.875; 23 | $octave: 2; 24 | $major-tenth: 2.5; 25 | $major-eleventh: 2.667; 26 | $major-twelfth: 3; 27 | $double-octave: 4; 28 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/helpers/_text-inputs-list.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// A list of all _text-based_ HTML inputs. 4 | /// 5 | /// @type list 6 | /// 7 | /// @access private 8 | 9 | $_text-inputs-list: ( 10 | "[type='color']", 11 | "[type='date']", 12 | "[type='datetime']", 13 | "[type='datetime-local']", 14 | "[type='email']", 15 | "[type='month']", 16 | "[type='number']", 17 | "[type='password']", 18 | "[type='search']", 19 | "[type='tel']", 20 | "[type='text']", 21 | "[type='time']", 22 | "[type='url']", 23 | "[type='week']", 24 | "input:not([type])", 25 | "textarea", 26 | ); 27 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/library/_border-color.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Provides a concise, one-line method for setting `border-color` on specific 4 | /// edges of a box. Use a `null` value to “skip” edges of the box with standard 5 | /// CSS shorthand. 6 | /// 7 | /// @argument {list} $values 8 | /// List of colors; accepts CSS shorthand. 9 | /// 10 | /// @example scss 11 | /// .element { 12 | /// @include border-color(#a60b55 #76cd9c null #e8ae1a); 13 | /// } 14 | /// 15 | /// // CSS Output 16 | /// .element { 17 | /// border-left-color: #e8ae1a; 18 | /// border-right-color: #76cd9c; 19 | /// border-top-color: #a60b55; 20 | /// } 21 | /// 22 | /// @require {mixin} _directional-property 23 | 24 | @mixin border-color($values) { 25 | @include _directional-property(border, color, $values); 26 | } 27 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/library/_border-radius.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Provides a concise, one-line method for setting `border-radius` on both the 4 | /// top-left and top-right of a box. 5 | /// 6 | /// @argument {number (with unit)} $radii 7 | /// 8 | /// @example scss 9 | /// .element { 10 | /// @include border-top-radius(4px); 11 | /// } 12 | /// 13 | /// // CSS Output 14 | /// .element { 15 | /// border-top-left-radius: 4px; 16 | /// border-top-right-radius: 4px; 17 | /// } 18 | 19 | @mixin border-top-radius($radii) { 20 | border-top-left-radius: $radii; 21 | border-top-right-radius: $radii; 22 | } 23 | 24 | /// Provides a concise, one-line method for setting `border-radius` on both the 25 | /// top-right and bottom-right of a box. 26 | /// 27 | /// @argument {number (with unit)} $radii 28 | /// 29 | /// @example scss 30 | /// .element { 31 | /// @include border-right-radius(3px); 32 | /// } 33 | /// 34 | /// // CSS Output 35 | /// .element { 36 | /// border-bottom-right-radius: 3px; 37 | /// border-top-right-radius: 3px; 38 | /// } 39 | 40 | @mixin border-right-radius($radii) { 41 | border-bottom-right-radius: $radii; 42 | border-top-right-radius: $radii; 43 | } 44 | 45 | /// Provides a concise, one-line method for setting `border-radius` on both the 46 | /// bottom-left and bottom-right of a box. 47 | /// 48 | /// @argument {number (with unit)} $radii 49 | /// 50 | /// @example scss 51 | /// .element { 52 | /// @include border-bottom-radius(2px); 53 | /// } 54 | /// 55 | /// // CSS Output 56 | /// .element { 57 | /// border-bottom-left-radius: 2px; 58 | /// border-bottom-right-radius: 2px; 59 | /// } 60 | 61 | @mixin border-bottom-radius($radii) { 62 | border-bottom-left-radius: $radii; 63 | border-bottom-right-radius: $radii; 64 | } 65 | 66 | /// Provides a concise, one-line method for setting `border-radius` on both the 67 | /// top-left and bottom-left of a box. 68 | /// 69 | /// @argument {number (with unit)} $radii 70 | /// 71 | /// @example scss 72 | /// .element { 73 | /// @include border-left-radius(1px); 74 | /// } 75 | /// 76 | /// // CSS Output 77 | /// .element { 78 | /// border-bottom-left-radius: 1px; 79 | /// border-top-left-radius: 1px; 80 | /// } 81 | 82 | @mixin border-left-radius($radii) { 83 | border-bottom-left-radius: $radii; 84 | border-top-left-radius: $radii; 85 | } 86 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/library/_border-style.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Provides a concise, one-line method for setting `border-style` on specific 4 | /// edges of a box. Use a `null` value to “skip” edges of the box with standard 5 | /// CSS shorthand. 6 | /// 7 | /// @argument {list} $values 8 | /// List of border styles; accepts CSS shorthand. 9 | /// 10 | /// @example scss 11 | /// .element { 12 | /// @include border-style(dashed null solid); 13 | /// } 14 | /// 15 | /// // CSS Output 16 | /// .element { 17 | /// border-bottom-style: solid; 18 | /// border-top-style: dashed; 19 | /// } 20 | /// 21 | /// @require {mixin} _directional-property 22 | 23 | @mixin border-style($values) { 24 | @include _directional-property(border, style, $values); 25 | } 26 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/library/_border-width.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Provides a concise, one-line method for setting `border-width` on specific 4 | /// edges of a box. Use a `null` value to “skip” edges of the box with standard 5 | /// CSS shorthand. 6 | /// 7 | /// @argument {list} $values 8 | /// List of border widths; accepts CSS shorthand. 9 | /// 10 | /// @example scss 11 | /// .element { 12 | /// @include border-width(1em null 20px); 13 | /// } 14 | /// 15 | /// // CSS Output 16 | /// .element { 17 | /// border-bottom-width: 20px; 18 | /// border-top-width: 1em; 19 | /// } 20 | /// 21 | /// @require {mixin} _directional-property 22 | 23 | @mixin border-width($values) { 24 | @include _directional-property(border, width, $values); 25 | } 26 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/library/_buttons.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | //// 4 | /// @type list 5 | /// 6 | /// @require {function} _assign-inputs 7 | /// 8 | /// @require {variable} $_buttons-list 9 | //// 10 | 11 | /// A list of all HTML button elements. Please note that you must interpolate 12 | /// the variable (`#{}`) to use it as a selector. 13 | /// 14 | /// @example scss 15 | /// #{$all-buttons} { 16 | /// background-color: #f00; 17 | /// } 18 | /// 19 | /// // CSS Output 20 | /// button, 21 | /// [type='button'], 22 | /// [type='reset'], 23 | /// [type='submit'] { 24 | /// background-color: #f00; 25 | /// } 26 | 27 | $all-buttons: _assign-inputs($_buttons-list); 28 | 29 | /// A list of all HTML button elements with the `:active` pseudo-class applied. 30 | /// Please note that you must interpolate the variable (`#{}`) to use it as a 31 | /// selector. 32 | /// 33 | /// @example scss 34 | /// #{$all-buttons-active} { 35 | /// background-color: #00f; 36 | /// } 37 | /// 38 | /// // CSS Output 39 | /// button:active, 40 | /// [type='button']:active, 41 | /// [type='reset']:active, 42 | /// [type='submit']:active { 43 | /// background-color: #00f; 44 | /// } 45 | 46 | $all-buttons-active: _assign-inputs($_buttons-list, active); 47 | 48 | /// A list of all HTML button elements with the `:focus` pseudo-class applied. 49 | /// Please note that you must interpolate the variable (`#{}`) to use it as a 50 | /// selector. 51 | /// 52 | /// @example scss 53 | /// #{$all-buttons-focus} { 54 | /// background-color: #0f0; 55 | /// } 56 | /// 57 | /// // CSS Output 58 | /// button:focus, 59 | /// [type='button']:focus, 60 | /// [type='reset']:focus, 61 | /// [type='submit']:focus { 62 | /// background-color: #0f0; 63 | /// } 64 | 65 | $all-buttons-focus: _assign-inputs($_buttons-list, focus); 66 | 67 | /// A list of all HTML button elements with the `:hover` pseudo-class applied. 68 | /// Please note that you must interpolate the variable (`#{}`) to use it as a 69 | /// selector. 70 | /// 71 | /// @example scss 72 | /// #{$all-buttons-hover} { 73 | /// background-color: #0f0; 74 | /// } 75 | /// 76 | /// // CSS Output 77 | /// button:hover, 78 | /// [type='button']:hover, 79 | /// [type='reset']:hover, 80 | /// [type='submit']:hover { 81 | /// background-color: #0f0; 82 | /// } 83 | 84 | $all-buttons-hover: _assign-inputs($_buttons-list, hover); 85 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/library/_clearfix.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Provides an easy way to include a clearfix for containing floats. 4 | /// 5 | /// @link https://goo.gl/yP5hiZ 6 | /// 7 | /// @example scss 8 | /// .element { 9 | /// @include clearfix; 10 | /// } 11 | /// 12 | /// // CSS Output 13 | /// .element::after { 14 | /// clear: both; 15 | /// content: ""; 16 | /// display: block; 17 | /// } 18 | 19 | @mixin clearfix { 20 | &::after { 21 | clear: both; 22 | content: ""; 23 | display: block; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/library/_contrast-switch.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Switches between two colors based on the contrast to another color. It’s 4 | /// like a [ternary operator] for color contrast and can be useful for building 5 | /// a button system. 6 | /// 7 | /// The calculation of the contrast ratio is based on the [WCAG 2.0 8 | /// specification]. However, we cannot guarantee full compliance, though all of 9 | /// our manual testing passed. 10 | /// 11 | /// [ternary operator]: https://goo.gl/ccfLqi 12 | /// [WCAG 2.0 specification]: https://goo.gl/zhQuYA 13 | /// 14 | /// @argument {color} $base-color 15 | /// The color to evaluate lightness against. 16 | /// 17 | /// @argument {color} $dark-color [#000] 18 | /// The color to be output when `$base-color` is light. Can also be set 19 | /// globally using the `contrast-switch-dark-color` key in the 20 | /// Bourbon settings. 21 | /// 22 | /// @argument {color} $light-color [#fff] 23 | /// The color to be output when `$base-color` is dark. Can also be set 24 | /// globally using the `contrast-switch-light-color` key in the 25 | /// Bourbon settings. 26 | /// 27 | /// @return {color} 28 | /// 29 | /// @example scss 30 | /// .element { 31 | /// color: contrast-switch(#bae6e6); 32 | /// } 33 | /// 34 | /// // CSS Output 35 | /// .element { 36 | /// color: #000; 37 | /// } 38 | /// 39 | /// @example scss 40 | /// .element { 41 | /// $button-color: #2d72d9; 42 | /// background-color: $button-color; 43 | /// color: contrast-switch($button-color, #222, #eee); 44 | /// } 45 | /// 46 | /// // CSS Output 47 | /// .element { 48 | /// background-color: #2d72d9; 49 | /// color: #eee; 50 | /// } 51 | /// 52 | /// @require {function} _fetch-bourbon-setting 53 | /// 54 | /// @require {function} _is-color 55 | /// 56 | /// @require {function} _contrast-ratio 57 | /// 58 | /// @since 5.0.0 59 | 60 | @function contrast-switch( 61 | $base-color, 62 | $dark-color: _fetch-bourbon-setting("contrast-switch-dark-color"), 63 | $light-color: _fetch-bourbon-setting("contrast-switch-light-color") 64 | ) { 65 | @if not _is-color($base-color) { 66 | @error "`#{$base-color}` is not a valid color for the `$base-color` " + 67 | "argument in the `contrast-switch` function."; 68 | } @else if not _is-color($dark-color) { 69 | @error "`#{$dark-color}` is not a valid color for the `$dark-color` " + 70 | "argument in the `contrast-switch` function."; 71 | } @else if not _is-color($light-color) { 72 | @error "`#{$light-color}` is not a valid color for the `$light-color` " + 73 | "argument in the `contrast-switch` function."; 74 | } @else { 75 | $-contrast-to-dark: _contrast-ratio($base-color, $dark-color); 76 | $-contrast-to-light: _contrast-ratio($base-color, $light-color); 77 | $-prefer-dark: $-contrast-to-dark >= $-contrast-to-light; 78 | 79 | @return if($-prefer-dark, $dark-color, $light-color); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/library/_ellipsis.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Truncates text and adds an ellipsis to represent overflow. 4 | /// 5 | /// @argument {number} $width [100%] 6 | /// The `max-width` for the string to respect before being truncated. 7 | /// 8 | /// @argument {string} $display [inline-block] 9 | /// Sets the display-value of the element. 10 | /// 11 | /// @example scss 12 | /// .element { 13 | /// @include ellipsis; 14 | /// } 15 | /// 16 | /// // CSS Output 17 | /// .element { 18 | /// display: inline-block; 19 | /// max-width: 100%; 20 | /// overflow: hidden; 21 | /// text-overflow: ellipsis; 22 | /// white-space: nowrap; 23 | /// word-wrap: normal; 24 | /// } 25 | 26 | @mixin ellipsis( 27 | $width: 100%, 28 | $display: inline-block 29 | ) { 30 | display: $display; 31 | max-width: $width; 32 | overflow: hidden; 33 | text-overflow: ellipsis; 34 | white-space: nowrap; 35 | word-wrap: normal; 36 | } 37 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/library/_font-face.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Generates an `@font-face` declaration. You can choose the specific file 4 | /// formats you need to output; the mixin supports `eot`, `ttf`, `svg`, `woff2` 5 | /// and `woff`. The mixin also supports usage with the Rails Asset Pipeline, 6 | /// which you can enable per use, or globally in the `$bourbon()` settings. 7 | /// 8 | /// @argument {string} $font-family 9 | /// 10 | /// @argument {string} $file-path 11 | /// 12 | /// @argument {string} $asset-pipeline [false] 13 | /// Set to `true` if you’re using the Rails Asset Pipeline (place the fonts 14 | /// in `app/assets/fonts/`). Can also be set globally using the 15 | /// `rails-asset-pipeline` key in the Bourbon settings. 16 | /// 17 | /// @argument {string | list} $file-formats [("ttf", "woff2", "woff")] 18 | /// List of the font file formats to include. Can also be set globally using 19 | /// the `global-font-file-formats` key in the Bourbon settings. 20 | /// 21 | /// @content 22 | /// Any additional CSS properties that are included in the `@include` 23 | /// directive will be output within the `@font-face` declaration, e.g. you can 24 | /// pass in `font-weight`, `font-style` and/or `unicode-range`. 25 | /// 26 | /// @example scss 27 | /// @include font-face( 28 | /// "source-sans-pro", 29 | /// "fonts/source-sans-pro-regular", 30 | /// ("woff2", "woff") 31 | /// ) { 32 | /// font-style: normal; 33 | /// font-weight: 400; 34 | /// } 35 | /// 36 | /// // CSS Output 37 | /// @font-face { 38 | /// font-family: "source-sans-pro"; 39 | /// src: url("fonts/source-sans-pro-regular.woff2") format("woff2"), 40 | /// url("fonts/source-sans-pro-regular.woff") format("woff"); 41 | /// font-style: normal; 42 | /// font-weight: 400; 43 | /// } 44 | /// 45 | /// @require {function} _font-source-declaration 46 | /// 47 | /// @require {function} _fetch-bourbon-setting 48 | 49 | @mixin font-face( 50 | $font-family, 51 | $file-path, 52 | $file-formats: _fetch-bourbon-setting("global-font-file-formats"), 53 | $asset-pipeline: _fetch-bourbon-setting("rails-asset-pipeline") 54 | ) { 55 | @font-face { 56 | font-family: $font-family; 57 | src: _font-source-declaration( 58 | $font-family, 59 | $file-path, 60 | $asset-pipeline, 61 | $file-formats 62 | ); 63 | @content; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/library/_hide-text.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Hides the text in an element, commonly used to show an image instead. Some 4 | /// elements will need block-level styles applied. 5 | /// 6 | /// @link https://goo.gl/EvLRIu 7 | /// 8 | /// @example scss 9 | /// .element { 10 | /// @include hide-text; 11 | /// } 12 | /// 13 | /// // CSS Output 14 | /// .element { 15 | /// overflow: hidden; 16 | /// text-indent: 101%; 17 | /// white-space: nowrap; 18 | /// } 19 | 20 | @mixin hide-text { 21 | overflow: hidden; 22 | text-indent: 101%; 23 | white-space: nowrap; 24 | } 25 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/library/_hide-visually.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Hides an element visually while still allowing the content to be accessible 4 | /// to assistive technology, e.g. screen readers. Passing `unhide` will reverse 5 | /// the affects of the hiding, which is handy for showing the element on focus, 6 | /// for example. 7 | /// 8 | /// @link https://goo.gl/Vf1TGn 9 | /// 10 | /// @argument {string} $toggle [hide] 11 | /// Accepts `hide` or `unhide`. `unhide` reverses the affects of `hide`. 12 | /// 13 | /// @example scss 14 | /// .element { 15 | /// @include hide-visually; 16 | /// 17 | /// &:active, 18 | /// &:focus { 19 | /// @include hide-visually("unhide"); 20 | /// } 21 | /// } 22 | /// 23 | /// // CSS Output 24 | /// .element { 25 | /// border: 0; 26 | /// clip: rect(1px, 1px, 1px, 1px); 27 | /// clip-path: inset(100%); 28 | /// height: 1px; 29 | /// overflow: hidden; 30 | /// padding: 0; 31 | /// position: absolute; 32 | /// width: 1px; 33 | /// } 34 | /// 35 | /// .hide-visually:active, 36 | /// .hide-visually:focus { 37 | /// clip: auto; 38 | /// clip-path: none; 39 | /// height: auto; 40 | /// overflow: visible; 41 | /// position: static; 42 | /// width: auto; 43 | /// } 44 | /// 45 | /// @since 5.0.0 46 | 47 | @mixin hide-visually($toggle: "hide") { 48 | @if not index("hide" "unhide", $toggle) { 49 | @error "`#{$toggle}` is not a valid value for the `$toggle` argument in " + 50 | "the `hide-visually` mixin. Must be either `hide` or `unhide`."; 51 | } @else if $toggle == "hide" { 52 | border: 0; 53 | clip: rect(1px, 1px, 1px, 1px); 54 | clip-path: inset(100%); 55 | height: 1px; 56 | overflow: hidden; 57 | padding: 0; 58 | position: absolute; 59 | white-space: nowrap; 60 | width: 1px; 61 | } @else if $toggle == "unhide" { 62 | clip: auto; 63 | clip-path: none; 64 | height: auto; 65 | overflow: visible; 66 | position: static; 67 | white-space: inherit; 68 | width: auto; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/library/_margin.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Provides a concise, one-line method for setting `margin` on specific edges 4 | /// of a box. Use a `null` value to “skip” edges of the box with standard 5 | /// CSS shorthand. 6 | /// 7 | /// @argument {list} $values 8 | /// List of margin values; accepts CSS shorthand. 9 | /// 10 | /// @example scss 11 | /// .element { 12 | /// @include margin(null auto); 13 | /// } 14 | /// 15 | /// // CSS Output 16 | /// .element { 17 | /// margin-left: auto; 18 | /// margin-right: auto; 19 | /// } 20 | /// 21 | /// @example scss 22 | /// .element { 23 | /// @include margin(10px 3em 20vh null); 24 | /// } 25 | /// 26 | /// // CSS Output 27 | /// .element { 28 | /// margin-bottom: 20vh; 29 | /// margin-right: 3em; 30 | /// margin-top: 10px; 31 | /// } 32 | /// 33 | /// @require {mixin} _directional-property 34 | 35 | @mixin margin($values) { 36 | @include _directional-property(margin, null, $values); 37 | } 38 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/library/_modular-scale.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Increments up or down a defined scale and returns an adjusted value. This 4 | /// helps establish consistent measurements and spacial relationships throughout 5 | /// your project. We provide a list of commonly used scales as 6 | /// [pre-defined variables][scales]. 7 | /// 8 | /// [scales]: https://github.com/thoughtbot/bourbon/blob/master/core/bourbon/settings/_scales.scss 9 | /// 10 | /// @argument {number (unitless)} $increment 11 | /// How many steps to increment up or down the scale. 12 | /// 13 | /// @argument {number (with unit) | list} $value [1em] 14 | /// The base value the scale starts at. Can also be set globally using the 15 | /// `modular-scale-base` key in the Bourbon settings. 16 | /// 17 | /// @argument {number (unitless)} $ratio [1.25] 18 | /// The ratio the scale is built on. Can also be set globally using the 19 | /// `modular-scale-ratio` key in the Bourbon settings. 20 | /// 21 | /// @return {number (with unit)} 22 | /// 23 | /// @example scss 24 | /// .element { 25 | /// font-size: modular-scale(2); 26 | /// } 27 | /// 28 | /// // CSS Output 29 | /// .element { 30 | /// font-size: 1.5625em; 31 | /// } 32 | /// 33 | /// @example scss 34 | /// .element { 35 | /// margin-right: modular-scale(3, 2em); 36 | /// } 37 | /// 38 | /// // CSS Output 39 | /// .element { 40 | /// margin-right: 3.90625em; 41 | /// } 42 | /// 43 | /// @example scss 44 | /// .element { 45 | /// font-size: modular-scale(3, 1em 1.6em, $major-seventh); 46 | /// } 47 | /// 48 | /// // CSS Output 49 | /// .element { 50 | /// font-size: 3em; 51 | /// } 52 | /// 53 | /// @example scss 54 | /// // Globally change the base ratio 55 | /// $bourbon: ( 56 | /// "modular-scale-ratio": 1.2, 57 | /// ); 58 | /// 59 | /// .element { 60 | /// font-size: modular-scale(3); 61 | /// } 62 | /// 63 | /// // CSS Output 64 | /// .element { 65 | /// font-size: 1.728em; 66 | /// } 67 | /// 68 | /// @require {function} _fetch-bourbon-setting 69 | 70 | @function modular-scale( 71 | $increment, 72 | $value: _fetch-bourbon-setting("modular-scale-base"), 73 | $ratio: _fetch-bourbon-setting("modular-scale-ratio") 74 | ) { 75 | $v1: nth($value, 1); 76 | $v2: nth($value, length($value)); 77 | $value: $v1; 78 | 79 | // scale $v2 to just above $v1 80 | @while $v2 > $v1 { 81 | $v2: ($v2 / $ratio); // will be off-by-1 82 | } 83 | @while $v2 < $v1 { 84 | $v2: ($v2 * $ratio); // will fix off-by-1 85 | } 86 | 87 | // check AFTER scaling $v2 to prevent double-counting corner-case 88 | $double-stranded: $v2 > $v1; 89 | 90 | @if $increment > 0 { 91 | @for $i from 1 through $increment { 92 | @if $double-stranded and ($v1 * $ratio) > $v2 { 93 | $value: $v2; 94 | $v2: ($v2 * $ratio); 95 | } @else { 96 | $v1: ($v1 * $ratio); 97 | $value: $v1; 98 | } 99 | } 100 | } 101 | 102 | @if $increment < 0 { 103 | // adjust $v2 to just below $v1 104 | @if $double-stranded { 105 | $v2: ($v2 / $ratio); 106 | } 107 | 108 | @for $i from $increment through -1 { 109 | @if $double-stranded and ($v1 / $ratio) < $v2 { 110 | $value: $v2; 111 | $v2: ($v2 / $ratio); 112 | } @else { 113 | $v1: ($v1 / $ratio); 114 | $value: $v1; 115 | } 116 | } 117 | } 118 | 119 | @return $value; 120 | } 121 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/library/_overflow-wrap.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Outputs the `overflow-wrap` property and its legacy name `word-wrap` to 4 | /// support browsers that do not yet use `overflow-wrap`. 5 | /// 6 | /// @argument {string} $wrap [break-word] 7 | /// Accepted CSS values are `normal`, `break-word`, `inherit`, `initial`, 8 | /// or `unset`. 9 | /// 10 | /// @example scss 11 | /// .wrapper { 12 | /// @include overflow-wrap; 13 | /// } 14 | /// 15 | /// // CSS Output 16 | /// .wrapper { 17 | /// word-wrap: break-word; 18 | /// overflow-wrap: break-word; 19 | /// } 20 | 21 | @mixin overflow-wrap($wrap: break-word) { 22 | word-wrap: $wrap; 23 | overflow-wrap: $wrap; 24 | } 25 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/library/_padding.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Provides a concise method for targeting `padding` on specific sides of a 4 | /// box. Use a `null` value to “skip” a side. 5 | /// 6 | /// @argument {list} $values 7 | /// List of padding values; accepts CSS shorthand. 8 | /// 9 | /// @example scss 10 | /// .element-one { 11 | /// @include padding(null 1rem); 12 | /// } 13 | /// 14 | /// // CSS Output 15 | /// .element-one { 16 | /// padding-left: 1rem; 17 | /// padding-right: 1rem; 18 | /// } 19 | /// 20 | /// @example scss 21 | /// .element-two { 22 | /// @include padding(10vh null 10px 5%); 23 | /// } 24 | /// 25 | /// // CSS Output 26 | /// .element-two { 27 | /// padding-bottom: 10px; 28 | /// padding-left: 5%; 29 | /// padding-top: 10vh; 30 | /// } 31 | /// 32 | /// @require {mixin} _directional-property 33 | 34 | @mixin padding($values) { 35 | @include _directional-property(padding, null, $values); 36 | } 37 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/library/_position.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Provides a concise, one-line method for setting an element’s positioning 4 | /// properties: `position`, `top`, `right`, `bottom` and `left`. Use a `null` 5 | /// value to “skip” an edge of the box. 6 | /// 7 | /// @argument {string} $position 8 | /// A CSS position value. 9 | /// 10 | /// @argument {list} $box-edge-values 11 | /// List of lengths; accepts CSS shorthand. 12 | /// 13 | /// @example scss 14 | /// .element { 15 | /// @include position(relative, 0 null null 10em); 16 | /// } 17 | /// 18 | /// // CSS Output 19 | /// .element { 20 | /// left: 10em; 21 | /// position: relative; 22 | /// top: 0; 23 | /// } 24 | /// 25 | /// @example scss 26 | /// .element { 27 | /// @include position(absolute, 0); 28 | /// } 29 | /// 30 | /// // CSS Output 31 | /// .element { 32 | /// position: absolute; 33 | /// top: 0; 34 | /// right: 0; 35 | /// bottom: 0; 36 | /// left: 0; 37 | /// } 38 | /// 39 | /// @require {function} _is-length 40 | /// 41 | /// @require {function} _unpack-shorthand 42 | 43 | @mixin position( 44 | $position, 45 | $box-edge-values 46 | ) { 47 | $box-edge-values: _unpack-shorthand($box-edge-values); 48 | $offsets: ( 49 | top: nth($box-edge-values, 1), 50 | right: nth($box-edge-values, 2), 51 | bottom: nth($box-edge-values, 3), 52 | left: nth($box-edge-values, 4), 53 | ); 54 | 55 | position: $position; 56 | 57 | @each $offset, $value in $offsets { 58 | @if _is-length($value) { 59 | #{$offset}: $value; 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/library/_prefixer.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Generates vendor prefixes. 4 | /// 5 | /// @argument {string} $property 6 | /// Property to prefix. 7 | /// 8 | /// @argument {string} $value 9 | /// Value to use. 10 | /// 11 | /// @argument {list} $prefixes 12 | /// Vendor prefixes to output. 13 | /// 14 | /// @example scss 15 | /// .element { 16 | /// @include prefixer(appearance, none, ("webkit", "moz")); 17 | /// } 18 | /// 19 | /// // CSS Output 20 | /// .element { 21 | /// -webkit-appearance: none; 22 | /// -moz-appearance: none; 23 | /// appearance: none; 24 | /// } 25 | /// 26 | /// @author Hugo Giraudel 27 | 28 | @mixin prefixer( 29 | $property, 30 | $value, 31 | $prefixes: () 32 | ) { 33 | @each $prefix in $prefixes { 34 | #{"-" + $prefix + "-" + $property}: $value; 35 | } 36 | #{$property}: $value; 37 | } 38 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/library/_shade.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Mixes a color with black. 4 | /// 5 | /// @argument {color} $color 6 | /// 7 | /// @argument {number (percentage)} $percent 8 | /// The amount of black to be mixed in. 9 | /// 10 | /// @return {color} 11 | /// 12 | /// @example scss 13 | /// .element { 14 | /// background-color: shade(#ffbb52, 60%); 15 | /// } 16 | /// 17 | /// // CSS Output 18 | /// .element { 19 | /// background-color: #664a20; 20 | /// } 21 | 22 | @function shade( 23 | $color, 24 | $percent 25 | ) { 26 | @if not _is-color($color) { 27 | @error "`#{$color}` is not a valid color for the `$color` argument in " + 28 | "the `shade` mixin."; 29 | } @else { 30 | @return mix(#000, $color, $percent); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/library/_size.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Sets the `width` and `height` of the element in one statement. 4 | /// 5 | /// @argument {number (with unit) | string} $width 6 | /// 7 | /// @argument {number (with unit) | string} $height [$width] 8 | /// 9 | /// @example scss 10 | /// .first-element { 11 | /// @include size(2em); 12 | /// } 13 | /// 14 | /// // CSS Output 15 | /// .first-element { 16 | /// width: 2em; 17 | /// height: 2em; 18 | /// } 19 | /// 20 | /// @example scss 21 | /// .second-element { 22 | /// @include size(auto, 10em); 23 | /// } 24 | /// 25 | /// // CSS Output 26 | /// .second-element { 27 | /// width: auto; 28 | /// height: 10em; 29 | /// } 30 | /// 31 | /// @require {function} _is-size 32 | 33 | @mixin size( 34 | $width, 35 | $height: $width 36 | ) { 37 | @if _is-size($height) { 38 | height: $height; 39 | } @else { 40 | @error "`#{$height}` is not a valid length for the `$height` argument " + 41 | "in the `size` mixin."; 42 | } 43 | 44 | @if _is-size($width) { 45 | width: $width; 46 | } @else { 47 | @error "`#{$width}` is not a valid length for the `$width` argument " + 48 | "in the `size` mixin."; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/library/_strip-unit.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Strips the unit from a number. 4 | /// 5 | /// @argument {number} $value 6 | /// 7 | /// @return {number (unitless)} 8 | /// 9 | /// @example scss 10 | /// $dimension: strip-unit(10em); 11 | /// 12 | /// // Output 13 | /// $dimension: 10; 14 | 15 | @function strip-unit($value) { 16 | @return ($value / ($value * 0 + 1)); 17 | } 18 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/library/_timing-functions.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | // scss-lint:disable SpaceAfterComma, UnnecessaryMantissa, TrailingZero 4 | 5 | //// 6 | /// CSS cubic-bezier timing functions. 7 | /// 8 | /// @link https://goo.gl/p8u6SK 9 | /// 10 | /// @type string 11 | //// 12 | 13 | $ease-in-quad: cubic-bezier(0.550, 0.085, 0.680, 0.530); 14 | $ease-in-cubic: cubic-bezier(0.550, 0.055, 0.675, 0.190); 15 | $ease-in-quart: cubic-bezier(0.895, 0.030, 0.685, 0.220); 16 | $ease-in-quint: cubic-bezier(0.755, 0.050, 0.855, 0.060); 17 | $ease-in-sine: cubic-bezier(0.470, 0.000, 0.745, 0.715); 18 | $ease-in-expo: cubic-bezier(0.950, 0.050, 0.795, 0.035); 19 | $ease-in-circ: cubic-bezier(0.600, 0.040, 0.980, 0.335); 20 | $ease-in-back: cubic-bezier(0.600, -0.280, 0.735, 0.045); 21 | 22 | $ease-out-quad: cubic-bezier(0.250, 0.460, 0.450, 0.940); 23 | $ease-out-cubic: cubic-bezier(0.215, 0.610, 0.355, 1.000); 24 | $ease-out-quart: cubic-bezier(0.165, 0.840, 0.440, 1.000); 25 | $ease-out-quint: cubic-bezier(0.230, 1.000, 0.320, 1.000); 26 | $ease-out-sine: cubic-bezier(0.390, 0.575, 0.565, 1.000); 27 | $ease-out-expo: cubic-bezier(0.190, 1.000, 0.220, 1.000); 28 | $ease-out-circ: cubic-bezier(0.075, 0.820, 0.165, 1.000); 29 | $ease-out-back: cubic-bezier(0.175, 0.885, 0.320, 1.275); 30 | 31 | $ease-in-out-quad: cubic-bezier(0.455, 0.030, 0.515, 0.955); 32 | $ease-in-out-cubic: cubic-bezier(0.645, 0.045, 0.355, 1.000); 33 | $ease-in-out-quart: cubic-bezier(0.770, 0.000, 0.175, 1.000); 34 | $ease-in-out-quint: cubic-bezier(0.860, 0.000, 0.070, 1.000); 35 | $ease-in-out-sine: cubic-bezier(0.445, 0.050, 0.550, 0.950); 36 | $ease-in-out-expo: cubic-bezier(1.000, 0.000, 0.000, 1.000); 37 | $ease-in-out-circ: cubic-bezier(0.785, 0.135, 0.150, 0.860); 38 | $ease-in-out-back: cubic-bezier(0.680, -0.550, 0.265, 1.550); 39 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/library/_tint.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Mixes a color with white. 4 | /// 5 | /// @argument {color} $color 6 | /// 7 | /// @argument {number (percentage)} $percent 8 | /// The amount of white to be mixed in. 9 | /// 10 | /// @return {color} 11 | /// 12 | /// @example scss 13 | /// .element { 14 | /// background-color: tint(#6ecaa6, 40%); 15 | /// } 16 | /// 17 | /// // CSS Output 18 | /// .element { 19 | /// background-color: #a8dfc9; 20 | /// } 21 | 22 | @function tint( 23 | $color, 24 | $percent 25 | ) { 26 | @if not _is-color($color) { 27 | @error "`#{$color}` is not a valid color for the `$color` argument in " + 28 | "the `tint` mixin."; 29 | } @else { 30 | @return mix(#fff, $color, $percent); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/library/_triangle.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Generates a triangle pointing in a specified direction. 4 | /// 5 | /// @argument {string} $direction 6 | /// The direction the triangle should point. Accepts `up`, `up-right`, 7 | /// `right`, `down-right`, `down`, `down-left`, `left` or `up-left`. 8 | /// 9 | /// @argument {number (with unit)} $width 10 | /// Width of the triangle. 11 | /// 12 | /// @argument {number (with unit)} $height 13 | /// Height of the triangle. 14 | /// 15 | /// @argument {color} $color 16 | /// Color of the triangle. 17 | /// 18 | /// @example scss 19 | /// .element { 20 | /// &::before { 21 | /// @include triangle("up", 2rem, 1rem, #b25c9c); 22 | /// content: ""; 23 | /// } 24 | /// } 25 | /// 26 | /// // CSS Output 27 | /// .element::before { 28 | /// border-style: solid; 29 | /// height: 0; 30 | /// width: 0; 31 | /// border-color: transparent transparent #b25c9c; 32 | /// border-width: 0 1rem 1rem; 33 | /// content: ""; 34 | /// } 35 | 36 | @mixin triangle( 37 | $direction, 38 | $width, 39 | $height, 40 | $color 41 | ) { 42 | @if not index( 43 | "up" "up-right" "right" "down-right" "down" "down-left" "left" "up-left", 44 | $direction 45 | ) { 46 | @error "Direction must be `up`, `up-right`, `right`, `down-right`, " + 47 | "`down`, `down-left`, `left` or `up-left`."; 48 | } @else if not _is-color($color) { 49 | @error "`#{$color}` is not a valid color for the `$color` argument in " + 50 | "the `triangle` mixin."; 51 | } @else { 52 | border-style: solid; 53 | height: 0; 54 | width: 0; 55 | 56 | @if $direction == "up" { 57 | border-color: transparent transparent $color; 58 | border-width: 0 ($width / 2) $height; 59 | } @else if $direction == "up-right" { 60 | border-color: transparent $color transparent transparent; 61 | border-width: 0 $width $width 0; 62 | } @else if $direction == "right" { 63 | border-color: transparent transparent transparent $color; 64 | border-width: ($height / 2) 0 ($height / 2) $width; 65 | } @else if $direction == "down-right" { 66 | border-color: transparent transparent $color; 67 | border-width: 0 0 $width $width; 68 | } @else if $direction == "down" { 69 | border-color: $color transparent transparent; 70 | border-width: $height ($width / 2) 0; 71 | } @else if $direction == "down-left" { 72 | border-color: transparent transparent transparent $color; 73 | border-width: $width 0 0 $width; 74 | } @else if $direction == "left" { 75 | border-color: transparent $color transparent transparent; 76 | border-width: ($height / 2) $width ($height / 2) 0; 77 | } @else if $direction == "up-left" { 78 | border-color: $color transparent transparent; 79 | border-width: $width $width 0 0; 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/library/_value-prefixer.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Generates vendor prefixes for values. 4 | /// 5 | /// @argument {string} $property 6 | /// Property to use. 7 | /// 8 | /// @argument {string} $value 9 | /// Value to prefix. 10 | /// 11 | /// @argument {list} $prefixes 12 | /// Vendor prefixes to output. 13 | /// 14 | /// @example scss 15 | /// .element { 16 | /// @include value-prefixer(cursor, grab, ("webkit", "moz")); 17 | /// } 18 | /// 19 | /// // CSS Output 20 | /// .element { 21 | /// cursor: -webkit-grab; 22 | /// cursor: -moz-grab; 23 | /// cursor: grab; 24 | /// } 25 | /// 26 | /// @author Matthew Tobiasz 27 | 28 | @mixin value-prefixer( 29 | $property, 30 | $value, 31 | $prefixes: () 32 | ) { 33 | @each $prefix in $prefixes { 34 | #{$property}: #{"-" + $prefix + "-" + $value}; 35 | } 36 | #{$property}: $value; 37 | } 38 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/settings/_settings.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Default global Bourbon settings. Values in this map are overwritten by any 4 | /// values set in the `$bourbon` map. 5 | /// 6 | /// @type map 7 | /// 8 | /// @property {color} contrast-switch-dark-color [#000] 9 | /// Global dark color for the `contrast-switch` function. 10 | /// 11 | /// @property {color} contrast-switch-light-color [#fff] 12 | /// Global light color for the `contrast-switch` function. 13 | /// 14 | /// @property {list} global-font-file-formats [("ttf", "woff2", "woff")] 15 | /// Global font file formats for the `font-face` mixin. 16 | /// 17 | /// @property {number (with unit)} modular-scale-base [1em] 18 | /// Global base value for the `modular-scale` function. 19 | /// 20 | /// @property {number (unitless)} modular-scale-ratio [$major-third (1.25)] 21 | /// Global base ratio for the `modular-scale` function. 22 | /// 23 | /// @property {boolean} rails-asset-pipeline [false] 24 | /// Set this to `true` when using the Rails Asset Pipeline and Bourbon will 25 | /// write asset paths using 26 | /// [sass-rails’ asset helpers](https://github.com/rails/sass-rails#asset-helpers). 27 | /// 28 | /// @access private 29 | 30 | $_bourbon-defaults: ( 31 | "contrast-switch-dark-color": #000, 32 | "contrast-switch-light-color": #fff, 33 | "global-font-file-formats": ("ttf", "woff2", "woff"), 34 | "modular-scale-base": 1em, 35 | "modular-scale-ratio": $major-third, 36 | "rails-asset-pipeline": false, 37 | ); 38 | 39 | /// Global Bourbon settings. 40 | /// 41 | /// @name Settings 42 | /// 43 | /// @type map 44 | /// 45 | /// @property {color} contrast-switch-dark-color [#000] 46 | /// Global dark color for the `contrast-switch` function. 47 | /// 48 | /// @property {color} contrast-switch-light-color [#fff] 49 | /// Global light color for the `contrast-switch` function. 50 | /// 51 | /// @property {list} global-font-file-formats [("ttf", "woff2", "woff")] 52 | /// Global font file formats for the `font-face` mixin. 53 | /// 54 | /// @property {number (with unit)} modular-scale-base [1em] 55 | /// Global base value for the `modular-scale` function. 56 | /// 57 | /// @property {number (unitless)} modular-scale-ratio [$major-third (1.25)] 58 | /// Global base ratio for the `modular-scale` function. 59 | /// 60 | /// @property {boolean} rails-asset-pipeline [false] 61 | /// Set this to `true` when using the Rails Asset Pipeline and Bourbon will 62 | /// write asset paths using 63 | /// [sass-rails’ asset helpers](https://github.com/rails/sass-rails#asset-helpers). 64 | /// 65 | /// @example scss 66 | /// $bourbon: ( 67 | /// "contrast-switch-dark-color": #000, 68 | /// "contrast-switch-light-color": #fff, 69 | /// "global-font-file-formats": ("ttf", "woff2", "woff"), 70 | /// "modular-scale-base": 1em, 71 | /// "modular-scale-ratio": $major-third, 72 | /// "rails-asset-pipeline": false, 73 | /// ); 74 | 75 | $bourbon: () !default; 76 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/utilities/_assign-inputs.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Append pseudo-classes to a selector(s). 4 | /// 5 | /// @argument {list | string} $inputs 6 | /// A selector, or list of selectors, to apply the pseudo-class to. 7 | /// 8 | /// @argument {pseudo-class} $pseudo [null] 9 | /// The pseudo-class to be appended. 10 | /// 11 | /// @return {list} 12 | /// 13 | /// @access private 14 | 15 | @function _assign-inputs( 16 | $inputs, 17 | $pseudo: null 18 | ) { 19 | $list: (); 20 | 21 | @each $input in $inputs { 22 | $input: unquote($input); 23 | $input: if($pseudo, $input + ":" + $pseudo, $input); 24 | $list: append($list, $input, comma); 25 | } 26 | 27 | @return $list; 28 | } 29 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/utilities/_compact-shorthand.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | // scss-lint:disable ElsePlacement 4 | 5 | /// Transforms shorthand to its shortest possible form. 6 | /// 7 | /// @argument {list} $values 8 | /// List of directional values. 9 | /// 10 | /// @example scss 11 | /// $values: _compact-shorthand(10px 20px 10px 20px); 12 | /// 13 | /// // Output 14 | /// $values: 10px 20px; 15 | /// 16 | /// @return {list} 17 | /// 18 | /// @access private 19 | 20 | @function _compact-shorthand($values) { 21 | $output: null; 22 | 23 | $a: nth($values, 1); 24 | $b: if(length($values) < 2, $a, nth($values, 2)); 25 | $c: if(length($values) < 3, $a, nth($values, 3)); 26 | $d: if(length($values) < 2, $a, nth($values, if(length($values) < 4, 2, 4))); 27 | 28 | @if $a == 0 { $a: 0; } 29 | @if $b == 0 { $b: 0; } 30 | @if $c == 0 { $c: 0; } 31 | @if $d == 0 { $d: 0; } 32 | 33 | @if $a == $b and $a == $c and $a == $d { $output: $a; } 34 | @else if $a == $c and $b == $d { $output: $a $b; } 35 | @else if $b == $d { $output: $a $b $c; } 36 | @else { $output: $a $b $c $d; } 37 | 38 | @return $output; 39 | } 40 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/utilities/_contrast-ratio.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Programatically determines the contrast ratio between two colors. 4 | /// 5 | /// Note that the alpha channel is ignored. 6 | /// 7 | /// @link https://goo.gl/54htLV 8 | /// 9 | /// @argument {color (hex)} $color-1 10 | /// 11 | /// @argument {color (hex)} $color-2 12 | /// 13 | /// @return {number (1-21)} 14 | /// 15 | /// @example scss 16 | /// _contrast-ratio(black, white) 17 | /// 18 | /// @require {function} _lightness 19 | /// 20 | /// @access private 21 | 22 | @function _contrast-ratio($color-1, $color-2) { 23 | $-local-lightness-1: _lightness($color-1) + 0.05; 24 | $-local-lightness-2: _lightness($color-2) + 0.05; 25 | 26 | @if $-local-lightness-1 > $-local-lightness-2 { 27 | @return $-local-lightness-1 / $-local-lightness-2; 28 | } @else { 29 | @return $-local-lightness-2 / $-local-lightness-1; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/utilities/_directional-property.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | // scss-lint:disable SpaceAroundOperator 4 | 5 | /// Builds directional properties by parsing CSS shorthand values. For example, 6 | /// a value of `10px null` will output top and bottom directional properties, 7 | /// but the `null` skips left and right from being output. 8 | /// 9 | /// @argument {string} $property 10 | /// Base property. 11 | /// 12 | /// @argument {string} $suffix 13 | /// Suffix to append. Use `null` to omit. 14 | /// 15 | /// @argument {list} $values 16 | /// List of values to set for the property. 17 | /// 18 | /// @example scss 19 | /// .element { 20 | /// @include _directional-property(border, width, null 5px); 21 | /// } 22 | /// 23 | /// // CSS Output 24 | /// .element { 25 | /// border-right-width: 5px; 26 | /// border-left-width: 5px; 27 | /// } 28 | /// 29 | /// @require {function} _compact-shorthand 30 | /// 31 | /// @require {function} _contains-falsy 32 | /// 33 | /// @access private 34 | 35 | @mixin _directional-property( 36 | $property, 37 | $suffix, 38 | $values 39 | ) { 40 | $top: $property + "-top" + if($suffix, "-#{$suffix}", ""); 41 | $bottom: $property + "-bottom" + if($suffix, "-#{$suffix}", ""); 42 | $left: $property + "-left" + if($suffix, "-#{$suffix}", ""); 43 | $right: $property + "-right" + if($suffix, "-#{$suffix}", ""); 44 | $all: $property + if($suffix, "-#{$suffix}", ""); 45 | 46 | $values: _compact-shorthand($values); 47 | 48 | @if _contains-falsy($values) { 49 | @if nth($values, 1) { #{$top}: nth($values, 1); } 50 | 51 | @if length($values) == 1 { 52 | @if nth($values, 1) { #{$right}: nth($values, 1); } 53 | } @else { 54 | @if nth($values, 2) { #{$right}: nth($values, 2); } 55 | } 56 | 57 | @if length($values) == 2 { 58 | @if nth($values, 1) { #{$bottom}: nth($values, 1); } 59 | @if nth($values, 2) { #{$left}: nth($values, 2); } 60 | } @else if length($values) == 3 { 61 | @if nth($values, 3) { #{$bottom}: nth($values, 3); } 62 | @if nth($values, 2) { #{$left}: nth($values, 2); } 63 | } @else if length($values) == 4 { 64 | @if nth($values, 3) { #{$bottom}: nth($values, 3); } 65 | @if nth($values, 4) { #{$left}: nth($values, 4); } 66 | } 67 | } @else { 68 | #{$all}: $values; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/utilities/_fetch-bourbon-setting.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Return a Bourbon setting. 4 | /// 5 | /// @argument {string} $setting 6 | /// 7 | /// @return {boolean | color | list | number | string} 8 | /// 9 | /// @example scss 10 | /// _fetch-bourbon-setting(rails-asset-pipeline) 11 | /// 12 | /// @access private 13 | 14 | @function _fetch-bourbon-setting($setting) { 15 | @return map-get(map-merge($_bourbon-defaults, $bourbon), $setting); 16 | } 17 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/utilities/_font-source-declaration.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Builds the `src` list for an `@font-face` declaration. 4 | /// 5 | /// @link https://goo.gl/Ru1bKP 6 | /// 7 | /// @argument {string} $font-family 8 | /// 9 | /// @argument {string} $file-path 10 | /// 11 | /// @argument {boolean} $asset-pipeline 12 | /// 13 | /// @argument {list} $file-formats 14 | /// 15 | /// @return {list} 16 | /// 17 | /// @require {function} _contains 18 | /// 19 | /// @access private 20 | 21 | @function _font-source-declaration( 22 | $font-family, 23 | $file-path, 24 | $asset-pipeline, 25 | $file-formats 26 | ) { 27 | $src: (); 28 | 29 | $formats-map: ( 30 | eot: "#{$file-path}.eot?#iefix" format("embedded-opentype"), 31 | woff2: "#{$file-path}.woff2" format("woff2"), 32 | woff: "#{$file-path}.woff" format("woff"), 33 | ttf: "#{$file-path}.ttf" format("truetype"), 34 | svg: "#{$file-path}.svg##{$font-family}" format("svg"), 35 | ); 36 | 37 | @each $key, $values in $formats-map { 38 | @if _contains($file-formats, $key) { 39 | $file-path: nth($values, 1); 40 | $font-format: nth($values, 2); 41 | 42 | @if $asset-pipeline == true { 43 | $src: append($src, font-url($file-path) $font-format, comma); 44 | } @else { 45 | $src: append($src, url($file-path) $font-format, comma); 46 | } 47 | } 48 | } 49 | 50 | @return $src; 51 | } 52 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/utilities/_gamma.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Performs gamma correction on a single color channel. 4 | /// 5 | /// Note that Sass does not have a `pow()` function, so the calculation 6 | /// is approximate. 7 | /// 8 | /// @argument {number (0-1)} $channel 9 | /// 10 | /// @return {number (0-1)} 11 | /// 12 | /// @access private 13 | 14 | @function _gamma($channel) { 15 | @if $channel < 0.03928 { 16 | @return $channel / 12.92; 17 | } @else { 18 | $c: ($channel + 0.055) / 1.055; 19 | @return (133 * $c * $c * $c + 155 * $c * $c) / 288; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/utilities/_lightness.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Programatically determines the lightness of a color. 4 | /// 5 | /// @argument {color (hex)} $hex-color 6 | /// 7 | /// @return {number (0-1)} 8 | /// 9 | /// @example scss 10 | /// _lightness($color) 11 | /// 12 | /// @access private 13 | 14 | @function _lightness($hex-color) { 15 | $-local-red-raw: red(rgba($hex-color, 1)); 16 | $-local-green-raw: green(rgba($hex-color, 1)); 17 | $-local-blue-raw: blue(rgba($hex-color, 1)); 18 | 19 | $-local-red: _gamma($-local-red-raw / 255); 20 | $-local-green: _gamma($-local-green-raw / 255); 21 | $-local-blue: _gamma($-local-blue-raw / 255); 22 | 23 | @return $-local-red * 0.2126 + $-local-green * 0.7152 + $-local-blue * 0.0722; 24 | } 25 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/utilities/_unpack-shorthand.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Transforms shorthand that can range from 1-to-4 values to be 4 values. 4 | /// 5 | /// @argument {list} $shorthand 6 | /// 7 | /// @example scss 8 | /// .element { 9 | /// margin: _unpack-shorthand(1em 2em); 10 | /// } 11 | /// 12 | /// // CSS Output 13 | /// .element { 14 | /// margin: 1em 2em 1em 2em; 15 | /// } 16 | /// 17 | /// @access private 18 | 19 | @function _unpack-shorthand($shorthand) { 20 | @if length($shorthand) == 1 { 21 | @return nth($shorthand, 1) nth($shorthand, 1) nth($shorthand, 1) nth($shorthand, 1); 22 | } @else if length($shorthand) == 2 { 23 | @return nth($shorthand, 1) nth($shorthand, 2) nth($shorthand, 1) nth($shorthand, 2); 24 | } @else if length($shorthand) == 3 { 25 | @return nth($shorthand, 1) nth($shorthand, 2) nth($shorthand, 3) nth($shorthand, 2); 26 | } @else { 27 | @return $shorthand; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/validators/_contains-falsy.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Checks if a list does not contain any values. 4 | /// 5 | /// @argument {list} $list 6 | /// The list to check against. 7 | /// 8 | /// @return {boolean} 9 | /// 10 | /// @access private 11 | 12 | @function _contains-falsy($list) { 13 | @each $item in $list { 14 | @if not $item { 15 | @return true; 16 | } 17 | } 18 | 19 | @return false; 20 | } 21 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/validators/_contains.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Checks if a list contains a value(s). 4 | /// 5 | /// @argument {list} $list 6 | /// The list to check against. 7 | /// 8 | /// @argument {list} $values 9 | /// A single value or list of values to check for. 10 | /// 11 | /// @return {boolean} 12 | /// 13 | /// @access private 14 | 15 | @function _contains( 16 | $list, 17 | $values... 18 | ) { 19 | @each $value in $values { 20 | @if type-of(index($list, $value)) != "number" { 21 | @return false; 22 | } 23 | } 24 | 25 | @return true; 26 | } 27 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/validators/_is-color.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Checks for a valid CSS color. 4 | /// 5 | /// @argument {string} $color 6 | /// 7 | /// @return {boolean} 8 | /// 9 | /// @access private 10 | 11 | @function _is-color($color) { 12 | @return (type-of($color) == color) or ($color == "currentColor"); 13 | } 14 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/validators/_is-length.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Checks for a valid CSS length. 4 | /// 5 | /// @argument {string} $value 6 | /// 7 | /// @return {boolean} 8 | /// 9 | /// @access private 10 | 11 | @function _is-length($value) { 12 | @return type-of($value) != "null" and (str-slice($value + "", 1, 4) == "calc" 13 | or index(auto inherit initial 0, $value) 14 | or (type-of($value) == "number" and not(unitless($value)))); 15 | } 16 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/validators/_is-number.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Checks for a valid number. 4 | /// 5 | /// @argument {number} $value 6 | /// 7 | /// @require {function} _contains 8 | /// 9 | /// @return {boolean} 10 | /// 11 | /// @access private 12 | 13 | @function _is-number($value) { 14 | @return _contains("0" "1" "2" "3" "4" "5" "6" "7" "8" "9" 0 1 2 3 4 5 6 7 8 9, $value); 15 | } 16 | -------------------------------------------------------------------------------- /assets/css/shared/bourbon/validators/_is-size.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Checks for a valid CSS size. 4 | /// 5 | /// @argument {string} $value 6 | /// 7 | /// @return {boolean} 8 | /// 9 | /// @require {function} _contains 10 | /// 11 | /// @require {function} _is-length 12 | /// 13 | /// @access private 14 | 15 | @function _is-size($value) { 16 | @return _is-length($value) 17 | or _contains("fill" "fit-content" "min-content" "max-content", $value); 18 | } 19 | -------------------------------------------------------------------------------- /assets/css/shared/flex-grid/_fg_breakpoint.scss: -------------------------------------------------------------------------------- 1 | //Override as required. 2 | $_fg_small: 768 !default; // up to "tablet" size 3 | $_fg_medium: 1024 !default; // up to "desktop" size 4 | $_fg_large: 1280 !default; // up to bigger desktop size 5 | 6 | @mixin _fg_breakpoint($_fg_media) { 7 | @if $_fg_media == small { 8 | @media only screen and (min-width: $_fg_small*1px) { @content; } 9 | } 10 | @else if $_fg_media == medium { 11 | @media only screen and (min-width: $_fg_medium*1px) { @content; } 12 | } 13 | @else if $_fg_media == large { 14 | @media only screen and (min-width: $_fg_large*1px) { @content; } 15 | } 16 | 17 | @else if type-of($_fg_media) == number { 18 | @media only screen and (min-width: $_fg_media*1px) { @content; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /assets/css/shared/flex-grid/_fg_grid.scss: -------------------------------------------------------------------------------- 1 | // Global variables: 2 | // Unitless, interpreted as pixels 3 | $_fg_gutter: 24 !default; // gutter between columns. Set as desired. 4 | $_fg_padding: 12 !default; // padding for column boxes. Set as desired, can override for individual columns. 5 | 6 | 7 | // *** Main mixin to create a per-row layout *** // 8 | @mixin _fg($colList, $gutter: $_fg_gutter, $padding: $_fg_padding) { 9 | @if type-of($colList) == number { // call _fg_grid() directly 10 | @include _fg_grid($colList, $gutter, $padding); 11 | 12 | } @else if type-of($colList) == list and length($colList) > 1 { 13 | 14 | // Count how many columns there are altogether 15 | $columnCount: 0; 16 | @each $i in $colList { 17 | $columnCount: $columnCount + $i; 18 | } 19 | 20 | @include _fg_grid($columnCount, $gutter, $padding); 21 | 22 | @for $i from 1 through length($colList) { // set child items widths using nth:child() 23 | $c: nth($colList, $i); 24 | & > :nth-child(#{length($colList)}n+#{$i}) { 25 | @include _fg_width($c/$columnCount, $gutter); 26 | } 27 | } 28 | } 29 | } 30 | 31 | 32 | // *** Set up grid with equal width columns *** // 33 | @mixin _fg_grid($cols: 0, $gutter: $_fg_gutter, $padding: $_fg_padding) { 34 | box-sizing: border-box; 35 | display: flex; 36 | flex-wrap: wrap; 37 | margin-left: (-1 * $gutter) * 1px; 38 | 39 | > * { 40 | @if $padding != 0 { 41 | padding: $padding * 1px; 42 | } 43 | margin-left: $gutter * 1px; 44 | box-sizing: border-box; 45 | } 46 | 47 | $calc_percent: (1/$cols) * 100%; 48 | $calc_gutter_allowance: $gutter * 1px; 49 | 50 | > * { width: calc(#{$calc_percent} - #{$calc_gutter_allowance}); } 51 | } 52 | 53 | 54 | // *** width override for a column *** // 55 | @mixin _fg_width($ratio, $gutter: $_fg_gutter) { 56 | $calc_percent: $ratio * 100%; 57 | $calc_gutter: $gutter * 1px; 58 | width: calc(#{$calc_percent} - #{$calc_gutter}); 59 | }; 60 | -------------------------------------------------------------------------------- /assets/css/shared/flex-grid/_flex-grid.sass: -------------------------------------------------------------------------------- 1 | @import './fg_grid' 2 | @import './fg_breakpoint' -------------------------------------------------------------------------------- /assets/css/shared/reset/_reset.scss: -------------------------------------------------------------------------------- 1 | /* BORROWED FROM: https://gist.github.com/hcatlin/1027867 2 | http://meyerweb.com/eric/tools/css/reset/ 3 | v2.0 | 20110126 4 | License: none (public domain) 5 | */ 6 | 7 | html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { 8 | margin: 0; 9 | padding: 0; 10 | border: 0; 11 | font-size: 100%; 12 | font: inherit; 13 | vertical-align: baseline; } 14 | 15 | /* HTML5 display-role reset for older browsers */ 16 | 17 | article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { 18 | display: block; } 19 | 20 | body { 21 | line-height: 1; } 22 | 23 | ol, ul { 24 | list-style: none; } 25 | 26 | blockquote, q { 27 | quotes: none; } 28 | 29 | blockquote { 30 | &:before, &:after { 31 | content: ''; 32 | content: none; } } 33 | 34 | q { 35 | &:before, &:after { 36 | content: ''; 37 | content: none; } } 38 | 39 | table { 40 | border-collapse: collapse; 41 | border-spacing: 0; } -------------------------------------------------------------------------------- /assets/css/shared/settings/_colors.sass: -------------------------------------------------------------------------------- 1 | $white: #FFFFFF 2 | $gallery-gray: #EEEEEE 3 | $alabaster-gray: #FAFAFA 4 | $dark-gray: #666666 5 | $ir-red: #e73536 6 | $green: #70ca63 7 | $orange: #f6bb42 8 | $warning-red: #e9573f 9 | $blue: #4a89dc 10 | -------------------------------------------------------------------------------- /assets/css/shared/settings/_fonts.sass: -------------------------------------------------------------------------------- 1 | $helvetica-neue: "Helvetica Neue",Helvetica,Arial,sans-serif -------------------------------------------------------------------------------- /assets/css/theme.sass: -------------------------------------------------------------------------------- 1 | // setup & base 2 | @import 'shared/bourbon/bourbon' 3 | @import 'shared/reset/reset' 4 | @import 'theme/settings/grid' 5 | @import 'shared/flex-grid/flex-grid' 6 | @import "~pikaday/scss/pikaday.scss" 7 | 8 | // global styles 9 | @import 'shared/settings/colors' 10 | @import 'shared/settings/fonts' 11 | @import 'theme/globals/global' 12 | 13 | // component styles 14 | @import 'theme/_extends/typography' 15 | @import 'theme/_extends/buttons' 16 | @import 'theme/_extends/select-input' 17 | @import 'theme/_extends/label' 18 | @import 'theme/_extends/text-input' 19 | 20 | @import 'theme/components/account-info' 21 | @import 'theme/components/nav' 22 | @import 'theme/components/table' 23 | @import 'theme/components/toolbar' 24 | @import 'theme/components/filters' 25 | @import 'theme/components/pagination' 26 | @import 'theme/components/header-and-content' 27 | @import 'theme/components/form' 28 | @import 'theme/components/panel' 29 | @import 'theme/components/datepicker' 30 | @import 'theme/components/flash-messages' 31 | 32 | // page styles 33 | @import 'theme/pages/index' 34 | @import 'theme/pages/show' 35 | @import 'theme/pages/edit' 36 | @import 'theme/pages/new' 37 | -------------------------------------------------------------------------------- /assets/css/theme/_extends/_buttons.sass: -------------------------------------------------------------------------------- 1 | %base-button-styles 2 | transition: all 250ms ease-in-out 3 | font-family: $helvetica-neue 4 | font-size: 14px 5 | padding: 9px 12px 6 | cursor: pointer 7 | background-color: $gallery-gray 8 | color: $dark-gray 9 | border: 1px solid transparent 10 | text-transform: capitalize 11 | 12 | %default-button 13 | @extend %base-button-styles 14 | border-color: rgba(0, 0, 0, 0.1) 15 | 16 | &:hover 17 | background-color: darken($gallery-gray, 15%) 18 | 19 | %red-button 20 | @extend %base-button-styles 21 | background-color: $ir-red 22 | color: $white 23 | 24 | &:hover 25 | background-color: darken($ir-red, 15%) 26 | 27 | %add-button 28 | &:before 29 | content: "+" 30 | display: inline-block 31 | font-size: 20px 32 | line-height: 10px 33 | font-weight: bold 34 | margin-right: 3px 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /assets/css/theme/_extends/_label.sass: -------------------------------------------------------------------------------- 1 | %base-label 2 | color: $dark-gray 3 | padding: 10px 0 4 | font-size: 14px 5 | display: block 6 | -------------------------------------------------------------------------------- /assets/css/theme/_extends/_select-input.sass: -------------------------------------------------------------------------------- 1 | %select-input 2 | transition: all 350ms ease-in-out 3 | appearance: none 4 | outline: 0 5 | margin: 0 6 | display: block 7 | border: 1px solid darken($gallery-gray, 10%) 8 | border-radius: 0px 9 | padding: 9px 25px 9px 10px 10 | font-family: $helvetica-neue 11 | font-size: 14px 12 | background: url('../images/down-arrow.png') no-repeat 97% 50% $white 13 | background-size: 17px 14 | background-position: 94% 15 | color: $dark-gray 16 | 17 | &:focus, 18 | &:hover 19 | border-color: $dark-gray 20 | -------------------------------------------------------------------------------- /assets/css/theme/_extends/_text-input.sass: -------------------------------------------------------------------------------- 1 | %text-input 2 | transition: all 350ms ease-in-out 3 | appearance: none 4 | outline: none 5 | background: none 6 | margin: 0 7 | padding: 10px 8 | font-family: $helvetica-neue 9 | font-size: 14px 10 | color: $dark-gray 11 | border: 1px solid darken($gallery-gray, 10%) 12 | display: block 13 | background-color: $white 14 | 15 | &:focus, 16 | &:hover 17 | border-color: $dark-gray 18 | border-width: 1px 19 | -------------------------------------------------------------------------------- /assets/css/theme/_extends/_typography.sass: -------------------------------------------------------------------------------- 1 | %h3-text 2 | font-size: 16px 3 | font-weight: bold 4 | font-family: $helvetica-neue 5 | 6 | %h3-gray-text 7 | @extend %h3-text 8 | color: $dark-gray -------------------------------------------------------------------------------- /assets/css/theme/components/_account-info.sass: -------------------------------------------------------------------------------- 1 | section#torch-account-info 2 | background-color: $ir-red 3 | text-align: right 4 | 5 | a 6 | margin: 6px 0 7 | display: inline-block 8 | padding: 0 10px 9 | border-right: 1px solid $white 10 | color: $white 11 | font-family: $helvetica-neue 12 | font-size: 14px 13 | 14 | .torch-container 15 | a 16 | &:last-child 17 | border-right: 0px 18 | 19 | -------------------------------------------------------------------------------- /assets/css/theme/components/_datepicker.sass: -------------------------------------------------------------------------------- 1 | .torch-datepicker 2 | .is-today 3 | &:not(.is-selected) 4 | .pika-button 5 | color: $ir-red 6 | 7 | .pika-button 8 | &:hover 9 | background: $ir-red 10 | color: $white !important 11 | 12 | .is-selected 13 | .pika-button 14 | background: $ir-red 15 | box-shadow: none 16 | 17 | &:hover 18 | background: $ir-red -------------------------------------------------------------------------------- /assets/css/theme/components/_filters.sass: -------------------------------------------------------------------------------- 1 | section#torch-filters 2 | background-color: $alabaster-gray 3 | padding: 20px 4 | 5 | h3 6 | @extend %h3-gray-text 7 | text-transform: capitalize 8 | 9 | hr 10 | appearance: none 11 | border: none 12 | border-bottom: 1px solid darken($gallery-gray, 10%) 13 | margin: 20px 0 10px 14 | 15 | .field 16 | display: flex 17 | flex-wrap: wrap 18 | 19 | label 20 | @extend %base-label 21 | flex: 1 22 | flex-basis: 100% 23 | 24 | select 25 | @extend %select-input 26 | flex: 1 27 | margin-right: 20px 28 | max-width: 30% 29 | 30 | input[type="number"] 31 | @extend %text-input 32 | flex: 3 33 | 34 | input[type="text"] 35 | @extend %text-input 36 | flex: 3 37 | 38 | &.datepicker 39 | width: calc(50% - 10px) 40 | 41 | &.start 42 | margin-right: 20px 43 | 44 | button 45 | @extend %default-button 46 | margin-top: 10px 47 | 48 | a 49 | margin-left: 20px 50 | color: $ir-red 51 | -------------------------------------------------------------------------------- /assets/css/theme/components/_flash-messages.sass: -------------------------------------------------------------------------------- 1 | section#torch-flash-messages 2 | margin-bottom: 20px 3 | 4 | .torch-flash 5 | padding: 8px 6 | text-align: center 7 | color: $white 8 | 9 | &.error 10 | background-color: $orange 11 | 12 | &.info 13 | background-color: $blue 14 | 15 | &.success 16 | background-color: $green 17 | 18 | .torch-flash-close 19 | appearance: none 20 | background-color: inherit 21 | border: 1px solid $white 22 | color: $white 23 | border-radius: 50% 24 | width: 22px 25 | height: 22px 26 | cursor: pointer 27 | 28 | &:focus 29 | outline: none -------------------------------------------------------------------------------- /assets/css/theme/components/_form.sass: -------------------------------------------------------------------------------- 1 | form#torch-form 2 | background-color: $white 3 | display: flex 4 | padding: 20px 5 | 6 | .torch-form-error 7 | background-color: $orange 8 | color: $white 9 | margin-bottom: 20px 10 | padding: 5px 11 | text-align: center 12 | 13 | .torch-form-group 14 | align-items: center 15 | display: flex 16 | flex-wrap: wrap 17 | margin-bottom: 20px 18 | 19 | label 20 | display: flex 21 | align-items: center 22 | justify-content: flex-end 23 | font-size: 15px 24 | font-family: $helvetica-neue 25 | color: $dark-gray 26 | flex: 1 27 | text-align: right 28 | margin-right: 20px 29 | 30 | input[type="text"], 31 | input[type="password"], 32 | textarea 33 | @extend %text-input 34 | flex: 1 35 | 36 | input[type="number"], 37 | input[type="datetime-local"] 38 | @extend %text-input 39 | 40 | select 41 | @extend %select-input 42 | 43 | .help-block 44 | margin-left: calc(30% + 12px) 45 | width: 70% 46 | text-transform: capitalize 47 | color: $orange 48 | font-size: 14px 49 | 50 | .torch-form-group-input 51 | align-items: center 52 | display: flex 53 | flex: 3 54 | flex-wrap: wrap 55 | 56 | select:first-child 57 | margin-left: 0 58 | 59 | select 60 | margin-right: 0.5em 61 | margin-left: 0.5em 62 | 63 | .form-field-error 64 | border: 1px solid red !important 65 | 66 | .invalid-feedback 67 | flex: 1 68 | margin-left: 1rem 69 | color: red 70 | 71 | .torch-submit-form 72 | display: flex 73 | justify-content: flex-end 74 | 75 | .torch-submit-button 76 | @extend %red-button 77 | -------------------------------------------------------------------------------- /assets/css/theme/components/_header-and-content.sass: -------------------------------------------------------------------------------- 1 | section#torch-header-and-content 2 | .header 3 | background-color: $alabaster-gray 4 | padding: 15px 20px 5 | border-top: 4px solid $ir-red 6 | border-radius: 3px 7 | border-bottom: 1px solid $gallery-gray 8 | 9 | h3 10 | @extend %h3-gray-text 11 | 12 | ul 13 | padding: 20px 14 | background-color: $white 15 | 16 | 17 | li 18 | display: flex 19 | padding: 10px 0 20 | 21 | .torch-show-label 22 | width: 20% 23 | text-align: center 24 | 25 | .torch-show-data 26 | width: 80% 27 | 28 | 29 | -------------------------------------------------------------------------------- /assets/css/theme/components/_nav.sass: -------------------------------------------------------------------------------- 1 | section#torch-nav 2 | background-color: $alabaster-gray 3 | 4 | .torch-container 5 | display: flex 6 | 7 | .torch-logo 8 | padding: 6px 0px 9 | 10 | a 11 | display: flex 12 | 13 | h3 14 | color: $ir-red 15 | font-family: $helvetica-neue 16 | text-transform: uppercase 17 | font-size: 18px 18 | font-weight: bold 19 | margin: 15px 10px 20 | 21 | &:before 22 | content: " " 23 | display: block 24 | background-image: url("../images/torch-logo.png") 25 | width: 50px 26 | height: 50px 27 | background-size: contain 28 | background-repeat: no-repeat 29 | 30 | .torch-nav 31 | display: flex 32 | 33 | a 34 | display: block 35 | font-size: 16px 36 | padding: 22px 10px 19px 10px 37 | border-bottom: 3px solid transparent 38 | color: lighten($dark-gray, 25%) 39 | 40 | &:hover 41 | color: $dark-gray 42 | 43 | &.active 44 | border-color: $ir_red 45 | color: $dark-gray 46 | -------------------------------------------------------------------------------- /assets/css/theme/components/_pagination.sass: -------------------------------------------------------------------------------- 1 | section#torch-pagination 2 | ul 3 | display: flex 4 | 5 | li 6 | a 7 | display: block 8 | padding: 10px 15px 9 | color: $ir-red 10 | text-decoration: none 11 | background-color: $white 12 | border: 1px solid $gallery-gray 13 | margin-left: -1px 14 | 15 | &:hover 16 | background-color: $alabaster-gray 17 | 18 | &.active 19 | background-color: $ir-red 20 | color: $white 21 | 22 | &:first-child 23 | a 24 | margin-left: 0px 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /assets/css/theme/components/_panel.sass: -------------------------------------------------------------------------------- 1 | .torch-panel 2 | border: 2px solid $gallery-gray 3 | padding: 25px 4 | flex: 1 5 | 6 | legend 7 | @extend %h3-gray-text 8 | padding: 0 6px 9 | -------------------------------------------------------------------------------- /assets/css/theme/components/_table.sass: -------------------------------------------------------------------------------- 1 | section#torch-table 2 | overflow-x: auto 3 | 4 | .torch-no-data 5 | text-transform: capitalize 6 | color: $dark-gray 7 | 8 | table 9 | color: $dark-gray 10 | font-size: 14px 11 | font-family: $helvetica-neue 12 | width: 100% 13 | background-color: $white 14 | 15 | th 16 | border-top: 1px solid $gallery-gray 17 | border-bottom: 1px solid $gallery-gray 18 | background-color: $alabaster-gray 19 | padding: 0 20 | color: $dark-gray 21 | vertical-align: middle 22 | 23 | &:hover 24 | background-color: darken($alabaster-gray, 15%) 25 | 26 | &:first-child 27 | border-left: 1px solid $gallery-gray 28 | 29 | &:last-child 30 | border-right: 1px solid $gallery-gray 31 | 32 | .caret 33 | border-left: 5px solid transparent 34 | border-right: 5px solid transparent 35 | display: inline-block 36 | height: 0 37 | margin-left: 5px 38 | margin-top: 5px 39 | position: absolute 40 | right: 10px 41 | top: 12px 42 | width: 0 43 | 44 | a, 45 | span:not(.caret) 46 | position: relative 47 | text-decoration: none 48 | color: $dark-gray 49 | padding: 12px 10px 50 | display: block 51 | 52 | a.active.desc 53 | .caret 54 | border-top: 5px solid $dark-gray 55 | 56 | a.active.asc 57 | .caret 58 | border-bottom: 5px solid $dark-gray 59 | 60 | td 61 | overflow: hidden 62 | text-overflow: ellipsis 63 | border-top: 1px solid $gallery-gray 64 | border-bottom: 1px solid $gallery-gray 65 | vertical-align: middle 66 | padding: 15px 10px 67 | max-width: 300px 68 | 69 | &:first-child 70 | border-left: 1px solid $gallery-gray 71 | 72 | &:last-child 73 | border-right: 1px solid $gallery-gray 74 | 75 | a 76 | color: $ir-red 77 | text-decoration: none 78 | 79 | img 80 | max-height: 30px 81 | max-width: 30px 82 | 83 | button 84 | @extend %red-button 85 | -------------------------------------------------------------------------------- /assets/css/theme/components/_toolbar.sass: -------------------------------------------------------------------------------- 1 | section#torch-toolbar 2 | .torch-container 3 | display: flex 4 | justify-content: flex-end 5 | 6 | a 7 | @extend %default-button 8 | margin-right: 20px 9 | 10 | &:last-child 11 | margin-right: 0px -------------------------------------------------------------------------------- /assets/css/theme/globals/_global.sass: -------------------------------------------------------------------------------- 1 | html 2 | background: $gallery-gray 3 | font-family: $helvetica-neue 4 | font-weight: normal 5 | min-height: 100vh 6 | 7 | body 8 | min-height: 100vh 9 | 10 | a 11 | text-decoration: none 12 | 13 | .torch-container 14 | margin: 0 auto 15 | padding-right: 15px 16 | padding-left: 15px 17 | -------------------------------------------------------------------------------- /assets/css/theme/pages/_edit.sass: -------------------------------------------------------------------------------- 1 | body.torch-edit, 2 | body.torch-update 3 | header 4 | margin-bottom: 20px 5 | 6 | section#torch-toolbar 7 | margin-bottom: 20px -------------------------------------------------------------------------------- /assets/css/theme/pages/_index.sass: -------------------------------------------------------------------------------- 1 | body.torch-index 2 | section#torch-nav 3 | margin-bottom: 20px 4 | 5 | section#torch-toolbar 6 | margin-bottom: 20px 7 | 8 | section#torch-index-content 9 | .torch-container 10 | display: flex 11 | 12 | section#torch-filters 13 | flex: 1 14 | margin-left: 35px 15 | order: 2 16 | 17 | section#torch-table 18 | flex: 3 19 | order: 1 20 | width: 70% 21 | 22 | table 23 | margin-bottom: 20px 24 | 25 | th 26 | text-align: left 27 | 28 | th:last-child 29 | text-align: right 30 | 31 | .torch-actions 32 | text-align: right 33 | 34 | section#torch-pagination 35 | display: flex 36 | justify-content: center 37 | margin-bottom: 20px 38 | -------------------------------------------------------------------------------- /assets/css/theme/pages/_new.sass: -------------------------------------------------------------------------------- 1 | body.torch-new, 2 | body.torch-create 3 | header 4 | margin-bottom: 20px 5 | 6 | section#torch-toolbar 7 | margin-bottom: 20px -------------------------------------------------------------------------------- /assets/css/theme/pages/_show.sass: -------------------------------------------------------------------------------- 1 | body.torch-show 2 | header 3 | margin-bottom: 20px 4 | 5 | section#torch-toolbar 6 | margin-bottom: 20px 7 | 8 | .torch-container header 9 | margin-bottom: 0 10 | 11 | .torch-show-details 12 | padding: 20px 13 | background-color: $white 14 | 15 | .torch-show-attribute 16 | display: flex 17 | padding: 0.5rem 0 18 | 19 | .torch-show-label 20 | border-right: 1px solid $dark-gray 21 | flex: 1 22 | margin-right: 1rem 23 | padding-right: 1rem 24 | text-align: right 25 | 26 | .torch-show-data 27 | flex: 4 28 | -------------------------------------------------------------------------------- /assets/css/theme/settings/_grid.sass: -------------------------------------------------------------------------------- 1 | // default grid 2 | $_fg_gutter: 36 3 | $_fg_padding: 0 -------------------------------------------------------------------------------- /assets/images/down-arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mojotech/torch/26ac2f942d7ab89cf2cd27caa01d3b11340540f8/assets/images/down-arrow.png -------------------------------------------------------------------------------- /assets/images/torch-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mojotech/torch/26ac2f942d7ab89cf2cd27caa01d3b11340540f8/assets/images/torch-logo.png -------------------------------------------------------------------------------- /assets/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "repository": {}, 3 | "dependencies": { 4 | "path": "^0.12.7", 5 | "phoenix": "file:../deps/phoenix", 6 | "phoenix_html": "file:../deps/phoenix_html", 7 | "pikaday": "1.8.2" 8 | }, 9 | "devDependencies": { 10 | "@parcel/transformer-sass": "^2.8.3", 11 | "node-sass": "^9.0.0", 12 | "parcel": "^2.8.3", 13 | "standard": "^17.0.0" 14 | }, 15 | "browserslist": [ 16 | "defaults", 17 | "not IE 11" 18 | ], 19 | "target": [ 20 | "web", 21 | "es5" 22 | ], 23 | "engines": { 24 | "node": ">14 <20" 25 | }, 26 | "scripts": { 27 | "compile": "npm run compile:js && npm run compile:css", 28 | "compile:js": "npx parcel build --dist-dir ../priv/static ./js/torch.js", 29 | "compile:css": "npx parcel build --dist-dir ../priv/static ./css/*.sass" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /assets/static/images/down-arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mojotech/torch/26ac2f942d7ab89cf2cd27caa01d3b11340540f8/assets/static/images/down-arrow.png -------------------------------------------------------------------------------- /assets/static/images/torch-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mojotech/torch/26ac2f942d7ab89cf2cd27caa01d3b11340540f8/assets/static/images/torch-logo.png -------------------------------------------------------------------------------- /bin/coverage: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Generates code coverage statistics and opens it in your browser 3 | 4 | mix coveralls.html || { 5 | echo 'Tests failed!' 6 | exit 1 7 | } 8 | open cover/excoveralls.html 9 | -------------------------------------------------------------------------------- /bin/release: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | puts 'What version number do you want to release?' 5 | print '> ' 6 | version = gets.gsub(/\n/, '') 7 | 8 | continue = system "git commit -am \"Release version #{version}\"" 9 | continue = system "git tag v#{version}" if continue 10 | continue = system 'git push' if continue 11 | continue = system "git push -f origin v#{version}" if continue 12 | continue = system 'mix deps.get' if continue 13 | continue = system 'mix hex.publish package' if continue 14 | continue = system 'mix hex.publish docs' if continue 15 | continue = system 'github_changelog_generator -u mojotech -p torch' if continue 16 | continue = system "git commit -am \"Update changelog for version #{version}\"" if continue 17 | continue = system 'git push' if continue 18 | 19 | if continue 20 | puts "Version #{version} was successfully released!" 21 | else 22 | puts "Version #{version} failed release process!" 23 | end 24 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Ensure Elixir is installed 4 | command -v elixir >/dev/null 2>&1 || { 5 | echo "This app requires Elixir, but it was not found on your system." 6 | echo "Install it using the instructions at http://elixir-lang.org" 7 | exit 1 8 | } 9 | 10 | # Ensure Node.js is installed 11 | command -v npm >/dev/null 2>&1 || { 12 | echo "This app requires Node.js to build assets, but it was not found on your system." 13 | echo "Install it using the instructions at http://nodejs.org" 14 | exit 1 15 | } 16 | 17 | # Ensure Npm is installed 18 | command -v npm >/dev/null 2>&1 || { 19 | echo "This app requires NPM package manager, but it was not found on your system." 20 | exit 1 21 | } 22 | 23 | echo "----------------------------------------------------------" 24 | echo "Running Tests..." 25 | echo "----------------------------------------------------------" 26 | 27 | bin/test 28 | -------------------------------------------------------------------------------- /bin/test: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | TEST_ROOT="$(pwd)/test" 4 | ASSETS_ROOT="$(pwd)/assets" 5 | 6 | # Run integration tests 7 | iexCurrentVersion="$(iex -v | tail -n 1 | cut -d " " -f2)" 8 | echo "[DEBUG] Current Elixir Version: $iexCurrentVersion" 9 | otpCurrentVersion="$(erl -eval 'erlang:display(erlang:system_info(otp_release)), halt().' -noshell | sed 's/\"//g')" 10 | echo "[DEBUG] Current OTP Version: $otpCurrentVersion" 11 | 12 | requiredMinVersion="23" 13 | if [ "$(printf '%s\n' "$requiredMinVersion" "$otpCurrentVersion" | sort -Vr | head -n1)" = "$requiredMinVersion" ]; then 14 | echo '[Skipping] OTP 23+ is required for Phoenix 1.7+' 15 | else 16 | cd "$TEST_ROOT/support/apps/phx1_7" && { 17 | bin/test || { 18 | echo 'Integration tests on regular Phoenix 1.7 project failed!' 19 | exit 1 20 | } 21 | } 22 | fi 23 | -------------------------------------------------------------------------------- /config/config.exs: -------------------------------------------------------------------------------- 1 | # This file is responsible for configuring your application 2 | # and its dependencies with the aid of the Mix.Config module. 3 | import Config 4 | 5 | # This configuration is loaded before any dependency and is restricted 6 | # to this project. If another project depends on this project, this 7 | # file won't be loaded nor affect the parent project. For this reason, 8 | # if you want to provide default values for your application for 9 | # 3rd-party users, it should be done in your "mix.exs" file. 10 | 11 | # You can configure your application as: 12 | # 13 | # config :torch, key: :value 14 | # 15 | # and access this configuration in your application as: 16 | # 17 | # Application.get_env(:torch, :key) 18 | # 19 | # You can also configure a 3rd-party app: 20 | # 21 | # config :logger, level: :info 22 | # 23 | 24 | # It is also possible to import configuration files, relative to this 25 | # directory. For example, you can emulate configuration per environment 26 | # by uncommenting the line below and defining dev.exs, test.exs and such. 27 | # Configuration from the imported file will override the ones defined 28 | # here (which is why it is important to import them last). 29 | # 30 | # import_config "#{Mix.env}.exs" 31 | -------------------------------------------------------------------------------- /coveralls.json: -------------------------------------------------------------------------------- 1 | { 2 | "skip_files": [], 3 | "coverage_options": { 4 | "treat_no_relevant_lines_as_covered": true 5 | } 6 | } -------------------------------------------------------------------------------- /lib/gettext.ex: -------------------------------------------------------------------------------- 1 | defmodule Torch.Gettext do 2 | @moduledoc """ 3 | A module providing Internationalization with a gettext-based API. 4 | By using [Gettext](https://hexdocs.pm/gettext), 5 | your module gains a set of macros for translations, for example: 6 | import ExchangeWeb.Gettext 7 | # Simple translation 8 | gettext("Here is the string to translate") 9 | # Plural translation 10 | ngettext("Here is the string to translate", 11 | "Here are the strings to translate", 12 | 3) 13 | # Domain-based translation 14 | dgettext("errors", "Here is the error message to translate") 15 | See the [Gettext Docs](https://hexdocs.pm/gettext) for detailed usage. 16 | """ 17 | use Gettext.Backend, otp_app: :torch 18 | end 19 | -------------------------------------------------------------------------------- /lib/mix/tasks/torch.gen.html.ex: -------------------------------------------------------------------------------- 1 | defmodule Mix.Tasks.Torch.Gen.Html do 2 | @moduledoc """ 3 | Light wrapper module around `mix phx.gen.html` which generates slightly 4 | modified HTML. 5 | 6 | Takes all the same params as the `phx.gen.html` task. 7 | 8 | ## Example 9 | 10 | mix torch.gen.html Accounts User users --no-schema 11 | """ 12 | 13 | @commands ~w[phx.gen.html phx.gen.context] 14 | 15 | def run(args) do 16 | if Mix.Project.umbrella?() do 17 | Mix.raise("mix torch.gen.html can only be run inside an application directory") 18 | end 19 | 20 | Mix.Torch.ensure_phoenix_is_loaded!("torch.gen.html") 21 | 22 | phoenix_version = :phoenix |> Application.spec(:vsn) |> to_string() 23 | 24 | if Version.match?(phoenix_version, "< 1.7.0") do 25 | Mix.raise( 26 | "Torch v5 Mix tasks will only run on Phoenix 1.7+. Phoenix version detected: #{phoenix_version}" 27 | ) 28 | end 29 | 30 | # First, backup the projects existing templates if they exist 31 | Enum.each(@commands, &Mix.Torch.backup_project_templates/1) 32 | 33 | # Inject the torch templates for the generator into the priv/ 34 | # directory so they will be picked up by the Phoenix generator 35 | Enum.each(@commands, &Mix.Torch.inject_templates/1) 36 | 37 | Mix.Task.run("phx.gen.html", args) 38 | 39 | # Remove the injected templates from priv/ so they will not 40 | # affect future Phoenix generator commands 41 | Enum.each(@commands, &Mix.Torch.remove_templates/1) 42 | 43 | # Restore the projects existing templates if present 44 | Enum.each(@commands, &Mix.Torch.restore_project_templates/1) 45 | 46 | Mix.shell().info(""" 47 | Ensure the following is added to your endpoint.ex: 48 | 49 | plug( 50 | Plug.Static, 51 | at: "/torch", 52 | from: {:torch, "priv/static"}, 53 | gzip: true, 54 | cache_control_for_etags: "public, max-age=86400", 55 | headers: [{"access-control-allow-origin", "*"}] 56 | ) 57 | """) 58 | 59 | Mix.shell().info(""" 60 | Also don't forget to add a link to layouts/torch.html if desired. 61 | 62 | 65 | """) 66 | end 67 | end 68 | -------------------------------------------------------------------------------- /lib/mix/tasks/torch.install.ex: -------------------------------------------------------------------------------- 1 | defmodule Mix.Tasks.Torch.Install do 2 | @moduledoc """ 3 | Installs torch layout to your `_web/templates` directory. 4 | 5 | ## Configuration 6 | 7 | config :torch, 8 | otp_app: :my_app 9 | 10 | ## Example 11 | 12 | Running without options will read configuration from your `config.exs` file, 13 | as shown above. 14 | 15 | mix torch.install 16 | 17 | Also accepts the `--app` option: 18 | 19 | mix torch.install --app my_app 20 | """ 21 | 22 | def run(args) do 23 | if Mix.Project.umbrella?() do 24 | Mix.raise("mix torch.install can only be run inside an application directory") 25 | end 26 | 27 | %{otp_app: otp_app} = Mix.Torch.parse_config!("torch.install", args) 28 | 29 | Mix.Torch.ensure_phoenix_is_loaded!("torch.install") 30 | 31 | phoenix_version = :phoenix |> Application.spec(:vsn) |> to_string() 32 | 33 | if Version.match?(phoenix_version, "< 1.7.0") do 34 | Mix.raise( 35 | "Torch v5 Mix tasks will only run on Phoenix 1.7+. Phoenix version detected: #{phoenix_version}" 36 | ) 37 | end 38 | 39 | Mix.Torch.copy_from("priv/templates/torch.install", [ 40 | {"layout.html.heex", "lib/#{otp_app}_web/components/layouts/torch.html.heex"} 41 | ]) 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /lib/mix/tasks/torch.uninstall.ex: -------------------------------------------------------------------------------- 1 | defmodule Mix.Tasks.Torch.Uninstall do 2 | @moduledoc """ 3 | Uninstalls torch layout. 4 | 5 | ## Example 6 | 7 | mix torch.uninstall 8 | 9 | Also accepts the `--app` option: 10 | 11 | mix torch.uninstall --app my_app 12 | """ 13 | 14 | def run(args) do 15 | if Mix.Project.umbrella?() do 16 | Mix.raise("mix torch.uninstall can only be run inside an application directory") 17 | end 18 | 19 | %{otp_app: otp_app} = Mix.Torch.parse_config!("torch.uninstall", args) 20 | 21 | Mix.Torch.ensure_phoenix_is_loaded!("torch.uninstall") 22 | 23 | phoenix_version = :phoenix |> Application.spec(:vsn) |> to_string() 24 | 25 | if Version.match?(phoenix_version, "< 1.7.0") do 26 | Mix.raise( 27 | "Torch v5 Mix tasks will only run on Phoenix 1.7+. Phoenix version detected: #{phoenix_version}" 28 | ) 29 | end 30 | 31 | paths = [ 32 | "lib/#{otp_app}_web/components/layouts/torch.html.heex" 33 | ] 34 | 35 | Enum.each(paths, &File.rm/1) 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /lib/torch.ex: -------------------------------------------------------------------------------- 1 | defmodule Torch do 2 | @moduledoc """ 3 | Documentation for Torch. 4 | """ 5 | end 6 | -------------------------------------------------------------------------------- /lib/torch/config.ex: -------------------------------------------------------------------------------- 1 | defmodule Torch.Config do 2 | @moduledoc """ 3 | Application config for torch. 4 | """ 5 | 6 | def otp_app do 7 | Application.get_env(:torch, :otp_app) 8 | end 9 | 10 | def i18n_backend do 11 | Application.get_env(:torch, :i18n_backend, Torch.I18n.Backend) 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/torch/i18n.ex: -------------------------------------------------------------------------------- 1 | defmodule Torch.I18n do 2 | @moduledoc """ 3 | Provides internationalization support for Torch apps using standard 4 | Gettext features as a default, but also allows Torch users to customize 5 | their own "messaging backends" for custom i18n support. 6 | """ 7 | 8 | def message(text_key), do: Torch.Config.i18n_backend().message(text_key) 9 | end 10 | -------------------------------------------------------------------------------- /lib/torch/i18n/backend.ex: -------------------------------------------------------------------------------- 1 | defmodule Torch.I18n.Backend do 2 | @moduledoc """ 3 | Provides messages for different parts of the package. Can 4 | also be overridden to include custom translations. 5 | """ 6 | 7 | use Gettext, backend: Torch.Gettext 8 | 9 | def message("Contains"), do: dgettext("default", "Contains") 10 | def message("Equals"), do: dgettext("default", "Equals") 11 | def message("Choose one"), do: dgettext("default", "Choose one") 12 | def message("Before"), do: dgettext("default", "Before") 13 | def message("After"), do: dgettext("default", "After") 14 | def message("Greater Than"), do: dgettext("default", "Greater Than") 15 | def message("Greater Than Or Equal"), do: dgettext("default", "Greater Than Or Equal") 16 | def message("Less Than"), do: dgettext("default", "Less Than") 17 | def message("start"), do: dgettext("default", "start") 18 | def message("end"), do: dgettext("default", "end") 19 | def message("Select Date"), do: dgettext("default", "Select Date") 20 | def message("Select Start Date"), do: dgettext("default", "Select Start Date") 21 | def message("Select End Date"), do: dgettext("default", "Select End Date") 22 | def message("< Prev"), do: dgettext("default", "< Prev") 23 | def message("Next >"), do: dgettext("default", "Next >") 24 | def message("Any"), do: dgettext("default", "Any") 25 | def message("True"), do: dgettext("default", "True") 26 | def message("False"), do: dgettext("default", "False") 27 | def message("Cancel"), do: dgettext("default", "Cancel") 28 | def message("Submit"), do: dgettext("default", "Submit") 29 | def message("Back"), do: dgettext("default", "Back") 30 | def message("Edit"), do: dgettext("default", "Edit") 31 | def message("Show"), do: dgettext("default", "Show") 32 | def message("Delete"), do: dgettext("default", "Delete") 33 | def message("Are you sure?"), do: dgettext("default", "Are you sure?") 34 | end 35 | -------------------------------------------------------------------------------- /lib/torch/views/flash_view.ex: -------------------------------------------------------------------------------- 1 | defmodule Torch.FlashView do 2 | @moduledoc """ 3 | Contains functions for dealing with flash messages. 4 | """ 5 | @moduledoc deprecated: "This module will be fully removed in Torch 6.0" 6 | 7 | use Phoenix.Component 8 | 9 | @doc """ 10 | DEPRECATED: Use Torch.Components.flash_messages/1 component instead 11 | 12 | Returns a formatted group of all flash messages available. 13 | 14 | ## Parameters 15 | 16 | - `assigns`: The current `Plug.Conn.assigns` map. 17 | 18 | ## Example 19 | 20 | iex> conn = %Plug.Conn{assigns: %{flash: %{"error" => "Error Message", "info" => "Info Message", "custom" => "Custom flash key"}}} 21 | ...> flash_messages(conn.assigns) |> Phoenix.HTML.Safe.to_iodata() |> IO.iodata_to_binary() 22 | "
\\n
\\n

Custom flash key 

Error Message 

Info Message 

\\n
\\n
" 23 | """ 24 | @spec flash_messages(%{assigns: %{flash: map}}) :: Phoenix.LiveView.Rendered.t() 25 | @deprecated "Use Torch.Components.flash_messages/1 instead" 26 | def flash_messages(assigns), do: Torch.Component.flash_messages(assigns) 27 | end 28 | -------------------------------------------------------------------------------- /lib/torch/views/page_view.ex: -------------------------------------------------------------------------------- 1 | defmodule Torch.PageView do 2 | @moduledoc deprecated: "This module will be fully removed in Torch 6.0" 3 | @doc """ 4 | DEPRECATED: Use Torch.Helpers.body_classes/1 instead 5 | 6 | Takes the controller action name and appends it to the torch- prefix. 7 | 8 | ## Example 9 | 10 | iex> body_classes(%Plug.Conn{private: %{phoenix_action: :create}}) 11 | "torch-create" 12 | 13 | iex> body_classes(%Plug.Conn{private: %{phoenix_action: :custom_action}}) 14 | "torch-custom-action" 15 | """ 16 | 17 | @spec body_classes(Plug.Conn.t()) :: String.t() 18 | @deprecated "Use Torch.Helpers.body_classes/1 instead" 19 | def body_classes(conn), do: Torch.Helpers.body_classes(conn) 20 | end 21 | -------------------------------------------------------------------------------- /mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Torch.MixProject do 2 | use Mix.Project 3 | 4 | @source_url "https://github.com/mojotech/torch" 5 | @version "5.5.0" 6 | 7 | def project do 8 | [ 9 | app: :torch, 10 | version: @version, 11 | elixir: "~> 1.14", 12 | start_permanent: Mix.env() == :prod, 13 | name: "Torch", 14 | description: "Rapid admin generator for Phoenix", 15 | source_url: @source_url, 16 | homepage_url: @source_url, 17 | test_paths: ["test/mix", "test/torch"], 18 | test_coverage: [tool: ExCoveralls], 19 | preferred_cli_env: [ 20 | coveralls: :test, 21 | "coveralls.detail": :test, 22 | "coveralls.post": :test, 23 | "coveralls.html": :test 24 | ], 25 | elixirc_paths: elixirc_paths(Mix.env()), 26 | package: package(), 27 | docs: docs(), 28 | deps: deps() 29 | ] 30 | end 31 | 32 | defp elixirc_paths(:test), do: ["lib", "test/support/cases"] 33 | defp elixirc_paths(_env), do: ["lib"] 34 | 35 | # Run "mix help compile.app" to learn about applications. 36 | def application do 37 | [ 38 | extra_applications: [:logger] 39 | ] 40 | end 41 | 42 | # Run "mix help deps" to learn about dependencies. 43 | defp deps do 44 | [ 45 | {:phoenix, "~> 1.7"}, 46 | {:phoenix_live_view, "~> 1.0 or ~> 0.20"}, 47 | {:phoenix_html, "~> 4.1"}, 48 | {:phoenix_html_helpers, "~> 1.0"}, 49 | {:gettext, "~> 0.16"}, 50 | {:scrivener_ecto, "~> 3.0"}, 51 | {:filtrex, "~> 0.4.1"}, 52 | {:jason, "~> 1.2", only: [:dev, :test]}, 53 | {:excoveralls, ">= 0.0.0", only: [:dev, :test]}, 54 | {:credo, "~> 1.1", only: [:dev, :test]}, 55 | {:ex_doc, ">= 0.0.0", only: [:dev, :test], runtime: false}, 56 | {:ex_unit_notifier, "~> 1.0", only: [:test]}, 57 | {:mix_test_watch, "~> 1.0", only: [:dev], runtime: false} 58 | ] 59 | end 60 | 61 | defp package do 62 | [ 63 | maintainers: ["MojoTech"], 64 | licenses: ["MIT"], 65 | files: ~w(lib priv mix.exs README.md LICENSE CHANGELOG.md CODE_OF_CONDUCT.md UPGRADING.md), 66 | links: %{ 67 | "Github" => @source_url 68 | } 69 | ] 70 | end 71 | 72 | defp docs do 73 | [ 74 | extras: [ 75 | "CHANGELOG.md": [title: "Changelog"], 76 | "CODE_OF_CONDUCT.md": [title: "Code of Conduct"], 77 | LICENSE: [title: "License"], 78 | "README.md": [title: "Overview"], 79 | "UPGRADING.md": [title: "Upgrading"] 80 | ], 81 | main: "readme", 82 | source_ref: "v#{@version}", 83 | formatters: ["html"] 84 | ] 85 | end 86 | end 87 | -------------------------------------------------------------------------------- /priv/gettext/de/LC_MESSAGES/default.po: -------------------------------------------------------------------------------- 1 | # # "msgid"s in this file come from POT (.pot) files. 2 | # # 3 | # # Do not add, change, or remove "msgid"s manually here as 4 | # # they're tied to the ones in the corresponding POT file 5 | # # (with the same domain). 6 | # # 7 | # # Use "mix gettext.extract --merge" or "mix gettext.merge" 8 | # # to merge POT files into PO files. 9 | msgid "" 10 | msgstr "" 11 | "Language: de_CH\n" 12 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 13 | "Project-Id-Version: Torch\n" 14 | "POT-Creation-Date: \n" 15 | "PO-Revision-Date: \n" 16 | "Last-Translator: \n" 17 | "Language-Team: https://github.com/mojotech/torch\n" 18 | "MIME-Version: 1.0\n" 19 | "Content-Type: text/plain; charset=UTF-8\n" 20 | "Content-Transfer-Encoding: 8bit\n" 21 | "X-Generator: Poedit 2.4.1\n" 22 | "X-Poedit-SourceCharset: UTF-8\n" 23 | 24 | #: lib/torch/i18n/backend.ex:22 25 | #, elixir-autogen 26 | msgid "< Prev" 27 | msgstr "< Zurück" 28 | 29 | #: lib/torch/i18n/backend.ex:23 30 | #, elixir-autogen 31 | msgid "Next >" 32 | msgstr "> Vorwärts" 33 | 34 | #: lib/torch/i18n/backend.ex:11 35 | #, elixir-autogen 36 | msgid "Choose one" 37 | msgstr "Wählen Sie eine" 38 | 39 | #: lib/torch/i18n/backend.ex:10 40 | #, elixir-autogen 41 | msgid "Equals" 42 | msgstr "Ist gleich" 43 | 44 | #: lib/torch/i18n/backend.ex:9 45 | #, elixir-autogen 46 | msgid "Contains" 47 | msgstr "Beinhaltet" 48 | 49 | #: lib/torch/i18n/backend.ex:14 50 | #, elixir-autogen 51 | msgid "Greater Than" 52 | msgstr "Grösser als" 53 | 54 | #: lib/torch/i18n/backend.ex:15 55 | #, elixir-autogen 56 | msgid "Greater Than Or Equal" 57 | msgstr "Grösser als oder gleich" 58 | 59 | #: lib/torch/i18n/backend.ex:16 60 | #, elixir-autogen 61 | msgid "Less Than" 62 | msgstr "Kleiner als" 63 | 64 | #: lib/torch/i18n/backend.ex:17 65 | #, elixir-autogen 66 | msgid "start" 67 | msgstr "Start" 68 | 69 | #: lib/torch/i18n/backend.ex:18 70 | #, elixir-autogen 71 | msgid "end" 72 | msgstr "Ende" 73 | 74 | #: lib/torch/i18n/backend.ex:20 75 | #, elixir-autogen 76 | msgid "Select Start Date" 77 | msgstr "Startdatum auswählen" 78 | 79 | #: lib/torch/i18n/backend.ex:21 80 | #, elixir-autogen 81 | msgid "Select End Date" 82 | msgstr "Enddatum auswählen" 83 | 84 | #: lib/torch/i18n/backend.ex:13 85 | #, elixir-autogen 86 | msgid "After" 87 | msgstr "Danach" 88 | 89 | #: lib/torch/i18n/backend.ex:12 90 | #, elixir-autogen 91 | msgid "Before" 92 | msgstr "Davor" 93 | 94 | #: lib/torch/i18n/backend.ex:19 95 | #, elixir-autogen 96 | msgid "Select Date" 97 | msgstr "Datum wählen" 98 | 99 | #: lib/torch/i18n/backend.ex:24 100 | #, elixir-autogen, elixir-format 101 | msgid "Any" 102 | msgstr "Jeder" 103 | 104 | #: lib/torch/i18n/backend.ex:26 105 | #, elixir-autogen, elixir-format 106 | msgid "False" 107 | msgstr "Falsch" 108 | 109 | #: lib/torch/i18n/backend.ex:25 110 | #, elixir-autogen, elixir-format 111 | msgid "True" 112 | msgstr "Wahr" 113 | 114 | #: lib/torch/i18n/backend.ex:33 115 | #, elixir-autogen, elixir-format 116 | msgid "Are you sure?" 117 | msgstr "Bist du dir sicher?" 118 | 119 | #: lib/torch/i18n/backend.ex:29 120 | #, elixir-autogen, elixir-format 121 | msgid "Back" 122 | msgstr "Geh zurück" 123 | 124 | #: lib/torch/i18n/backend.ex:27 125 | #, elixir-autogen, elixir-format 126 | msgid "Cancel" 127 | msgstr "Stornieren" 128 | 129 | #: lib/torch/i18n/backend.ex:32 130 | #, elixir-autogen, elixir-format 131 | msgid "Delete" 132 | msgstr "Löschen" 133 | 134 | #: lib/torch/i18n/backend.ex:30 135 | #, elixir-autogen, elixir-format 136 | msgid "Edit" 137 | msgstr "Bearbeiten" 138 | 139 | #: lib/torch/i18n/backend.ex:31 140 | #, elixir-autogen, elixir-format 141 | msgid "Show" 142 | msgstr "Zeigen" 143 | 144 | #: lib/torch/i18n/backend.ex:28 145 | #, elixir-autogen, elixir-format 146 | msgid "Submit" 147 | msgstr "Einreichen" 148 | -------------------------------------------------------------------------------- /priv/gettext/default.pot: -------------------------------------------------------------------------------- 1 | # # This file is a PO Template file. 2 | # # 3 | # # `msgid`s here are often extracted from source code. 4 | # # Add new translations manually only if they're dynamic 5 | # # translations that can't be statically extracted. 6 | # # 7 | # # Run `mix gettext.extract` to bring this file up to 8 | # # date. Leave `msgstr`s empty as changing them here as no 9 | # # effect: edit them in PO (`.po`) files instead. 10 | msgid "" 11 | msgstr "" 12 | "Project-Id-Version: Torch\n" 13 | "POT-Creation-Date: \n" 14 | "PO-Revision-Date: \n" 15 | "Last-Translator: \n" 16 | "Language-Team: https://github.com/mojotech/torch\n" 17 | "MIME-Version: 1.0\n" 18 | "Content-Type: text/plain; charset=UTF-8\n" 19 | "Content-Transfer-Encoding: 8bit\n" 20 | "X-Generator: Poedit 2.4.1\n" 21 | "X-Poedit-SourceCharset: UTF-8\n" 22 | 23 | #: lib/torch/i18n/backend.ex:22 24 | #, elixir-autogen 25 | msgid "< Prev" 26 | msgstr "" 27 | 28 | #: lib/torch/i18n/backend.ex:23 29 | #, elixir-autogen 30 | msgid "Next >" 31 | msgstr "" 32 | 33 | #: lib/torch/i18n/backend.ex:11 34 | #, elixir-autogen 35 | msgid "Choose one" 36 | msgstr "" 37 | 38 | #: lib/torch/i18n/backend.ex:10 39 | #, elixir-autogen 40 | msgid "Equals" 41 | msgstr "" 42 | 43 | #: lib/torch/i18n/backend.ex:9 44 | #, elixir-autogen 45 | msgid "Contains" 46 | msgstr "" 47 | 48 | #: lib/torch/i18n/backend.ex:14 49 | #, elixir-autogen 50 | msgid "Greater Than" 51 | msgstr "" 52 | 53 | #: lib/torch/i18n/backend.ex:15 54 | #, elixir-autogen 55 | msgid "Greater Than Or Equal" 56 | msgstr "" 57 | 58 | #: lib/torch/i18n/backend.ex:16 59 | #, elixir-autogen 60 | msgid "Less Than" 61 | msgstr "" 62 | 63 | #: lib/torch/i18n/backend.ex:17 64 | #, elixir-autogen 65 | msgid "start" 66 | msgstr "" 67 | 68 | #: lib/torch/i18n/backend.ex:18 69 | #, elixir-autogen 70 | msgid "end" 71 | msgstr "" 72 | 73 | #: lib/torch/i18n/backend.ex:20 74 | #, elixir-autogen 75 | msgid "Select Start Date" 76 | msgstr "" 77 | 78 | #: lib/torch/i18n/backend.ex:21 79 | #, elixir-autogen 80 | msgid "Select End Date" 81 | msgstr "" 82 | 83 | #: lib/torch/i18n/backend.ex:13 84 | #, elixir-autogen 85 | msgid "After" 86 | msgstr "" 87 | 88 | #: lib/torch/i18n/backend.ex:12 89 | #, elixir-autogen 90 | msgid "Before" 91 | msgstr "" 92 | 93 | #: lib/torch/i18n/backend.ex:19 94 | #, elixir-autogen 95 | msgid "Select Date" 96 | msgstr "" 97 | 98 | #: lib/torch/i18n/backend.ex:24 99 | #, elixir-autogen, elixir-format 100 | msgid "Any" 101 | msgstr "" 102 | 103 | #: lib/torch/i18n/backend.ex:26 104 | #, elixir-autogen, elixir-format 105 | msgid "False" 106 | msgstr "" 107 | 108 | #: lib/torch/i18n/backend.ex:25 109 | #, elixir-autogen, elixir-format 110 | msgid "True" 111 | msgstr "" 112 | 113 | #: lib/torch/i18n/backend.ex:33 114 | #, elixir-autogen, elixir-format 115 | msgid "Are you sure?" 116 | msgstr "" 117 | 118 | #: lib/torch/i18n/backend.ex:29 119 | #, elixir-autogen, elixir-format 120 | msgid "Back" 121 | msgstr "" 122 | 123 | #: lib/torch/i18n/backend.ex:27 124 | #, elixir-autogen, elixir-format 125 | msgid "Cancel" 126 | msgstr "" 127 | 128 | #: lib/torch/i18n/backend.ex:32 129 | #, elixir-autogen, elixir-format 130 | msgid "Delete" 131 | msgstr "" 132 | 133 | #: lib/torch/i18n/backend.ex:30 134 | #, elixir-autogen, elixir-format 135 | msgid "Edit" 136 | msgstr "" 137 | 138 | #: lib/torch/i18n/backend.ex:31 139 | #, elixir-autogen, elixir-format 140 | msgid "Show" 141 | msgstr "" 142 | 143 | #: lib/torch/i18n/backend.ex:28 144 | #, elixir-autogen, elixir-format 145 | msgid "Submit" 146 | msgstr "" 147 | -------------------------------------------------------------------------------- /priv/gettext/en/LC_MESSAGES/default.po: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 4 | "Project-Id-Version: Torch\n" 5 | "POT-Creation-Date: \n" 6 | "PO-Revision-Date: \n" 7 | "Last-Translator: \n" 8 | "Language-Team: https://github.com/mojotech/torch\n" 9 | "MIME-Version: 1.0\n" 10 | "Content-Type: text/plain; charset=UTF-8\n" 11 | "Content-Transfer-Encoding: 8bit\n" 12 | "Language: en\n" 13 | "X-Generator: Poedit 2.4.1\n" 14 | "X-Poedit-SourceCharset: UTF-8\n" 15 | 16 | #: lib/torch/i18n/backend.ex:22 17 | #, elixir-autogen 18 | msgid "< Prev" 19 | msgstr "" 20 | 21 | #: lib/torch/i18n/backend.ex:23 22 | #, elixir-autogen 23 | msgid "Next >" 24 | msgstr "" 25 | 26 | #: lib/torch/i18n/backend.ex:11 27 | #, elixir-autogen 28 | msgid "Choose one" 29 | msgstr "" 30 | 31 | #: lib/torch/i18n/backend.ex:10 32 | #, elixir-autogen 33 | msgid "Equals" 34 | msgstr "" 35 | 36 | #: lib/torch/i18n/backend.ex:9 37 | #, elixir-autogen 38 | msgid "Contains" 39 | msgstr "" 40 | 41 | #: lib/torch/i18n/backend.ex:14 42 | #, elixir-autogen 43 | msgid "Greater Than" 44 | msgstr "" 45 | 46 | #: lib/torch/i18n/backend.ex:15 47 | #, elixir-autogen 48 | msgid "Greater Than Or Equal" 49 | msgstr "" 50 | 51 | #: lib/torch/i18n/backend.ex:16 52 | #, elixir-autogen 53 | msgid "Less Than" 54 | msgstr "" 55 | 56 | #: lib/torch/i18n/backend.ex:17 57 | #, elixir-autogen 58 | msgid "start" 59 | msgstr "" 60 | 61 | #: lib/torch/i18n/backend.ex:18 62 | #, elixir-autogen 63 | msgid "end" 64 | msgstr "" 65 | 66 | #: lib/torch/i18n/backend.ex:20 67 | #, elixir-autogen 68 | msgid "Select Start Date" 69 | msgstr "" 70 | 71 | #: lib/torch/i18n/backend.ex:21 72 | #, elixir-autogen 73 | msgid "Select End Date" 74 | msgstr "" 75 | 76 | #: lib/torch/i18n/backend.ex:13 77 | #, elixir-autogen 78 | msgid "After" 79 | msgstr "" 80 | 81 | #: lib/torch/i18n/backend.ex:12 82 | #, elixir-autogen 83 | msgid "Before" 84 | msgstr "" 85 | 86 | #: lib/torch/i18n/backend.ex:19 87 | #, elixir-autogen 88 | msgid "Select Date" 89 | msgstr "" 90 | 91 | #: lib/torch/i18n/backend.ex:24 92 | #, elixir-autogen, elixir-format 93 | msgid "Any" 94 | msgstr "" 95 | 96 | #: lib/torch/i18n/backend.ex:26 97 | #, elixir-autogen, elixir-format 98 | msgid "False" 99 | msgstr "" 100 | 101 | #: lib/torch/i18n/backend.ex:25 102 | #, elixir-autogen, elixir-format 103 | msgid "True" 104 | msgstr "" 105 | 106 | #: lib/torch/i18n/backend.ex:33 107 | #, elixir-autogen, elixir-format 108 | msgid "Are you sure?" 109 | msgstr "" 110 | 111 | #: lib/torch/i18n/backend.ex:29 112 | #, elixir-autogen, elixir-format 113 | msgid "Back" 114 | msgstr "" 115 | 116 | #: lib/torch/i18n/backend.ex:27 117 | #, elixir-autogen, elixir-format 118 | msgid "Cancel" 119 | msgstr "" 120 | 121 | #: lib/torch/i18n/backend.ex:32 122 | #, elixir-autogen, elixir-format 123 | msgid "Delete" 124 | msgstr "" 125 | 126 | #: lib/torch/i18n/backend.ex:30 127 | #, elixir-autogen, elixir-format 128 | msgid "Edit" 129 | msgstr "" 130 | 131 | #: lib/torch/i18n/backend.ex:31 132 | #, elixir-autogen, elixir-format 133 | msgid "Show" 134 | msgstr "" 135 | 136 | #: lib/torch/i18n/backend.ex:28 137 | #, elixir-autogen, elixir-format 138 | msgid "Submit" 139 | msgstr "" 140 | -------------------------------------------------------------------------------- /priv/gettext/es/LC_MESSAGES/default.po: -------------------------------------------------------------------------------- 1 | # # "msgid"s in this file come from POT (.pot) files. 2 | # # 3 | # # Do not add, change, or remove "msgid"s manually here as 4 | # # they're tied to the ones in the corresponding POT file 5 | # # (with the same domain). 6 | # # 7 | # # Use "mix gettext.extract --merge" or "mix gettext.merge" 8 | # # to merge POT files into PO files. 9 | msgid "" 10 | msgstr "" 11 | "Language: es\n" 12 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 13 | "Project-Id-Version: Torch\n" 14 | "POT-Creation-Date: \n" 15 | "PO-Revision-Date: \n" 16 | "Last-Translator: \n" 17 | "Language-Team: https://github.com/mojotech/torch\n" 18 | "MIME-Version: 1.0\n" 19 | "Content-Type: text/plain; charset=UTF-8\n" 20 | "Content-Transfer-Encoding: 8bit\n" 21 | "X-Generator: Poedit 2.4.1\n" 22 | "X-Poedit-SourceCharset: UTF-8\n" 23 | 24 | #: lib/torch/i18n/backend.ex:22 25 | #, elixir-autogen 26 | msgid "< Prev" 27 | msgstr "< Prev" 28 | 29 | #: lib/torch/i18n/backend.ex:23 30 | #, elixir-autogen 31 | msgid "Next >" 32 | msgstr "Sig >" 33 | 34 | #: lib/torch/i18n/backend.ex:11 35 | #, elixir-autogen 36 | msgid "Choose one" 37 | msgstr "Elija uno" 38 | 39 | #: lib/torch/i18n/backend.ex:10 40 | #, elixir-autogen 41 | msgid "Equals" 42 | msgstr "Igual a" 43 | 44 | #: lib/torch/i18n/backend.ex:9 45 | #, elixir-autogen 46 | msgid "Contains" 47 | msgstr "Contiene" 48 | 49 | #: lib/torch/i18n/backend.ex:14 50 | #, elixir-autogen 51 | msgid "Greater Than" 52 | msgstr "Mayor a" 53 | 54 | #: lib/torch/i18n/backend.ex:15 55 | #, elixir-autogen 56 | msgid "Greater Than Or Equal" 57 | msgstr "Mayor o igual a" 58 | 59 | #: lib/torch/i18n/backend.ex:16 60 | #, elixir-autogen 61 | msgid "Less Than" 62 | msgstr "Menor a" 63 | 64 | #: lib/torch/i18n/backend.ex:17 65 | #, elixir-autogen 66 | msgid "start" 67 | msgstr "inicio" 68 | 69 | #: lib/torch/i18n/backend.ex:18 70 | #, elixir-autogen 71 | msgid "end" 72 | msgstr "fin" 73 | 74 | #: lib/torch/i18n/backend.ex:20 75 | #, elixir-autogen 76 | msgid "Select Start Date" 77 | msgstr "Seleccione fecha de inicio" 78 | 79 | #: lib/torch/i18n/backend.ex:21 80 | #, elixir-autogen 81 | msgid "Select End Date" 82 | msgstr "Seleccione fecha de fin" 83 | 84 | #: lib/torch/i18n/backend.ex:13 85 | #, elixir-autogen 86 | msgid "After" 87 | msgstr "Después de" 88 | 89 | #: lib/torch/i18n/backend.ex:12 90 | #, elixir-autogen 91 | msgid "Before" 92 | msgstr "Antes de" 93 | 94 | #: lib/torch/i18n/backend.ex:19 95 | #, elixir-autogen 96 | msgid "Select Date" 97 | msgstr "Seleccione fecha de fin" 98 | 99 | #: lib/torch/i18n/backend.ex:24 100 | #, elixir-autogen, elixir-format 101 | msgid "Any" 102 | msgstr "Todo" 103 | 104 | #: lib/torch/i18n/backend.ex:26 105 | #, elixir-autogen, elixir-format 106 | msgid "False" 107 | msgstr "Falso" 108 | 109 | #: lib/torch/i18n/backend.ex:25 110 | #, elixir-autogen, elixir-format 111 | msgid "True" 112 | msgstr "Verdad" 113 | 114 | #: lib/torch/i18n/backend.ex:33 115 | #, elixir-autogen, elixir-format 116 | msgid "Are you sure?" 117 | msgstr "Estas seguro" 118 | 119 | #: lib/torch/i18n/backend.ex:29 120 | #, elixir-autogen, elixir-format 121 | msgid "Back" 122 | msgstr "Regresa" 123 | 124 | #: lib/torch/i18n/backend.ex:27 125 | #, elixir-autogen, elixir-format 126 | msgid "Cancel" 127 | msgstr "Cancelar" 128 | 129 | #: lib/torch/i18n/backend.ex:32 130 | #, elixir-autogen, elixir-format 131 | msgid "Delete" 132 | msgstr "Borrar" 133 | 134 | #: lib/torch/i18n/backend.ex:30 135 | #, elixir-autogen, elixir-format 136 | msgid "Edit" 137 | msgstr "Editar" 138 | 139 | #: lib/torch/i18n/backend.ex:31 140 | #, elixir-autogen, elixir-format 141 | msgid "Show" 142 | msgstr "Mostrar" 143 | 144 | #: lib/torch/i18n/backend.ex:28 145 | #, elixir-autogen, elixir-format 146 | msgid "Submit" 147 | msgstr "Enviar" 148 | -------------------------------------------------------------------------------- /priv/gettext/ja/LC_MESSAGES/default.po: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 4 | "Project-Id-Version: Torch\n" 5 | "POT-Creation-Date: \n" 6 | "PO-Revision-Date: \n" 7 | "Last-Translator: \n" 8 | "Language-Team: https://github.com/mojotech/torch\n" 9 | "MIME-Version: 1.0\n" 10 | "Content-Type: text/plain; charset=UTF-8\n" 11 | "Content-Transfer-Encoding: 8bit\n" 12 | "Language: ja\n" 13 | "X-Generator: Poedit 2.4.1\n" 14 | "X-Poedit-SourceCharset: UTF-8\n" 15 | 16 | #: lib/torch/i18n/backend.ex:22 17 | #, elixir-autogen 18 | msgid "< Prev" 19 | msgstr "前へ" 20 | 21 | #: lib/torch/i18n/backend.ex:23 22 | #, elixir-autogen 23 | msgid "Next >" 24 | msgstr "次へ" 25 | 26 | #: lib/torch/i18n/backend.ex:11 27 | #, elixir-autogen 28 | msgid "Choose one" 29 | msgstr "一つ選択" 30 | 31 | #: lib/torch/i18n/backend.ex:10 32 | #, elixir-autogen 33 | msgid "Equals" 34 | msgstr "等しい" 35 | 36 | #: lib/torch/i18n/backend.ex:9 37 | #, elixir-autogen 38 | msgid "Contains" 39 | msgstr "含む" 40 | 41 | #: lib/torch/i18n/backend.ex:14 42 | #, elixir-autogen 43 | msgid "Greater Than" 44 | msgstr "より大きい" 45 | 46 | #: lib/torch/i18n/backend.ex:15 47 | #, elixir-autogen 48 | msgid "Greater Than Or Equal" 49 | msgstr "以上" 50 | 51 | #: lib/torch/i18n/backend.ex:16 52 | #, elixir-autogen 53 | msgid "Less Than" 54 | msgstr "より小さい" 55 | 56 | #: lib/torch/i18n/backend.ex:17 57 | #, elixir-autogen 58 | msgid "start" 59 | msgstr "開始" 60 | 61 | #: lib/torch/i18n/backend.ex:18 62 | #, elixir-autogen 63 | msgid "end" 64 | msgstr "修了" 65 | 66 | #: lib/torch/i18n/backend.ex:20 67 | #, elixir-autogen 68 | msgid "Select Start Date" 69 | msgstr "開始日を選択" 70 | 71 | #: lib/torch/i18n/backend.ex:21 72 | #, elixir-autogen 73 | msgid "Select End Date" 74 | msgstr "終了日を選択" 75 | 76 | #: lib/torch/i18n/backend.ex:13 77 | #, elixir-autogen 78 | msgid "After" 79 | msgstr "後" 80 | 81 | #: lib/torch/i18n/backend.ex:12 82 | #, elixir-autogen 83 | msgid "Before" 84 | msgstr "前" 85 | 86 | #: lib/torch/i18n/backend.ex:19 87 | #, elixir-autogen 88 | msgid "Select Date" 89 | msgstr "日付を選択" 90 | 91 | #: lib/torch/i18n/backend.ex:24 92 | #, elixir-autogen, elixir-format 93 | msgid "Any" 94 | msgstr "任意" 95 | 96 | #: lib/torch/i18n/backend.ex:26 97 | #, elixir-autogen, elixir-format 98 | msgid "False" 99 | msgstr "偽" 100 | 101 | #: lib/torch/i18n/backend.ex:25 102 | #, elixir-autogen, elixir-format 103 | msgid "True" 104 | msgstr "真" 105 | 106 | #: lib/torch/i18n/backend.ex:33 107 | #, elixir-autogen, elixir-format 108 | msgid "Are you sure?" 109 | msgstr "本当によろしいですか?" 110 | 111 | #: lib/torch/i18n/backend.ex:29 112 | #, elixir-autogen, elixir-format 113 | msgid "Back" 114 | msgstr "戻る" 115 | 116 | #: lib/torch/i18n/backend.ex:27 117 | #, elixir-autogen, elixir-format 118 | msgid "Cancel" 119 | msgstr "キャンセル" 120 | 121 | #: lib/torch/i18n/backend.ex:32 122 | #, elixir-autogen, elixir-format 123 | msgid "Delete" 124 | msgstr "削除" 125 | 126 | #: lib/torch/i18n/backend.ex:30 127 | #, elixir-autogen, elixir-format 128 | msgid "Edit" 129 | msgstr "編集" 130 | 131 | #: lib/torch/i18n/backend.ex:31 132 | #, elixir-autogen, elixir-format 133 | msgid "Show" 134 | msgstr "閲覧" 135 | 136 | #: lib/torch/i18n/backend.ex:28 137 | #, elixir-autogen, elixir-format 138 | msgid "Submit" 139 | msgstr "送信" 140 | -------------------------------------------------------------------------------- /priv/gettext/pt_BR/LC_MESSAGES/default.po: -------------------------------------------------------------------------------- 1 | ## "msgid"s in this file come from POT (.pot) files. 2 | ### 3 | ### Do not add, change, or remove "msgid"s manually here as 4 | ### they're tied to the ones in the corresponding POT file 5 | ### (with the same domain). 6 | ### 7 | ### Use "mix gettext.extract --merge" or "mix gettext.merge" 8 | ### to merge POT files into PO files. 9 | msgid "" 10 | msgstr "" 11 | "Language: pt_BR\n" 12 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 13 | "Project-Id-Version: Torch\n" 14 | "POT-Creation-Date: \n" 15 | "PO-Revision-Date: \n" 16 | "Last-Translator: \n" 17 | "Language-Team: https://github.com/mojotech/torch\n" 18 | "MIME-Version: 1.0\n" 19 | "Content-Type: text/plain; charset=UTF-8\n" 20 | "Content-Transfer-Encoding: 8bit\n" 21 | "X-Generator: Poedit 2.4.1\n" 22 | "X-Poedit-SourceCharset: UTF-8\n" 23 | 24 | #: lib/torch/i18n/backend.ex:22 25 | #, elixir-autogen 26 | msgid "< Prev" 27 | msgstr "< Anterior" 28 | 29 | #: lib/torch/i18n/backend.ex:23 30 | #, elixir-autogen 31 | msgid "Next >" 32 | msgstr "Próximo >" 33 | 34 | #: lib/torch/i18n/backend.ex:11 35 | #, elixir-autogen 36 | msgid "Choose one" 37 | msgstr "Escolha um" 38 | 39 | #: lib/torch/i18n/backend.ex:10 40 | #, elixir-autogen 41 | msgid "Equals" 42 | msgstr "Igual" 43 | 44 | #: lib/torch/i18n/backend.ex:9 45 | #, elixir-autogen 46 | msgid "Contains" 47 | msgstr "Contém" 48 | 49 | #: lib/torch/i18n/backend.ex:14 50 | #, elixir-autogen 51 | msgid "Greater Than" 52 | msgstr "Maior que" 53 | 54 | #: lib/torch/i18n/backend.ex:15 55 | #, elixir-autogen 56 | msgid "Greater Than Or Equal" 57 | msgstr "Maior que ou igual" 58 | 59 | #: lib/torch/i18n/backend.ex:16 60 | #, elixir-autogen 61 | msgid "Less Than" 62 | msgstr "Menor que" 63 | 64 | #: lib/torch/i18n/backend.ex:17 65 | #, elixir-autogen 66 | msgid "start" 67 | msgstr "início" 68 | 69 | #: lib/torch/i18n/backend.ex:18 70 | #, elixir-autogen 71 | msgid "end" 72 | msgstr "final" 73 | 74 | #: lib/torch/i18n/backend.ex:20 75 | #, elixir-autogen 76 | msgid "Select Start Date" 77 | msgstr "Selecione a Data de Início" 78 | 79 | #: lib/torch/i18n/backend.ex:21 80 | #, elixir-autogen 81 | msgid "Select End Date" 82 | msgstr "Selecione a Data Final" 83 | 84 | #: lib/torch/i18n/backend.ex:13 85 | #, elixir-autogen 86 | msgid "After" 87 | msgstr "Após" 88 | 89 | #: lib/torch/i18n/backend.ex:12 90 | #, elixir-autogen 91 | msgid "Before" 92 | msgstr "Anterior" 93 | 94 | #: lib/torch/i18n/backend.ex:19 95 | #, elixir-autogen 96 | msgid "Select Date" 97 | msgstr "Selecione a Data" 98 | 99 | #: lib/torch/i18n/backend.ex:24 100 | #, elixir-autogen, elixir-format 101 | msgid "Any" 102 | msgstr "Qualquer" 103 | 104 | #: lib/torch/i18n/backend.ex:26 105 | #, elixir-autogen, elixir-format 106 | msgid "False" 107 | msgstr "Falso" 108 | 109 | #: lib/torch/i18n/backend.ex:25 110 | #, elixir-autogen, elixir-format 111 | msgid "True" 112 | msgstr "Verdadeiro" 113 | 114 | #: lib/torch/i18n/backend.ex:33 115 | #, elixir-autogen, elixir-format 116 | msgid "Are you sure?" 117 | msgstr "Você tem certeza?" 118 | 119 | #: lib/torch/i18n/backend.ex:29 120 | #, elixir-autogen, elixir-format 121 | msgid "Back" 122 | msgstr "Voltar" 123 | 124 | #: lib/torch/i18n/backend.ex:27 125 | #, elixir-autogen, elixir-format 126 | msgid "Cancel" 127 | msgstr "Cancelar" 128 | 129 | #: lib/torch/i18n/backend.ex:32 130 | #, elixir-autogen, elixir-format 131 | msgid "Delete" 132 | msgstr "Remover" 133 | 134 | #: lib/torch/i18n/backend.ex:30 135 | #, elixir-autogen, elixir-format 136 | msgid "Edit" 137 | msgstr "Editar" 138 | 139 | #: lib/torch/i18n/backend.ex:31 140 | #, elixir-autogen, elixir-format 141 | msgid "Show" 142 | msgstr "Exibir" 143 | 144 | #: lib/torch/i18n/backend.ex:28 145 | #, elixir-autogen, elixir-format 146 | msgid "Submit" 147 | msgstr "Enviar" 148 | -------------------------------------------------------------------------------- /priv/gettext/ru/LC_MESSAGES/default.po: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : 2);\n" 4 | "Project-Id-Version: Torch\n" 5 | "POT-Creation-Date: \n" 6 | "PO-Revision-Date: \n" 7 | "Last-Translator: \n" 8 | "Language-Team: https://github.com/mojotech/torch\n" 9 | "MIME-Version: 1.0\n" 10 | "Content-Type: text/plain; charset=UTF-8\n" 11 | "Content-Transfer-Encoding: 8bit\n" 12 | "Language: ru\n" 13 | "X-Generator: Poedit 2.4.1\n" 14 | "X-Poedit-SourceCharset: UTF-8\n" 15 | 16 | #: lib/torch/i18n/backend.ex:22 17 | #, elixir-autogen 18 | msgid "< Prev" 19 | msgstr "< Предыдущая" 20 | 21 | #: lib/torch/i18n/backend.ex:23 22 | #, elixir-autogen 23 | msgid "Next >" 24 | msgstr "Следующая >" 25 | 26 | #: lib/torch/i18n/backend.ex:11 27 | #, elixir-autogen 28 | msgid "Choose one" 29 | msgstr "Выберите один элемент" 30 | 31 | #: lib/torch/i18n/backend.ex:10 32 | #, elixir-autogen 33 | msgid "Equals" 34 | msgstr "Равно" 35 | 36 | #: lib/torch/i18n/backend.ex:9 37 | #, elixir-autogen 38 | msgid "Contains" 39 | msgstr "Содержит" 40 | 41 | #: lib/torch/i18n/backend.ex:14 42 | #, elixir-autogen 43 | msgid "Greater Than" 44 | msgstr "Больше" 45 | 46 | #: lib/torch/i18n/backend.ex:15 47 | #, elixir-autogen 48 | msgid "Greater Than Or Equal" 49 | msgstr "Больше или равно" 50 | 51 | #: lib/torch/i18n/backend.ex:16 52 | #, elixir-autogen 53 | msgid "Less Than" 54 | msgstr "Меньше" 55 | 56 | #: lib/torch/i18n/backend.ex:17 57 | #, elixir-autogen 58 | msgid "start" 59 | msgstr "начало" 60 | 61 | #: lib/torch/i18n/backend.ex:18 62 | #, elixir-autogen 63 | msgid "end" 64 | msgstr "конец" 65 | 66 | #: lib/torch/i18n/backend.ex:20 67 | #, elixir-autogen 68 | msgid "Select Start Date" 69 | msgstr "Выберите дату начала" 70 | 71 | #: lib/torch/i18n/backend.ex:21 72 | #, elixir-autogen 73 | msgid "Select End Date" 74 | msgstr "Выберите дату окончания" 75 | 76 | #: lib/torch/i18n/backend.ex:13 77 | #, elixir-autogen 78 | msgid "After" 79 | msgstr "" 80 | 81 | #: lib/torch/i18n/backend.ex:12 82 | #, elixir-autogen 83 | msgid "Before" 84 | msgstr "" 85 | 86 | #: lib/torch/i18n/backend.ex:19 87 | #, elixir-autogen 88 | msgid "Select Date" 89 | msgstr "Выберите дату окончания" 90 | 91 | #: lib/torch/i18n/backend.ex:24 92 | #, elixir-autogen, elixir-format 93 | msgid "Any" 94 | msgstr "Любые" 95 | 96 | #: lib/torch/i18n/backend.ex:26 97 | #, elixir-autogen, elixir-format 98 | msgid "False" 99 | msgstr "ЛОЖЬ" 100 | 101 | #: lib/torch/i18n/backend.ex:25 102 | #, elixir-autogen, elixir-format 103 | msgid "True" 104 | msgstr "истинный" 105 | 106 | #: lib/torch/i18n/backend.ex:33 107 | #, elixir-autogen, elixir-format 108 | msgid "Are you sure?" 109 | msgstr "Вы уверены?" 110 | 111 | #: lib/torch/i18n/backend.ex:29 112 | #, elixir-autogen, elixir-format 113 | msgid "Back" 114 | msgstr "Вернуться" 115 | 116 | #: lib/torch/i18n/backend.ex:27 117 | #, elixir-autogen, elixir-format 118 | msgid "Cancel" 119 | msgstr "Отмена" 120 | 121 | #: lib/torch/i18n/backend.ex:32 122 | #, elixir-autogen, elixir-format 123 | msgid "Delete" 124 | msgstr "Удалить" 125 | 126 | #: lib/torch/i18n/backend.ex:30 127 | #, elixir-autogen, elixir-format 128 | msgid "Edit" 129 | msgstr "Редактировать" 130 | 131 | #: lib/torch/i18n/backend.ex:31 132 | #, elixir-autogen, elixir-format 133 | msgid "Show" 134 | msgstr "Показать" 135 | 136 | #: lib/torch/i18n/backend.ex:28 137 | #, elixir-autogen, elixir-format 138 | msgid "Submit" 139 | msgstr "Отправить" 140 | -------------------------------------------------------------------------------- /priv/gettext/vi/LC_MESSAGES/default.po: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 4 | "Project-Id-Version: Torch\n" 5 | "POT-Creation-Date: \n" 6 | "PO-Revision-Date: \n" 7 | "Last-Translator: \n" 8 | "Language-Team: https://github.com/mojotech/torch\n" 9 | "MIME-Version: 1.0\n" 10 | "Content-Type: text/plain; charset=UTF-8\n" 11 | "Content-Transfer-Encoding: 8bit\n" 12 | "Language: vi\n" 13 | "X-Generator: Poedit 2.4.1\n" 14 | "X-Poedit-SourceCharset: UTF-8\n" 15 | 16 | #: lib/torch/i18n/backend.ex:22 17 | #, elixir-autogen 18 | msgid "< Prev" 19 | msgstr "< Trước" 20 | 21 | #: lib/torch/i18n/backend.ex:23 22 | #, elixir-autogen 23 | msgid "Next >" 24 | msgstr "Kế tiếp >" 25 | 26 | #: lib/torch/i18n/backend.ex:11 27 | #, elixir-autogen 28 | msgid "Choose one" 29 | msgstr "Chọn một mục" 30 | 31 | #: lib/torch/i18n/backend.ex:10 32 | #, elixir-autogen 33 | msgid "Equals" 34 | msgstr "Bằng" 35 | 36 | #: lib/torch/i18n/backend.ex:9 37 | #, elixir-autogen 38 | msgid "Contains" 39 | msgstr "Chứa" 40 | 41 | #: lib/torch/i18n/backend.ex:14 42 | #, elixir-autogen 43 | msgid "Greater Than" 44 | msgstr "Lớn hơn" 45 | 46 | #: lib/torch/i18n/backend.ex:15 47 | #, elixir-autogen 48 | msgid "Greater Than Or Equal" 49 | msgstr "Lớn hơn hoặc bằng" 50 | 51 | #: lib/torch/i18n/backend.ex:16 52 | #, elixir-autogen 53 | msgid "Less Than" 54 | msgstr "Nhỏ hơn" 55 | 56 | #: lib/torch/i18n/backend.ex:17 57 | #, elixir-autogen 58 | msgid "start" 59 | msgstr "bắt đầu" 60 | 61 | #: lib/torch/i18n/backend.ex:18 62 | #, elixir-autogen 63 | msgid "end" 64 | msgstr "kết thúc" 65 | 66 | #: lib/torch/i18n/backend.ex:20 67 | #, elixir-autogen 68 | msgid "Select Start Date" 69 | msgstr "Chọn ngày bắt đầu" 70 | 71 | #: lib/torch/i18n/backend.ex:21 72 | #, elixir-autogen 73 | msgid "Select End Date" 74 | msgstr "Chọn ngày kết thúc" 75 | 76 | #: lib/torch/i18n/backend.ex:13 77 | #, elixir-autogen 78 | msgid "After" 79 | msgstr "Sau" 80 | 81 | #: lib/torch/i18n/backend.ex:12 82 | #, elixir-autogen 83 | msgid "Before" 84 | msgstr "Trước" 85 | 86 | #: lib/torch/i18n/backend.ex:19 87 | #, elixir-autogen 88 | msgid "Select Date" 89 | msgstr "Chọn ngày" 90 | 91 | #: lib/torch/i18n/backend.ex:24 92 | #, elixir-autogen, elixir-format 93 | msgid "Any" 94 | msgstr "không tí nào" 95 | 96 | #: lib/torch/i18n/backend.ex:26 97 | #, elixir-autogen, elixir-format 98 | msgid "False" 99 | msgstr "Sai" 100 | 101 | #: lib/torch/i18n/backend.ex:25 102 | #, elixir-autogen, elixir-format 103 | msgid "True" 104 | msgstr "Thật" 105 | 106 | #: lib/torch/i18n/backend.ex:33 107 | #, elixir-autogen, elixir-format 108 | msgid "Are you sure?" 109 | msgstr "Bạn có chắc không?" 110 | 111 | #: lib/torch/i18n/backend.ex:29 112 | #, elixir-autogen, elixir-format 113 | msgid "Back" 114 | msgstr "Quay lại" 115 | 116 | #: lib/torch/i18n/backend.ex:27 117 | #, elixir-autogen, elixir-format 118 | msgid "Cancel" 119 | msgstr "Hủy bỏ" 120 | 121 | #: lib/torch/i18n/backend.ex:32 122 | #, elixir-autogen, elixir-format 123 | msgid "Delete" 124 | msgstr "Xóa bỏ" 125 | 126 | #: lib/torch/i18n/backend.ex:30 127 | #, elixir-autogen, elixir-format 128 | msgid "Edit" 129 | msgstr "Chỉnh sửa" 130 | 131 | #: lib/torch/i18n/backend.ex:31 132 | #, elixir-autogen, elixir-format 133 | msgid "Show" 134 | msgstr "Hiển thị" 135 | 136 | #: lib/torch/i18n/backend.ex:28 137 | #, elixir-autogen, elixir-format 138 | msgid "Submit" 139 | msgstr "Gửi" 140 | -------------------------------------------------------------------------------- /priv/static/down-arrow.e17911d3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mojotech/torch/26ac2f942d7ab89cf2cd27caa01d3b11340540f8/priv/static/down-arrow.e17911d3.png -------------------------------------------------------------------------------- /priv/static/torch-logo.a963df87.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mojotech/torch/26ac2f942d7ab89cf2cd27caa01d3b11340540f8/priv/static/torch-logo.a963df87.png -------------------------------------------------------------------------------- /priv/static/torch.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /*! 2 | * Pikaday 3 | * 4 | * Copyright © 2014 David Bushell | BSD & MIT license | https://github.com/Pikaday/Pikaday 5 | */ 6 | -------------------------------------------------------------------------------- /priv/templates/phx.gen.context/_grid.sass: -------------------------------------------------------------------------------- 1 | // default grid 2 | $fg_gutter: 36 3 | $fg_padding: 0 -------------------------------------------------------------------------------- /priv/templates/phx.gen.context/context.ex: -------------------------------------------------------------------------------- 1 | defmodule <%= inspect context.module %> do 2 | @moduledoc """ 3 | The <%= context.name %> context. 4 | """ 5 | 6 | import Ecto.Query, warn: false 7 | alias <%= inspect schema.repo %> 8 | end -------------------------------------------------------------------------------- /priv/templates/phx.gen.context/context_test.exs: -------------------------------------------------------------------------------- 1 | defmodule <%= inspect context.module %>Test do 2 | use <%= inspect context.base_module %>.DataCase 3 | 4 | alias <%= inspect context.module %> 5 | end -------------------------------------------------------------------------------- /priv/templates/phx.gen.context/schema_access.ex: -------------------------------------------------------------------------------- 1 | 2 | alias <%= inspect schema.module %> 3 | 4 | use Torch.Pagination, 5 | repo: <%= inspect schema.repo %>, 6 | model: <%= inspect schema.module %>, 7 | name: <%= inspect String.to_atom(schema.plural) %> 8 | 9 | 10 | @doc """ 11 | Returns the list of <%= schema.plural %>. 12 | 13 | ## Examples 14 | 15 | iex> list_<%= schema.plural %>() 16 | [%<%= inspect schema.alias %>{}, ...] 17 | 18 | """ 19 | def list_<%= schema.plural %> do 20 | Repo.all(<%= inspect schema.alias %>) 21 | end 22 | 23 | @doc """ 24 | Gets a single <%= schema.singular %>. 25 | 26 | Raises `Ecto.NoResultsError` if the <%= schema.human_singular %> does not exist. 27 | 28 | ## Examples 29 | 30 | iex> get_<%= schema.singular %>!(123) 31 | %<%= inspect schema.alias %>{} 32 | 33 | iex> get_<%= schema.singular %>!(456) 34 | ** (Ecto.NoResultsError) 35 | 36 | """ 37 | def get_<%= schema.singular %>!(id), do: Repo.get!(<%= inspect schema.alias %>, id) 38 | 39 | @doc """ 40 | Creates a <%= schema.singular %>. 41 | 42 | ## Examples 43 | 44 | iex> create_<%= schema.singular %>(%{field: value}) 45 | {:ok, %<%= inspect schema.alias %>{}} 46 | 47 | iex> create_<%= schema.singular %>(%{field: bad_value}) 48 | {:error, %Ecto.Changeset{}} 49 | 50 | """ 51 | def create_<%= schema.singular %>(attrs \\ %{}) do 52 | %<%= inspect schema.alias %>{} 53 | |> <%= inspect schema.alias %>.changeset(attrs) 54 | |> Repo.insert() 55 | end 56 | 57 | @doc """ 58 | Updates a <%= schema.singular %>. 59 | 60 | ## Examples 61 | 62 | iex> update_<%= schema.singular %>(<%= schema.singular %>, %{field: new_value}) 63 | {:ok, %<%= inspect schema.alias %>{}} 64 | 65 | iex> update_<%= schema.singular %>(<%= schema.singular %>, %{field: bad_value}) 66 | {:error, %Ecto.Changeset{}} 67 | 68 | """ 69 | def update_<%= schema.singular %>(%<%= inspect schema.alias %>{} = <%= schema.singular %>, attrs) do 70 | <%= schema.singular %> 71 | |> <%= inspect schema.alias %>.changeset(attrs) 72 | |> Repo.update() 73 | end 74 | 75 | @doc """ 76 | Deletes a <%= inspect schema.alias %>. 77 | 78 | ## Examples 79 | 80 | iex> delete_<%= schema.singular %>(<%= schema.singular %>) 81 | {:ok, %<%= inspect schema.alias %>{}} 82 | 83 | iex> delete_<%= schema.singular %>(<%= schema.singular %>) 84 | {:error, %Ecto.Changeset{}} 85 | 86 | """ 87 | def delete_<%= schema.singular %>(%<%= inspect schema.alias %>{} = <%= schema.singular %>) do 88 | Repo.delete(<%= schema.singular %>) 89 | end 90 | 91 | @doc """ 92 | Returns an `%Ecto.Changeset{}` for tracking <%= schema.singular %> changes. 93 | 94 | ## Examples 95 | 96 | iex> change_<%= schema.singular %>(<%= schema.singular %>) 97 | %Ecto.Changeset{source: %<%= inspect schema.alias %>{}} 98 | 99 | """ 100 | def change_<%= schema.singular %>(%<%= inspect schema.alias %>{} = <%= schema.singular %>, attrs \\ %{}) do 101 | <%= inspect schema.alias %>.changeset(<%= schema.singular %>, attrs) 102 | end 103 | -------------------------------------------------------------------------------- /priv/templates/phx.gen.html/controller.ex: -------------------------------------------------------------------------------- 1 | defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>Controller do 2 | use <%= inspect context.web_module %>, :controller 3 | 4 | alias <%= inspect context.module %> 5 | alias <%= inspect schema.module %> 6 | 7 | plug(:put_root_layout, {<%= inspect context.web_module %>.Layouts, "torch.html"}) 8 | plug(:put_layout, false) 9 | 10 | def index(conn, params) do 11 | case <%= inspect context.alias %>.paginate_<%= schema.plural %>(params) do 12 | {:ok, assigns} -> 13 | render(conn, :index, assigns) 14 | {:error, error} -> 15 | conn 16 | |> put_flash(:error, "There was an error rendering <%= schema.human_plural %>. #{inspect(error)}") 17 | |> redirect(to: ~p"<%= schema.route_prefix %>") 18 | end 19 | end 20 | 21 | def new(conn, _params) do 22 | changeset = <%= inspect context.alias %>.change_<%= schema.singular %>(%<%= inspect schema.alias %>{}) 23 | render(conn, :new, changeset: changeset) 24 | end 25 | 26 | def create(conn, %{<%= inspect schema.singular %> => <%= schema.singular %>_params}) do 27 | case <%= inspect context.alias %>.create_<%= schema.singular %>(<%= schema.singular %>_params) do 28 | {:ok, <%= schema.singular %>} -> 29 | conn 30 | |> put_flash(:info, "<%= schema.human_singular %> created successfully.") 31 | |> redirect(to: ~p"<%= schema.route_prefix %>/#{<%= schema.singular %>}") 32 | {:error, %Ecto.Changeset{} = changeset} -> 33 | render(conn, :new, changeset: changeset) 34 | end 35 | end 36 | 37 | def show(conn, %{"id" => id}) do 38 | <%= schema.singular %> = <%= inspect context.alias %>.get_<%= schema.singular %>!(id) 39 | render(conn, :show, <%= schema.singular %>: <%= schema.singular %>) 40 | end 41 | 42 | def edit(conn, %{"id" => id}) do 43 | <%= schema.singular %> = <%= inspect context.alias %>.get_<%= schema.singular %>!(id) 44 | changeset = <%= inspect context.alias %>.change_<%= schema.singular %>(<%= schema.singular %>) 45 | render(conn, :edit, <%= schema.singular %>: <%= schema.singular %>, changeset: changeset) 46 | end 47 | 48 | def update(conn, %{"id" => id, <%= inspect schema.singular %> => <%= schema.singular %>_params}) do 49 | <%= schema.singular %> = <%= inspect context.alias %>.get_<%= schema.singular %>!(id) 50 | 51 | case <%= inspect context.alias %>.update_<%= schema.singular %>(<%= schema.singular %>, <%= schema.singular %>_params) do 52 | {:ok, <%= schema.singular %>} -> 53 | conn 54 | |> put_flash(:info, "<%= schema.human_singular %> updated successfully.") 55 | |> redirect(to: ~p"<%= schema.route_prefix %>/#{<%= schema.singular %>}") 56 | {:error, %Ecto.Changeset{} = changeset} -> 57 | render(conn, :edit, <%= schema.singular %>: <%= schema.singular %>, changeset: changeset) 58 | end 59 | end 60 | 61 | def delete(conn, %{"id" => id}) do 62 | <%= schema.singular %> = <%= inspect context.alias %>.get_<%= schema.singular %>!(id) 63 | {:ok, _<%= schema.singular %>} = <%= inspect context.alias %>.delete_<%= schema.singular %>(<%= schema.singular %>) 64 | 65 | conn 66 | |> put_flash(:info, "<%= schema.human_singular %> deleted successfully.") 67 | |> redirect(to: ~p"<%= schema.route_prefix %>") 68 | end 69 | end 70 | -------------------------------------------------------------------------------- /priv/templates/phx.gen.html/edit.html.heex: -------------------------------------------------------------------------------- 1 |
2 |
3 | <.link href={~p"<%= schema.route_prefix %>"} class="torch-button"><%%= Torch.I18n.message("Cancel") %> 4 |
5 |
6 | 7 |
8 |
9 |
10 |

Edit <%= String.capitalize(schema.human_singular) %>

11 |
12 | <.<%= schema.singular %>_form changeset={@changeset} action={~p"<%= schema.route_prefix %>/#{@<%= schema.singular %>}"} /> 13 |
14 |
15 | -------------------------------------------------------------------------------- /priv/templates/phx.gen.html/edit_1_7_0.html.heex: -------------------------------------------------------------------------------- 1 |
2 |
3 | <.link href={~p"<%= schema.route_prefix %>"} class="torch-button"><%%= Torch.I18n.message("Cancel") %> 4 |
5 |
6 | 7 |
8 |
9 |
10 |

Edit <%= String.capitalize(schema.human_singular) %>

11 |
12 | <.form :let={f} for={@changeset} action={~p"<%= schema.route_prefix %>/#{@<%= schema.singular %>}"} id="torch-form" enctype="multipart/form-data"> 13 |
14 | 15 | Details 16 | 17 | <%%= if @changeset.action do %> 18 |

Oops, something went wrong! Please check the errors below.

19 | <%% end %> 20 | <%= Mix.Torch.indent_inputs(Mix.Torch.torch_inputs(schema), 8) %> 21 |
22 | 23 |
24 |
25 | 26 |
27 |
28 | -------------------------------------------------------------------------------- /priv/templates/phx.gen.html/html.ex: -------------------------------------------------------------------------------- 1 | defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>HTML do 2 | use <%= inspect context.web_module %>, :html 3 | 4 | import Phoenix.HTML.Form 5 | use PhoenixHTMLHelpers 6 | 7 | import Torch.TableView 8 | import Torch.FilterView 9 | import Torch.Component 10 | 11 | def error_tag(form, field) do 12 | Enum.map(Keyword.get_values(form.errors, field), fn error -> 13 | content_tag(:span, Torch.Component.translate_error(error), 14 | class: "invalid-feedback", 15 | phx_feedback_for: input_name(form, field) 16 | ) 17 | end) 18 | end 19 | 20 | embed_templates "<%= schema.singular %>_html/*" 21 | end 22 | -------------------------------------------------------------------------------- /priv/templates/phx.gen.html/index.html.heex: -------------------------------------------------------------------------------- 1 |
2 |
3 | <.link href={~p"<%= schema.route_prefix %>/new"} class="torch-button">New <%= schema.human_singular %> 4 |
5 |
6 |
7 |
8 |
9 |

Find <%= schema.human_plural %>

10 | <%%= form_tag @conn.request_path, method: :get, id: "torch-filters-form" do %> 11 | <%= for {key, type} <- schema.attrs, type in [:string, :text] do %> 12 |
13 | 14 | <%%= filter_select(:<%= schema.singular %>, :<%= key %>, @conn.params) %> 15 | <%%= filter_string_input(:<%= schema.singular %>, :<%= key %>, @conn.params) %> 16 |
17 | <% end %> 18 | <%= for {key, type} <- schema.attrs, type in [:boolean] do %> 19 |
20 | 21 | <%%= filter_boolean_input(:<%= schema.singular %>, :<%= key %>, @conn.params) %> 22 |
23 | <% end %> 24 | <%= for {key, type} <- schema.attrs, type in [:date, :datetime, :utc_datetime, :naive_datetime] do %> 25 |
26 | 27 | <%%= filter_date_input(:<%= schema.singular %>, :<%= key %>, @conn.params) %> 28 |
29 | <% end %> 30 | <%= for {key, type} <- schema.attrs, type in [:number, :integer] do %> 31 |
32 | 33 | <%%= number_filter_select(:<%= schema.singular %>, :<%= key %>, @conn.params) %> 34 | <%%= filter_number_input(:<%= schema.singular %>, :<%= key %>, @conn.params) %> 35 |
36 | <% end %> 37 | 38 | <%%= link "Clear Filters", to: ~p"<%= schema.route_prefix %>" %> 39 | <%% end %> 40 | 41 |
42 | 43 |
44 | <%%= if length(@<%= schema.plural %>) > 0 do %> 45 | 46 | 47 | 48 | <%= for {k, _} <- schema.attrs do %> 49 | 50 | <% end %> 51 | 52 | 53 | 54 | 55 | <%%= for <%= schema.singular %> <- @<%= schema.plural %> do %> 56 | 57 | <%= for {k, _} <- schema.attrs do %> 58 | 59 | <% end %> 60 | 65 | 66 | <%% end %> 67 | 68 |
<%%= table_link(@conn, "<%= Phoenix.Naming.humanize(Atom.to_string(k)) %>", <%= inspect(k) %>) %>Actions
<%%= <%= schema.singular %>.<%= k %> %> 61 | <.link href={~p"<%= schema.route_prefix %>/#{<%= schema.singular %>}"}><%%= Torch.I18n.message("Show") %> 62 | <.link href={~p"<%= schema.route_prefix %>/#{<%= schema.singular %>}/edit"}><%%= Torch.I18n.message("Edit") %> 63 | <.link href={~p"<%= schema.route_prefix %>/#{<%= schema.singular %>}"} method="delete" data-confirm={Torch.I18n.message("Are you sure?")}><%%= Torch.I18n.message("Delete") %> 64 |
69 | <%%= Torch.PaginationView.pagination(@conn) %> 70 | <%% else %> 71 |

No <%= schema.human_plural %> match your search.

72 | <%% end %> 73 |
74 |
75 |
76 | -------------------------------------------------------------------------------- /priv/templates/phx.gen.html/new.html.heex: -------------------------------------------------------------------------------- 1 |
2 |
3 | <.link href={~p"<%= schema.route_prefix %>"} class="torch-button"><%%= Torch.I18n.message("Cancel") %> 4 |
5 |
6 | 7 |
8 |
9 |
10 |

New <%= String.capitalize(schema.human_singular) %>

11 |
12 | <.<%= schema.singular %>_form changeset={@changeset} action={~p"<%= schema.route_prefix %>"} /> 13 |
14 |
15 | -------------------------------------------------------------------------------- /priv/templates/phx.gen.html/new_1_7_0.html.heex: -------------------------------------------------------------------------------- 1 |
2 |
3 | <.link href={~p"<%= schema.route_prefix %>"} class="torch-button"><%%= Torch.I18n.message("Cancel") %> 4 |
5 |
6 | 7 |
8 |
9 |
10 |

New <%= String.capitalize(schema.human_singular) %>

11 |
12 | <.form :let={f} for={@changeset} action={~p"<%= schema.route_prefix %>"} id="torch-form" enctype="multipart/form-data"> 13 |
14 | 15 | Details 16 | 17 | <%%= if @changeset.action do %> 18 |

Oops, something went wrong! Please check the errors below.

19 | <%% end %> 20 | <%= Mix.Torch.indent_inputs(Mix.Torch.torch_inputs(schema), 8) %> 21 |
22 | 23 |
24 |
25 | 26 |
27 |
28 | -------------------------------------------------------------------------------- /priv/templates/phx.gen.html/resource_form.html.heex: -------------------------------------------------------------------------------- 1 | <.form :let={f} for={@changeset} action={@action} id="torch-form" enctype="multipart/form-data"> 2 |
3 | 4 | Details 5 | 6 | <%%= if @changeset.action do %> 7 |

Oops, something went wrong! Please check the errors below.

8 | <%% end %> 9 | <%= Mix.Torch.indent_inputs(Mix.Torch.torch_inputs(schema), 4) %> 10 |
11 | 12 |
13 |
14 | 15 | -------------------------------------------------------------------------------- /priv/templates/phx.gen.html/show.html.heex: -------------------------------------------------------------------------------- 1 |
2 |
3 | <.link href={~p"<%= schema.route_prefix %>/#{@<%= schema.singular %>}/edit"} class="torch-button"><%%= Torch.I18n.message("Edit") %> 4 | <.link href={~p"<%= schema.route_prefix %>"} class="torch-button"><%%= Torch.I18n.message("Back") %> 5 |
6 |
7 | 8 |
9 |
10 |
11 |

<%= String.capitalize(schema.human_singular) %> Details

12 |
13 |
14 | <%= for {k, _} <- schema.attrs do %> 15 |
16 |
<%= Phoenix.Naming.humanize(Atom.to_string(k)) %>:
17 |
<%%= @<%= schema.singular %>.<%= k %> %>
18 |
19 | <% end %> 20 |
21 |
22 |
23 | -------------------------------------------------------------------------------- /priv/templates/torch.install/layout.html.heex: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | <%= PhoenixHTMLHelpers.Tag.csrf_meta_tag() %> 8 | Torch Admin 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |
18 | user@example.com 19 | Logout 20 |
21 |
22 | 23 |
24 |
25 | 30 | 33 |
34 |
35 |
36 | 37 | 38 | <%= @inner_content %> 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /test/mix/tasks/torch.gen.html_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Mix.Tasks.Torch.Gen.HtmlTest do 2 | use Torch.MixCase, async: false 3 | 4 | describe ".run/1" do 5 | # FIXME: this is not needed an invalid as of Phx 1.7? 6 | # test_mix_config_errors("torch.gen.html") 7 | 8 | # TODO: Add integration test for umbrella app 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /test/mix/tasks/torch.install_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Mix.Tasks.Torch.InstallTest do 2 | use Torch.MixCase 3 | 4 | describe ".run/1" do 5 | test_mix_config_errors("torch.install") 6 | 7 | # TODO: add test for umbrella project 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /test/mix/tasks/torch.uninstall_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Mix.Tasks.Torch.UninstallTest do 2 | use Torch.MixCase 3 | 4 | describe ".run/1" do 5 | test_mix_config_errors("torch.uninstall") 6 | 7 | Mix.Task.rerun("torch.install", ["--app", "my_app"]) 8 | Mix.Task.rerun("torch.uninstall", ["--app", "my_app"]) 9 | 10 | # TODO: add test for umbrella project 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /test/mix/test_helper.exs: -------------------------------------------------------------------------------- 1 | if System.get_env("CI") do 2 | ExUnit.configure(formatters: [ExUnit.CLIFormatter]) 3 | else 4 | ExUnit.configure(formatters: [ExUnit.CLIFormatter, ExUnitNotifier]) 5 | end 6 | 7 | ExUnit.start() 8 | -------------------------------------------------------------------------------- /test/support/apps/phx1_7/.formatter.exs: -------------------------------------------------------------------------------- 1 | [ 2 | import_deps: [:ecto, :ecto_sql, :phoenix], 3 | subdirectories: ["priv/*/migrations"], 4 | plugins: [Phoenix.LiveView.HTMLFormatter], 5 | inputs: ["*.{heex,ex,exs}", "{config,lib,test}/**/*.{heex,ex,exs}", "priv/*/seeds.exs"] 6 | ] 7 | -------------------------------------------------------------------------------- /test/support/apps/phx1_7/.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 3rd-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 | # Temporary files, for example, from tests. 23 | /tmp/ 24 | 25 | # Ignore package tarball (built via "mix hex.build"). 26 | phx1_7-*.tar 27 | 28 | # Ignore assets that are produced by build tools. 29 | /priv/static/assets/ 30 | 31 | # Ignore digested assets cache. 32 | /priv/static/cache_manifest.json 33 | 34 | # In case you use Node.js/npm, you want to ignore these. 35 | npm-debug.log 36 | /assets/node_modules/ 37 | 38 | -------------------------------------------------------------------------------- /test/support/apps/phx1_7/README.md: -------------------------------------------------------------------------------- 1 | # Phx17 2 | 3 | To start your Phoenix server: 4 | 5 | * Run `mix setup` to install and setup dependencies 6 | * Start Phoenix endpoint with `mix phx.server` or inside IEx with `iex -S mix phx.server` 7 | 8 | Now you can visit [`localhost:4000`](http://localhost:4000) from your browser. 9 | 10 | Ready to run in production? Please [check our deployment guides](https://hexdocs.pm/phoenix/deployment.html). 11 | 12 | ## Learn more 13 | 14 | * Official website: https://www.phoenixframework.org/ 15 | * Guides: https://hexdocs.pm/phoenix/overview.html 16 | * Docs: https://hexdocs.pm/phoenix 17 | * Forum: https://elixirforum.com/c/phoenix-forum 18 | * Source: https://github.com/phoenixframework/phoenix 19 | -------------------------------------------------------------------------------- /test/support/apps/phx1_7/assets/css/app.css: -------------------------------------------------------------------------------- 1 | @import "tailwindcss/base"; 2 | @import "tailwindcss/components"; 3 | @import "tailwindcss/utilities"; 4 | 5 | /* This file is for your main application CSS */ 6 | -------------------------------------------------------------------------------- /test/support/apps/phx1_7/assets/js/app.js: -------------------------------------------------------------------------------- 1 | // If you want to use Phoenix channels, run `mix help phx.gen.channel` 2 | // to get started and then uncomment the line below. 3 | // import "./user_socket.js" 4 | 5 | // You can include dependencies in two ways. 6 | // 7 | // The simplest option is to put them in assets/vendor and 8 | // import them using relative paths: 9 | // 10 | // import "../vendor/some-package.js" 11 | // 12 | // Alternatively, you can `npm install some-package --prefix assets` and import 13 | // them using a path starting with the package name: 14 | // 15 | // import "some-package" 16 | // 17 | 18 | // Include phoenix_html to handle method=PUT/DELETE in forms and buttons. 19 | import "phoenix_html" 20 | // Establish Phoenix Socket and LiveView configuration. 21 | import {Socket} from "phoenix" 22 | import {LiveSocket} from "phoenix_live_view" 23 | import topbar from "../vendor/topbar" 24 | 25 | let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content") 26 | let liveSocket = new LiveSocket("/live", Socket, {params: {_csrf_token: csrfToken}}) 27 | 28 | // Show progress bar on live navigation and form submits 29 | topbar.config({barColors: {0: "#29d"}, shadowColor: "rgba(0, 0, 0, .3)"}) 30 | window.addEventListener("phx:page-loading-start", _info => topbar.show(300)) 31 | window.addEventListener("phx:page-loading-stop", _info => topbar.hide()) 32 | 33 | // connect if there are any LiveViews on the page 34 | liveSocket.connect() 35 | 36 | // expose liveSocket on window for web console debug logs and latency simulation: 37 | // >> liveSocket.enableDebug() 38 | // >> liveSocket.enableLatencySim(1000) // enabled for duration of browser session 39 | // >> liveSocket.disableLatencySim() 40 | window.liveSocket = liveSocket 41 | 42 | -------------------------------------------------------------------------------- /test/support/apps/phx1_7/assets/tailwind.config.js: -------------------------------------------------------------------------------- 1 | // See the Tailwind configuration guide for advanced usage 2 | // https://tailwindcss.com/docs/configuration 3 | 4 | const plugin = require("tailwindcss/plugin") 5 | 6 | module.exports = { 7 | content: [ 8 | "./js/**/*.js", 9 | "../lib/*_web.ex", 10 | "../lib/*_web/**/*.*ex" 11 | ], 12 | theme: { 13 | extend: { 14 | colors: { 15 | brand: "#FD4F00", 16 | } 17 | }, 18 | }, 19 | plugins: [ 20 | require("@tailwindcss/forms"), 21 | plugin(({addVariant}) => addVariant("phx-no-feedback", [".phx-no-feedback&", ".phx-no-feedback &"])), 22 | plugin(({addVariant}) => addVariant("phx-click-loading", [".phx-click-loading&", ".phx-click-loading &"])), 23 | plugin(({addVariant}) => addVariant("phx-submit-loading", [".phx-submit-loading&", ".phx-submit-loading &"])), 24 | plugin(({addVariant}) => addVariant("phx-change-loading", [".phx-change-loading&", ".phx-change-loading &"])) 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /test/support/apps/phx1_7/bin/test: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Clean up generated files 4 | function cleanup() { 5 | rm -rf priv/templates 6 | rm -rf priv/repo/migrations/*.exs 7 | rm -rf lib/phx1_7/blog.ex 8 | rm -rf lib/phx1_7/blog 9 | rm -rf test/phx1_7/blog_test.exs 10 | rm -rf lib/phx1_7_web/controllers/post_controller.ex 11 | rm -rf lib/phx1_7_web/templates/layout/torch.html.heex 12 | rm -rf lib/phx1_7_web/templates/post/ 13 | rm -rf lib/phx1_7_web/views/post_view.ex 14 | rm -rf test/phx1_7_web/controllers/post_controller_test.exs 15 | rm -rf test/support/fixtures/ 16 | rm -rf lib/phx1_7_web/components/layouts/torch.html.heex 17 | rm -rf lib/phx1_7_web/controllers/post_html.ex 18 | rm -rf lib/phx1_7_web/controllers/post_html/ 19 | 20 | patch -i ../../patches/install-torch.diff -p 1 -R 21 | patch -i ../../patches/install-route.diff -p 1 -R 22 | } 23 | 24 | patch -i ../../patches/install-torch.diff -p 1 25 | mix deps.get || { cleanup; echo 'Dependencies could not be fetched!'; exit 1; } 26 | MIX_ENV=test mix ecto.drop || { cleanup; echo 'Database could not be dropped'; exit 1; } 27 | MIX_ENV=test mix torch.install || { cleanup; echo 'Torch could not be installed!'; exit 1; } 28 | MIX_ENV=test mix torch.gen.html Blog Post posts title:string published:boolean published_at:datetime views:integer || { echo 'Torch files not generated!'; exit 1; } 29 | patch -i ../../patches/install-route.diff -p 1 30 | MIX_ENV=test mix ecto.setup || { cleanup; echo 'Torch database could not be setup!'; exit 1; } 31 | MIX_ENV=test mix test || { echo 'Tests failed!'; cleanup; exit 1; } 32 | 33 | # Ensure that put_root_layout is used by default on > Phx 1.5 34 | if ! grep -q "plug(:put_root_layout" lib/phx1_7_web/controllers/post_controller.ex ; then 35 | echo 'Generated Phoenix controller not using `put_root_layout` syntax' 36 | cleanup 37 | exit 1; 38 | fi 39 | 40 | cleanup 41 | 42 | echo 'Tests succeeded!' 43 | exit 0 44 | -------------------------------------------------------------------------------- /test/support/apps/phx1_7/config/config.exs: -------------------------------------------------------------------------------- 1 | # This file is responsible for configuring your application 2 | # and its dependencies with the aid of the Config module. 3 | # 4 | # This configuration file is loaded before any dependency and 5 | # is restricted to this project. 6 | 7 | # General application configuration 8 | import Config 9 | 10 | config :phx1_7, 11 | ecto_repos: [Phx17.Repo] 12 | 13 | # Configures the endpoint 14 | config :phx1_7, Phx17Web.Endpoint, 15 | url: [host: "localhost"], 16 | render_errors: [ 17 | formats: [html: Phx17Web.ErrorHTML, json: Phx17Web.ErrorJSON], 18 | layout: false 19 | ], 20 | pubsub_server: Phx17.PubSub, 21 | live_view: [signing_salt: "8b3KX+rn"] 22 | 23 | # Configures the mailer 24 | # 25 | # By default it uses the "Local" adapter which stores the emails 26 | # locally. You can see the emails in your browser, at "/dev/mailbox". 27 | # 28 | # For production it's recommended to configure a different adapter 29 | # at the `config/runtime.exs`. 30 | config :phx1_7, Phx17.Mailer, adapter: Swoosh.Adapters.Local 31 | 32 | # Configure esbuild (the version is required) 33 | config :esbuild, 34 | version: "0.14.41", 35 | default: [ 36 | args: 37 | ~w(js/app.js --bundle --target=es2017 --outdir=../priv/static/assets --external:/fonts/* --external:/images/*), 38 | cd: Path.expand("../assets", __DIR__), 39 | env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)} 40 | ] 41 | 42 | # Configure tailwind (the version is required) 43 | config :tailwind, 44 | version: "3.2.4", 45 | default: [ 46 | args: ~w( 47 | --config=tailwind.config.js 48 | --input=css/app.css 49 | --output=../priv/static/assets/app.css 50 | ), 51 | cd: Path.expand("../assets", __DIR__) 52 | ] 53 | 54 | # Configures Elixir's Logger 55 | config :logger, :console, 56 | format: "$time $metadata[$level] $message\n", 57 | metadata: [:request_id] 58 | 59 | # Use Jason for JSON parsing in Phoenix 60 | config :phoenix, :json_library, Jason 61 | 62 | # Import environment specific config. This must remain at the bottom 63 | # of this file so it overrides the configuration defined above. 64 | import_config "#{config_env()}.exs" 65 | -------------------------------------------------------------------------------- /test/support/apps/phx1_7/config/dev.exs: -------------------------------------------------------------------------------- 1 | import Config 2 | 3 | # Configure your database 4 | config :phx1_7, Phx17.Repo, 5 | username: "postgres", 6 | password: "postgres", 7 | hostname: "localhost", 8 | database: "phx1_7_dev", 9 | stacktrace: true, 10 | show_sensitive_data_on_connection_error: true, 11 | pool_size: 10 12 | 13 | # For development, we disable any cache and enable 14 | # debugging and code reloading. 15 | # 16 | # The watchers configuration can be used to run external 17 | # watchers to your application. For example, we use it 18 | # with esbuild to bundle .js and .css sources. 19 | config :phx1_7, Phx17Web.Endpoint, 20 | # Binding to loopback ipv4 address prevents access from other machines. 21 | # Change to `ip: {0, 0, 0, 0}` to allow access from other machines. 22 | http: [ip: {127, 0, 0, 1}, port: 4000], 23 | check_origin: false, 24 | code_reloader: true, 25 | debug_errors: true, 26 | secret_key_base: "19IzTkNsmuimyLpuAG1foyIGCFGux/qM5o+9Po75mKTogJIXlKESYuliyjzqLDFD", 27 | watchers: [ 28 | esbuild: {Esbuild, :install_and_run, [:default, ~w(--sourcemap=inline --watch)]}, 29 | tailwind: {Tailwind, :install_and_run, [:default, ~w(--watch)]} 30 | ] 31 | 32 | # ## SSL Support 33 | # 34 | # In order to use HTTPS in development, a self-signed 35 | # certificate can be generated by running the following 36 | # Mix task: 37 | # 38 | # mix phx.gen.cert 39 | # 40 | # Run `mix help phx.gen.cert` for more information. 41 | # 42 | # The `http:` config above can be replaced with: 43 | # 44 | # https: [ 45 | # port: 4001, 46 | # cipher_suite: :strong, 47 | # keyfile: "priv/cert/selfsigned_key.pem", 48 | # certfile: "priv/cert/selfsigned.pem" 49 | # ], 50 | # 51 | # If desired, both `http:` and `https:` keys can be 52 | # configured to run both http and https servers on 53 | # different ports. 54 | 55 | # Watch static and templates for browser reloading. 56 | config :phx1_7, Phx17Web.Endpoint, 57 | live_reload: [ 58 | patterns: [ 59 | ~r"priv/static/.*(js|css|png|jpeg|jpg|gif|svg)$", 60 | ~r"priv/gettext/.*(po)$", 61 | ~r"lib/phx1_7_web/(controllers|live|components)/.*(ex|heex)$" 62 | ] 63 | ] 64 | 65 | # Enable dev routes for dashboard and mailbox 66 | config :phx1_7, dev_routes: true 67 | 68 | # Do not include metadata nor timestamps in development logs 69 | config :logger, :console, format: "[$level] $message\n" 70 | 71 | # Set a higher stacktrace during development. Avoid configuring such 72 | # in production as building large stacktraces may be expensive. 73 | config :phoenix, :stacktrace_depth, 20 74 | 75 | # Initialize plugs at runtime for faster development compilation 76 | config :phoenix, :plug_init_mode, :runtime 77 | 78 | # Disable swoosh api client as it is only required for production adapters. 79 | config :swoosh, :api_client, false 80 | -------------------------------------------------------------------------------- /test/support/apps/phx1_7/config/prod.exs: -------------------------------------------------------------------------------- 1 | import Config 2 | 3 | # For production, don't forget to configure the url host 4 | # to something meaningful, Phoenix uses this information 5 | # when generating URLs. 6 | 7 | # Note we also include the path to a cache manifest 8 | # containing the digested version of static files. This 9 | # manifest is generated by the `mix phx.digest` task, 10 | # which you should run after static files are built and 11 | # before starting your production server. 12 | config :phx1_7, Phx17Web.Endpoint, cache_static_manifest: "priv/static/cache_manifest.json" 13 | 14 | # Configures Swoosh API Client 15 | config :swoosh, api_client: Swoosh.ApiClient.Finch, finch_name: Phx17.Finch 16 | 17 | # Do not print debug messages in production 18 | config :logger, level: :info 19 | 20 | # Runtime production configuration, including reading 21 | # of environment variables, is done on config/runtime.exs. 22 | -------------------------------------------------------------------------------- /test/support/apps/phx1_7/config/test.exs: -------------------------------------------------------------------------------- 1 | import Config 2 | 3 | # Configure your database 4 | # 5 | # The MIX_TEST_PARTITION environment variable can be used 6 | # to provide built-in test partitioning in CI environment. 7 | # Run `mix help test` for more information. 8 | config :phx1_7, Phx17.Repo, 9 | username: "postgres", 10 | password: "postgres", 11 | hostname: "localhost", 12 | database: "phx1_7_test#{System.get_env("MIX_TEST_PARTITION")}", 13 | pool: Ecto.Adapters.SQL.Sandbox, 14 | pool_size: 10 15 | 16 | # We don't run a server during test. If one is required, 17 | # you can enable the server option below. 18 | config :phx1_7, Phx17Web.Endpoint, 19 | http: [ip: {127, 0, 0, 1}, port: 4002], 20 | secret_key_base: "uYFVmobYDpSImRi+J3xTBoQkUKiSXLdFIKocI31psYeQna4iIaluILDsjFYa56h6", 21 | server: false 22 | 23 | # In test we don't send emails. 24 | config :phx1_7, Phx17.Mailer, adapter: Swoosh.Adapters.Test 25 | 26 | # Disable swoosh api client as it is only required for production adapters. 27 | config :swoosh, :api_client, false 28 | 29 | # Print only warnings and errors during test 30 | config :logger, level: :warning 31 | 32 | # Initialize plugs at runtime for faster test compilation 33 | config :phoenix, :plug_init_mode, :runtime 34 | -------------------------------------------------------------------------------- /test/support/apps/phx1_7/lib/phx1_7.ex: -------------------------------------------------------------------------------- 1 | defmodule Phx17 do 2 | @moduledoc """ 3 | Phx17 keeps the contexts that define your domain 4 | and business logic. 5 | 6 | Contexts are also responsible for managing your data, regardless 7 | if it comes from the database, an external API or others. 8 | """ 9 | end 10 | -------------------------------------------------------------------------------- /test/support/apps/phx1_7/lib/phx1_7/application.ex: -------------------------------------------------------------------------------- 1 | defmodule Phx17.Application do 2 | # See https://hexdocs.pm/elixir/Application.html 3 | # for more information on OTP Applications 4 | @moduledoc false 5 | 6 | use Application 7 | 8 | @impl true 9 | def start(_type, _args) do 10 | children = [ 11 | # Start the Telemetry supervisor 12 | Phx17Web.Telemetry, 13 | # Start the Ecto repository 14 | Phx17.Repo, 15 | # Start the PubSub system 16 | {Phoenix.PubSub, name: Phx17.PubSub}, 17 | # Start Finch 18 | {Finch, name: Phx17.Finch}, 19 | # Start the Endpoint (http/https) 20 | Phx17Web.Endpoint 21 | # Start a worker by calling: Phx17.Worker.start_link(arg) 22 | # {Phx17.Worker, arg} 23 | ] 24 | 25 | # See https://hexdocs.pm/elixir/Supervisor.html 26 | # for other strategies and supported options 27 | opts = [strategy: :one_for_one, name: Phx17.Supervisor] 28 | Supervisor.start_link(children, opts) 29 | end 30 | 31 | # Tell Phoenix to update the endpoint configuration 32 | # whenever the application is updated. 33 | @impl true 34 | def config_change(changed, _new, removed) do 35 | Phx17Web.Endpoint.config_change(changed, removed) 36 | :ok 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /test/support/apps/phx1_7/lib/phx1_7/mailer.ex: -------------------------------------------------------------------------------- 1 | defmodule Phx17.Mailer do 2 | use Swoosh.Mailer, otp_app: :phx1_7 3 | end 4 | -------------------------------------------------------------------------------- /test/support/apps/phx1_7/lib/phx1_7/repo.ex: -------------------------------------------------------------------------------- 1 | defmodule Phx17.Repo do 2 | use Ecto.Repo, 3 | otp_app: :phx1_7, 4 | adapter: Ecto.Adapters.Postgres 5 | end 6 | -------------------------------------------------------------------------------- /test/support/apps/phx1_7/lib/phx1_7_web.ex: -------------------------------------------------------------------------------- 1 | defmodule Phx17Web do 2 | @moduledoc """ 3 | The entrypoint for defining your web interface, such 4 | as controllers, components, channels, and so on. 5 | 6 | This can be used in your application as: 7 | 8 | use Phx17Web, :controller 9 | use Phx17Web, :html 10 | 11 | The definitions below will be executed for every controller, 12 | component, etc, so keep them short and clean, focused 13 | on imports, uses and aliases. 14 | 15 | Do NOT define functions inside the quoted expressions 16 | below. Instead, define additional modules and import 17 | those modules here. 18 | """ 19 | 20 | def static_paths, do: ~w(assets fonts images favicon.ico robots.txt) 21 | 22 | def router do 23 | quote do 24 | use Phoenix.Router, helpers: false 25 | 26 | # Import common connection and controller functions to use in pipelines 27 | import Plug.Conn 28 | import Phoenix.Controller 29 | import Phoenix.LiveView.Router 30 | end 31 | end 32 | 33 | def channel do 34 | quote do 35 | use Phoenix.Channel 36 | end 37 | end 38 | 39 | def controller do 40 | quote do 41 | use Phoenix.Controller, 42 | formats: [:html, :json], 43 | layouts: [html: Phx17Web.Layouts] 44 | 45 | import Plug.Conn 46 | import Phx17Web.Gettext 47 | 48 | unquote(verified_routes()) 49 | end 50 | end 51 | 52 | def live_view do 53 | quote do 54 | use Phoenix.LiveView, 55 | layout: {Phx17Web.Layouts, :app} 56 | 57 | unquote(html_helpers()) 58 | end 59 | end 60 | 61 | def live_component do 62 | quote do 63 | use Phoenix.LiveComponent 64 | 65 | unquote(html_helpers()) 66 | end 67 | end 68 | 69 | def html do 70 | quote do 71 | use Phoenix.Component 72 | 73 | # Import convenience functions from controllers 74 | import Phoenix.Controller, 75 | only: [get_csrf_token: 0, view_module: 1, view_template: 1] 76 | 77 | # Include general helpers for rendering HTML 78 | unquote(html_helpers()) 79 | end 80 | end 81 | 82 | defp html_helpers do 83 | quote do 84 | # HTML escaping functionality 85 | import Phoenix.HTML 86 | # Core UI components and translation 87 | import Phx17Web.CoreComponents 88 | import Phx17Web.Gettext 89 | 90 | # Shortcut for generating JS commands 91 | alias Phoenix.LiveView.JS 92 | 93 | # Routes generation with the ~p sigil 94 | unquote(verified_routes()) 95 | end 96 | end 97 | 98 | def verified_routes do 99 | quote do 100 | use Phoenix.VerifiedRoutes, 101 | endpoint: Phx17Web.Endpoint, 102 | router: Phx17Web.Router, 103 | statics: Phx17Web.static_paths() 104 | end 105 | end 106 | 107 | @doc """ 108 | When used, dispatch to the appropriate controller/view/etc. 109 | """ 110 | defmacro __using__(which) when is_atom(which) do 111 | apply(__MODULE__, which, []) 112 | end 113 | end 114 | -------------------------------------------------------------------------------- /test/support/apps/phx1_7/lib/phx1_7_web/components/layouts.ex: -------------------------------------------------------------------------------- 1 | defmodule Phx17Web.Layouts do 2 | use Phx17Web, :html 3 | 4 | embed_templates "layouts/*" 5 | end 6 | -------------------------------------------------------------------------------- /test/support/apps/phx1_7/lib/phx1_7_web/components/layouts/root.html.heex: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | <.live_title suffix=" · Phoenix Framework"> 8 | <%= assigns[:page_title] || "Phx17" %> 9 | 10 | 11 | 13 | 14 | 15 | <%= @inner_content %> 16 | 17 | 18 | -------------------------------------------------------------------------------- /test/support/apps/phx1_7/lib/phx1_7_web/controllers/error_html.ex: -------------------------------------------------------------------------------- 1 | defmodule Phx17Web.ErrorHTML do 2 | use Phx17Web, :html 3 | 4 | # If you want to customize your error pages, 5 | # uncomment the embed_templates/1 call below 6 | # and add pages to the error directory: 7 | # 8 | # * lib/phx1_7_web/controllers/error_html/404.html.heex 9 | # * lib/phx1_7_web/controllers/error_html/500.html.heex 10 | # 11 | # embed_templates "error_html/*" 12 | 13 | # The default is to render a plain text page based on 14 | # the template name. For example, "404.html" becomes 15 | # "Not Found". 16 | def render(template, _assigns) do 17 | Phoenix.Controller.status_message_from_template(template) 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /test/support/apps/phx1_7/lib/phx1_7_web/controllers/error_json.ex: -------------------------------------------------------------------------------- 1 | defmodule Phx17Web.ErrorJSON do 2 | # If you want to customize a particular status code, 3 | # you may add your own clauses, such as: 4 | # 5 | # def render("500.json", _assigns) do 6 | # %{errors: %{detail: "Internal Server Error"}} 7 | # end 8 | 9 | # By default, Phoenix returns the status message from 10 | # the template name. For example, "404.json" becomes 11 | # "Not Found". 12 | def render(template, _assigns) do 13 | %{errors: %{detail: Phoenix.Controller.status_message_from_template(template)}} 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /test/support/apps/phx1_7/lib/phx1_7_web/controllers/page_controller.ex: -------------------------------------------------------------------------------- 1 | defmodule Phx17Web.PageController do 2 | use Phx17Web, :controller 3 | 4 | def home(conn, _params) do 5 | # The home page is often custom made, 6 | # so skip the default app layout. 7 | render(conn, :home, layout: false) 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /test/support/apps/phx1_7/lib/phx1_7_web/controllers/page_html.ex: -------------------------------------------------------------------------------- 1 | defmodule Phx17Web.PageHTML do 2 | use Phx17Web, :html 3 | 4 | embed_templates "page_html/*" 5 | end 6 | -------------------------------------------------------------------------------- /test/support/apps/phx1_7/lib/phx1_7_web/endpoint.ex: -------------------------------------------------------------------------------- 1 | defmodule Phx17Web.Endpoint do 2 | use Phoenix.Endpoint, otp_app: :phx1_7 3 | 4 | # The session will be stored in the cookie and signed, 5 | # this means its contents can be read but not tampered with. 6 | # Set :encryption_salt if you would also like to encrypt it. 7 | @session_options [ 8 | store: :cookie, 9 | key: "_phx1_7_key", 10 | signing_salt: "3jDgYIOc", 11 | same_site: "Lax" 12 | ] 13 | 14 | socket "/live", Phoenix.LiveView.Socket, websocket: [connect_info: [session: @session_options]] 15 | 16 | # Serve at "/" the static files from "priv/static" directory. 17 | # 18 | # You should set gzip to true if you are running phx.digest 19 | # when deploying your static files in production. 20 | plug Plug.Static, 21 | at: "/", 22 | from: :phx1_7, 23 | gzip: false, 24 | only: Phx17Web.static_paths() 25 | 26 | # Code reloading can be explicitly enabled under the 27 | # :code_reloader configuration of your endpoint. 28 | if code_reloading? do 29 | socket "/phoenix/live_reload/socket", Phoenix.LiveReloader.Socket 30 | plug Phoenix.LiveReloader 31 | plug Phoenix.CodeReloader 32 | plug Phoenix.Ecto.CheckRepoStatus, otp_app: :phx1_7 33 | end 34 | 35 | plug Phoenix.LiveDashboard.RequestLogger, 36 | param_key: "request_logger", 37 | cookie_key: "request_logger" 38 | 39 | plug Plug.RequestId 40 | plug Plug.Telemetry, event_prefix: [:phoenix, :endpoint] 41 | 42 | plug Plug.Parsers, 43 | parsers: [:urlencoded, :multipart, :json], 44 | pass: ["*/*"], 45 | json_decoder: Phoenix.json_library() 46 | 47 | plug Plug.MethodOverride 48 | plug Plug.Head 49 | plug Plug.Session, @session_options 50 | plug Phx17Web.Router 51 | end 52 | -------------------------------------------------------------------------------- /test/support/apps/phx1_7/lib/phx1_7_web/gettext.ex: -------------------------------------------------------------------------------- 1 | defmodule Phx17Web.Gettext do 2 | @moduledoc """ 3 | A module providing Internationalization with a gettext-based API. 4 | 5 | By using [Gettext](https://hexdocs.pm/gettext), 6 | your module gains a set of macros for translations, for example: 7 | 8 | import Phx17Web.Gettext 9 | 10 | # Simple translation 11 | gettext("Here is the string to translate") 12 | 13 | # Plural translation 14 | ngettext("Here is the string to translate", 15 | "Here are the strings to translate", 16 | 3) 17 | 18 | # Domain-based translation 19 | dgettext("errors", "Here is the error message to translate") 20 | 21 | See the [Gettext Docs](https://hexdocs.pm/gettext) for detailed usage. 22 | """ 23 | use Gettext, otp_app: :phx1_7 24 | end 25 | -------------------------------------------------------------------------------- /test/support/apps/phx1_7/lib/phx1_7_web/router.ex: -------------------------------------------------------------------------------- 1 | defmodule Phx17Web.Router do 2 | use Phx17Web, :router 3 | 4 | pipeline :browser do 5 | plug :accepts, ["html"] 6 | plug :fetch_session 7 | plug :fetch_live_flash 8 | plug :put_root_layout, {Phx17Web.Layouts, :root} 9 | plug :protect_from_forgery 10 | plug :put_secure_browser_headers 11 | end 12 | 13 | pipeline :api do 14 | plug :accepts, ["json"] 15 | end 16 | 17 | scope "/", Phx17Web do 18 | pipe_through :browser 19 | 20 | get "/", PageController, :home 21 | end 22 | 23 | # Other scopes may use custom stacks. 24 | # scope "/api", Phx17Web do 25 | # pipe_through :api 26 | # end 27 | 28 | # Enable LiveDashboard and Swoosh mailbox preview in development 29 | if Application.compile_env(:phx1_7, :dev_routes) do 30 | # If you want to use the LiveDashboard in production, you should put 31 | # it behind authentication and allow only admins to access it. 32 | # If your application does not have an admins-only section yet, 33 | # you can use Plug.BasicAuth to set up some basic authentication 34 | # as long as you are also using SSL (which you should anyway). 35 | import Phoenix.LiveDashboard.Router 36 | 37 | scope "/dev" do 38 | pipe_through :browser 39 | 40 | live_dashboard "/dashboard", metrics: Phx17Web.Telemetry 41 | forward "/mailbox", Plug.Swoosh.MailboxPreview 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /test/support/apps/phx1_7/lib/phx1_7_web/router.ex.orig: -------------------------------------------------------------------------------- 1 | defmodule Phx17Web.Router do 2 | use Phx17Web, :router 3 | 4 | pipeline :browser do 5 | plug :accepts, ["html"] 6 | plug :fetch_session 7 | plug :fetch_live_flash 8 | plug :put_root_layout, {Phx17Web.Layouts, :root} 9 | plug :protect_from_forgery 10 | plug :put_secure_browser_headers 11 | end 12 | 13 | pipeline :api do 14 | plug :accepts, ["json"] 15 | end 16 | 17 | scope "/", Phx17Web do 18 | pipe_through :browser 19 | 20 | get "/", PageController, :home 21 | end 22 | 23 | # Other scopes may use custom stacks. 24 | # scope "/api", Phx17Web do 25 | # pipe_through :api 26 | # end 27 | 28 | # Enable LiveDashboard and Swoosh mailbox preview in development 29 | if Application.compile_env(:phx1_7, :dev_routes) do 30 | # If you want to use the LiveDashboard in production, you should put 31 | # it behind authentication and allow only admins to access it. 32 | # If your application does not have an admins-only section yet, 33 | # you can use Plug.BasicAuth to set up some basic authentication 34 | # as long as you are also using SSL (which you should anyway). 35 | import Phoenix.LiveDashboard.Router 36 | 37 | scope "/dev" do 38 | pipe_through :browser 39 | 40 | live_dashboard "/dashboard", metrics: Phx17Web.Telemetry 41 | forward "/mailbox", Plug.Swoosh.MailboxPreview 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /test/support/apps/phx1_7/lib/phx1_7_web/telemetry.ex: -------------------------------------------------------------------------------- 1 | defmodule Phx17Web.Telemetry do 2 | use Supervisor 3 | import Telemetry.Metrics 4 | 5 | def start_link(arg) do 6 | Supervisor.start_link(__MODULE__, arg, name: __MODULE__) 7 | end 8 | 9 | @impl true 10 | def init(_arg) do 11 | children = [ 12 | # Telemetry poller will execute the given period measurements 13 | # every 10_000ms. Learn more here: https://hexdocs.pm/telemetry_metrics 14 | {:telemetry_poller, measurements: periodic_measurements(), period: 10_000} 15 | # Add reporters as children of your supervision tree. 16 | # {Telemetry.Metrics.ConsoleReporter, metrics: metrics()} 17 | ] 18 | 19 | Supervisor.init(children, strategy: :one_for_one) 20 | end 21 | 22 | def metrics do 23 | [ 24 | # Phoenix Metrics 25 | summary("phoenix.endpoint.start.system_time", 26 | unit: {:native, :millisecond} 27 | ), 28 | summary("phoenix.endpoint.stop.duration", 29 | unit: {:native, :millisecond} 30 | ), 31 | summary("phoenix.router_dispatch.start.system_time", 32 | tags: [:route], 33 | unit: {:native, :millisecond} 34 | ), 35 | summary("phoenix.router_dispatch.exception.duration", 36 | tags: [:route], 37 | unit: {:native, :millisecond} 38 | ), 39 | summary("phoenix.router_dispatch.stop.duration", 40 | tags: [:route], 41 | unit: {:native, :millisecond} 42 | ), 43 | summary("phoenix.socket_connected.duration", 44 | unit: {:native, :millisecond} 45 | ), 46 | summary("phoenix.channel_join.duration", 47 | unit: {:native, :millisecond} 48 | ), 49 | summary("phoenix.channel_handled_in.duration", 50 | tags: [:event], 51 | unit: {:native, :millisecond} 52 | ), 53 | 54 | # Database Metrics 55 | summary("phx1_7.repo.query.total_time", 56 | unit: {:native, :millisecond}, 57 | description: "The sum of the other measurements" 58 | ), 59 | summary("phx1_7.repo.query.decode_time", 60 | unit: {:native, :millisecond}, 61 | description: "The time spent decoding the data received from the database" 62 | ), 63 | summary("phx1_7.repo.query.query_time", 64 | unit: {:native, :millisecond}, 65 | description: "The time spent executing the query" 66 | ), 67 | summary("phx1_7.repo.query.queue_time", 68 | unit: {:native, :millisecond}, 69 | description: "The time spent waiting for a database connection" 70 | ), 71 | summary("phx1_7.repo.query.idle_time", 72 | unit: {:native, :millisecond}, 73 | description: 74 | "The time the connection spent waiting before being checked out for the query" 75 | ), 76 | 77 | # VM Metrics 78 | summary("vm.memory.total", unit: {:byte, :kilobyte}), 79 | summary("vm.total_run_queue_lengths.total"), 80 | summary("vm.total_run_queue_lengths.cpu"), 81 | summary("vm.total_run_queue_lengths.io") 82 | ] 83 | end 84 | 85 | defp periodic_measurements do 86 | [ 87 | # A module, function and arguments to be invoked periodically. 88 | # This function must call :telemetry.execute/3 and a metric must be added above. 89 | # {Phx17Web, :count_users, []} 90 | ] 91 | end 92 | end 93 | -------------------------------------------------------------------------------- /test/support/apps/phx1_7/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Phx17.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :phx1_7, 7 | version: "0.1.0", 8 | elixir: "~> 1.14", 9 | elixirc_paths: elixirc_paths(Mix.env()), 10 | start_permanent: Mix.env() == :prod, 11 | aliases: aliases(), 12 | deps: deps() 13 | ] 14 | end 15 | 16 | # Configuration for the OTP application. 17 | # 18 | # Type `mix help compile.app` for more information. 19 | def application do 20 | [ 21 | mod: {Phx17.Application, []}, 22 | extra_applications: [:logger, :runtime_tools] 23 | ] 24 | end 25 | 26 | # Specifies which paths to compile per environment. 27 | defp elixirc_paths(:test), do: ["lib", "test/support"] 28 | defp elixirc_paths(_), do: ["lib"] 29 | 30 | # Specifies your project dependencies. 31 | # 32 | # Type `mix help deps` for examples and options. 33 | defp deps do 34 | [ 35 | {:phoenix, "~> 1.7"}, 36 | {:phoenix_ecto, "~> 4.6"}, 37 | {:ecto_sql, "~> 3.6"}, 38 | {:postgrex, ">= 0.0.0"}, 39 | {:phoenix_html, "~> 4.0"}, 40 | {:phoenix_html_helpers, "~> 1.0"}, 41 | {:phoenix_live_reload, "~> 1.2", only: :dev}, 42 | {:phoenix_live_view, "~> 1.0"}, 43 | {:heroicons, "~> 0.5"}, 44 | {:floki, ">= 0.37.0", only: :test}, 45 | {:phoenix_live_dashboard, "~> 0.8.6"}, 46 | {:esbuild, "~> 0.5", runtime: Mix.env() == :dev}, 47 | {:tailwind, "~> 0.2.0", runtime: Mix.env() == :dev}, 48 | {:swoosh, "~> 1.3"}, 49 | {:finch, "~> 0.13"}, 50 | {:telemetry_metrics, "~> 0.6"}, 51 | {:telemetry_poller, "~> 1.0"}, 52 | {:gettext, "~> 0.20"}, 53 | {:jason, "~> 1.2"}, 54 | {:plug_cowboy, "~> 2.5"} 55 | ] 56 | end 57 | 58 | # Aliases are shortcuts or tasks specific to the current project. 59 | # For example, to install project dependencies and perform other setup tasks, run: 60 | # 61 | # $ mix setup 62 | # 63 | # See the documentation for `Mix` for more info on aliases. 64 | defp aliases do 65 | [ 66 | setup: ["deps.get", "ecto.setup", "assets.setup", "assets.build"], 67 | "ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"], 68 | "ecto.reset": ["ecto.drop", "ecto.setup"], 69 | test: ["ecto.create --quiet", "ecto.migrate --quiet", "test"], 70 | "assets.setup": ["tailwind.install --if-missing", "esbuild.install --if-missing"], 71 | "assets.build": ["tailwind default", "esbuild default"], 72 | "assets.deploy": ["tailwind default --minify", "esbuild default --minify", "phx.digest"] 73 | ] 74 | end 75 | end 76 | -------------------------------------------------------------------------------- /test/support/apps/phx1_7/priv/gettext/en/LC_MESSAGES/errors.po: -------------------------------------------------------------------------------- 1 | ## `msgid`s in this file come from POT (.pot) files. 2 | ## 3 | ## Do not add, change, or remove `msgid`s manually here as 4 | ## they're tied to the ones in the corresponding POT file 5 | ## (with the same domain). 6 | ## 7 | ## Use `mix gettext.extract --merge` or `mix gettext.merge` 8 | ## to merge POT files into PO files. 9 | msgid "" 10 | msgstr "" 11 | "Language: en\n" 12 | 13 | ## From Ecto.Changeset.cast/4 14 | msgid "can't be blank" 15 | msgstr "" 16 | 17 | ## From Ecto.Changeset.unique_constraint/3 18 | msgid "has already been taken" 19 | msgstr "" 20 | 21 | ## From Ecto.Changeset.put_change/3 22 | msgid "is invalid" 23 | msgstr "" 24 | 25 | ## From Ecto.Changeset.validate_acceptance/3 26 | msgid "must be accepted" 27 | msgstr "" 28 | 29 | ## From Ecto.Changeset.validate_format/3 30 | msgid "has invalid format" 31 | msgstr "" 32 | 33 | ## From Ecto.Changeset.validate_subset/3 34 | msgid "has an invalid entry" 35 | msgstr "" 36 | 37 | ## From Ecto.Changeset.validate_exclusion/3 38 | msgid "is reserved" 39 | msgstr "" 40 | 41 | ## From Ecto.Changeset.validate_confirmation/3 42 | msgid "does not match confirmation" 43 | msgstr "" 44 | 45 | ## From Ecto.Changeset.no_assoc_constraint/3 46 | msgid "is still associated with this entry" 47 | msgstr "" 48 | 49 | msgid "are still associated with this entry" 50 | msgstr "" 51 | 52 | ## From Ecto.Changeset.validate_length/3 53 | msgid "should have %{count} item(s)" 54 | msgid_plural "should have %{count} item(s)" 55 | msgstr[0] "" 56 | msgstr[1] "" 57 | 58 | msgid "should be %{count} character(s)" 59 | msgid_plural "should be %{count} character(s)" 60 | msgstr[0] "" 61 | msgstr[1] "" 62 | 63 | msgid "should be %{count} byte(s)" 64 | msgid_plural "should be %{count} byte(s)" 65 | msgstr[0] "" 66 | msgstr[1] "" 67 | 68 | msgid "should have at least %{count} item(s)" 69 | msgid_plural "should have at least %{count} item(s)" 70 | msgstr[0] "" 71 | msgstr[1] "" 72 | 73 | msgid "should be at least %{count} character(s)" 74 | msgid_plural "should be at least %{count} character(s)" 75 | msgstr[0] "" 76 | msgstr[1] "" 77 | 78 | msgid "should be at least %{count} byte(s)" 79 | msgid_plural "should be at least %{count} byte(s)" 80 | msgstr[0] "" 81 | msgstr[1] "" 82 | 83 | msgid "should have at most %{count} item(s)" 84 | msgid_plural "should have at most %{count} item(s)" 85 | msgstr[0] "" 86 | msgstr[1] "" 87 | 88 | msgid "should be at most %{count} character(s)" 89 | msgid_plural "should be at most %{count} character(s)" 90 | msgstr[0] "" 91 | msgstr[1] "" 92 | 93 | msgid "should be at most %{count} byte(s)" 94 | msgid_plural "should be at most %{count} byte(s)" 95 | msgstr[0] "" 96 | msgstr[1] "" 97 | 98 | ## From Ecto.Changeset.validate_number/3 99 | msgid "must be less than %{number}" 100 | msgstr "" 101 | 102 | msgid "must be greater than %{number}" 103 | msgstr "" 104 | 105 | msgid "must be less than or equal to %{number}" 106 | msgstr "" 107 | 108 | msgid "must be greater than or equal to %{number}" 109 | msgstr "" 110 | 111 | msgid "must be equal to %{number}" 112 | msgstr "" 113 | -------------------------------------------------------------------------------- /test/support/apps/phx1_7/priv/gettext/errors.pot: -------------------------------------------------------------------------------- 1 | ## This is a PO Template file. 2 | ## 3 | ## `msgid`s here are often extracted from source code. 4 | ## Add new translations manually only if they're dynamic 5 | ## translations that can't be statically extracted. 6 | ## 7 | ## Run `mix gettext.extract` to bring this file up to 8 | ## date. Leave `msgstr`s empty as changing them here has no 9 | ## effect: edit them in PO (`.po`) files instead. 10 | 11 | ## From Ecto.Changeset.cast/4 12 | msgid "can't be blank" 13 | msgstr "" 14 | 15 | ## From Ecto.Changeset.unique_constraint/3 16 | msgid "has already been taken" 17 | msgstr "" 18 | 19 | ## From Ecto.Changeset.put_change/3 20 | msgid "is invalid" 21 | msgstr "" 22 | 23 | ## From Ecto.Changeset.validate_acceptance/3 24 | msgid "must be accepted" 25 | msgstr "" 26 | 27 | ## From Ecto.Changeset.validate_format/3 28 | msgid "has invalid format" 29 | msgstr "" 30 | 31 | ## From Ecto.Changeset.validate_subset/3 32 | msgid "has an invalid entry" 33 | msgstr "" 34 | 35 | ## From Ecto.Changeset.validate_exclusion/3 36 | msgid "is reserved" 37 | msgstr "" 38 | 39 | ## From Ecto.Changeset.validate_confirmation/3 40 | msgid "does not match confirmation" 41 | msgstr "" 42 | 43 | ## From Ecto.Changeset.no_assoc_constraint/3 44 | msgid "is still associated with this entry" 45 | msgstr "" 46 | 47 | msgid "are still associated with this entry" 48 | msgstr "" 49 | 50 | ## From Ecto.Changeset.validate_length/3 51 | msgid "should have %{count} item(s)" 52 | msgid_plural "should have %{count} item(s)" 53 | msgstr[0] "" 54 | msgstr[1] "" 55 | 56 | msgid "should be %{count} character(s)" 57 | msgid_plural "should be %{count} character(s)" 58 | msgstr[0] "" 59 | msgstr[1] "" 60 | 61 | msgid "should be %{count} byte(s)" 62 | msgid_plural "should be %{count} byte(s)" 63 | msgstr[0] "" 64 | msgstr[1] "" 65 | 66 | msgid "should have at least %{count} item(s)" 67 | msgid_plural "should have at least %{count} item(s)" 68 | msgstr[0] "" 69 | msgstr[1] "" 70 | 71 | msgid "should be at least %{count} character(s)" 72 | msgid_plural "should be at least %{count} character(s)" 73 | msgstr[0] "" 74 | msgstr[1] "" 75 | 76 | msgid "should be at least %{count} byte(s)" 77 | msgid_plural "should be at least %{count} byte(s)" 78 | msgstr[0] "" 79 | msgstr[1] "" 80 | 81 | msgid "should have at most %{count} item(s)" 82 | msgid_plural "should have at most %{count} item(s)" 83 | msgstr[0] "" 84 | msgstr[1] "" 85 | 86 | msgid "should be at most %{count} character(s)" 87 | msgid_plural "should be at most %{count} character(s)" 88 | msgstr[0] "" 89 | msgstr[1] "" 90 | 91 | msgid "should be at most %{count} byte(s)" 92 | msgid_plural "should be at most %{count} byte(s)" 93 | msgstr[0] "" 94 | msgstr[1] "" 95 | 96 | ## From Ecto.Changeset.validate_number/3 97 | msgid "must be less than %{number}" 98 | msgstr "" 99 | 100 | msgid "must be greater than %{number}" 101 | msgstr "" 102 | 103 | msgid "must be less than or equal to %{number}" 104 | msgstr "" 105 | 106 | msgid "must be greater than or equal to %{number}" 107 | msgstr "" 108 | 109 | msgid "must be equal to %{number}" 110 | msgstr "" 111 | -------------------------------------------------------------------------------- /test/support/apps/phx1_7/priv/repo/migrations/.formatter.exs: -------------------------------------------------------------------------------- 1 | [ 2 | import_deps: [:ecto_sql], 3 | inputs: ["*.exs"] 4 | ] 5 | -------------------------------------------------------------------------------- /test/support/apps/phx1_7/priv/repo/seeds.exs: -------------------------------------------------------------------------------- 1 | # Script for populating the database. You can run it as: 2 | # 3 | # mix run priv/repo/seeds.exs 4 | # 5 | # Inside the script, you can read and write to any of your 6 | # repositories directly: 7 | # 8 | # Phx17.Repo.insert!(%Phx17.SomeSchema{}) 9 | # 10 | # We recommend using the bang functions (`insert!`, `update!` 11 | # and so on) as they will fail if something goes wrong. 12 | -------------------------------------------------------------------------------- /test/support/apps/phx1_7/priv/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mojotech/torch/26ac2f942d7ab89cf2cd27caa01d3b11340540f8/test/support/apps/phx1_7/priv/static/favicon.ico -------------------------------------------------------------------------------- /test/support/apps/phx1_7/priv/static/robots.txt: -------------------------------------------------------------------------------- 1 | # See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file 2 | # 3 | # To ban all spiders from the entire site uncomment the next two lines: 4 | # User-agent: * 5 | # Disallow: / 6 | -------------------------------------------------------------------------------- /test/support/apps/phx1_7/test/phx1_7_web/controllers/error_html_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Phx17Web.ErrorHTMLTest do 2 | use Phx17Web.ConnCase, async: true 3 | 4 | # Bring render_to_string/4 for testing custom views 5 | import Phoenix.Template 6 | 7 | test "renders 404.html" do 8 | assert render_to_string(Phx17Web.ErrorHTML, "404", "html", []) == "Not Found" 9 | end 10 | 11 | test "renders 500.html" do 12 | assert render_to_string(Phx17Web.ErrorHTML, "500", "html", []) == "Internal Server Error" 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /test/support/apps/phx1_7/test/phx1_7_web/controllers/error_json_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Phx17Web.ErrorJSONTest do 2 | use Phx17Web.ConnCase, async: true 3 | 4 | test "renders 404" do 5 | assert Phx17Web.ErrorJSON.render("404.json", %{}) == %{errors: %{detail: "Not Found"}} 6 | end 7 | 8 | test "renders 500" do 9 | assert Phx17Web.ErrorJSON.render("500.json", %{}) == 10 | %{errors: %{detail: "Internal Server Error"}} 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /test/support/apps/phx1_7/test/phx1_7_web/controllers/page_controller_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Phx17Web.PageControllerTest do 2 | use Phx17Web.ConnCase 3 | 4 | test "GET /", %{conn: conn} do 5 | conn = get(conn, ~p"/") 6 | assert html_response(conn, 200) =~ "Peace of mind from prototype to production" 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /test/support/apps/phx1_7/test/support/conn_case.ex: -------------------------------------------------------------------------------- 1 | defmodule Phx17Web.ConnCase do 2 | @moduledoc """ 3 | This module defines the test case to be used by 4 | tests that require setting up a connection. 5 | 6 | Such tests rely on `Phoenix.ConnTest` and also 7 | import other functionality to make it easier 8 | to build common data structures and query the data layer. 9 | 10 | Finally, if the test case interacts with the database, 11 | we enable the SQL sandbox, so changes done to the database 12 | are reverted at the end of every test. If you are using 13 | PostgreSQL, you can even run database tests asynchronously 14 | by setting `use Phx17Web.ConnCase, async: true`, although 15 | this option is not recommended for other databases. 16 | """ 17 | 18 | use ExUnit.CaseTemplate 19 | 20 | using do 21 | quote do 22 | # The default endpoint for testing 23 | @endpoint Phx17Web.Endpoint 24 | 25 | use Phx17Web, :verified_routes 26 | 27 | # Import conveniences for testing with connections 28 | import Plug.Conn 29 | import Phoenix.ConnTest 30 | import Phx17Web.ConnCase 31 | end 32 | end 33 | 34 | setup tags do 35 | Phx17.DataCase.setup_sandbox(tags) 36 | {:ok, conn: Phoenix.ConnTest.build_conn()} 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /test/support/apps/phx1_7/test/support/data_case.ex: -------------------------------------------------------------------------------- 1 | defmodule Phx17.DataCase do 2 | @moduledoc """ 3 | This module defines the setup for tests requiring 4 | access to the application's data layer. 5 | 6 | You may define functions here to be used as helpers in 7 | your tests. 8 | 9 | Finally, if the test case interacts with the database, 10 | we enable the SQL sandbox, so changes done to the database 11 | are reverted at the end of every test. If you are using 12 | PostgreSQL, you can even run database tests asynchronously 13 | by setting `use Phx17.DataCase, async: true`, although 14 | this option is not recommended for other databases. 15 | """ 16 | 17 | use ExUnit.CaseTemplate 18 | 19 | using do 20 | quote do 21 | alias Phx17.Repo 22 | 23 | import Ecto 24 | import Ecto.Changeset 25 | import Ecto.Query 26 | import Phx17.DataCase 27 | end 28 | end 29 | 30 | setup tags do 31 | Phx17.DataCase.setup_sandbox(tags) 32 | :ok 33 | end 34 | 35 | @doc """ 36 | Sets up the sandbox based on the test tags. 37 | """ 38 | def setup_sandbox(tags) do 39 | pid = Ecto.Adapters.SQL.Sandbox.start_owner!(Phx17.Repo, shared: not tags[:async]) 40 | on_exit(fn -> Ecto.Adapters.SQL.Sandbox.stop_owner(pid) end) 41 | end 42 | 43 | @doc """ 44 | A helper that transforms changeset errors into a map of messages. 45 | 46 | assert {:error, changeset} = Accounts.create_user(%{password: "short"}) 47 | assert "password is too short" in errors_on(changeset).password 48 | assert %{password: ["password is too short"]} = errors_on(changeset) 49 | 50 | """ 51 | def errors_on(changeset) do 52 | Ecto.Changeset.traverse_errors(changeset, fn {message, opts} -> 53 | Regex.replace(~r"%{(\w+)}", message, fn _, key -> 54 | opts |> Keyword.get(String.to_existing_atom(key), key) |> to_string() 55 | end) 56 | end) 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /test/support/apps/phx1_7/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | Ecto.Adapters.SQL.Sandbox.mode(Phx17.Repo, :manual) 3 | -------------------------------------------------------------------------------- /test/support/cases/mix_case.ex: -------------------------------------------------------------------------------- 1 | defmodule Torch.MixCase do 2 | @moduledoc false 3 | 4 | use ExUnit.CaseTemplate 5 | 6 | using do 7 | quote do 8 | import Torch.MixCase 9 | end 10 | end 11 | 12 | @doc false 13 | # Generates tests on the given mix task to ensure it handles errors properly 14 | defmacro test_mix_config_errors(task) do 15 | quote location: :keep do 16 | test "raises error if :otp_app not specified" do 17 | assert_raise Mix.Error, 18 | """ 19 | You need to specify an OTP app to generate files within. Either 20 | configure it as shown below or pass it in via the `--app` option. 21 | 22 | config :torch, 23 | otp_app: :my_app 24 | 25 | # Alternatively 26 | mix #{unquote(task)} --app my_app 27 | """, 28 | fn -> 29 | Mix.Task.rerun(unquote(task), ["--format", "eex"]) 30 | end 31 | end 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /test/support/patches/install-route.diff: -------------------------------------------------------------------------------- 1 | diff --git a/lib/phx1_7_web/router.ex b/lib/phx1_7_web/router.ex 2 | index 437a6d3..5625ebb 100644 3 | --- a/lib/phx1_7_web/router.ex 4 | +++ b/lib/phx1_7_web/router.ex 5 | @@ -18,6 +18,7 @@ defmodule Phx17Web.Router do 6 | pipe_through :browser 7 | 8 | get "/", PageController, :home 9 | + resources "/posts", PostController 10 | end 11 | 12 | # Other scopes may use custom stacks. 13 | -------------------------------------------------------------------------------- /test/support/patches/install-torch.diff: -------------------------------------------------------------------------------- 1 | diff --git a/config/config.exs b/config/config.exs 2 | index f58eb52..a3022e3 100644 3 | --- a/config/config.exs 4 | +++ b/config/config.exs 5 | @@ -59,6 +59,9 @@ config :logger, :console, 6 | # Use Jason for JSON parsing in Phoenix 7 | config :phoenix, :json_library, Jason 8 | 9 | +config :torch, 10 | + otp_app: :phx1_7 11 | + 12 | # Import environment specific config. This must remain at the bottom 13 | # of this file so it overrides the configuration defined above. 14 | import_config "#{config_env()}.exs" 15 | diff --git a/lib/phx1_7_web/endpoint.ex b/lib/phx1_7_web/endpoint.ex 16 | index 622d5e1..804a311 100644 17 | --- a/lib/phx1_7_web/endpoint.ex 18 | +++ b/lib/phx1_7_web/endpoint.ex 19 | @@ -23,6 +23,12 @@ defmodule Phx17Web.Endpoint do 20 | gzip: false, 21 | only: Phx17Web.static_paths() 22 | 23 | + plug Plug.Static, 24 | + at: "/torch", 25 | + from: {:torch, "priv/static"}, 26 | + gzip: true, 27 | + cache_control_for_etags: "public, max-age=86400" 28 | + 29 | # Code reloading can be explicitly enabled under the 30 | # :code_reloader configuration of your endpoint. 31 | if code_reloading? do 32 | diff --git a/mix.exs b/mix.exs 33 | index 34ce721..257007a 100644 34 | --- a/mix.exs 35 | +++ b/mix.exs 36 | @@ -51,6 +51,8 @@ defmodule Phx17.MixProject do 37 | {:telemetry_poller, "~> 1.0"}, 38 | {:gettext, "~> 0.20"}, 39 | {:jason, "~> 1.2"}, 40 | - {:plug_cowboy, "~> 2.5"} 41 | + {:plug_cowboy, "~> 2.5"}, 42 | + {:ssl_verify_fun, manager: :rebar3, runtime: false, override: true}, 43 | + {:torch, path: "../../../../"} 44 | ] 45 | end 46 | -------------------------------------------------------------------------------- /test/torch/helpers_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Torch.HelpersTest do 2 | use ExUnit.Case, async: true 3 | 4 | doctest Torch.Helpers, import: true 5 | end 6 | -------------------------------------------------------------------------------- /test/torch/i18n_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Torch.I18nTest do 2 | use ExUnit.Case 3 | 4 | defmodule CustomI18nBackend do 5 | def message("Contains"), do: "** CUSTOMIZED **" 6 | def message(t), do: Torch.I18n.Backend.message(t) 7 | end 8 | 9 | setup_all do 10 | on_exit(fn -> 11 | Application.put_env(:torch, :i18n_backend, Torch.I18n.Backend) 12 | end) 13 | 14 | [i18n_backend: Torch.Config.i18n_backend()] 15 | end 16 | 17 | test "uses a default backend if none configured", context do 18 | Application.put_env(:torch, :i18n_backend, context[:i18n_backend]) 19 | 20 | assert Torch.I18n.Backend == Torch.Config.i18n_backend() 21 | assert "Contains" == Torch.I18n.message("Contains") 22 | end 23 | 24 | test "allows a custom backend to be defined" do 25 | Application.put_env(:torch, :i18n_backend, CustomI18nBackend) 26 | 27 | assert CustomI18nBackend == Torch.Config.i18n_backend() 28 | assert "** CUSTOMIZED **" == Torch.I18n.message("Contains") 29 | assert "Equals" == Torch.I18n.message("Equals") 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /test/torch/test_helper.exs: -------------------------------------------------------------------------------- 1 | if System.get_env("CI") do 2 | ExUnit.configure(formatters: [ExUnit.CLIFormatter]) 3 | else 4 | ExUnit.configure(formatters: [ExUnit.CLIFormatter, ExUnitNotifier]) 5 | end 6 | 7 | ExUnit.start() 8 | -------------------------------------------------------------------------------- /test/torch/torch_test.exs: -------------------------------------------------------------------------------- 1 | defmodule TorchTest do 2 | use ExUnit.Case 3 | 4 | doctest Torch 5 | end 6 | -------------------------------------------------------------------------------- /test/torch/views/flash_view_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Torch.FlashViewTest do 2 | use ExUnit.Case 3 | 4 | doctest Torch.FlashView, import: true 5 | end 6 | -------------------------------------------------------------------------------- /test/torch/views/page_view_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Torch.PageViewTest do 2 | use ExUnit.Case 3 | 4 | doctest Torch.PageView, import: true 5 | end 6 | -------------------------------------------------------------------------------- /test/torch/views/table_view_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Torch.TableViewTest do 2 | use ExUnit.Case 3 | 4 | import Phoenix.HTML, only: [safe_to_string: 1] 5 | 6 | doctest Torch.TableView, import: true 7 | end 8 | --------------------------------------------------------------------------------