├── .editorconfig
├── .env.example
├── .github
├── CODEOWNERS
├── CONTRIBUTING.md
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── WORKFLOW.md
└── workflows
│ └── test.yml
├── .gitignore
├── .gitignore.dist
├── .prettierrc
├── .styleci.yml
├── .vscode
└── settings.json
├── LICENSE
├── README.md
├── composer.json
├── config
├── analytics.php
├── blade-icons.php
├── cms.php
├── cms
│ ├── editor.php
│ ├── embeds.php
│ ├── enabled.php
│ ├── form.php
│ ├── menu.php
│ └── social.php
├── deploy.php
├── htmlmin.php
├── seotools.php
├── translatable.php
├── twill-navigation.php
├── twill.php
└── twill
│ ├── block_editor.php
│ ├── dashboard.php
│ ├── file_library.php
│ ├── glide.php
│ └── media_library.php
├── database
├── factories
│ ├── BlockFactory.php
│ ├── CategoryFactory.php
│ ├── CityLabFactory.php
│ ├── FormFactory.php
│ ├── MediaFactory.php
│ ├── MenuFactory.php
│ ├── PageFactory.php
│ ├── PartnerFactory.php
│ ├── PersonFactory.php
│ ├── ResponseFactory.php
│ └── UserFactory.php
└── migrations
│ ├── default
│ ├── 2020_02_10_000001_create_pages_tables.php
│ ├── 2020_02_10_000002_create_menus_tables.php
│ ├── 2020_02_10_000003_create_forms_tables.php
│ ├── 2020_02_10_000004_create_responses_tables.php
│ ├── 2020_02_10_000005_create_partners_tables.php
│ ├── 2020_02_10_000006_create_posts_tables.php
│ └── 2020_02_10_000007_create_categories_tables.php
│ └── people
│ ├── 2020_05_04_000001_create_city_labs_tables.php
│ └── 2020_05_04_000002_create_people_tables.php
├── deploy
└── assets.php
├── package.json
├── phpcs.xml
├── phpstan.neon
├── phpunit.xml
├── resources
├── assets
│ ├── ckeditor
│ │ ├── src
│ │ │ └── ckeditor.js
│ │ └── webpack.config.js
│ ├── css
│ │ ├── app.pcss
│ │ ├── content.pcss
│ │ └── fonts.pcss
│ ├── fonts
│ │ └── titillium-web-latin-ext
│ │ │ ├── 200-italic.woff
│ │ │ ├── 200-italic.woff2
│ │ │ ├── 200.woff
│ │ │ ├── 200.woff2
│ │ │ ├── 300-italic.woff
│ │ │ ├── 300-italic.woff2
│ │ │ ├── 300.woff
│ │ │ ├── 300.woff2
│ │ │ ├── 400-italic.woff
│ │ │ ├── 400-italic.woff2
│ │ │ ├── 400.woff
│ │ │ ├── 400.woff2
│ │ │ ├── 600-italic.woff
│ │ │ ├── 600-italic.woff2
│ │ │ ├── 600.woff
│ │ │ ├── 600.woff2
│ │ │ ├── 700-italic.woff
│ │ │ ├── 700-italic.woff2
│ │ │ ├── 700.woff
│ │ │ ├── 700.woff2
│ │ │ ├── 900.woff
│ │ │ └── 900.woff2
│ ├── js
│ │ ├── app.js
│ │ └── components
│ │ │ ├── .gitignore
│ │ │ └── Ckeditor.vue
│ └── svg
│ │ ├── 404.svg
│ │ ├── hex.svg
│ │ ├── icons
│ │ ├── author.svg
│ │ ├── calendar.svg
│ │ ├── camera-lens.svg
│ │ ├── camera.svg
│ │ ├── category.svg
│ │ ├── community.svg
│ │ ├── dropdown.svg
│ │ ├── facebook.svg
│ │ ├── github.svg
│ │ ├── global.svg
│ │ ├── instagram.svg
│ │ ├── linkedin.svg
│ │ ├── quote.svg
│ │ ├── tiktok.svg
│ │ ├── triangle-down.svg
│ │ ├── triangle-up.svg
│ │ └── twitter.svg
│ │ ├── logo-gray.svg
│ │ ├── logo-sm-gray.svg
│ │ ├── logo-sm.svg
│ │ └── logo.svg
├── lang
│ ├── en
│ │ ├── admin.php
│ │ ├── date.php
│ │ ├── email.php
│ │ ├── errors.php
│ │ ├── footer.php
│ │ ├── form.php
│ │ ├── misc.php
│ │ ├── pagination.php
│ │ └── validation.php
│ ├── hu
│ │ └── errors.php
│ └── ro
│ │ ├── date.php
│ │ └── errors.php
└── views
│ ├── admin
│ ├── blocks
│ │ ├── accordion.blade.php
│ │ ├── button.blade.php
│ │ ├── callToAction.blade.php
│ │ ├── cityLabs.blade.php
│ │ ├── counter.blade.php
│ │ ├── embed.blade.php
│ │ ├── form.blade.php
│ │ ├── formSection.blade.php
│ │ ├── hero.blade.php
│ │ ├── html.blade.php
│ │ ├── imageGrid.blade.php
│ │ ├── imageText.blade.php
│ │ ├── menuItem.blade.php
│ │ ├── newsletter.blade.php
│ │ ├── notice.blade.php
│ │ ├── partners.blade.php
│ │ ├── people.blade.php
│ │ ├── quote.blade.php
│ │ ├── separator.blade.php
│ │ └── text.blade.php
│ ├── categories
│ │ └── form.blade.php
│ ├── cityLabs
│ │ └── form.blade.php
│ ├── forms
│ │ └── form.blade.php
│ ├── menus
│ │ └── form.blade.php
│ ├── pages
│ │ └── form.blade.php
│ ├── partners
│ │ └── form.blade.php
│ ├── people
│ │ └── form.blade.php
│ ├── posts
│ │ └── form.blade.php
│ ├── repeaters
│ │ ├── accordionItem.blade.php
│ │ ├── counterItem.blade.php
│ │ ├── formField.blade.php
│ │ └── subMenuItem.blade.php
│ ├── responses
│ │ └── form.blade.php
│ ├── settings
│ │ ├── mailchimp.blade.php
│ │ ├── site.blade.php
│ │ └── social.blade.php
│ └── utils
│ │ ├── ckeditor.blade.php
│ │ └── menu-item-template.blade.php
│ ├── components
│ ├── button.blade.php
│ ├── container.blade.php
│ ├── figure.blade.php
│ ├── hex-badge.blade.php
│ ├── image.blade.php
│ ├── input.blade.php
│ ├── link.blade.php
│ ├── notice.blade.php
│ └── social-network-link.blade.php
│ ├── emails
│ └── formResponseSubmitted.blade.php
│ ├── errors
│ └── 404.blade.php
│ └── front
│ ├── blocks
│ ├── _container.blade.php
│ ├── accordion.blade.php
│ ├── accordionItem.blade.php
│ ├── button.blade.php
│ ├── callToAction.blade.php
│ ├── cityLabs.blade.php
│ ├── counter.blade.php
│ ├── counterItem.blade.php
│ ├── embed.blade.php
│ ├── form.blade.php
│ ├── formSection.blade.php
│ ├── hero.blade.php
│ ├── html.blade.php
│ ├── imageGrid.blade.php
│ ├── imageText.blade.php
│ ├── newsletter.blade.php
│ ├── notice.blade.php
│ ├── partners.blade.php
│ ├── people.blade.php
│ ├── quote.blade.php
│ ├── separator.blade.php
│ └── text.blade.php
│ ├── categories
│ └── show.blade.php
│ ├── cityLabs
│ ├── index.blade.php
│ └── show.blade.php
│ ├── form
│ ├── _error.blade.php
│ ├── _field.blade.php
│ ├── checkbox.blade.php
│ ├── input.blade.php
│ ├── radio.blade.php
│ ├── select.blade.php
│ └── textarea.blade.php
│ ├── layouts
│ ├── app.blade.php
│ └── blocks.blade.php
│ ├── menu
│ ├── footer.blade.php
│ └── header.blade.php
│ ├── pages
│ └── show.blade.php
│ ├── partials
│ ├── analytics.blade.php
│ ├── footer.blade.php
│ ├── header.blade.php
│ ├── notice.blade.php
│ ├── page-header.blade.php
│ ├── pagination.blade.php
│ └── scripts.blade.php
│ ├── partners
│ └── card.blade.php
│ ├── people
│ └── card.blade.php
│ └── posts
│ ├── card.blade.php
│ ├── index.blade.php
│ └── show.blade.php
├── routes
├── admin.php
└── web.php
├── src
├── CmsServiceProvider.php
├── Commands
│ ├── Build.php
│ ├── Command.php
│ └── Install.php
├── Faker
│ └── PicsumImageProvider.php
├── FakerServiceProvider.php
├── Helpers
│ ├── MailchimpHelper.php
│ ├── SettingsHelper.php
│ ├── SocialHelper.php
│ └── UrlHelper.php
├── Http
│ ├── Controllers
│ │ ├── Admin
│ │ │ ├── CategoryController.php
│ │ │ ├── CityLabController.php
│ │ │ ├── FormController.php
│ │ │ ├── MenuController.php
│ │ │ ├── ModuleController.php
│ │ │ ├── PageController.php
│ │ │ ├── PartnerController.php
│ │ │ ├── PersonController.php
│ │ │ ├── PostController.php
│ │ │ └── ResponseController.php
│ │ └── Front
│ │ │ ├── CategoryController.php
│ │ │ ├── CityLabController.php
│ │ │ ├── Controller.php
│ │ │ ├── FormController.php
│ │ │ ├── NewsletterSubscriptionController.php
│ │ │ ├── PageController.php
│ │ │ └── PostController.php
│ ├── Middleware
│ │ ├── Authenticate.php
│ │ ├── DefaultSeoConfig.php
│ │ └── RedirectTrailingSlash.php
│ └── Requests
│ │ ├── Admin
│ │ ├── CategoryRequest.php
│ │ ├── CityLabRequest.php
│ │ ├── FormRequest.php
│ │ ├── MenuRequest.php
│ │ ├── PageRequest.php
│ │ ├── PartnerRequest.php
│ │ ├── PersonRequest.php
│ │ └── PostRequest.php
│ │ └── Front
│ │ ├── FormRequest.php
│ │ └── NewsletterSubscriptionRequest.php
├── LocaleServiceProvider.php
├── Mail
│ └── FormResponseSubmitted.php
├── Models
│ ├── BaseModel.php
│ ├── Category.php
│ ├── CityLab.php
│ ├── Form.php
│ ├── Menu.php
│ ├── Page.php
│ ├── Partner.php
│ ├── Person.php
│ ├── Post.php
│ ├── Response.php
│ ├── Revisions
│ │ ├── CityLabRevision.php
│ │ ├── PageRevision.php
│ │ └── PostRevision.php
│ ├── Slugs
│ │ ├── CategorySlug.php
│ │ ├── CityLabSlug.php
│ │ ├── PageSlug.php
│ │ └── PostSlug.php
│ └── Translations
│ │ ├── CategoryTranslation.php
│ │ ├── CityLabTranslation.php
│ │ ├── FormTranslation.php
│ │ ├── MenuTranslation.php
│ │ ├── PageTranslation.php
│ │ ├── PersonTranslation.php
│ │ └── PostTranslation.php
├── ObserverServiceProvider.php
├── Observers
│ ├── MenuObserver.php
│ └── SettingTranslationObserver.php
├── Presenters
│ ├── BlockPresenter.php
│ ├── PartnerPresenter.php
│ ├── PersonPresenter.php
│ ├── PostPresenter.php
│ ├── Presenter.php
│ └── ResponsePresenter.php
├── Repositories
│ ├── CategoryRepository.php
│ ├── CityLabRepository.php
│ ├── FormRepository.php
│ ├── MenuRepository.php
│ ├── PageRepository.php
│ ├── PartnerRepository.php
│ ├── PersonRepository.php
│ ├── PostRepository.php
│ └── ResponseRepository.php
├── RouteServiceProvider.php
├── Rules
│ └── OneEmailPerLine.php
└── Traits
│ └── WithSeoTags.php
├── tailwind.config.js
├── tests
├── TestCase.php
└── Unit
│ ├── Helpers
│ ├── SettingsHelperTest.php
│ ├── SocialHelperTest.php
│ └── UrlHelperTest.php
│ ├── Http
│ ├── Controllers
│ │ └── Front
│ │ │ ├── CityLabControllerTest.php
│ │ │ └── PageControllerTest.php
│ └── Middleware
│ │ ├── DefaultSeoConfigTest.php
│ │ └── RedirectTrailingSlashTest.php
│ ├── Models
│ ├── CityLabTest.php
│ ├── FormTest.php
│ ├── MenuTest.php
│ ├── PartnerTest.php
│ └── PersonTest.php
│ ├── Presenters
│ ├── BlockPresenterTest.php
│ ├── PartnerPresenterTest.php
│ └── PersonPresenterTest.php
│ ├── Rules
│ └── OneEmailPerLineTest.php
│ └── Traits
│ └── WithSeoTagsTest.php
└── webpack.mix.js
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 4
7 | trim_trailing_whitespace = true
8 | insert_final_newline = true
9 | end_of_line = lf
10 |
11 | [*.{yml,yaml}]
12 | indent_size = 2
13 |
--------------------------------------------------------------------------------
/.env.example:
--------------------------------------------------------------------------------
1 | APP_NAME=
2 | APP_ENV=local
3 | APP_KEY=
4 | APP_DEBUG=true
5 | APP_URL=localhost
6 |
7 | ADMIN_APP_URL=localhost
8 | ADMIN_APP_PATH=admin
9 |
10 | LOG_CHANNEL=stack
11 |
12 | DB_CONNECTION=mysql
13 | DB_HOST=127.0.0.1
14 | DB_PORT=3306
15 | DB_DATABASE=laravel
16 | DB_USERNAME=root
17 | DB_PASSWORD=
18 |
19 | BROADCAST_DRIVER=log
20 | CACHE_DRIVER=file
21 | QUEUE_CONNECTION=sync
22 | SESSION_DRIVER=file
23 | SESSION_LIFETIME=120
24 |
25 | REDIS_HOST=127.0.0.1
26 | REDIS_PASSWORD=null
27 | REDIS_PORT=6379
28 |
29 | MAIL_DRIVER=smtp
30 | MAIL_HOST=smtp.mailtrap.io
31 | MAIL_PORT=2525
32 | MAIL_USERNAME=null
33 | MAIL_PASSWORD=null
34 | MAIL_ENCRYPTION=null
35 | MAIL_FROM_ADDRESS=null
36 | MAIL_FROM_NAME="${APP_NAME}"
37 |
38 | AWS_ACCESS_KEY_ID=
39 | AWS_SECRET_ACCESS_KEY=
40 | AWS_DEFAULT_REGION=
41 | AWS_BUCKET=
42 | AWS_USE_HTTPS=true
43 |
44 | MEDIA_LIBRARY_ENDPOINT_TYPE=
45 | MEDIA_LIBRARY_CASCADE_DELETE=true
46 | MEDIA_LIBRARY_ACL=private
47 | MEDIA_LIBRARY_FILESIZE_LIMIT=50
48 |
49 | FILE_LIBRARY_ENDPOINT_TYPE=
50 | FILE_LIBRARY_CASCADE_DELETE=true
51 | FILE_LIBRARY_ACL=public-read
52 | FILE_LIBRARY_FILESIZE_LIMIT=50
53 |
54 |
55 | GLIDE_SOURCE=
56 | GLIDE_CACHE=
57 | GLIDE_CACHE_PATH_PREFIX=glide_cache
58 | GLIDE_BASE_URL=
59 | GLIDE_BASE_PATH=img
60 | GLIDE_USE_SIGNED_URLS=false
61 | GLIDE_SIGN_KEY=
62 | GLIDE_DRIVER=gd
63 |
64 | DEPLOY_REPOSITORY=git@github.com:code4romania/[CHANGEME].git
65 |
66 | DEPLOY_PRODUCTION_HOSTNAME=
67 | DEPLOY_PRODUCTION_PATH=
68 |
69 | DEPLOY_STAGING_HOSTNAME=
70 | DEPLOY_STAGING_PATH=
71 |
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # These owners will be the default owners for everything in
2 | # the repo. Unless a later match takes precedence,
3 | # they will be requested for review when someone
4 | # opens a pull request.
5 | * @andreiio
6 |
7 | # More details on creating a codeowners file:
8 | # https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners
9 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. iOS]
28 | - Browser [e.g. chrome, safari]
29 | - Version [e.g. 22]
30 |
31 | **Smartphone (please complete the following information):**
32 | - Device: [e.g. iPhone6]
33 | - OS: [e.g. iOS8.1]
34 | - Browser [e.g. stock browser, safari]
35 | - Version [e.g. 22]
36 |
37 | **Additional context**
38 | Add any other context about the problem here.
39 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: Test
2 |
3 | on: [push]
4 |
5 | jobs:
6 | test:
7 | name: PHP ${{ matrix.php-version }} - ${{ matrix.dependency-version }}
8 | runs-on: ubuntu-latest
9 | strategy:
10 | fail-fast: false
11 | matrix:
12 | php-version:
13 | - 7.4
14 | dependency-version:
15 | # - prefer-lowest
16 | - prefer-stable
17 |
18 | services:
19 | mysql:
20 | image: mariadb:10.4
21 | env:
22 | MYSQL_ALLOW_EMPTY_PASSWORD: yes
23 | MYSQL_DATABASE: code4_cms_tests
24 | ports:
25 | - 3306
26 | options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
27 |
28 | steps:
29 | - name: Checkout code
30 | uses: actions/checkout@v2
31 |
32 | - name: Setup PHP
33 | uses: shivammathur/setup-php@v2
34 | with:
35 | php-version: ${{ matrix.php-version }}
36 | extensions: mbstring, sqlite, pdo_sqlite
37 | coverage: none
38 |
39 | - name: Cache dependencies
40 | uses: actions/cache@v1
41 | with:
42 | path: ~/.composer/cache/files
43 | key: dependencies-php-${{ matrix.php-version }}-composer-${{ hashFiles('composer.json') }}
44 |
45 | - name: Install dependencies
46 | run: composer update --${{ matrix.dependency-version }} --prefer-dist --no-interaction --no-suggest
47 |
48 | - name: Run tests
49 | run: composer test
50 | env:
51 | DB_PORT: ${{ job.services.mysql.ports[3306] }}
52 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /public
2 | /vendor
3 | /node_modules
4 | /coverage
5 | .phpunit.result.cache
6 | package-lock.json
7 | composer.lock
8 |
--------------------------------------------------------------------------------
/.gitignore.dist:
--------------------------------------------------------------------------------
1 | /node_modules
2 | /public/hot
3 | /public/storage
4 | /public/assets
5 | /public/mix-manifest.json
6 | /storage/*.key
7 | /vendor
8 | .env
9 | .env.backup
10 | .phpunit.result.cache
11 | Homestead.json
12 | Homestead.yaml
13 | npm-debug.log
14 | yarn-error.log
15 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "trailingComma": "es5",
3 | "printWidth": 80,
4 | "tabWidth": 4,
5 | "useTabs": false,
6 | "semi": true,
7 | "singleQuote": true,
8 | "overrides": [
9 | {
10 | "files": ["*.yml", "*.yaml"],
11 | "options": {
12 | "tabWidth": 2
13 | }
14 | },
15 | {
16 | "files": ["*.php"],
17 | "options": {
18 | "printWidth": 120
19 | }
20 | }
21 | ]
22 | }
23 |
--------------------------------------------------------------------------------
/.styleci.yml:
--------------------------------------------------------------------------------
1 | preset: psr2
2 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "i18n-ally.localesPaths": "resources/lang"
3 | }
4 |
--------------------------------------------------------------------------------
/config/analytics.php:
--------------------------------------------------------------------------------
1 | env('ANALYTICS_TRACKING_ID'),
9 |
10 | /*
11 | * The view id of which you want to display data.
12 | */
13 | 'view_id' => env('ANALYTICS_VIEW_ID'),
14 |
15 | /*
16 | * Path to the client secret json file. Take a look at the README of this package
17 | * to learn how to get this file. You can also pass the credentials as an array
18 | * instead of a file path.
19 | */
20 | 'service_account_credentials_json' => storage_path('app/analytics/service-account-credentials.json'),
21 |
22 | /*
23 | * The amount of minutes the Google API responses will be cached.
24 | * If you set this to zero, the responses won't be cached at all.
25 | */
26 | 'cache_lifetime_in_minutes' => 60 * 24,
27 |
28 | /*
29 | * Here you may configure the "store" that the underlying Google_Client will
30 | * use to store it's data. You may also add extra parameters that will
31 | * be passed on setCacheConfig (see docs for google-api-php-client).
32 | *
33 | * Optional parameters: "lifetime", "prefix"
34 | */
35 | 'cache' => [
36 | 'store' => 'file',
37 | ],
38 | ];
39 |
--------------------------------------------------------------------------------
/config/cms.php:
--------------------------------------------------------------------------------
1 | [
8 | 'primary',
9 | 'warning',
10 | 'danger',
11 | 'success',
12 | 'black',
13 | 'gray',
14 | 'none',
15 | ]
16 |
17 | ];
18 |
--------------------------------------------------------------------------------
/config/cms/editor.php:
--------------------------------------------------------------------------------
1 | 'tiptap', // 'tiptap' or 'quill'
8 | 'toolbar' => [
9 | ['header' => [2, 3, false]],
10 | 'bold', 'italic', 'underline', 'strike', 'link', 'blockquote',
11 | 'list',
12 |
13 | ['list' => 'ordered'],
14 | ['list' => 'bullet'],
15 | ['script' => 'sub'],
16 | ['script' => 'super'],
17 | ['align' => []],
18 | 'table',
19 | ],
20 |
21 | ];
22 |
--------------------------------------------------------------------------------
/config/cms/embeds.php:
--------------------------------------------------------------------------------
1 | 60 * 60 * 24 * 30,
9 |
10 | 'args' => [
11 | // When set to true, this chooses the bigger image as the main image
12 | // instead the first found, that usually is the most relevant.
13 | 'choose_bigger_image' => true,
14 | ],
15 |
16 | // This should match the aspect raio values defined in tailwind.config.js
17 | 'aspectRatio' => [
18 | '1/1' => 1 / 1,
19 | '5/4' => 5 / 4,
20 | '4/3' => 4 / 3,
21 | '3/2' => 3 / 2,
22 | '5/3' => 5 / 3,
23 | '16/9' => 16 / 9,
24 | '2/1' => 2 / 1,
25 | '3/1' => 3 / 1,
26 | '5/6' => 5 / 6,
27 | '4/5' => 4 / 5,
28 | '3/4' => 3 / 4,
29 | '2/3' => 2 / 3,
30 | '3/5' => 3 / 5,
31 | '9/16' => 9 / 16,
32 | '1/2' => 1 / 2,
33 | '1/3' => 1 / 3,
34 | ],
35 |
36 | ];
37 |
--------------------------------------------------------------------------------
/config/cms/enabled.php:
--------------------------------------------------------------------------------
1 | true,
8 |
9 | ];
10 |
--------------------------------------------------------------------------------
/config/cms/form.php:
--------------------------------------------------------------------------------
1 | [
8 | 'text',
9 | 'textarea',
10 | 'url',
11 | 'email',
12 | 'number',
13 | 'date',
14 | 'file',
15 | 'select',
16 | 'radio',
17 | 'checkbox',
18 | ],
19 |
20 | ];
21 |
--------------------------------------------------------------------------------
/config/cms/menu.php:
--------------------------------------------------------------------------------
1 | [
8 | 'header',
9 | 'footer',
10 | ],
11 |
12 | 'itemTypes' => [
13 | 'external',
14 | 'page',
15 | 'category',
16 | 'blog',
17 | ],
18 |
19 | ];
20 |
--------------------------------------------------------------------------------
/config/cms/social.php:
--------------------------------------------------------------------------------
1 | [
9 | 'facebook' => [
10 | 'name' => 'Facebook',
11 | 'baseUrl' => 'https://www.facebook.com/',
12 | ],
13 | 'twitter' => [
14 | 'name' => 'Twitter',
15 | 'baseUrl' => 'https://twitter.com/',
16 | ],
17 | 'instagram' => [
18 | 'name' => 'Instagram',
19 | 'baseUrl' => 'https://www.instagram.com/',
20 | ],
21 | 'github' => [
22 | 'name' => 'GitHub',
23 | 'baseUrl' => 'https://github.com/',
24 | ],
25 | 'linkedin' => [
26 | 'name' => 'LinkedIn',
27 | 'baseUrl' => 'https://www.linkedin.com/',
28 | ],
29 | 'tiktok' => [
30 | 'name' => 'TikTok',
31 | 'baseUrl' => 'https://www.tiktok.com/@',
32 | ],
33 | ],
34 |
35 | ];
36 |
--------------------------------------------------------------------------------
/config/twill.php:
--------------------------------------------------------------------------------
1 | 'Code4Romania\Cms',
8 |
9 | 'admin_app_url' => env('ADMIN_APP_URL', env('APP_URL', 'http://localhost')),
10 | 'admin_app_path' => env('ADMIN_APP_PATH', 'admin'),
11 |
12 | 'migrations_use_big_integers' => true,
13 | 'load_default_migrations_from_twill' => true,
14 |
15 | 'enabled' => [
16 |
17 | 'users-management' => true,
18 | 'media-library' => true,
19 | 'file-library' => true,
20 | 'dashboard' => true,
21 | 'search' => true,
22 | 'block-editor' => true,
23 | 'buckets' => false,
24 | 'users-image' => false,
25 | 'users-description' => false,
26 | 'site-link' => false,
27 | 'settings' => true,
28 | 'activitylog' => true,
29 |
30 | ],
31 |
32 | ];
33 |
--------------------------------------------------------------------------------
/config/twill/block_editor.php:
--------------------------------------------------------------------------------
1 | 'front.layouts.blocks',
9 |
10 | // Path where a view file per block type is stored
11 | 'block_views_path' => 'front.blocks',
12 |
13 | // Custom mapping of block types and views
14 | 'block_views_mappings' => [],
15 |
16 | // Indicates if childs should be rendered when using repeater in blocks
17 | 'block_preview_render_childs' => false,
18 |
19 | // Allows setting a custom presenter to a block model
20 | 'block_presenter_path' => Code4Romania\Cms\Presenters\BlockPresenter::class,
21 |
22 | //
23 | 'inline_blocks_templates' => true,
24 |
25 | // Use builtin twill blocks
26 | 'use_twill_blocks' => false,
27 |
28 |
29 | 'directories' => [
30 | 'source' => [
31 | 'blocks' => [
32 | [
33 | 'path' => resource_path('views/admin/blocks'),
34 | 'source' => A17\Twill\Services\Blocks\Block::SOURCE_APP,
35 | ],
36 | ],
37 |
38 | 'repeaters' => [
39 | [
40 | 'path' => resource_path('views/admin/repeaters'),
41 | 'source' => A17\Twill\Services\Blocks\Block::SOURCE_APP,
42 | ],
43 | ],
44 |
45 | 'icons' => [
46 | base_path('vendor/area17/twill/frontend/icons'),
47 | resource_path('assets/svg/icons'),
48 | ],
49 | ],
50 |
51 | 'destination' => [
52 | 'make_dir' => true,
53 |
54 | 'blocks' => resource_path('views/admin/blocks'),
55 |
56 | 'repeaters' => resource_path('views/admin/repeaters'),
57 | ],
58 | ],
59 | ];
60 |
--------------------------------------------------------------------------------
/config/twill/dashboard.php:
--------------------------------------------------------------------------------
1 | [
6 | 'enabled' => boolval(env('ANALYTICS_VIEW_ID')),
7 | 'service_account_credentials_json' => storage_path('app/analytics/service-account-credentials.json'),
8 | ],
9 |
10 | 'modules' => [
11 | /**
12 | * @param array $module Array containing the module config params.
13 | *
14 | * 'moduleName' = [
15 | * 'name' => (string) [required] Module name
16 | * 'label' => (string) [optional] If the name of your module above does not work as a label
17 | * 'label_singular' => (string) [optional] If the automated singular version does not work as a label
18 | * 'routePrefix' => (string) [optional] If the module is living under a specific routes group
19 | * 'count' => (boolean) [required] Show total count with link to index of this module
20 | * 'create' => (boolean) [required] Show link in create new dropdown
21 | * 'activity' => (boolean) [required] Show activities on this module in actities list
22 | * 'draft => (boolean) [required] Show drafts of this module for current user
23 | * 'search' => (boolean) [required] Show results for this module in global search
24 | * ]
25 | */
26 |
27 | 'page' => [
28 | 'name' => 'pages',
29 | 'label' => 'Pages',
30 | 'label_singular' => 'Page',
31 | 'routePrefix' => '',
32 | 'count' => true,
33 | 'create' => true,
34 | 'activity' => true,
35 | 'draft' => true,
36 | 'search' => true,
37 | ],
38 |
39 | ],
40 | ];
41 |
--------------------------------------------------------------------------------
/config/twill/file_library.php:
--------------------------------------------------------------------------------
1 | 'twill_file_library',
22 | 'endpoint_type' => env('FILE_LIBRARY_ENDPOINT_TYPE', 'local'),
23 | 'cascade_delete' => env('FILE_LIBRARY_CASCADE_DELETE', true),
24 | 'local_path' => env('FILE_LIBRARY_LOCAL_PATH', 'uploads'),
25 | 'file_service' => env('FILE_LIBRARY_FILE_SERVICE', 'A17\Twill\Services\FileLibrary\Disk'),
26 | 'acl' => env('FILE_LIBRARY_ACL', 'public-read'),
27 | 'filesize_limit' => env('FILE_LIBRARY_FILESIZE_LIMIT', 50),
28 | 'allowed_extensions' => [],
29 | 'prefix_uuid_with_local_path' => false,
30 | ];
31 |
--------------------------------------------------------------------------------
/config/twill/glide.php:
--------------------------------------------------------------------------------
1 | env('GLIDE_SOURCE', storage_path('app/public/' . env('MEDIA_LIBRARY_LOCAL_PATH', 'uploads'))),
15 | 'cache' => env('GLIDE_CACHE', storage_path('app')),
16 | 'cache_path_prefix' => env('GLIDE_CACHE_PATH_PREFIX', 'glide_cache'),
17 | 'base_url' => env('GLIDE_BASE_URL', env('APP_URL', 'http://localhost')),
18 | 'base_path' => env('GLIDE_BASE_PATH', 'img'),
19 | 'use_signed_urls' => env('GLIDE_USE_SIGNED_URLS', false),
20 | 'sign_key' => env('GLIDE_SIGN_KEY'),
21 | 'driver' => env('GLIDE_DRIVER', 'gd'),
22 | 'add_params_to_svgs' => false,
23 |
24 | 'default_params' => [
25 | // 'fm' => 'jpg',
26 | 'q' => '80',
27 | 'fit' => 'max',
28 | ],
29 |
30 | 'lqip_default_params' => [
31 | 'fm' => 'png',
32 | 'blur' => 10,
33 | 'dpr' => 1,
34 | ],
35 |
36 | 'social_default_params' => [
37 | 'fm' => 'jpg',
38 | 'w' => 1200,
39 | 'h' => 630,
40 | 'fit' => 'crop',
41 | ],
42 |
43 | 'cms_default_params' => [
44 | 'q' => '60',
45 | 'dpr' => '1',
46 | ],
47 |
48 | 'presets' => [
49 | //
50 | ],
51 | ];
52 |
--------------------------------------------------------------------------------
/config/twill/media_library.php:
--------------------------------------------------------------------------------
1 | 'twill_media_library',
23 | 'endpoint_type' => env('MEDIA_LIBRARY_ENDPOINT_TYPE', 'local'),
24 | 'cascade_delete' => env('MEDIA_LIBRARY_CASCADE_DELETE', true),
25 | 'local_path' => env('MEDIA_LIBRARY_LOCAL_PATH', 'uploads'),
26 | 'image_service' => env('MEDIA_LIBRARY_IMAGE_SERVICE', 'A17\Twill\Services\MediaLibrary\Glide'),
27 | 'acl' => env('MEDIA_LIBRARY_ACL', 'private'),
28 | 'filesize_limit' => env('MEDIA_LIBRARY_FILESIZE_LIMIT', 50),
29 | 'allowed_extensions' => ['jpg', 'gif', 'png', 'jpeg'],
30 | 'init_alt_text_from_filename' => true,
31 | 'prefix_uuid_with_local_path' => config('twill.file_library.prefix_uuid_with_local_path', false),
32 | 'translated_form_fields' => false,
33 | ];
34 |
--------------------------------------------------------------------------------
/database/factories/BlockFactory.php:
--------------------------------------------------------------------------------
1 | define(Block::class, static function (Faker $faker): array {
11 | return [
12 | 'type' => null,
13 | 'position' => $faker->randomDigitNotNull,
14 | 'content' => [],
15 | ];
16 | });
17 |
--------------------------------------------------------------------------------
/database/factories/FormFactory.php:
--------------------------------------------------------------------------------
1 | define(Form::class, static function (Faker $faker): array {
12 | return [
13 | 'published' => false,
14 | 'store' => false,
15 | 'send' => false,
16 | 'confirm' => false,
17 | 'recipients' => null,
18 | ];
19 | });
20 |
21 | $factory->state(Form::class, 'published', [
22 | 'published' => true,
23 | ]);
24 |
25 | $factory->define(FormTranslation::class, static function (Faker $faker): array {
26 | return [
27 | 'form_id' => null,
28 | 'title' => $faker->sentence,
29 | 'locale' => 'en',
30 | 'active' => false,
31 | ];
32 | });
33 |
34 | $factory->state(FormTranslation::class, 'active', [
35 | 'active' => true,
36 | ]);
37 |
38 | $factory->afterCreating(Form::class, static function (Form $form, Faker $faker): void {
39 | $locales = collect(config('translatable.locales'));
40 |
41 | $form->translation()->saveMany(
42 | $locales->map(function ($locale) use ($form) {
43 | return factory(FormTranslation::class)
44 | ->state('active')
45 | ->create([
46 | 'form_id' => $form->id,
47 | 'locale' => $locale,
48 | ]);
49 | })
50 | );
51 |
52 | // we need to manually "reload" the collection built from the relationship
53 | // otherwise $this->translations()->get() would NOT be the same as $this->translations
54 | $form->load('translations');
55 | });
56 |
--------------------------------------------------------------------------------
/database/factories/MediaFactory.php:
--------------------------------------------------------------------------------
1 | define(Media::class, static function (Faker $faker): array {
11 | $uuid = $faker->uuid;
12 | $width = $faker->numberBetween(500, 1000);
13 | $height = $faker->numberBetween(500, 1000);
14 | $filename = $faker->image(storage_path("app/public/uploads/{$uuid}"), $width, $height, false);
15 |
16 | return [
17 | 'uuid' => $uuid . '/' . $filename,
18 | 'filename' => $filename,
19 | 'width' => $width,
20 | 'height' => $height,
21 | 'alt_text' => $faker->sentence,
22 | 'caption' => null,
23 | ];
24 | });
25 |
--------------------------------------------------------------------------------
/database/factories/MenuFactory.php:
--------------------------------------------------------------------------------
1 | define(Menu::class, static function (Faker $faker): array {
12 | return [
13 | 'published' => false,
14 | 'location' => null,
15 | ];
16 | });
17 |
18 |
19 | $factory->state(Menu::class, 'published', [
20 | 'published' => true,
21 | ]);
22 |
23 | $factory->state(Menu::class, 'header', [
24 | 'location' => 'header',
25 | ]);
26 |
27 | $factory->state(Menu::class, 'footer', [
28 | 'location' => 'footer',
29 | ]);
30 |
31 |
32 | $factory->state(MenuTranslation::class, 'active', [
33 | 'active' => true,
34 | ]);
35 |
36 | $factory->define(MenuTranslation::class, static function (Faker $faker): array {
37 | return [];
38 | });
39 |
40 | $factory->afterCreating(Menu::class, static function (Menu $menu, Faker $faker) {
41 | $locales = collect(config('translatable.locales'));
42 |
43 | $menu->translation()->saveMany(
44 | $locales->map(function ($locale) use ($menu) {
45 | return factory(MenuTranslation::class)
46 | ->state('active')
47 | ->create([
48 | 'menu_id' => $menu->id,
49 | 'locale' => $locale,
50 | ]);
51 | })
52 | );
53 |
54 | // we need to manually "reload" the collection built from the relationship
55 | // otherwise $this->translations()->get() would NOT be the same as $this->translations
56 | $menu->load('translations');
57 | });
58 |
--------------------------------------------------------------------------------
/database/factories/PartnerFactory.php:
--------------------------------------------------------------------------------
1 | define(Partner::class, static function (Faker $faker): array {
11 | return [
12 | 'published' => false,
13 | 'name' => $faker->name,
14 | 'website' => $faker->boolean(75) ? 'https://' . $faker->safeEmailDomain : null,
15 | ];
16 | });
17 |
18 |
19 | $factory->state(Partner::class, 'published', [
20 | 'published' => true,
21 | ]);
22 |
--------------------------------------------------------------------------------
/database/factories/PersonFactory.php:
--------------------------------------------------------------------------------
1 | define(Person::class, static function (Faker $faker): array {
12 | return [
13 | 'published' => false,
14 | 'name' => $faker->name,
15 | ];
16 | });
17 |
18 |
19 | $factory->state(Person::class, 'published', [
20 | 'published' => true,
21 | ]);
22 |
23 |
24 | $factory->state(PersonTranslation::class, 'active', [
25 | 'active' => true,
26 | ]);
27 |
28 | $factory->define(PersonTranslation::class, static function (Faker $faker): array {
29 | return [];
30 | });
31 |
32 | $factory->afterCreating(Person::class, static function (Person $person, Faker $faker) {
33 | $locales = collect(config('translatable.locales'));
34 |
35 | $person->translation()->saveMany(
36 | $locales->map(function ($locale) use ($person) {
37 | return factory(PersonTranslation::class)
38 | ->state('active')
39 | ->create([
40 | 'person_id' => $person->id,
41 | 'locale' => $locale,
42 | ]);
43 | })
44 | );
45 |
46 | // we need to manually "reload" the collection built from the relationship
47 | // otherwise $this->translations()->get() would NOT be the same as $this->translations
48 | $person->load('translations');
49 | });
50 |
--------------------------------------------------------------------------------
/database/factories/ResponseFactory.php:
--------------------------------------------------------------------------------
1 | define(Response::class, static function (Faker $faker): array {
12 | return [
13 | 'form_id' => factory(Form::class),
14 | 'data' => collect(range(0, $faker->randomDigitNotNull))
15 | ->map(function () use ($faker) {
16 | return [
17 | 'title' => $faker->sentence,
18 | 'fields' => collect(range(0, $faker->randomDigitNotNull))
19 | ->map(function () use ($faker) {
20 | return [
21 | 'label' => $faker->sentence,
22 | 'value' => $faker->word,
23 | ];
24 | }),
25 | ];
26 | }),
27 | ];
28 | });
29 |
--------------------------------------------------------------------------------
/database/factories/UserFactory.php:
--------------------------------------------------------------------------------
1 | define(User::class, static function (Faker $faker): array {
11 | return [
12 | 'published' => false,
13 | 'name' => $faker->name,
14 | 'email' => $faker->safeEmail,
15 | 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
16 | 'role' => 'VIEWONLY',
17 | ];
18 | });
19 |
20 | $factory->state(User::class, 'active', [
21 | 'published' => true,
22 | ]);
23 |
24 | $factory->state(User::class, 'admin', [
25 | 'role' => 'ADMIN',
26 | ]);
27 |
28 | $factory->state(User::class, 'publisher', [
29 | 'role' => 'PUBLISHER',
30 | ]);
31 |
--------------------------------------------------------------------------------
/database/migrations/default/2020_02_10_000001_create_pages_tables.php:
--------------------------------------------------------------------------------
1 | integer('position')->unsigned()->nullable();
17 |
18 | // enable publication timeframe fields
19 | $table->timestamp('publish_start_date')->nullable();
20 | $table->timestamp('publish_end_date')->nullable();
21 |
22 | $table->boolean('show_header')->default(true);
23 | });
24 |
25 | Schema::create('page_translations', static function (Blueprint $table): void {
26 | createDefaultTranslationsTableFields($table, 'page');
27 | $table->string('title', 200)->nullable();
28 | $table->text('description')->nullable();
29 | });
30 |
31 | Schema::create('page_slugs', static function (Blueprint $table): void {
32 | createDefaultSlugsTableFields($table, 'page');
33 | });
34 |
35 | Schema::create('page_revisions', static function (Blueprint $table): void {
36 | createDefaultRevisionsTableFields($table, 'page');
37 | });
38 | }
39 |
40 | public function down(): void
41 | {
42 | Schema::dropIfExists('page_revisions');
43 | Schema::dropIfExists('page_translations');
44 | Schema::dropIfExists('page_slugs');
45 | Schema::dropIfExists('pages');
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/database/migrations/default/2020_02_10_000002_create_menus_tables.php:
--------------------------------------------------------------------------------
1 | string('location')->nullable();
16 | });
17 |
18 | Schema::create('menu_translations', static function (Blueprint $table): void {
19 | createDefaultTranslationsTableFields($table, 'menu');
20 | $table->string('title')->nullable();
21 | });
22 | }
23 |
24 | public function down(): void
25 | {
26 | Schema::dropIfExists('menu_translations');
27 | Schema::dropIfExists('menus');
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/database/migrations/default/2020_02_10_000003_create_forms_tables.php:
--------------------------------------------------------------------------------
1 | boolean('store')->default(false);
16 | $table->boolean('send')->default(false);
17 | $table->boolean('confirm')->default(false);
18 | $table->text('recipients')->nullable();
19 | });
20 |
21 | Schema::create('form_translations', static function (Blueprint $table): void {
22 | createDefaultTranslationsTableFields($table, 'form');
23 | $table->string('title')->nullable();
24 | });
25 | }
26 |
27 | public function down(): void
28 | {
29 | Schema::dropIfExists('form_translations');
30 | Schema::dropIfExists('forms');
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/database/migrations/default/2020_02_10_000004_create_responses_tables.php:
--------------------------------------------------------------------------------
1 | json('data')->nullable();
16 | $table->foreignId('form_id')->constrained();
17 | });
18 | }
19 |
20 | public function down(): void
21 | {
22 | Schema::dropIfExists('responses');
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/database/migrations/default/2020_02_10_000005_create_partners_tables.php:
--------------------------------------------------------------------------------
1 | string('name', 200)->nullable();
17 | $table->string('website', 500)->nullable();
18 |
19 | $table->integer('position')->unsigned()->nullable();
20 | });
21 | }
22 |
23 | public function down()
24 | {
25 | Schema::dropIfExists('partners');
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/database/migrations/default/2020_02_10_000006_create_posts_tables.php:
--------------------------------------------------------------------------------
1 | string('author', 200)->nullable();
17 |
18 | // add those 2 columns to enable publication timeframe fields (you can use publish_start_date only if you don't need to provide the ability to specify an end date)
19 | $table->timestamp('publish_start_date')->nullable();
20 | $table->timestamp('publish_end_date')->nullable();
21 | });
22 |
23 | Schema::create('post_translations', static function (Blueprint $table): void {
24 | createDefaultTranslationsTableFields($table, 'post');
25 | $table->string('title', 200)->nullable();
26 | $table->text('description')->nullable();
27 | });
28 |
29 | Schema::create('post_slugs', static function (Blueprint $table): void {
30 | createDefaultSlugsTableFields($table, 'post');
31 | });
32 |
33 | Schema::create('post_revisions', static function (Blueprint $table): void {
34 | createDefaultRevisionsTableFields($table, 'post');
35 | });
36 | }
37 |
38 | public function down()
39 | {
40 | Schema::dropIfExists('post_revisions');
41 | Schema::dropIfExists('post_translations');
42 | Schema::dropIfExists('post_slugs');
43 | Schema::dropIfExists('posts');
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/database/migrations/default/2020_02_10_000007_create_categories_tables.php:
--------------------------------------------------------------------------------
1 | string('title', 200)->nullable();
20 | $table->text('description')->nullable();
21 | });
22 |
23 | Schema::create('category_slugs', static function (Blueprint $table): void {
24 | createDefaultSlugsTableFields($table, 'category');
25 | });
26 |
27 | Schema::create('category_post', static function (Blueprint $table): void {
28 | $table->{twillIncrementsMethod()}('id');
29 | $table->integer('position')->unsigned()->nullable();
30 | createDefaultRelationshipTableFields($table, 'category', 'post');
31 | });
32 | }
33 |
34 | public function down()
35 | {
36 | Schema::dropIfExists('category_post');
37 | Schema::dropIfExists('category_translations');
38 | Schema::dropIfExists('category_slugs');
39 | Schema::dropIfExists('categories');
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/database/migrations/people/2020_05_04_000001_create_city_labs_tables.php:
--------------------------------------------------------------------------------
1 | string('name', 200)->nullable();
20 | $table->text('description')->nullable();
21 | });
22 |
23 | Schema::create('city_lab_slugs', static function (Blueprint $table): void {
24 | createDefaultSlugsTableFields($table, 'city_lab');
25 | });
26 |
27 | Schema::create('city_lab_revisions', static function (Blueprint $table): void {
28 | createDefaultRevisionsTableFields($table, 'city_lab');
29 | });
30 | }
31 |
32 | public function down()
33 | {
34 | Schema::dropIfExists('city_lab_revisions');
35 | Schema::dropIfExists('city_lab_translations');
36 | Schema::dropIfExists('city_lab_slugs');
37 | Schema::dropIfExists('city_labs');
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/database/migrations/people/2020_05_04_000002_create_people_tables.php:
--------------------------------------------------------------------------------
1 | string('name', 200);
17 | $table->string('linkedin', 200)->nullable();
18 | $table->string('github', 200)->nullable();
19 | });
20 |
21 | Schema::create('person_translations', static function (Blueprint $table): void {
22 | createDefaultTranslationsTableFields($table, 'person');
23 | $table->string('title', 200)->nullable();
24 | $table->text('description')->nullable();
25 | });
26 |
27 | Schema::create('personables', function (Blueprint $table) {
28 | $table->increments('id');
29 | $table->{twillIntegerMethod()}('position')->unsigned()->nullable();
30 | $table->{twillIntegerMethod()}('personable_id')->nullable()->unsigned();
31 | $table->string('personable_type')->nullable();
32 | $table->{twillIntegerMethod()}('person_id')->unsigned();
33 | $table->foreign('person_id', 'fk_personables_person_id')->references('id')->on('people')->onDelete('cascade')->onUpdate('cascade');
34 | $table->index(['personable_type', 'personable_id']);
35 | });
36 | }
37 |
38 | public function down()
39 | {
40 | Schema::dropIfExists('personables');
41 | Schema::dropIfExists('person_translations');
42 | Schema::dropIfExists('people');
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/deploy/assets.php:
--------------------------------------------------------------------------------
1 | local();
15 |
16 | desc('Build frontend assets locally');
17 | task('assets:build', function () {
18 | if (test('[ -d public/assets ]')) {
19 | return;
20 | }
21 |
22 | run('{{bin/npm}} run production');
23 | })->local();
24 |
25 | desc('Upload assets to your hosts');
26 | task('assets:upload', function () {
27 | upload('public/assets/', '{{release_path}}/public/assets/');
28 | });
29 |
--------------------------------------------------------------------------------
/phpcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | src
8 | tests
9 |
10 | migrations/*
11 | seeds/*
12 | vendor/*
13 | *.blade.php
14 | *.js
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/phpstan.neon:
--------------------------------------------------------------------------------
1 | includes:
2 | - ./vendor/nunomaduro/larastan/extension.neon
3 |
4 | parameters:
5 |
6 | paths:
7 | - src
8 |
9 | # The level 8 is the highest level
10 | level: 5
11 |
12 | ignoreErrors:
13 | - '#Unsafe usage of new static#'
14 |
15 | excludes_analyse:
16 | - ./*/*/FileToBeExcluded.php
17 |
18 | # checkMissingIterableValueType: false
19 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
15 |
16 |
17 | ./tests/Unit
18 |
19 |
20 |
21 |
22 | src
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/resources/assets/css/app.pcss:
--------------------------------------------------------------------------------
1 | @import 'tailwindcss/base';
2 | @import 'tailwindcss/components';
3 | @import 'tailwindcss/utilities';
4 |
5 | @import 'fonts.pcss';
6 | @import 'content.pcss';
7 |
8 | [x-cloak] {
9 | display: none;
10 | }
11 |
--------------------------------------------------------------------------------
/resources/assets/fonts/titillium-web-latin-ext/200-italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/cms/c83a48b5902a7b2fafbb56abd38df4d95a1c1883/resources/assets/fonts/titillium-web-latin-ext/200-italic.woff
--------------------------------------------------------------------------------
/resources/assets/fonts/titillium-web-latin-ext/200-italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/cms/c83a48b5902a7b2fafbb56abd38df4d95a1c1883/resources/assets/fonts/titillium-web-latin-ext/200-italic.woff2
--------------------------------------------------------------------------------
/resources/assets/fonts/titillium-web-latin-ext/200.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/cms/c83a48b5902a7b2fafbb56abd38df4d95a1c1883/resources/assets/fonts/titillium-web-latin-ext/200.woff
--------------------------------------------------------------------------------
/resources/assets/fonts/titillium-web-latin-ext/200.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/cms/c83a48b5902a7b2fafbb56abd38df4d95a1c1883/resources/assets/fonts/titillium-web-latin-ext/200.woff2
--------------------------------------------------------------------------------
/resources/assets/fonts/titillium-web-latin-ext/300-italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/cms/c83a48b5902a7b2fafbb56abd38df4d95a1c1883/resources/assets/fonts/titillium-web-latin-ext/300-italic.woff
--------------------------------------------------------------------------------
/resources/assets/fonts/titillium-web-latin-ext/300-italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/cms/c83a48b5902a7b2fafbb56abd38df4d95a1c1883/resources/assets/fonts/titillium-web-latin-ext/300-italic.woff2
--------------------------------------------------------------------------------
/resources/assets/fonts/titillium-web-latin-ext/300.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/cms/c83a48b5902a7b2fafbb56abd38df4d95a1c1883/resources/assets/fonts/titillium-web-latin-ext/300.woff
--------------------------------------------------------------------------------
/resources/assets/fonts/titillium-web-latin-ext/300.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/cms/c83a48b5902a7b2fafbb56abd38df4d95a1c1883/resources/assets/fonts/titillium-web-latin-ext/300.woff2
--------------------------------------------------------------------------------
/resources/assets/fonts/titillium-web-latin-ext/400-italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/cms/c83a48b5902a7b2fafbb56abd38df4d95a1c1883/resources/assets/fonts/titillium-web-latin-ext/400-italic.woff
--------------------------------------------------------------------------------
/resources/assets/fonts/titillium-web-latin-ext/400-italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/cms/c83a48b5902a7b2fafbb56abd38df4d95a1c1883/resources/assets/fonts/titillium-web-latin-ext/400-italic.woff2
--------------------------------------------------------------------------------
/resources/assets/fonts/titillium-web-latin-ext/400.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/cms/c83a48b5902a7b2fafbb56abd38df4d95a1c1883/resources/assets/fonts/titillium-web-latin-ext/400.woff
--------------------------------------------------------------------------------
/resources/assets/fonts/titillium-web-latin-ext/400.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/cms/c83a48b5902a7b2fafbb56abd38df4d95a1c1883/resources/assets/fonts/titillium-web-latin-ext/400.woff2
--------------------------------------------------------------------------------
/resources/assets/fonts/titillium-web-latin-ext/600-italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/cms/c83a48b5902a7b2fafbb56abd38df4d95a1c1883/resources/assets/fonts/titillium-web-latin-ext/600-italic.woff
--------------------------------------------------------------------------------
/resources/assets/fonts/titillium-web-latin-ext/600-italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/cms/c83a48b5902a7b2fafbb56abd38df4d95a1c1883/resources/assets/fonts/titillium-web-latin-ext/600-italic.woff2
--------------------------------------------------------------------------------
/resources/assets/fonts/titillium-web-latin-ext/600.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/cms/c83a48b5902a7b2fafbb56abd38df4d95a1c1883/resources/assets/fonts/titillium-web-latin-ext/600.woff
--------------------------------------------------------------------------------
/resources/assets/fonts/titillium-web-latin-ext/600.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/cms/c83a48b5902a7b2fafbb56abd38df4d95a1c1883/resources/assets/fonts/titillium-web-latin-ext/600.woff2
--------------------------------------------------------------------------------
/resources/assets/fonts/titillium-web-latin-ext/700-italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/cms/c83a48b5902a7b2fafbb56abd38df4d95a1c1883/resources/assets/fonts/titillium-web-latin-ext/700-italic.woff
--------------------------------------------------------------------------------
/resources/assets/fonts/titillium-web-latin-ext/700-italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/cms/c83a48b5902a7b2fafbb56abd38df4d95a1c1883/resources/assets/fonts/titillium-web-latin-ext/700-italic.woff2
--------------------------------------------------------------------------------
/resources/assets/fonts/titillium-web-latin-ext/700.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/cms/c83a48b5902a7b2fafbb56abd38df4d95a1c1883/resources/assets/fonts/titillium-web-latin-ext/700.woff
--------------------------------------------------------------------------------
/resources/assets/fonts/titillium-web-latin-ext/700.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/cms/c83a48b5902a7b2fafbb56abd38df4d95a1c1883/resources/assets/fonts/titillium-web-latin-ext/700.woff2
--------------------------------------------------------------------------------
/resources/assets/fonts/titillium-web-latin-ext/900.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/cms/c83a48b5902a7b2fafbb56abd38df4d95a1c1883/resources/assets/fonts/titillium-web-latin-ext/900.woff
--------------------------------------------------------------------------------
/resources/assets/fonts/titillium-web-latin-ext/900.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code4romania/cms/c83a48b5902a7b2fafbb56abd38df4d95a1c1883/resources/assets/fonts/titillium-web-latin-ext/900.woff2
--------------------------------------------------------------------------------
/resources/assets/js/app.js:
--------------------------------------------------------------------------------
1 | import 'alpinejs';
2 | import lazyload from '@area17/a17-lazyload';
3 |
4 | document.addEventListener('DOMContentLoaded', () => lazyload());
5 |
--------------------------------------------------------------------------------
/resources/assets/js/components/.gitignore:
--------------------------------------------------------------------------------
1 | dist/
2 |
--------------------------------------------------------------------------------
/resources/assets/js/components/Ckeditor.vue:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 |
3 |
13 |
14 |
15 |
16 |
17 |
18 |
61 |
--------------------------------------------------------------------------------
/resources/assets/svg/hex.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/assets/svg/icons/author.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/assets/svg/icons/calendar.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/assets/svg/icons/camera-lens.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/assets/svg/icons/camera.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/assets/svg/icons/category.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/assets/svg/icons/community.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/assets/svg/icons/dropdown.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/assets/svg/icons/facebook.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/assets/svg/icons/github.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/assets/svg/icons/global.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/assets/svg/icons/instagram.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/assets/svg/icons/linkedin.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/assets/svg/icons/quote.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/assets/svg/icons/tiktok.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/assets/svg/icons/triangle-down.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/assets/svg/icons/triangle-up.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/assets/svg/icons/twitter.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/assets/svg/logo-sm-gray.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/assets/svg/logo-sm.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/lang/en/date.php:
--------------------------------------------------------------------------------
1 | 'MMMM Do YYYY',
6 |
7 | ];
8 |
--------------------------------------------------------------------------------
/resources/lang/en/email.php:
--------------------------------------------------------------------------------
1 | [
6 | 'subject' => 'Form something something',
7 | ],
8 |
9 | ];
10 |
--------------------------------------------------------------------------------
/resources/lang/en/errors.php:
--------------------------------------------------------------------------------
1 | 'Back to the main page',
6 | '401' => 'Sorry, you are not authorized to access this page.',
7 | '403' => 'Sorry, you are forbidden from accessing this page.',
8 | '404' => 'Sorry, the page you are looking for could not be found.',
9 | '419' => 'Sorry, your session has expired. Please refresh and try again.',
10 | '429' => 'Sorry, you are making too many requests to our servers.',
11 | '500' => 'Whoops, something went wrong on our servers.',
12 | '503' => 'Sorry, we are doing some maintenance. Please check back soon.',
13 |
14 | ];
15 |
--------------------------------------------------------------------------------
/resources/lang/en/footer.php:
--------------------------------------------------------------------------------
1 | 'A project by',
6 | 'tagline' => 'An independent, non-partisan, non-political, non-govermental organization.',
7 |
8 | ];
9 |
--------------------------------------------------------------------------------
/resources/lang/en/misc.php:
--------------------------------------------------------------------------------
1 | 'Community',
6 |
7 | ];
8 |
--------------------------------------------------------------------------------
/resources/lang/en/pagination.php:
--------------------------------------------------------------------------------
1 | '← Previous',
17 | 'next' => 'Next →',
18 | 'page' => 'Page :page',
19 | 'label' => 'Pagination Navigation',
20 | 'goto' => 'Go to page :page',
21 | ];
22 |
--------------------------------------------------------------------------------
/resources/lang/hu/errors.php:
--------------------------------------------------------------------------------
1 | 'Vissza az első oldalra',
6 | '401' => 'Sajnáljuk, nem vagy azonosítva hogy ide belépj',
7 | '403' => 'Sajnáljuk, nem vagy jogosult hogy ide belépj',
8 | '404' => 'Sajnáljuk, nem találtuk meg a keresett oldalt.',
9 | '419' => 'Sajnos a munkamenet lejárt. Kérjük próbáld újra.',
10 | '429' => 'Sajnáljuk, túl sok kérést küldesz szervereinkhez.',
11 | '500' => 'Hoppá, valami nem ment jól a szervereinken.',
12 | '503' => 'Sajnáljuk, a webhely karbantartásán fáradozunk. Kérjük, próbáld újra később.',
13 |
14 | ];
15 |
--------------------------------------------------------------------------------
/resources/lang/ro/date.php:
--------------------------------------------------------------------------------
1 | 'DD MMMM YYYY',
6 |
7 | ];
8 |
--------------------------------------------------------------------------------
/resources/lang/ro/errors.php:
--------------------------------------------------------------------------------
1 | 'Înapoi la prima pagină',
6 | '401' => 'Ne pare rău, nu ești autorizat să accesezi această pagină.',
7 | '403' => 'Ne pare rău, nu ai dreptul să accesezi această pagină.',
8 | '404' => 'Ne pare rău, nu am găsit pagina pe care o cauți.',
9 | '419' => 'Ne pare rău, sesiunea ta a expirat. Te rugăm să încerci din nou.',
10 | '429' => 'Ne pare rău, faci prea multe request-uri către serverele noastre.',
11 | '500' => 'Oops, ceva nu a mers bine pe serverele noastre.',
12 | '503' => 'Ne pare rău, lucrăm la întreținerea site-ului. Te rugăm să încerci mai târziu.',
13 |
14 | ];
15 |
--------------------------------------------------------------------------------
/resources/views/admin/blocks/accordion.blade.php:
--------------------------------------------------------------------------------
1 | @twillBlockTitle('Accordion')
2 | @twillBlockIcon('media-list')
3 | @twillBlockGroup('content')
4 |
5 | @formField('input', [
6 | 'name' => 'title',
7 | 'label' => __('admin.field.title'),
8 | 'translated' => true,
9 | ])
10 |
11 | @formField('repeater', [
12 | 'type' => 'accordionItem'
13 | ])
14 |
--------------------------------------------------------------------------------
/resources/views/admin/blocks/button.blade.php:
--------------------------------------------------------------------------------
1 | @twillBlockTitle('Button')
2 | @twillBlockIcon('colors')
3 | @twillBlockGroup('content')
4 |
5 | @formField('select', [
6 | 'name' => 'button_color',
7 | 'label' => __('admin.field.buttonColor'),
8 | 'required' => true,
9 | 'default' => 'primary',
10 | 'options' => collect(config('cms.colors'))->map(function($key) {
11 | return [
12 | 'value' => $key,
13 | 'label' => ucfirst($key),
14 | ];
15 | })->toArray(),
16 | ])
17 |
18 | @formField('input', [
19 | 'name' => 'button_text',
20 | 'label' => __('admin.field.buttonText'),
21 | 'type' => 'text',
22 | 'required' => true,
23 | 'translated' => true,
24 | 'maxlength' => 100,
25 | ])
26 |
27 | @formField('input', [
28 | 'name' => 'button_url',
29 | 'label' => __('admin.field.buttonUrl'),
30 | 'type' => 'text',
31 | 'required' => true,
32 | 'translated' => true,
33 | 'maxlength' => 100,
34 | ])
35 |
--------------------------------------------------------------------------------
/resources/views/admin/blocks/callToAction.blade.php:
--------------------------------------------------------------------------------
1 | @twillBlockTitle('Call to action')
2 | @twillBlockIcon('colors')
3 | @twillBlockGroup('content')
4 |
5 | @formField('input', [
6 | 'name' => 'title',
7 | 'label' => __('admin.field.title'),
8 | 'type' => 'text',
9 | 'required' => true,
10 | 'translated' => true,
11 | 'maxlength' => 100,
12 | ])
13 |
14 | @include('admin.utils.ckeditor', [
15 | 'name' => 'description',
16 | 'label' => __('admin.field.description'),
17 | 'translated' => true,
18 | ])
19 |
20 | @formField('select', [
21 | 'name' => 'button_color',
22 | 'label' => __('admin.field.buttonColor'),
23 | 'required' => true,
24 | 'default' => 'primary',
25 | 'options' => collect(config('cms.colors'))->map(function($key) {
26 | return [
27 | 'value' => $key,
28 | 'label' => ucfirst($key),
29 | ];
30 | })->toArray(),
31 | ])
32 |
33 | @formField('input', [
34 | 'name' => 'button_text',
35 | 'label' => __('admin.field.buttonText'),
36 | 'type' => 'text',
37 | 'required' => true,
38 | 'translated' => true,
39 | 'maxlength' => 100,
40 | ])
41 |
42 | @formField('input', [
43 | 'name' => 'button_url',
44 | 'label' => __('admin.field.buttonUrl'),
45 | 'type' => 'text',
46 | 'required' => true,
47 | 'translated' => true,
48 | 'maxlength' => 100,
49 | ])
50 |
--------------------------------------------------------------------------------
/resources/views/admin/blocks/cityLabs.blade.php:
--------------------------------------------------------------------------------
1 | @twillBlockTitle('City labs list')
2 | @twillBlockIcon('fix-grid')
3 | @twillBlockGroup('content')
4 |
5 | @formField('browser', [
6 | 'routePrefix' => 'people',
7 | 'moduleName' => 'cityLabs',
8 | 'name' => 'cityLabs',
9 | 'label' => __('admin.cityLabs'),
10 | 'max' => 100,
11 | ])
12 |
--------------------------------------------------------------------------------
/resources/views/admin/blocks/counter.blade.php:
--------------------------------------------------------------------------------
1 | @twillBlockTitle('Counter')
2 | @twillBlockIcon('star-feature')
3 | @twillBlockGroup('content')
4 |
5 | @formField('input', [
6 | 'name' => 'title',
7 | 'label' => __('admin.field.title'),
8 | 'translated' => true,
9 | ])
10 |
11 | @formField('select', [
12 | 'name' => 'background',
13 | 'label' => __('admin.field.background'),
14 | 'required' => true,
15 | 'default' => 'none',
16 | 'options' => collect(config('cms.colors'))->map(function($key) {
17 | return [
18 | 'value' => $key,
19 | 'label' => ucfirst($key),
20 | ];
21 | })->toArray(),
22 | ])
23 |
24 | @formField('select', [
25 | 'name' => 'columns',
26 | 'label' => __('admin.field.columns'),
27 | 'required' => true,
28 | 'default' => 3,
29 | 'options' => collect(range(1, 3))->map(function($key) {
30 | return [
31 | 'value' => $key,
32 | 'label' => $key,
33 | ];
34 | })->toArray(),
35 | ])
36 |
37 | @formField('repeater', [
38 | 'type' => 'counterItem'
39 | ])
40 |
--------------------------------------------------------------------------------
/resources/views/admin/blocks/embed.blade.php:
--------------------------------------------------------------------------------
1 | @twillBlockTitle('Embed')
2 | @twillBlockIcon('revision-single')
3 | @twillBlockGroup('content')
4 |
5 | @formField('input', [
6 | 'name' => 'title',
7 | 'label' => __('admin.field.title'),
8 | 'translated' => true,
9 | ])
10 |
11 | @formField('input', [
12 | 'name' => 'url',
13 | 'label' => __('admin.field.url'),
14 | 'note' => __('admin.fieldNote.embedUrl'),
15 | 'placeholder' => 'https://',
16 | 'required' => true,
17 | ])
18 |
--------------------------------------------------------------------------------
/resources/views/admin/blocks/form.blade.php:
--------------------------------------------------------------------------------
1 | @twillBlockTitle('Form')
2 | @twillBlockIcon('edit')
3 | @twillBlockGroup('content')
4 |
5 | @formField('select', [
6 | 'name' => 'form',
7 | 'label' => __('admin.form'),
8 | 'required' => true,
9 | 'native' => true,
10 | 'max' => 1,
11 | 'options' => Code4Romania\Cms\Models\Form::query()
12 | ->with('translation:id,form_id,title')
13 | ->get('id')
14 | ->mapWithKeys(fn($form) => [ $form->id => $form->title ]),
15 | ])
16 |
--------------------------------------------------------------------------------
/resources/views/admin/blocks/formSection.blade.php:
--------------------------------------------------------------------------------
1 | @twillBlockTitle('Form section')
2 | @twillBlockIcon('editor')
3 | @twillBlockGroup('form')
4 |
5 | @formField('input', [
6 | 'name' => 'name',
7 | 'label' => __('admin.field.name'),
8 | 'type' => 'text',
9 | 'required' => true,
10 | 'translated' => true,
11 | ])
12 |
13 | @include('admin.utils.ckeditor', [
14 | 'name' => 'description',
15 | 'label' => __('admin.field.description'),
16 | 'translated' => true,
17 | ])
18 |
19 | @formField('repeater', [
20 | 'type' => 'formField',
21 | ])
22 |
--------------------------------------------------------------------------------
/resources/views/admin/blocks/html.blade.php:
--------------------------------------------------------------------------------
1 | @twillBlockTitle('HTML')
2 | @twillBlockIcon('website')
3 | @twillBlockGroup('content')
4 |
5 | @formField('input', [
6 | 'name' => 'html',
7 | 'label' => __('admin.field.html'),
8 | 'type' => 'textarea',
9 | 'rows' => 20,
10 | 'translated' => true,
11 | ])
12 |
--------------------------------------------------------------------------------
/resources/views/admin/blocks/imageGrid.blade.php:
--------------------------------------------------------------------------------
1 | @twillBlockTitle('Image grid')
2 | @twillBlockIcon('fix-grid')
3 | @twillBlockGroup('content')
4 |
5 | @formField('input', [
6 | 'name' => 'title',
7 | 'label' => __('admin.field.title'),
8 | 'translated' => true,
9 | ])
10 |
11 | @formField('select', [
12 | 'name' => 'columns',
13 | 'label' => __('admin.field.columns'),
14 | 'default' => 1,
15 | 'unpack' => true,
16 | 'options' => collect(range(1, 4))->map(function($i) {
17 | return [
18 | 'value' => $i,
19 | 'label' => $i,
20 | ];
21 | })->toArray(),
22 | ])
23 |
24 | @formField('medias', [
25 | 'name' => 'image',
26 | 'label' => __('admin.field.images'),
27 | 'max' => 12,
28 | 'note' => __('admin.fieldNote.imagesUpTo', ['count' => 12]),
29 | 'required' => true,
30 | 'withVideoUrl' => false,
31 | ])
32 |
--------------------------------------------------------------------------------
/resources/views/admin/blocks/menuItem.blade.php:
--------------------------------------------------------------------------------
1 | @twillBlockTitle('Menu item')
2 | @twillBlockIcon('info')
3 | @twillBlockGroup('menu')
4 |
5 | @include('admin.utils.menu-item-template')
6 |
7 | @formField('repeater', [
8 | 'type' => 'subMenuItem',
9 | ])
10 |
--------------------------------------------------------------------------------
/resources/views/admin/blocks/newsletter.blade.php:
--------------------------------------------------------------------------------
1 | @twillBlockTitle('Newsletter form')
2 | @twillBlockIcon('info')
3 | @twillBlockGroup('content')
4 |
5 | @inject('mailchimp', 'Code4Romania\Cms\Helpers\MailchimpHelper')
6 |
7 | @include('admin.utils.ckeditor', [
8 | 'name' => 'text',
9 | 'label' => __('admin.field.text'),
10 | 'translated' => true,
11 | ])
12 |
13 | @formField('select', [
14 | 'name' => 'list',
15 | 'label' => __('admin.field.list'),
16 | 'unpack' => false,
17 | 'options' => $mailchimp->getListsCached()
18 | ->map(function($list) {
19 | return [
20 | 'value' => $list['id'],
21 | 'label' => $list['name'] . " ({$list['id']})",
22 | ];
23 | })
24 | ->toArray(),
25 | ])
26 |
--------------------------------------------------------------------------------
/resources/views/admin/blocks/notice.blade.php:
--------------------------------------------------------------------------------
1 | @twillBlockTitle('Notice')
2 | @twillBlockIcon('info')
3 | @twillBlockGroup('content')
4 |
5 | @formField('select', [
6 | 'name' => 'color',
7 | 'label' => __('admin.field.background'),
8 | 'required' => true,
9 | 'default' => 'none',
10 | 'options' => collect(config('cms.colors'))
11 | ->map(function($key) {
12 | return [
13 | 'value' => $key,
14 | 'label' => ucfirst($key),
15 | ];
16 | })->toArray(),
17 | ])
18 |
19 | @include('admin.utils.ckeditor', [
20 | 'name' => 'content',
21 | 'label' => __('admin.field.content'),
22 | 'translated' => true,
23 | ])
24 |
--------------------------------------------------------------------------------
/resources/views/admin/blocks/partners.blade.php:
--------------------------------------------------------------------------------
1 | @twillBlockTitle('Partners list')
2 | @twillBlockIcon('fix-grid')
3 | @twillBlockGroup('content')
4 |
5 | @formField('input', [
6 | 'name' => 'title',
7 | 'label' => __('admin.field.title'),
8 | 'translated' => true,
9 | ])
10 |
11 | @formField('select', [
12 | 'name' => 'columns',
13 | 'label' => __('admin.field.columns'),
14 | 'default' => 4,
15 | 'unpack' => true,
16 | 'options' => collect(range(2, 6))->map(function($i) {
17 | return [
18 | 'value' => $i,
19 | 'label' => $i,
20 | ];
21 | })->toArray(),
22 | ])
23 |
24 | @formField('browser', [
25 | 'moduleName' => 'partners',
26 | 'name' => 'partners',
27 | 'label' => __('admin.partners'),
28 | 'max' => 100,
29 | ])
30 |
--------------------------------------------------------------------------------
/resources/views/admin/blocks/people.blade.php:
--------------------------------------------------------------------------------
1 | @twillBlockTitle('People list')
2 | @twillBlockIcon('fix-grid')
3 | @twillBlockGroup('content')
4 |
5 | @formField('input', [
6 | 'name' => 'title',
7 | 'label' => __('admin.field.title'),
8 | 'translated' => true,
9 | ])
10 |
11 | @formField('select', [
12 | 'name' => 'columns',
13 | 'label' => __('admin.field.columns'),
14 | 'default' => 4,
15 | 'unpack' => true,
16 | 'options' => collect(range(2, 6))->map(function($i) {
17 | return [
18 | 'value' => $i,
19 | 'label' => $i,
20 | ];
21 | })->toArray(),
22 | ])
23 |
24 | @formField('browser', [
25 | 'routePrefix' => 'people',
26 | 'moduleName' => 'people',
27 | 'name' => 'people',
28 | 'label' => __('admin.people'),
29 | 'max' => 100,
30 | ])
31 |
32 | @formField('select', [
33 | 'name' => 'showDescriptions',
34 | 'label' => __('admin.field.showDescriptions'),
35 | 'default' => false,
36 | 'unpack' => true,
37 | 'options' => [
38 | [
39 | 'value' => true,
40 | 'label' => 'Yes',
41 | ],
42 | [
43 | 'value' => false,
44 | 'label' => 'No',
45 | ],
46 | ],
47 | ])
48 |
--------------------------------------------------------------------------------
/resources/views/admin/blocks/quote.blade.php:
--------------------------------------------------------------------------------
1 | @twillBlockTitle('Quote')
2 | @twillBlockIcon('quote')
3 | @twillBlockGroup('content')
4 |
5 | @include('admin.utils.ckeditor', [
6 | 'name' => 'quote',
7 | 'label' => __('admin.field.quote'),
8 | 'translated' => true,
9 | ])
10 |
11 | @formField('input', [
12 | 'name' => 'author',
13 | 'label' => __('admin.field.author'),
14 | 'type' => 'text',
15 | 'required' => true,
16 | 'translated' => true,
17 | 'maxlength' => 100,
18 | ])
19 |
20 | @formField('input', [
21 | 'name' => 'affiliation',
22 | 'label' => __('admin.field.affiliation'),
23 | 'type' => 'text',
24 | 'translated' => true,
25 | 'maxlength' => 100,
26 | ])
27 |
--------------------------------------------------------------------------------
/resources/views/admin/blocks/separator.blade.php:
--------------------------------------------------------------------------------
1 | @twillBlockTitle('Separator')
2 | @twillBlockIcon('more-dots')
3 | @twillBlockGroup('content')
4 |
--------------------------------------------------------------------------------
/resources/views/admin/blocks/text.blade.php:
--------------------------------------------------------------------------------
1 | @twillBlockTitle('Text')
2 | @twillBlockIcon('text')
3 | @twillBlockGroup('content')
4 |
5 | @include('admin.utils.ckeditor', [
6 | 'name' => 'text',
7 | 'label' => __('admin.field.text'),
8 | 'translated' => true,
9 | ])
10 |
--------------------------------------------------------------------------------
/resources/views/admin/categories/form.blade.php:
--------------------------------------------------------------------------------
1 | @extends('twill::layouts.form')
2 |
3 | @section('contentFields')
4 | @formField('wysiwyg', [
5 | 'name' => 'description',
6 | 'label' => __('admin.field.description'),
7 | 'type' => config('cms.editor.type'),
8 | 'toolbarOptions' => config('cms.editor.toolbar'),
9 | 'editSource' => true,
10 | 'translated' => true,
11 | ])
12 | @endsection
13 |
--------------------------------------------------------------------------------
/resources/views/admin/cityLabs/form.blade.php:
--------------------------------------------------------------------------------
1 | @extends('twill::layouts.form', [
2 | 'disableContentFieldset' => true,
3 | 'additionalFieldsets' => [
4 | [
5 | 'fieldset' => 'summary',
6 | 'label' => __('admin.field.summary'),
7 | ],
8 | [
9 | 'fieldset' => 'content',
10 | 'label' => __('admin.field.content'),
11 | ],
12 | [
13 | 'fieldset' => 'people',
14 | 'label' => __('admin.people'),
15 | ],
16 | ],
17 | ])
18 |
19 | @section('fieldsets')
20 |
21 | @formField('medias', [
22 | 'name' => 'image',
23 | 'label' => __('admin.field.image'),
24 | ])
25 |
26 | @include('admin.utils.ckeditor', [
27 | 'name' => 'description',
28 | 'label' => __('admin.field.description'),
29 | 'translated' => true,
30 | ])
31 |
32 |
33 |
34 | @formField('block_editor', [
35 | 'withoutSeparator' => true,
36 | 'group' => 'content',
37 | ])
38 |
39 |
40 |
41 | @formField('browser', [
42 | 'routePrefix' => 'people',
43 | 'moduleName' => 'people',
44 | 'name' => 'people',
45 | 'label' => false,
46 | 'note' => trans_choice('admin.fieldNote.peopleUpTo', 100),
47 | 'max' => 100,
48 | ])
49 |
50 | @endsection
51 |
--------------------------------------------------------------------------------
/resources/views/admin/menus/form.blade.php:
--------------------------------------------------------------------------------
1 | @extends('twill::layouts.form')
2 |
3 | @section('contentFields')
4 | @formField('select', [
5 | 'name' => 'location',
6 | 'label' => __('admin.field.menuLocation'),
7 | 'required' => true,
8 | 'default' => false,
9 | 'options' => collect(config('cms.menu.locations'))->map(function($key) {
10 | return [
11 | 'value' => $key,
12 | 'label' => ucfirst($key),
13 | ];
14 | })->toArray(),
15 | ])
16 | @endsection
17 |
18 | @section('fieldsets')
19 |
20 | @formField('block_editor', [
21 | 'withoutSeparator' => true,
22 | 'group' => 'menu',
23 | ])
24 |
25 | @endsection
26 |
--------------------------------------------------------------------------------
/resources/views/admin/pages/form.blade.php:
--------------------------------------------------------------------------------
1 | @extends('twill::layouts.form', [
2 | 'contentFieldsetLabel' => __('admin.field.summary'),
3 | 'additionalFieldsets' => [
4 | [
5 | 'fieldset' => 'content-blocks',
6 | 'label' => __('admin.field.content'),
7 | ],
8 | ],
9 | ])
10 |
11 | @section('contentFields')
12 | @formField('checkbox', [
13 | 'name' => 'show_header',
14 | 'label' => __('admin.field.showHeader'),
15 | 'default' => true,
16 | ])
17 |
18 | @include('admin.utils.ckeditor', [
19 | 'name' => 'description',
20 | 'label' => __('admin.field.description'),
21 | 'translated' => true,
22 | ])
23 | @stop
24 |
25 |
26 | @section('fieldsets')
27 |
28 | @formField('block_editor', [
29 | 'withoutSeparator' => true,
30 | 'group' => 'content',
31 | ])
32 |
33 | @stop
34 |
--------------------------------------------------------------------------------
/resources/views/admin/partners/form.blade.php:
--------------------------------------------------------------------------------
1 | @extends('twill::layouts.form')
2 |
3 | @section('contentFields')
4 | @formField('input', [
5 | 'name' => 'website',
6 | 'label' => __('admin.field.website'),
7 | 'type' => 'text',
8 | ])
9 |
10 | @formField('medias', [
11 | 'name' => 'logo',
12 | 'label' => __('admin.field.logo'),
13 | 'withVideoUrl' => false,
14 | 'withAddInfo' => false,
15 | 'withCaption' => false,
16 | ])
17 | @endsection
18 |
--------------------------------------------------------------------------------
/resources/views/admin/people/form.blade.php:
--------------------------------------------------------------------------------
1 | @extends('twill::layouts.form', [
2 | 'translateTitle' => false,
3 | 'controlLanguagesPublication' => true,
4 | 'contentFieldsetLabel' => 'Profile',
5 | 'additionalFieldsets' => [
6 | [
7 | 'fieldset' => 'image',
8 | 'label' => __('admin.field.image'),
9 | ],
10 | ],
11 | ])
12 |
13 | @section('contentFields')
14 | @foreach (['github', 'linkedin'] as $network)
15 | @formField('input', [
16 | 'name' => $network,
17 | 'label' => config("cms.social.networks.{$network}.name"),
18 | 'translated' => false,
19 | ])
20 | @endforeach
21 |
22 | @formField('browser', [
23 | 'routePrefix' => 'people',
24 | 'moduleName' => 'cityLabs',
25 | 'name' => 'cityLab',
26 | 'label' => __('admin.cityLab'),
27 | 'max' => 1,
28 | ])
29 |
30 | @formField('input', [
31 | 'name' => 'title',
32 | 'label' => __('admin.field.title'),
33 | 'translated' => true,
34 | ])
35 |
36 | @include('admin.utils.ckeditor', [
37 | 'name' => 'description',
38 | 'label' => __('admin.field.description'),
39 | 'translated' => true,
40 | ])
41 | @endsection
42 |
43 | @section('fieldsets')
44 |
45 | @formField('medias', [
46 | 'name' => 'image',
47 | 'label' => false,
48 | ])
49 |
50 | @endsection
51 |
--------------------------------------------------------------------------------
/resources/views/admin/posts/form.blade.php:
--------------------------------------------------------------------------------
1 | @extends('twill::layouts.form', [
2 | 'contentFieldsetLabel' => __('admin.field.summary'),
3 | 'additionalFieldsets' => [
4 | [
5 | 'fieldset' => 'content-blocks',
6 | 'label' => __('admin.field.content'),
7 | ],
8 | ],
9 | ])
10 |
11 | @section('contentFields')
12 | @formField('input', [
13 | 'name' => 'description',
14 | 'type' => 'textarea',
15 | 'label' => __('admin.field.description'),
16 | 'translated' => true,
17 | ])
18 |
19 | @formField('medias', [
20 | 'name' => 'image',
21 | 'label' => __('admin.field.image'),
22 | 'max' => 1,
23 | 'required' => true,
24 | 'withVideoUrl' => false,
25 | 'withAddInfo' => false,
26 | 'withCaption' => false,
27 | ])
28 |
29 | @formField('input', [
30 | 'name' => 'author',
31 | 'type' => 'text',
32 | 'label' => __('admin.field.author'),
33 | ])
34 |
35 | @formField('browser', [
36 | 'label' => __('admin.categories'),
37 | 'routePrefix' => 'blog',
38 | 'name' => 'categories',
39 | 'moduleName' => 'categories',
40 | 'sortable' => false,
41 | 'max' => 5,
42 | ])
43 | @endsection
44 |
45 |
46 | @section('fieldsets')
47 |
48 | @formField('block_editor', [
49 | 'withoutSeparator' => true,
50 | 'group' => 'content',
51 | ])
52 |
53 | @endsection
54 |
--------------------------------------------------------------------------------
/resources/views/admin/repeaters/accordionItem.blade.php:
--------------------------------------------------------------------------------
1 | @twillRepeaterTitle('Accordion Item')
2 | @twillRepeaterTrigger('Add accordion item')
3 | @twillRepeaterGroup('app')
4 |
5 | @formField('input', [
6 | 'name' => 'header',
7 | 'label' => __('admin.field.header'),
8 | 'translated' => true,
9 | ])
10 |
11 | @include('admin.utils.ckeditor', [
12 | 'name' => 'description',
13 | 'label' => __('admin.field.description'),
14 | 'translated' => true,
15 | ])
16 |
--------------------------------------------------------------------------------
/resources/views/admin/repeaters/counterItem.blade.php:
--------------------------------------------------------------------------------
1 | @twillRepeaterTitle('Counter item')
2 | @twillRepeaterTrigger('Add counter item')
3 | @twillRepeaterGroup('app')
4 |
5 | @formField('input', [
6 | 'name' => 'number',
7 | 'label' => __('admin.field.number'),
8 | 'translated' => false,
9 | ])
10 |
11 | @formField('input', [
12 | 'name' => 'label',
13 | 'label' => __('admin.field.label'),
14 | 'translated' => true,
15 | ])
16 |
--------------------------------------------------------------------------------
/resources/views/admin/repeaters/subMenuItem.blade.php:
--------------------------------------------------------------------------------
1 | @twillRepeaterTitle('Submenu item')
2 | @twillRepeaterTrigger('Add submenu item')
3 | @twillRepeaterGroup('app')
4 |
5 | @include('admin.utils.menu-item-template')
6 |
--------------------------------------------------------------------------------
/resources/views/admin/responses/form.blade.php:
--------------------------------------------------------------------------------
1 | @extends('twill::layouts.free')
2 |
3 | @section('customPageContent')
4 |
5 | @formField('input', [
6 | 'readonly' => true,
7 | 'name' => 'created_at',
8 | 'label' => __('form.created_at'),
9 | 'default' => $item->created_at,
10 | ])
11 |
12 | @formField('input', [
13 | 'readonly' => true,
14 | 'name' => 'form',
15 | 'label' => __('admin.form'),
16 | 'default' => $item->presentAdmin()->form,
17 | ])
18 |
19 |
20 | @foreach ($item->data as $sectionIndex => $section)
21 |
22 | @foreach ($section['fields'] as $fieldIndex =>$field)
23 | @formField('input', [
24 | 'readonly' => true,
25 | 'name' => "field[{$sectionIndex}][{$fieldIndex}]",
26 | 'label' => $field['label'],
27 | 'default' => $field['value'],
28 | ])
29 | @endforeach
30 |
31 | @endforeach
32 | @endsection
33 |
--------------------------------------------------------------------------------
/resources/views/admin/settings/mailchimp.blade.php:
--------------------------------------------------------------------------------
1 | @extends('twill::layouts.settings')
2 |
3 | @section('contentFields')
4 | @formField('input', [
5 | 'name' => 'apiKey',
6 | 'label' => __('admin.field.apiKey'),
7 | 'translated' => false,
8 | ])
9 | @stop
10 |
--------------------------------------------------------------------------------
/resources/views/admin/settings/social.blade.php:
--------------------------------------------------------------------------------
1 | @extends('twill::layouts.settings')
2 |
3 | @section('contentFields')
4 | @foreach (config('cms.social.networks') as $id => $network)
5 | @formField('input', [
6 | 'name' => $id,
7 | 'label' => $network['name'],
8 | 'prefix' => $network['baseUrl'],
9 | 'translated' => false,
10 | ])
11 | @endforeach
12 | @stop
13 |
--------------------------------------------------------------------------------
/resources/views/components/button.blade.php:
--------------------------------------------------------------------------------
1 | @inject('url', 'Code4Romania\Cms\Helpers\UrlHelper')
2 |
3 | @php
4 | $href ??= false;
5 | $type ??= 'button';
6 | $color ??= 'primary';
7 |
8 | $buttonBase = 'relative inline-block w-full px-6 py-2 font-semibold leading-snug tracking-wide text-center shadow-md sm:w-auto hover:shadow-lg focus:outline-none focus:shadow-md';
9 |
10 | switch ($color) {
11 | case 'primary':
12 | $buttonColor = 'text-white bg-primary-500 focus:bg-primary-600';
13 | break;
14 |
15 | case 'warning':
16 | $buttonColor = 'text-black bg-warning-500 focus:bg-warning-600';
17 | break;
18 |
19 | case 'danger':
20 | $buttonColor = 'text-white bg-danger-500 focus:bg-danger-600';
21 | break;
22 |
23 | case 'success':
24 | $buttonColor = 'text-white bg-success-500 focus:bg-success-600';
25 | break;
26 |
27 | case 'black':
28 | $buttonColor = 'text-white bg-black focus:bg-gray-900';
29 | break;
30 |
31 | case 'gray':
32 | $buttonColor = 'text-white bg-gray-500 focus:bg-gray-600';
33 | break;
34 |
35 | default:
36 | $buttonColor = 'border focus:bg-gray-100';
37 | break;
38 | }
39 | @endphp
40 |
41 | @if ($href !== false)
42 | isExternal($href))
47 | rel="noopener noreferrer"
48 | target="_blank"
49 | @endif
50 | >{{ $slot }}
51 | @else
52 |
56 | @endif
57 |
--------------------------------------------------------------------------------
/resources/views/components/container.blade.php:
--------------------------------------------------------------------------------
1 |
merge(['class' => 'grid row-gap-12 lg:row-gap-20']) }}>
2 | {{ $slot }}
3 |
4 |
--------------------------------------------------------------------------------
/resources/views/components/figure.blade.php:
--------------------------------------------------------------------------------
1 | @php
2 | $alt ??= false;
3 | $caption ??= false;
4 | $class ??= '';
5 | $lqip ??= false;
6 | @endphp
7 |
8 |
9 |
10 |
11 | @if ($caption)
12 |
13 |
14 | {{ svg('icons/camera-lens', 'w-6 h-6 text-gray-400') }}
15 |
16 | {{ $caption }}
17 |
18 | @endif
19 |
20 |
--------------------------------------------------------------------------------
/resources/views/components/hex-badge.blade.php:
--------------------------------------------------------------------------------
1 | @php
2 | $title ??= '';
3 | $icon ??= '';
4 | @endphp
5 |
6 |
7 |
8 | {{ svg('hex', 'block w-auto h-16 md:h-24 text-primary-500') }}
9 | {{ svg("icons/$icon", 'absolute inset-0 p-4 md:p-6 m-auto text-white') }}
10 |
11 | {{ $title }}
12 |
13 |
--------------------------------------------------------------------------------
/resources/views/components/image.blade.php:
--------------------------------------------------------------------------------
1 | @php
2 | $alt = $alt ?? '';
3 | $class = $class ?? 'block w-full';
4 | $lqip = $lqip ?? false;
5 | @endphp
6 |
7 |
19 |
--------------------------------------------------------------------------------
/resources/views/components/input.blade.php:
--------------------------------------------------------------------------------
1 | @php
2 | $type = $type ?? 'text';
3 | $required = $required ?? false;
4 | $label = $label ?? null;
5 | $placeholder = $placeholder ?? null;
6 | @endphp
7 |
8 |
9 | @if ($label)
10 |
11 | @endif
12 |
20 |
21 |
--------------------------------------------------------------------------------
/resources/views/components/link.blade.php:
--------------------------------------------------------------------------------
1 | {{ $slot }}
9 |
--------------------------------------------------------------------------------
/resources/views/components/notice.blade.php:
--------------------------------------------------------------------------------
1 | @php
2 | $classes = collect();
3 |
4 | switch ($color) {
5 | case 'primary':
6 | $classes->push('bg-primary-700');
7 | $classes->push('text-white');
8 | break;
9 |
10 | case 'warning':
11 | $classes->push('bg-warning-400');
12 | $classes->push('text-black');
13 | break;
14 |
15 | case 'danger':
16 | $classes->push('bg-danger-700');
17 | $classes->push('text-white');
18 | break;
19 |
20 | case 'gray':
21 | $classes->push('bg-gray-800');
22 | $classes->push('text-white');
23 | break;
24 | }
25 | @endphp
26 |
27 |
28 |
29 | {!! $content !!}
30 |
31 |
32 |
--------------------------------------------------------------------------------
/resources/views/components/social-network-link.blade.php:
--------------------------------------------------------------------------------
1 | @php
2 | $network ??= null;
3 | $link ??= null;
4 | @endphp
5 |
6 | @if ($link)
7 |
13 | {{ svg("icons/$network", 'block h-4 fill-current') }}
14 |
15 | @endif
16 |
--------------------------------------------------------------------------------
/resources/views/emails/formResponseSubmitted.blade.php:
--------------------------------------------------------------------------------
1 | @component('mail::message')
2 |
3 | {{-- Begin section --}}
4 | @foreach ($response->data as $section)
5 |
6 | # {{ $section['title'] }}
7 |
8 | {{-- Begin field --}}
9 | @foreach ($section['fields'] as $field)
10 |
11 | {{ $loop->iteration }}. {{ $field['label'] }}
12 | {{ $field['value'] ?? '-' }}
13 |
14 | @endforeach
15 | {{-- End field --}}
16 |
17 | @endforeach
18 | {{-- End section --}}
19 |
20 | @endcomponent
21 |
--------------------------------------------------------------------------------
/resources/views/errors/404.blade.php:
--------------------------------------------------------------------------------
1 | @extends('front.layouts.app')
2 |
3 | @section('content')
4 |
5 | {{ __('errors.404') }}
6 |
7 |
8 | {{ __('errors.back') }}
12 |
13 |
14 |
15 | {{ svg('404', 'block w-full h-full') }}
16 |
17 |
18 | @endsection
19 |
--------------------------------------------------------------------------------
/resources/views/front/blocks/_container.blade.php:
--------------------------------------------------------------------------------
1 |
2 | {!! $item->renderBlocks(false) !!}
3 |
4 |
--------------------------------------------------------------------------------
/resources/views/front/blocks/accordion.blade.php:
--------------------------------------------------------------------------------
1 | @inject('url', 'Code4Romania\Cms\Helpers\UrlHelper')
2 |
3 |
4 | @if ($block->translatedInput('title'))
5 | {{ $block->translatedInput('title') }}
6 | @endif
7 |
8 | @foreach ($block->children as $child)
9 | @include('front.blocks.accordionItem', [
10 | 'index' => $loop->index,
11 | 'block' => $child,
12 | 'isPreview' => $url->isAdminUrl(),
13 | ])
14 | @endforeach
15 |
16 |
--------------------------------------------------------------------------------
/resources/views/front/blocks/accordionItem.blade.php:
--------------------------------------------------------------------------------
1 | @php
2 | $isPreview = $isPreview ?? false;
3 | @endphp
4 |
5 |
6 |
16 | {{ $block->translatedInput('header') }}
17 |
20 |
21 |
{!! $block->translatedInput('description') !!}
25 |
26 |
--------------------------------------------------------------------------------
/resources/views/front/blocks/button.blade.php:
--------------------------------------------------------------------------------
1 |
2 | {{ $block->translatedInput('button_text') }}
6 |
7 |
--------------------------------------------------------------------------------
/resources/views/front/blocks/callToAction.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
{{ $block->translatedInput('title') }}
5 |
6 | {!! $block->translatedInput('description') !!}
7 |
8 |
9 |
10 |
11 | {{ $block->translatedInput('button_text') }}
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/resources/views/front/blocks/cityLabs.blade.php:
--------------------------------------------------------------------------------
1 |
2 | @foreach ($block->present()->cityLabsListPublished as $cityLab)
3 |
9 |
10 |
11 | {{ $cityLab->name }}
12 |
13 | @endforeach
14 |
15 |
--------------------------------------------------------------------------------
/resources/views/front/blocks/counterItem.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ svg('hex', 'absolute inset-0 z-0 ' . $badgeBackground) }}
4 | {{ $block->input('number') }}
5 |
6 |
7 |
{{ $block->translatedInput('label') }}
8 |
9 |
--------------------------------------------------------------------------------
/resources/views/front/blocks/embed.blade.php:
--------------------------------------------------------------------------------
1 | @php
2 | $ratio = $block->present()->embedAspectRatio;
3 | @endphp
4 |
5 |
6 | @if ($block->translatedInput('title'))
7 | {{ $block->translatedInput('title') }}
8 | @endif
9 |
10 |
11 | {!! $block->present()->embedCode !!}
12 |
13 |
14 |
--------------------------------------------------------------------------------
/resources/views/front/blocks/form.blade.php:
--------------------------------------------------------------------------------
1 | @php
2 | $form = $block->present()->formPublished;
3 |
4 | if (is_null($form)) {
5 | return;
6 | }
7 |
8 | $sections = $form->blocks->where('type', 'formSection');
9 |
10 | $fieldsBySection = $form->blocks
11 | ->where('type', 'formField')
12 | ->filter(fn ($block) => $block->parent_id !== null)
13 | ->groupBy('parent_id');
14 |
15 | $data = $sections->map(function($section, $sectionIndex) use ($fieldsBySection) {
16 | return $fieldsBySection
17 | ->get($section->id)
18 | ->map(fn ($field, $fieldIndex) => null);
19 | });
20 | @endphp
21 |
22 |
37 |
--------------------------------------------------------------------------------
/resources/views/front/blocks/formSection.blade.php:
--------------------------------------------------------------------------------
1 | @php
2 | $fields ??= $block->children;
3 | $sectionIndex ??= null;
4 | @endphp
5 |
6 |
22 |
--------------------------------------------------------------------------------
/resources/views/front/blocks/hero.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
{{ $block->translatedInput('title') }}
5 | {{ $block->translatedInput('subtitle') }}
6 |
7 |
8 |
9 | {!! $block->translatedInput('content') !!}
10 |
11 |
12 |
{{ $block->translatedInput('button_text') }}
16 |
17 |
18 | @if ($block->hasImage('image'))
19 |
20 |
27 |
28 | @endif
29 |
30 |
--------------------------------------------------------------------------------
/resources/views/front/blocks/html.blade.php:
--------------------------------------------------------------------------------
1 |
2 | {!! $block->translatedInput('html') !!}
3 |
4 |
--------------------------------------------------------------------------------
/resources/views/front/blocks/imageGrid.blade.php:
--------------------------------------------------------------------------------
1 | @php
2 | switch ((int) $block->input('columns')) {
3 | case 1:
4 | default:
5 | $cols = 'md:grid-cols-1';
6 | break;
7 |
8 | case 2:
9 | $cols = 'md:grid-cols-2';
10 | break;
11 |
12 | case 3:
13 | $cols = 'md:grid-cols-3';
14 | break;
15 |
16 | case 4:
17 | $cols = 'md:grid-cols-4';
18 | break;
19 | }
20 | @endphp
21 |
22 |
23 | @if ($block->translatedInput('title'))
24 | {{ $block->translatedInput('title') }}
25 | @endif
26 |
27 |
28 | @foreach ($block->imageObjects('image') as $media)
29 |
34 | @endforeach
35 |
36 |
37 |
--------------------------------------------------------------------------------
/resources/views/front/blocks/imageText.blade.php:
--------------------------------------------------------------------------------
1 | @php
2 | $container = collect();
3 | $imageRight = collect('col-span-1');
4 | $content = collect('ck-content');
5 |
6 | switch ($block->input('width')) {
7 | case '1/4':
8 | $container->push('md:grid-cols-4');
9 | $imageRight->push('md:col-start-4');
10 | $content->push('md:col-span-3');
11 | break;
12 |
13 | case '1/3':
14 | $container->push('md:grid-cols-3');
15 | $imageRight->push('md:col-start-3');
16 | $content->push('md:col-span-2');
17 | break;
18 |
19 | case '1/2':
20 | $container->push('md:grid-cols-2');
21 | $imageRight->push('md:col-start-2');
22 | $content->push('md:col-span-1');
23 | break;
24 | }
25 |
26 | switch ($block->input('valign')) {
27 | case 'top':
28 | $container->push('items-start');
29 | break;
30 |
31 | case 'center':
32 | $container->push('items-center');
33 | break;
34 |
35 | case 'bottom':
36 | $container->push('items-end');
37 | break;
38 | }
39 |
40 | if ($block->input('position') === 'right') {
41 | $figure = $imageRight->implode(' ');
42 | } else {
43 | $figure = null;
44 | }
45 | @endphp
46 |
47 |
48 |
55 |
56 |
57 | {!! $block->translatedInput('text') !!}
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/resources/views/front/blocks/newsletter.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 | {!! $block->translatedInput('text') !!}
4 |
5 |
6 |
34 |
35 |
--------------------------------------------------------------------------------
/resources/views/front/blocks/notice.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/views/front/blocks/partners.blade.php:
--------------------------------------------------------------------------------
1 | @php
2 | switch ($block->input('columns')) {
3 | case 2:
4 | $columns = 'sm:grid-cols-2';
5 | break;
6 |
7 | case 3:
8 | $columns = 'sm:grid-cols-2 lg:grid-cols-3';
9 | break;
10 |
11 | case 4:
12 | $columns = 'sm:grid-cols-2 lg:grid-cols-4';
13 | break;
14 |
15 | case 5:
16 | $columns = 'sm:grid-cols-2 lg:grid-cols-5';
17 | break;
18 |
19 | case 6:
20 | $columns = 'sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-6';
21 | break;
22 |
23 | default:
24 | $columns = null;
25 | break;
26 | }
27 | @endphp
28 |
29 |
30 | @if ($block->translatedInput('title'))
31 | {{ $block->translatedInput('title') }}
32 | @endif
33 |
34 |
35 | @foreach ($block->present()->partnersListPublished as $partner)
36 | @include('front.partners.card', [
37 | 'partner' => $partner,
38 | ])
39 | @endforeach
40 |
41 |
42 |
--------------------------------------------------------------------------------
/resources/views/front/blocks/people.blade.php:
--------------------------------------------------------------------------------
1 | @php
2 | switch ($block->input('columns')) {
3 | case 2:
4 | $columns = 'sm:grid-cols-2';
5 | break;
6 |
7 | case 3:
8 | $columns = 'sm:grid-cols-2 lg:grid-cols-3';
9 | break;
10 |
11 | case 4:
12 | $columns = 'sm:grid-cols-2 lg:grid-cols-4';
13 | break;
14 |
15 | case 5:
16 | $columns = 'sm:grid-cols-2 lg:grid-cols-5';
17 | break;
18 |
19 | case 6:
20 | $columns = 'sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-6';
21 | break;
22 |
23 | default:
24 | $columns = null;
25 | break;
26 | }
27 | @endphp
28 |
29 |
30 | @if ($block->translatedInput('title'))
31 | {{ $block->translatedInput('title') }}
32 | @endif
33 |
34 |
35 | @foreach ($block->present()->peopleListPublished as $person)
36 | @include('front.people.card', [
37 | 'person' => $person,
38 | 'showDescription' => $block->input('showDescriptions'),
39 | ])
40 | @endforeach
41 |
42 |
43 |
--------------------------------------------------------------------------------
/resources/views/front/blocks/quote.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 | {!! $block->translatedInput('quote') !!}
4 |
5 |
6 | @if ($block->translatedInput('author'))
7 |
8 | {{ $block->translatedInput('author') }}
9 |
10 | @if ($block->translatedInput('affiliation'))
11 |
{{ $block->translatedInput('affiliation') }}
12 | @endif
13 |
14 | @endif
15 |
16 |
--------------------------------------------------------------------------------
/resources/views/front/blocks/separator.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/resources/views/front/blocks/text.blade.php:
--------------------------------------------------------------------------------
1 |
2 | {!! $block->translatedInput('text') !!}
3 |
4 |
--------------------------------------------------------------------------------
/resources/views/front/categories/show.blade.php:
--------------------------------------------------------------------------------
1 | @inject('settings', 'Code4Romania\Cms\Helpers\settingsHelper')
2 |
3 | @extends('front.layouts.app')
4 |
5 | @section('content')
6 | @include('front.partials.page-header', [
7 | 'title' => $item->title,
8 | 'description' => $item->description,
9 | ])
10 |
11 |
12 | @foreach ($item->posts as $item)
13 | @include('front.posts.card', [
14 | 'item' => $item,
15 | ])
16 | @endforeach
17 |
18 | @endsection
19 |
--------------------------------------------------------------------------------
/resources/views/front/cityLabs/index.blade.php:
--------------------------------------------------------------------------------
1 | @extends('front.layouts.app')
2 |
3 | @section('content')
4 |
5 | @foreach ($items as $item)
6 |
7 | {{ $item->name }}
8 | @endforeach
9 | @endsection
10 |
--------------------------------------------------------------------------------
/resources/views/front/cityLabs/show.blade.php:
--------------------------------------------------------------------------------
1 | @extends('front.layouts.app')
2 |
3 | @section('content')
4 |
5 |
6 |
7 |
16 |
17 |
{{ $item->name }}
18 | {!! $item->description !!}
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | @foreach ($item->people as $person)
28 | @include('front.people.card', [
29 | 'person' => $person,
30 | ])
31 | @endforeach
32 |
33 |
34 |
35 | {!! $item->renderBlocks(false) !!}
36 |
37 | @endsection
38 |
--------------------------------------------------------------------------------
/resources/views/front/form/_error.blade.php:
--------------------------------------------------------------------------------
1 | @if ($errors->has($name))
2 |
3 | {{ $errors->first($name) }}
4 |
5 | @endif
6 |
--------------------------------------------------------------------------------
/resources/views/front/form/_field.blade.php:
--------------------------------------------------------------------------------
1 | @php
2 | $sectionIndex ??= null;
3 | $fieldIndex ??= null;
4 |
5 | $fieldName = "fields[{$sectionIndex}][{$fieldIndex}]";
6 | $fieldId = "fields.{$sectionIndex}.{$fieldIndex}";
7 |
8 | $fieldClass = collect(['field', 'block']);
9 |
10 | switch ($field->input('width')) {
11 | case 'half':
12 | $fieldClass->push('col-span-1');
13 | break;
14 |
15 | case 'full':
16 | default:
17 | $fieldClass->push('md:col-span-2');
18 | break;
19 | }
20 | @endphp
21 |
22 |
23 |
30 |
31 | @includeFirst(["front.form.{$type}", 'front.form.input'], [
32 | 'type' => $type,
33 | 'name' => $fieldName,
34 | 'id' => $fieldId,
35 | 'field' => $field,
36 | 'attributes' => $field->present()->formFieldAttributes,
37 | ])
38 |
39 | @include('front.form._error', [
40 | 'name' => $fieldId,
41 | ])
42 |
43 |
--------------------------------------------------------------------------------
/resources/views/front/form/checkbox.blade.php:
--------------------------------------------------------------------------------
1 |
2 | @foreach ($field->present()->formFieldOptions as $option)
3 |
7 | @endforeach
8 |
9 |
--------------------------------------------------------------------------------
/resources/views/front/form/input.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/views/front/form/radio.blade.php:
--------------------------------------------------------------------------------
1 |
2 | @foreach ($field->present()->formFieldOptions as $option)
3 |
7 | @endforeach
8 |
9 |
--------------------------------------------------------------------------------
/resources/views/front/form/select.blade.php:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/resources/views/front/form/textarea.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/resources/views/front/layouts/app.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | {!! \Artesaos\SEOTools\Facades\SEOTools::generate() !!}
10 |
11 |
12 |
13 | {{-- Favicons --}}
14 |
15 |
16 |
17 |
18 |
19 |
20 | @include('front.partials.header')
21 |
22 |
23 | @yield('content')
24 |
25 |
26 | @include('front.partials.footer')
27 | @include('front.partials.scripts')
28 | @include('front.partials.analytics')
29 |
30 |
31 |
--------------------------------------------------------------------------------
/resources/views/front/layouts/blocks.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | @yield('content')
14 |
15 |
16 | @include('front.partials.scripts')
17 |
18 |
19 |
--------------------------------------------------------------------------------
/resources/views/front/menu/footer.blade.php:
--------------------------------------------------------------------------------
1 |
2 | @foreach (Code4Romania\Cms\Models\Menu::getLocation('footer') as $item)
3 |
4 | -
5 | @if (!empty($item['url']))
6 | {{ $item['label'] }}
11 | @else
12 | {{ $item['label'] }}
13 | @endif
14 |
15 |
16 | @foreach ($item['children'] as $children)
17 | -
18 | {{ $children['label'] }}
23 |
24 | @endforeach
25 |
26 | @endforeach
27 |
28 |
--------------------------------------------------------------------------------
/resources/views/front/pages/show.blade.php:
--------------------------------------------------------------------------------
1 | @extends('front.layouts.app')
2 |
3 | @section('content')
4 | @includeWhen($item->show_header === true, 'front.partials.page-header', [
5 | 'title' => $item->title,
6 | 'description' => $item->description,
7 | ])
8 |
9 | @include('front.blocks._container', [
10 | 'item' => $item
11 | ])
12 | @endsection
13 |
--------------------------------------------------------------------------------
/resources/views/front/partials/analytics.blade.php:
--------------------------------------------------------------------------------
1 | @if (config('analytics.tracking_id'))
2 |
29 | @endif
30 |
--------------------------------------------------------------------------------
/resources/views/front/partials/footer.blade.php:
--------------------------------------------------------------------------------
1 | @inject('social', 'Code4Romania\Cms\Helpers\SocialHelper')
2 |
3 |
29 |
--------------------------------------------------------------------------------
/resources/views/front/partials/header.blade.php:
--------------------------------------------------------------------------------
1 |
20 |
21 | @include('front.partials.notice')
22 |
--------------------------------------------------------------------------------
/resources/views/front/partials/notice.blade.php:
--------------------------------------------------------------------------------
1 | @inject('settings', 'Code4Romania\Cms\Helpers\SettingsHelper')
2 |
3 | @php
4 | $site = $settings->getSection('site');
5 | $enabled = boolval($site['notice_enabled'] ?? false);
6 | $content = $site['notice_content'] ?? null;
7 |
8 | // workaround until this get merged: https://github.com/area17/twill/pull/653
9 | if (isset($site['notice_color'])) {
10 | $color = config('cms.colors')[$site['notice_color']] ?? null;
11 | }
12 |
13 | $color ??= null;
14 | @endphp
15 |
16 | @if ($enabled)
17 |
18 | @endif
19 |
--------------------------------------------------------------------------------
/resources/views/front/partials/page-header.blade.php:
--------------------------------------------------------------------------------
1 | @php
2 | $title ??= '';
3 | $description ??= '';
4 | @endphp
5 |
6 |
7 |
8 | {{ $title }}
9 |
10 |
11 | @if ($description)
12 | {!! $description !!}
13 | @endif
14 |
15 |
--------------------------------------------------------------------------------
/resources/views/front/partials/scripts.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/resources/views/front/partners/card.blade.php:
--------------------------------------------------------------------------------
1 | @php
2 | $outerClass = 'relative h-0 bg-white border border-gray-400 aspect-ratio-1/1';
3 | @endphp
4 |
5 |
6 | @if ($partner->website)
7 |
14 | @else
15 |
16 | @endif
17 |
18 |
19 |
24 |
25 |
26 | @if ($partner->website)
27 |
28 | @else
29 |
30 | @endif
31 |
32 |
33 |
--------------------------------------------------------------------------------
/resources/views/front/people/card.blade.php:
--------------------------------------------------------------------------------
1 | @php
2 | $showDescription ??= false;
3 | @endphp
4 |
5 |
6 |
7 |
8 |
14 |
15 | @foreach (['github', 'linkedin'] as $network)
16 | @continue(!$person->$network)
17 |
18 |
19 | @endforeach
20 |
21 |
22 |
23 |
{{ $person->name }}
24 | {{ $person->title }}
25 |
26 |
27 |
28 |
29 | @if ($showDescription && $person->description)
30 |
31 | {!! $person->description !!}
32 |
33 | @endif
34 |
35 |
--------------------------------------------------------------------------------
/resources/views/front/posts/card.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | @if ($item->hasImage('image'))
5 |
11 | @else
12 | {{ svg('logo-sm-gray', 'absolute inset-0 flex items-center justify-center w-full h-full p-10 lg:p-20') }}
13 | @endif
14 |
15 |
16 |
17 | {{ $item->present()->publishDate }}
18 |
19 | @if ($item->author)
20 | ·
21 | {{ $item->author }}
22 | @endif
23 |
24 |
25 |
{{ $item->title }}
26 |
27 |
{{ $item->description }}
28 |
29 | @if ($item->categories->count())
30 |
31 | {{ $item->categories->pluck('title')->join(', ') }}
32 |
33 | @endif
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/resources/views/front/posts/index.blade.php:
--------------------------------------------------------------------------------
1 | @inject('settings', 'Code4Romania\Cms\Helpers\settingsHelper')
2 |
3 | @extends('front.layouts.app')
4 |
5 | @section('content')
6 | @include('front.partials.page-header', [
7 | 'title' => $settings->get('blogTitle', 'site'),
8 | 'description' => $settings->get('blogDescription', 'site'),
9 | ])
10 |
11 |
12 | @foreach ($items as $item)
13 | @include('front.posts.card', [
14 | 'item' => $item,
15 | ])
16 | @endforeach
17 |
18 | {{ $items->links('front.partials.pagination') }}
19 |
20 | @endsection
21 |
--------------------------------------------------------------------------------
/routes/admin.php:
--------------------------------------------------------------------------------
1 | group(static function (): void {
11 | Route::module('posts');
12 | Route::module('categories');
13 | });
14 |
15 | if (config('cms.enabled.people')) {
16 | Route::prefix('people')->group(static function (): void {
17 | Route::module('people');
18 | Route::module('cityLabs');
19 | });
20 | }
21 |
22 | Route::prefix('forms')->group(static function (): void {
23 | Route::module('forms');
24 | Route::module('responses');
25 | });
26 | }
27 |
--------------------------------------------------------------------------------
/src/Commands/Build.php:
--------------------------------------------------------------------------------
1 | option('install')) {
29 | $this->info('Installing npm dependencies');
30 | $this->runProcess(['npm', 'install', '--no-save', '--prefer-offline', '--no-audit']);
31 | $this->runProcess(['npm', 'ci'], base_path('vendor/area17/twill'));
32 | } else {
33 | $this->info('Reusing npm dependencies');
34 | }
35 |
36 | $this->info('Building the ckeditor');
37 | $this->runProcess(['npm', 'run', 'ckeditor:build']);
38 |
39 | $this->info('Building the public frontend');
40 | $this->runProcess(['npm', 'run', 'prod']);
41 |
42 | $this->info('Building the Twill frontend');
43 | $this->call('twill:build', ['--noInstall' => true]);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/Commands/Command.php:
--------------------------------------------------------------------------------
1 | setTty(Process::isTtySupported())
16 | ->setWorkingDirectory($cwd ?? getcwd())
17 | ->setTimeout($timeout)
18 | ->mustRun();
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/FakerServiceProvider.php:
--------------------------------------------------------------------------------
1 | app->bind(Generator::class, static function () {
23 | $faker = Factory::create();
24 | $faker->addProvider(new PicsumImageProvider($faker));
25 |
26 | return $faker;
27 | });
28 | }
29 |
30 | /**
31 | * Bootstrap services.
32 | *
33 | * @return void
34 | */
35 | public function boot()
36 | {
37 | //
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/Helpers/MailchimpHelper.php:
--------------------------------------------------------------------------------
1 | map(function ($list) {
20 | return [
21 | 'id' => $list['id'],
22 | 'name' => $list['name'],
23 | ];
24 | });
25 | });
26 | } catch (Throwable $th) {
27 | return collect();
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Helpers/SettingsHelper.php:
--------------------------------------------------------------------------------
1 | saveAll($fields, $section);
22 | }
23 |
24 | public static function getSection(string $section): array
25 | {
26 | return Cache::rememberForever('settings.' . $section, function () use ($section) {
27 | return Setting::query()
28 | ->where('section', $section)
29 | ->with('translations')
30 | ->get()
31 | ->mapWithKeys(fn ($item) => [$item->key => $item->value])
32 | ->toArray();
33 | });
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/Helpers/SocialHelper.php:
--------------------------------------------------------------------------------
1 | map(function ($value, $key) use ($settings): ?string {
20 | $username = $settings[$key] ?? null;
21 |
22 | if ($username === null) {
23 | return null;
24 | }
25 |
26 | return $value['baseUrl'] . $username;
27 | })
28 | ->filter();
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Http/Controllers/Admin/CategoryController.php:
--------------------------------------------------------------------------------
1 | */
16 | protected $indexOptions = [
17 | 'editInModal' => false,
18 | 'publish' => false,
19 | ];
20 |
21 | /** @var array */
22 | protected $indexWith = [
23 | 'translations',
24 | ];
25 |
26 | /** @var array */
27 | protected $indexForm = [
28 | 'translations',
29 | ];
30 | }
31 |
--------------------------------------------------------------------------------
/src/Http/Controllers/Admin/CityLabController.php:
--------------------------------------------------------------------------------
1 | */
28 | protected $indexWith = [
29 | 'medias',
30 | ];
31 |
32 | /** @var array */
33 | protected $indexOptions = [];
34 |
35 | /** @var array */
36 | protected $indexColumns = [
37 | 'image' => [
38 | 'thumb' => true,
39 | 'field' => 'image',
40 | 'variant' => [
41 | 'role' => 'image',
42 | 'crop' => 'default',
43 | ],
44 | ],
45 | 'name' => [
46 | 'title' => 'Name',
47 | 'field' => 'name',
48 | 'sort' => true,
49 | ],
50 | 'people' => [
51 | 'title' => 'People',
52 | 'field' => 'people_count',
53 | 'sort' => true,
54 | ],
55 | ];
56 |
57 | /** @var array */
58 | protected $browserColumns = [
59 | 'title' => [
60 | 'title' => 'Name',
61 | 'field' => 'name',
62 | ],
63 | ];
64 | }
65 |
--------------------------------------------------------------------------------
/src/Http/Controllers/Admin/FormController.php:
--------------------------------------------------------------------------------
1 | */
12 | protected $formWith = [
13 | 'blocks.files',
14 | 'blocks.medias',
15 | ];
16 |
17 | /** @var array */
18 | protected $indexOptions = [
19 | 'permalink' => false,
20 | 'editInModal' => false,
21 | 'reorder' => false,
22 | ];
23 | }
24 |
--------------------------------------------------------------------------------
/src/Http/Controllers/Admin/MenuController.php:
--------------------------------------------------------------------------------
1 | */
12 | protected $formWith = [
13 | 'blocks.files',
14 | 'blocks.medias',
15 | ];
16 |
17 | /** @var array */
18 | protected $indexOptions = [
19 | 'permalink' => false,
20 | 'editInModal' => false,
21 | 'reorder' => false,
22 | ];
23 |
24 | /**
25 | * Disable the content editor (full screen block editor).
26 | *
27 | * @var bool
28 | */
29 | protected $disableEditor = true;
30 |
31 | /** @var array */
32 | protected $indexColumns = [
33 | 'title' => [
34 | 'title' => 'Title',
35 | 'field' => 'title',
36 | 'sort' => true,
37 | ],
38 | 'location' => [
39 | 'title' => 'Location',
40 | 'field' => 'location',
41 | ],
42 | ];
43 | }
44 |
--------------------------------------------------------------------------------
/src/Http/Controllers/Admin/ModuleController.php:
--------------------------------------------------------------------------------
1 | moduleHas('translations') ? '{language}/' : '')
26 | . ($this->moduleHas('revisions') ? '{preview}/' : '')
27 | . ($this->permalinkBase ?? $this->moduleName)
28 | . (isset($this->permalinkBase) && empty($this->permalinkBase) ? '' : '/');
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Http/Controllers/Admin/PageController.php:
--------------------------------------------------------------------------------
1 | */
19 | protected $indexWith = [
20 | 'translations',
21 | ];
22 | }
23 |
--------------------------------------------------------------------------------
/src/Http/Controllers/Admin/PartnerController.php:
--------------------------------------------------------------------------------
1 | */
24 | protected $indexWith = [
25 | 'medias',
26 | ];
27 |
28 | /** @var array */
29 | protected $indexOptions = [
30 | 'permalink' => false,
31 | 'reorder' => true,
32 | ];
33 |
34 | /** @var array */
35 | protected $indexColumns = [
36 | 'image' => [
37 | 'thumb' => true,
38 | 'field' => 'image',
39 | 'variant' => [
40 | 'role' => 'logo',
41 | 'crop' => 'default',
42 | ],
43 | ],
44 | 'name' => [
45 | 'title' => 'Name',
46 | 'field' => 'name',
47 | 'sort' => true,
48 | ],
49 | 'website' => [
50 | 'title' => 'Website',
51 | 'field' => 'website',
52 | ],
53 | ];
54 | }
55 |
--------------------------------------------------------------------------------
/src/Http/Controllers/Admin/PostController.php:
--------------------------------------------------------------------------------
1 | */
19 | protected $indexWith = [
20 | 'translations',
21 | ];
22 |
23 | /** @var array */
24 | protected $indexForm = [
25 | 'translations',
26 | ];
27 |
28 | /** @var array */
29 | protected $indexColumns = [
30 | 'title' => [
31 | 'title' => 'Title',
32 | 'field' => 'title',
33 | 'sort' => true,
34 | ],
35 | 'publishDate' => [
36 | 'title' => 'Publish Date',
37 | 'field' => 'publishDate',
38 | 'present' => true,
39 | ],
40 | ];
41 | }
42 |
--------------------------------------------------------------------------------
/src/Http/Controllers/Admin/ResponseController.php:
--------------------------------------------------------------------------------
1 | */
12 | protected $indexOptions = [
13 | 'create' => false,
14 | 'edit' => true,
15 | 'publish' => false,
16 | 'bulkPublish' => false,
17 | 'feature' => false,
18 | 'bulkFeature' => false,
19 | 'restore' => true,
20 | 'bulkRestore' => true,
21 | 'delete' => true,
22 | 'bulkDelete' => true,
23 | 'reorder' => false,
24 | 'permalink' => false,
25 | 'bulkEdit' => true,
26 | 'editInModal' => false,
27 | 'forceDelete' => true,
28 | 'bulkForceDelete' => true,
29 | ];
30 |
31 | /** @var array */
32 | protected $indexColumns = [
33 | 'title' => [
34 | 'title' => 'Title',
35 | 'field' => 'title',
36 | 'sort' => true,
37 | ],
38 | 'form' => [
39 | 'title' => 'Form',
40 | 'field' => 'form',
41 | 'present' => true,
42 | ],
43 | 'date' => [
44 | 'title' => 'Date',
45 | 'field' => 'created_at',
46 | 'sort' => true,
47 | 'present' => true,
48 | ],
49 | ];
50 | }
51 |
--------------------------------------------------------------------------------
/src/Http/Controllers/Front/CategoryController.php:
--------------------------------------------------------------------------------
1 | route('front.posts.index');
16 | }
17 |
18 | public function show(string $slug): View
19 | {
20 | $item = Category::query()
21 | ->forSlug($slug)
22 | ->firstOrFail();
23 |
24 | $this->seo([
25 | 'title' => $item->title,
26 | 'description' => $item->description,
27 | 'routeName' => 'front.categories.show',
28 | 'routeArg' => 'slug',
29 | 'slug' => $slug,
30 | ]);
31 |
32 | return view('front.categories.show')->with([
33 | 'item' => $item,
34 | ]);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/Http/Controllers/Front/Controller.php:
--------------------------------------------------------------------------------
1 | findOrFail($request->route('id'));
23 |
24 | $values = $request->validated()['fields'];
25 |
26 | $data = [];
27 |
28 | foreach ($form->getFieldsBySection() as $sectionIndex => $section) {
29 | $data[$sectionIndex] = [
30 | 'title' => $section['title'] ?? null,
31 | 'fields' => [],
32 | ];
33 | foreach ($section['fields'] as $fieldIndex => $field) {
34 | $data[$sectionIndex]['fields'][$fieldIndex] = [
35 | 'label' => $field['label'] ?? null,
36 | 'value' => $values[$sectionIndex][$fieldIndex] ?? null,
37 | ];
38 | }
39 | }
40 |
41 | if ($form->store) {
42 | $response = app(ResponseRepository::class)->create([
43 | 'form_id' => $form->id,
44 | 'data' => $data,
45 | ]);
46 | }
47 |
48 | if ($form->send) {
49 | $form->recipients_collection->each(function ($recipient) use ($response) {
50 | Mail::to($recipient)->send(new FormResponseSubmitted($response));
51 | });
52 | }
53 |
54 | return 'ok';
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/Http/Controllers/Front/NewsletterSubscriptionController.php:
--------------------------------------------------------------------------------
1 | validated();
19 |
20 | Mailchimp::subscribe($attributes['list'], $attributes['email']);
21 |
22 | return back()->with('success', __('form.confirmSubscription'));
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Http/Controllers/Front/PageController.php:
--------------------------------------------------------------------------------
1 | seo([
20 | 'routeName' => 'front.pages.index',
21 | ]);
22 |
23 | return view('front.pages.show')->with([
24 | 'item' => $item,
25 | ]);
26 | }
27 |
28 | public function show(string $slug): View
29 | {
30 | $item = Page::query()
31 | ->forSlug($slug)
32 | ->publishedInListings()
33 | ->firstOrFail();
34 |
35 | $this->seo([
36 | 'title' => $item->title,
37 | 'description' => $item->description,
38 | 'routeName' => 'front.pages.show',
39 | 'routeArg' => 'slug',
40 | 'slug' => $slug,
41 | ]);
42 |
43 | return view('front.pages.show')->with([
44 | 'item' => $item,
45 | ]);
46 | }
47 |
48 | public function preview(string $slug): View
49 | {
50 | $item = Page::query()
51 | ->forSlug($slug)
52 | ->firstOrFail();
53 |
54 | $this->seo([
55 | 'title' => $item->title,
56 | 'description' => $item->description,
57 | ]);
58 |
59 | return view('front.pages.show')->with([
60 | 'item' => $item,
61 | ]);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/Http/Middleware/Authenticate.php:
--------------------------------------------------------------------------------
1 | expectsJson()) {
20 | return route('admin.login.form');
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Http/Middleware/DefaultSeoConfig.php:
--------------------------------------------------------------------------------
1 | $title,
26 | 'seotools.opengraph.defaults.title' => $title,
27 | 'seotools.opengraph.defaults.site_name' => $title,
28 | 'seotools.json-ld.defaults.title' => $title,
29 | ]);
30 | }
31 |
32 | if ('' !== ($description = strip_tags($seo['siteDescription'] ?? ''))) {
33 | Config::set([
34 | 'seotools.meta.defaults.description' => $description,
35 | 'seotools.opengraph.defaults.description' => $description,
36 | 'seotools.json-ld.defaults.description' => $description,
37 | ]);
38 | }
39 |
40 | return $next($request);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/Http/Middleware/RedirectTrailingSlash.php:
--------------------------------------------------------------------------------
1 | getRequestUri())) {
20 | return redirect(rtrim($request->getRequestUri(), '/'), 301);
21 | }
22 |
23 | return $next($request);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Http/Requests/Admin/CategoryRequest.php:
--------------------------------------------------------------------------------
1 | ['required', 'boolean'],
21 | 'send' => ['required', 'boolean'],
22 | 'recipients' => ['required_if:send,1', new OneEmailPerLine],
23 | ];
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Http/Requests/Admin/MenuRequest.php:
--------------------------------------------------------------------------------
1 | ['nullable', 'url'],
18 | ];
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Http/Requests/Admin/PersonRequest.php:
--------------------------------------------------------------------------------
1 | findOrFail($this->route('id'))
21 | ->getFieldsColumn('validation');
22 | }
23 |
24 | /**
25 | * Get custom attributes for validator errors.
26 | *
27 | * @return array
28 | */
29 | public function attributes(): array
30 | {
31 | return Form::query()
32 | ->findOrFail($this->route('id'))
33 | ->getFieldsColumn('label');
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/Http/Requests/Front/NewsletterSubscriptionRequest.php:
--------------------------------------------------------------------------------
1 | ['required', 'email'],
22 | 'list' => ['required', Rule::in(MailchimpHelper::getListsCached()->pluck('id'))],
23 | ];
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Mail/FormResponseSubmitted.php:
--------------------------------------------------------------------------------
1 | response = $response;
28 | }
29 |
30 | /**
31 | * Build the message.
32 | *
33 | * @return $this
34 | */
35 | public function build()
36 | {
37 | return $this
38 | ->subject(__('email.formResponseSubmitted.subject'))
39 | ->markdown('emails.formResponseSubmitted');
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/Models/BaseModel.php:
--------------------------------------------------------------------------------
1 | orderByRaw('FIELD(id,' . implode(',', $ids) . ')');
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/Models/Category.php:
--------------------------------------------------------------------------------
1 | */
18 | protected $with = [
19 | 'translation',
20 | ];
21 |
22 | protected $fillable = [
23 | 'title',
24 | 'description',
25 | ];
26 |
27 | public $translatedAttributes = [
28 | 'title',
29 | 'description',
30 | 'active',
31 | ];
32 |
33 | public $slugAttributes = [
34 | 'title',
35 | ];
36 |
37 | public function posts(): BelongsToMany
38 | {
39 | return $this->belongsToMany(Post::class);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/Models/CityLab.php:
--------------------------------------------------------------------------------
1 | */
20 | protected $with = [
21 | 'translations',
22 | ];
23 |
24 | /** @var array */
25 | protected $withCount = [
26 | 'people',
27 | ];
28 |
29 | /** @var array */
30 | protected $fillable = [
31 | 'published',
32 | 'name',
33 | 'description',
34 | 'position',
35 | ];
36 |
37 | /** @var array */
38 | public $translatedAttributes = [
39 | 'name',
40 | 'description',
41 | 'active',
42 | ];
43 |
44 | /**
45 | * Required when using the HasSlug trait
46 | *
47 | * @var array
48 | */
49 | public $slugAttributes = [
50 | 'name',
51 | ];
52 |
53 | /** @var array */
54 | public $mediasParams = [
55 | 'image' => [
56 | 'default' => [
57 | [
58 | 'name' => 'default',
59 | 'ratio' => 1,
60 | ],
61 | ],
62 | ],
63 | ];
64 |
65 | public function getTitleInBrowserAttribute(): string
66 | {
67 | return $this->name;
68 | }
69 |
70 | public function people()
71 | {
72 | return $this->morphToMany(Person::class, 'personable');
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/Models/Partner.php:
--------------------------------------------------------------------------------
1 | */
24 | protected $fillable = [
25 | 'published',
26 | 'name',
27 | 'website',
28 | 'position',
29 | ];
30 |
31 | /** @var array */
32 | public $mediasParams = [
33 | 'logo' => [
34 | 'default' => [
35 | [
36 | 'name' => 'default',
37 | ],
38 | ],
39 | ],
40 | ];
41 |
42 | public function getTitleInBrowserAttribute(): string
43 | {
44 | return $this->name;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/Models/Response.php:
--------------------------------------------------------------------------------
1 | */
14 | protected $with = [
15 | 'form',
16 | ];
17 |
18 | /** @var array */
19 | protected $casts = [
20 | 'data' => 'array',
21 | ];
22 |
23 | /** @var Presenter */
24 | protected $presenterAdmin = ResponsePresenter::class;
25 |
26 | /** @var array */
27 | protected $fillable = [
28 | 'form_id',
29 | 'data',
30 | ];
31 |
32 | public function form(): BelongsTo
33 | {
34 | return $this->belongsTo(Form::class);
35 | }
36 |
37 | public function attachLabelsToData(array $sections): array
38 | {
39 | $labels = $this->form->getFieldsColumn('label');
40 |
41 | $result = [];
42 | foreach ($sections as $sectionIndex => $section) {
43 | $result[$sectionIndex] = [];
44 | foreach ($section as $fieldIndex => $field) {
45 | $result[$sectionIndex][$fieldIndex] = [
46 | 'label' => $labels["fields.${sectionIndex}.${fieldIndex}"] ?? null,
47 | 'value' => $field,
48 | ];
49 | }
50 | }
51 |
52 | return $result;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/Models/Revisions/CityLabRevision.php:
--------------------------------------------------------------------------------
1 | each(fn ($location) => Cache::forget('menu.' . $location));
16 | }
17 |
18 | /**
19 | * Handle the setting "created" event.
20 | */
21 | public function created(Menu $menu): void
22 | {
23 | $this->clearMenuLocationCache($menu);
24 | }
25 |
26 | /**
27 | * Handle the setting "updated" event.
28 | */
29 | public function updated(Menu $menu): void
30 | {
31 | $this->clearMenuLocationCache($menu);
32 | }
33 |
34 | /**
35 | * Handle the setting "deleted" event.
36 | */
37 | public function deleted(Menu $menu): void
38 | {
39 | $this->clearMenuLocationCache($menu);
40 | }
41 |
42 | /**
43 | * Handle the setting "restored" event.
44 | */
45 | public function restored(Menu $menu): void
46 | {
47 | $this->clearMenuLocationCache($menu);
48 | }
49 |
50 | /**
51 | * Handle the setting "force deleted" event.
52 | */
53 | public function forceDeleted(Menu $menu): void
54 | {
55 | $this->clearMenuLocationCache($menu);
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/Observers/SettingTranslationObserver.php:
--------------------------------------------------------------------------------
1 | setting_id)->section;
16 |
17 | Cache::forget('settings.' . $section);
18 |
19 | if ($section === 'mailchimp') {
20 | Cache::forget('settings.mailchimp.lists');
21 | }
22 | }
23 |
24 | /**
25 | * Handle the setting "created" event.
26 | */
27 | public function created(SettingTranslation $settingTranslation): void
28 | {
29 | $this->clearSettingSectionCache($settingTranslation);
30 | }
31 |
32 | /**
33 | * Handle the setting "updated" event.
34 | */
35 | public function updated(SettingTranslation $settingTranslation): void
36 | {
37 | $this->clearSettingSectionCache($settingTranslation);
38 | }
39 |
40 | /**
41 | * Handle the setting "deleted" event.
42 | */
43 | public function deleted(SettingTranslation $settingTranslation): void
44 | {
45 | $this->clearSettingSectionCache($settingTranslation);
46 | }
47 |
48 | /**
49 | * Handle the setting "restored" event.
50 | */
51 | public function restored(SettingTranslation $settingTranslation): void
52 | {
53 | $this->clearSettingSectionCache($settingTranslation);
54 | }
55 |
56 | /**
57 | * Handle the setting "force deleted" event.
58 | */
59 | public function forceDeleted(SettingTranslation $settingTranslation): void
60 | {
61 | $this->clearSettingSectionCache($settingTranslation);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/Presenters/PartnerPresenter.php:
--------------------------------------------------------------------------------
1 | model->hasImage('logo')) {
12 | return null;
13 | }
14 |
15 | return $this->model->image('logo', 'default', [
16 | 'w' => $size
17 | ]);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Presenters/PersonPresenter.php:
--------------------------------------------------------------------------------
1 | model->cityLab->first()->name ?? '–';
12 | }
13 |
14 | public function imageSrc(int $width = 96): string
15 | {
16 | if (!$this->model->hasImage('image')) {
17 | return $this->model->placeholder_avatar;
18 | }
19 |
20 | return $this->model->image('image', 'default', [
21 | 'w' => $width
22 | ]);
23 | }
24 |
25 | public function imageLqip(): ?string
26 | {
27 | if (!$this->model->hasImage('image')) {
28 | return null;
29 | }
30 |
31 | return $this->model->lowQualityImagePlaceholder('image');
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/Presenters/PostPresenter.php:
--------------------------------------------------------------------------------
1 | model->publish_start_date ?? $this->model->created_at)
14 | ->isoFormat(__('date.format'));
15 | }
16 |
17 | public function categories(): Collection
18 | {
19 | return $this->model->categories
20 | ->map(function ($category) {
21 | return [
22 | 'title' => $category->title,
23 | 'url' => route('front.categories.show', ['slug' => $category->slug]),
24 | ];
25 | });
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Presenters/Presenter.php:
--------------------------------------------------------------------------------
1 | model = $model;
17 | }
18 |
19 | /**
20 | * Allow for property-style retrieval
21 | *
22 | * @return mixed
23 | */
24 | public function __get(string $property)
25 | {
26 | if (method_exists($this, $property)) {
27 | return $this->$property();
28 | }
29 |
30 | return $this->model->$property;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/Presenters/ResponsePresenter.php:
--------------------------------------------------------------------------------
1 | model->form->title ?? '–';
12 | }
13 |
14 | public function created_at(): string
15 | {
16 | return $this->model->created_at->toCookieString();
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/Repositories/CategoryRepository.php:
--------------------------------------------------------------------------------
1 | model = $model;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Repositories/CityLabRepository.php:
--------------------------------------------------------------------------------
1 | [
21 | 'routePrefix' => 'people',
22 | 'titleKey' => 'name',
23 | ],
24 | ];
25 |
26 | public function __construct(CityLab $model)
27 | {
28 | $this->model = $model;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Repositories/FormRepository.php:
--------------------------------------------------------------------------------
1 | model = $model;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Repositories/MenuRepository.php:
--------------------------------------------------------------------------------
1 | model = $model;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Repositories/PageRepository.php:
--------------------------------------------------------------------------------
1 | model = $model;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Repositories/PartnerRepository.php:
--------------------------------------------------------------------------------
1 | model = $model;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Repositories/PersonRepository.php:
--------------------------------------------------------------------------------
1 | [
19 | 'routePrefix' => 'people',
20 | 'titleKey' => 'name',
21 | ],
22 | ];
23 |
24 | public function __construct(Person $model)
25 | {
26 | $this->model = $model;
27 | }
28 |
29 | /**
30 | * @param \Illuminate\Database\Query\Builder $query
31 | * @param array $scopes
32 | * @return \Illuminate\Database\Query\Builder
33 | */
34 | public function filter($query, array $scopes = [])
35 | {
36 | if (array_key_exists('cityLab', $scopes)) {
37 | $cityLab = CityLab::find($scopes['cityLab']);
38 |
39 | if ($cityLab) {
40 | return $cityLab->people();
41 | }
42 | }
43 |
44 | return parent::filter($query, $scopes);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/Repositories/PostRepository.php:
--------------------------------------------------------------------------------
1 | model = $model;
23 |
24 | $this->browsers = [
25 | 'categories' => [
26 | 'routePrefix' => 'blog',
27 | ],
28 | ];
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Repositories/ResponseRepository.php:
--------------------------------------------------------------------------------
1 | model = $model;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/Rules/OneEmailPerLine.php:
--------------------------------------------------------------------------------
1 | ['required', 'email'],
14 | ];
15 |
16 | /**
17 | * Determine if the validation rule passes.
18 | *
19 | * @param string $attribute
20 | * @param mixed $value
21 | * @return bool
22 | */
23 | public function passes($attribute, $value): bool
24 | {
25 | $emails = preg_split('/\r\n|\r|\n/', $value);
26 |
27 | foreach ($emails as $email) {
28 | if (Validator::make(['email' => $email], $this->rules)->fails()) {
29 | return false;
30 | }
31 | }
32 |
33 | return true;
34 | }
35 |
36 | /**
37 | * Get the validation error message.
38 | *
39 | * @return string
40 | */
41 | public function message(): string
42 | {
43 | return __('validation.email');
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/tests/Unit/Helpers/SettingsHelperTest.php:
--------------------------------------------------------------------------------
1 | faker->word;
16 | $section = $this->faker->word;
17 |
18 | $settings = [
19 | $field => $this->faker->word,
20 | ];
21 |
22 |
23 | SettingsHelper::set($settings, $section);
24 |
25 | $this->assertEquals($settings[$field], SettingsHelper::get($field, $section));
26 | $this->assertNull(SettingsHelper::get('thisFieldDoesNotExist', $section));
27 | }
28 |
29 | /** @test */
30 | public function it_gets_value_for_section()
31 | {
32 | $field = $this->faker->word;
33 | $section = $this->faker->word;
34 |
35 | $settings = [
36 | $field => $this->faker->word,
37 | ];
38 |
39 | SettingsHelper::set($settings, $section);
40 |
41 | $this->assertEquals($settings, SettingsHelper::getSection($section));
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/tests/Unit/Helpers/SocialHelperTest.php:
--------------------------------------------------------------------------------
1 | assertEmpty(SocialHelper::getNetworks()->toArray());
17 | }
18 |
19 | /** @test */
20 | public function it_fetches_formatted_networks()
21 | {
22 | $user = $this->faker->userName;
23 | $networks = collect(config('cms.social.networks'));
24 |
25 | SettingsHelper::set(
26 | $networks->map(fn (): string => $user)->toArray(),
27 | 'social'
28 | );
29 |
30 | $this->assertSame(
31 | SocialHelper::getNetworks()->toArray(),
32 | $networks
33 | ->map(fn ($network) => $network['baseUrl'] . $user)
34 | ->toArray()
35 | );
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/tests/Unit/Http/Middleware/DefaultSeoConfigTest.php:
--------------------------------------------------------------------------------
1 | states('published')
18 | ->create();
19 |
20 | SettingsHelper::set(['frontPage' => $page->id], 'site');
21 |
22 | $config = [
23 | 'siteTitle' => $this->faker->word,
24 | 'siteDescription' => $this->faker->paragraph,
25 | ];
26 |
27 | SettingsHelper::set($config, 'site');
28 |
29 | $this->visitRoute('front.pages.index')
30 | ->see('' . $config['siteTitle'] . '')
31 | ->see('')
32 | ->see('')
33 |
34 | ->see('')
35 | ->see('');
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/tests/Unit/Http/Middleware/RedirectTrailingSlashTest.php:
--------------------------------------------------------------------------------
1 | handle(Request::create($url, 'GET'), fn () => response('OK', 200))
21 | ->getStatusCode();
22 | }
23 |
24 | /** @test */
25 | public function it_removes_trailing_slash_from_url()
26 | {
27 | $page = factory(Page::class)
28 | ->states('published')
29 | ->create();
30 |
31 | $this->assertEquals(301, $this->requestWithMiddleware("/en/{$page->slug}/"));
32 | $this->assertEquals(200, $this->requestWithMiddleware("/en/{$page->slug}"));
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/tests/Unit/Models/CityLabTest.php:
--------------------------------------------------------------------------------
1 | create();
16 |
17 | $this->assertEquals($cityLab->name, $cityLab->title_in_browser);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/tests/Unit/Models/PartnerTest.php:
--------------------------------------------------------------------------------
1 | create();
16 |
17 | $this->assertEquals($partner->name, $partner->title_in_browser);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/tests/Unit/Models/PersonTest.php:
--------------------------------------------------------------------------------
1 | deleteDirectory('avatars');
18 |
19 | $person = factory(Person::class)->create();
20 |
21 | $this->assertEquals($person->placeholder_avatar, $person->present()->imageSrc);
22 | }
23 |
24 | /** @test */
25 | public function it_fetches_the_browser_title()
26 | {
27 | $person = factory(Person::class)->create();
28 |
29 | $this->assertEquals($person->name, $person->title_in_browser);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/tests/Unit/Presenters/PartnerPresenterTest.php:
--------------------------------------------------------------------------------
1 | create();
17 | $image = factory(Media::class)->create([
18 | 'width' => 200,
19 | 'height' => 200,
20 | ]);
21 |
22 | $partner->medias()->save($image, [
23 | 'crop_x' => 0,
24 | 'crop_y' => 0,
25 | 'crop_w' => $image->width,
26 | 'crop_h' => $image->height,
27 | 'role' => 'logo',
28 | 'crop' => 'default',
29 | 'ratio' => 'default',
30 | 'lqip_data' => null,
31 | 'metadatas' => json_encode([
32 | 'caption' => null,
33 | 'altText' => null,
34 | 'video' => null,
35 | ]),
36 | ]);
37 |
38 | $partner->load('medias');
39 |
40 | $this->assertStringContainsString("/img/{$image->uuid}", $partner->present()->imageSrc);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/tests/Unit/Rules/OneEmailPerLineTest.php:
--------------------------------------------------------------------------------
1 | rule = new OneEmailPerLine();
20 | }
21 |
22 | /**
23 | * @test
24 | * @dataProvider oneEmailPerLine
25 | */
26 | public function it_passes_valid_input(string $input)
27 | {
28 | $this->assertTrue($this->rule->passes('test', $input));
29 | }
30 |
31 | /**
32 | * @test
33 | * @dataProvider multipleEmailsPerLine
34 | */
35 | public function it_fails_invalid_input(string $input)
36 | {
37 | $this->assertFalse($this->rule->passes('test', $input));
38 | }
39 |
40 | public function oneEmailPerLine(): array
41 | {
42 | return [
43 | 'single' => ["test1@example.net"],
44 | '\n' => ["test2@example.net\ntest2@example.org"],
45 | '\r' => ["test3@example.net\rtest3@example.org"],
46 | '\r\n' => ["test4@example.net\r\ntest4@example.org"],
47 | ];
48 | }
49 |
50 | public function multipleEmailsPerLine(): array
51 | {
52 | return [
53 | 'space' => ["test2@example.net test2@example.org"],
54 | 'comma' => ["test3@example.net,test3@example.org"],
55 | 'tab' => ["test4@example.net\ttest4@example.org"],
56 | ];
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/webpack.mix.js:
--------------------------------------------------------------------------------
1 | const mix = require('laravel-mix');
2 |
3 | mix.config.fileLoaderDirs.fonts = 'fonts';
4 |
5 | mix.webpackConfig({
6 | devtool: mix.config.production ? 'none' : 'source-map',
7 | });
8 |
9 | if (mix.config.production) {
10 | mix.version();
11 | }
12 |
13 | const config = [
14 | require('postcss-import'),
15 | require('tailwindcss')('./tailwind.config.js'),
16 | require('postcss-nested')({
17 | bubble: ['screen'],
18 | }),
19 | ];
20 |
21 | mix.setPublicPath('public/assets/cms')
22 | .setResourceRoot('./')
23 |
24 | .js('resources/assets/js/app.js', 'public/assets/cms')
25 | .postCss('resources/assets/css/app.pcss', 'public/assets/cms', config)
26 | .postCss('resources/assets/css/content.pcss', 'public/assets/cms', config)
27 | .extract();
28 |
--------------------------------------------------------------------------------