Compare commits

...

195 Commits

Author SHA1 Message Date
edX requirements bot
3f12c52221 chore!: Dropped support for Node 12 (#207)
BREAKING CHANGE: Dropped Node12 support
2022-05-16 20:56:26 +05:00
Renovate Bot
826d071566 chore(deps): update dependency @edx/paragon to v19.22.1 2022-05-16 11:37:34 +00:00
edX requirements bot
b66ae651b6 feat: Add package-lock file version check (#206) 2022-05-12 12:22:31 +05:00
Renovate Bot
d23a4e2443 chore(deps): update dependency redux to v4.2.0 2022-05-09 10:46:31 +00:00
Renovate Bot
898b90eb07 chore(deps): update dependency @edx/paragon to v19.20.0 2022-05-02 11:29:16 +00:00
Renovate Bot
dbb806d0a3 chore(deps): update dependency @edx/frontend-build to v9.2.2 2022-05-02 11:21:30 +00:00
Renovate Bot
702bce8587 chore(deps): update dependency prop-types to v15.8.1 2022-04-25 11:43:11 +00:00
Renovate Bot
0bd6c9d452 chore(deps): update dependency @edx/paragon to v19.19.0 2022-04-25 11:35:17 +00:00
Renovate Bot
3d4d356665 chore(deps): update dependency @edx/paragon to v19.18.0 2022-04-18 14:59:37 +00:00
Renovate Bot
e656865502 chore(deps): update dependency react-router-dom to v5.3.1 2022-04-18 14:51:49 +00:00
Renovate Bot
2b4283ac5f chore(deps): update dependency @edx/paragon to v19.15.0 2022-04-11 12:59:17 +00:00
Renovate Bot
38d9a2076b fix(deps): update dependency @fortawesome/react-fontawesome to v0.1.18 2022-04-11 12:51:38 +00:00
Usama Sadiq
a31d1a5387 Merge pull request #190 from openedx/jenkins/transifex-client-migration-dcc3617
fix: transifex migration to new client
2022-04-06 12:43:06 +05:00
UsamaSadiq
a374cee7dd build: update transifex pull translations command 2022-04-05 15:35:38 +05:00
Renovate Bot
3f50a4d333 chore(deps): update dependency react-redux to v7.2.8 2022-04-04 11:11:31 +00:00
Renovate Bot
45f0f20f0f chore(deps): update dependency @edx/frontend-build to v9.1.4 2022-04-04 11:03:03 +00:00
Adolfo R. Brandes
29a5db5e1a Merge pull request #178 from ayrtonlr/master
Change the logo to link to the LMS
2022-03-24 06:46:46 -03:00
Ayrton Lima
7982251640 fix: change logo anchor tag to link to the LMS 2022-03-23 20:21:53 -03:00
edX requirements bot
9824aecd16 fix: transifex migration to new client 2022-03-17 08:47:05 -04:00
Renovate Bot
dcc361747e chore(deps): update dependency @edx/frontend-build to v9.1.2 2022-03-14 10:12:05 +00:00
Jawayria
863ecb41bd Merge pull request #187 from openedx/jawayria/upgrade-deps
fix: Upgraded dependencies for Node 16 support
2022-03-04 14:47:23 +05:00
Jawayria
f6d02d177d fix: Upgraded dependencies for Node 16 support 2022-03-04 13:53:46 +05:00
David Joy
7e196f48cf build: We no longer want this CODEOWNERS file.
The community-engineering team no longer exists.
2022-02-28 09:53:13 -05:00
Jawayria
46e4c78af8 Merge pull request #185 from openedx/jawayria/fix-release-ci
fix: Added semantic-release v17 in package.json to fix release CI
2022-02-28 18:44:58 +05:00
Jawayria
affbcbeb19 fix: Added semantic-release v17 in package.json to fix release CI 2022-02-28 17:31:34 +05:00
Jawayria
8c10919eb9 Merge pull request #177 from openedx/jenkins/node-16-2b56d27
feat: Added support for node v16
2022-02-25 17:25:02 +05:00
edX requirements bot
314781ac0b feat: Added support for Node v16 2022-02-25 17:22:36 +05:00
Sarina Canelake
b75ab299bd Merge DEPR automation workflow
Add DEPR workflow automation
2022-02-24 15:21:45 -05:00
Sarina Canelake
1fb4475b9a build: add DEPR workflow automation 2022-02-23 14:36:53 -05:00
Renovate Bot
2b56d270a2 chore(deps): update dependency @edx/frontend-platform to v1.14.1 2021-11-29 09:47:56 +00:00
Renovate Bot
395c9240a0 chore(deps): update dependency @edx/frontend-platform to v1.14.0 2021-11-08 09:03:26 +00:00
Renovate Bot
60ceedced9 chore(deps): update dependency redux to v4.1.2 2021-11-01 09:59:30 +00:00
Renovate Bot
032e4dd73f chore(deps): update dependency react-redux to v7.2.6 2021-11-01 09:48:29 +00:00
Renovate Bot
212bc015ad fix(deps): update dependency @fortawesome/react-fontawesome to v0.1.16 2021-10-25 09:42:17 +00:00
Renovate Bot
d72eaa6fab chore(deps): update dependency husky to v7.0.4 2021-10-25 09:30:59 +00:00
Ned Batchelder
1f5b74de21 build: no need for local commitlint.config.js 2021-10-22 14:23:04 -04:00
Ned Batchelder
07728e1498 build: use the organization commitlint check 2021-10-07 13:48:27 -04:00
Renovate Bot
5d44307136 chore(deps): update commitlint monorepo to v13.2.0 2021-10-04 08:21:39 +00:00
Renovate Bot
1769069cfe chore(deps): update dependency @edx/frontend-platform to v1.12.7 2021-09-20 08:33:36 +00:00
Renovate Bot
2fb0cac399 chore(deps): update dependency @edx/frontend-platform to v1.12.6 2021-09-13 11:48:51 +00:00
Renovate Bot
807dc66714 chore(deps): update dependency react-router-dom to v5.3.0 2021-09-06 08:38:27 +00:00
Renovate Bot
ea837695e9 chore(deps): update dependency react-redux to v7.2.5 2021-09-06 08:26:11 +00:00
stvn
e4801b8b81 merge(#135): renovate/codecov-codecov-action-2.x
commits
=======
- chore(deps): update codecov/codecov-action action to v2
2021-09-01 15:35:58 -07:00
Renovate Bot
89337c4819 chore(deps): update codecov/codecov-action action to v2 2021-08-30 08:41:29 +00:00
Renovate Bot
c75f6c079e chore(deps): update dependency husky to v7.0.2 2021-08-30 08:41:09 +00:00
Renovate Bot
77c251467c chore(deps): update dependency @edx/frontend-platform to v1.12.4 2021-08-23 09:20:49 +00:00
Renovate Bot
caba23d51b chore(deps): update dependency @edx/frontend-platform to v1.12.3 2021-08-16 06:55:48 +00:00
stvn
efbae26c56 merge(#137): renovate/major-commitlint-monorepo
commits
=======
- chore(deps): update commitlint monorepo to v13
2021-08-10 10:34:25 -07:00
Renovate Bot
efeacb8b73 chore(deps): update commitlint monorepo to v13 2021-08-10 06:39:06 +00:00
stvn
a0865c9c56 merge(#131): renovate/husky-7.x
commits
=======
- chore(deps): update dependency husky to v7
2021-08-09 23:34:47 -07:00
Renovate Bot
7cfd6932d5 chore(deps): update dependency husky to v7 2021-08-09 08:59:46 +00:00
Renovate Bot
e2f92992b6 fix(deps): update font awesome 2021-08-09 08:49:15 +00:00
Renovate Bot
f37e6c164e chore(deps): update dependency redux to v4.1.1 2021-08-09 08:35:40 +00:00
Renovate Bot
fef30fb8b5 chore(deps): update dependency @edx/frontend-platform to v1.11.3 2021-08-02 06:43:59 +00:00
Renovate Bot
bcac04d0cc chore(deps): update dependency codecov to v3.8.3 2021-07-26 07:06:11 +00:00
Renovate Bot
15ff0203ab chore(deps): update dependency @edx/frontend-platform to v1.11.1 2021-07-12 08:08:45 +00:00
stvn
940294d2a0 merge(#93): renovate/major-commitlint-monorepo
commits
=======
- chore(deps): update commitlint monorepo to v12
2021-06-14 15:35:19 -07:00
Renovate Bot
acd4a843a4 chore(deps): update commitlint monorepo to v12 2021-06-14 20:17:17 +00:00
Renovate Bot
d8ee5425bf chore(deps): update dependency @edx/paragon to v12.8.0 2021-06-14 20:13:11 +00:00
Renovate Bot
1d9e8d3c47 chore(deps): update dependency @edx/frontend-platform to v1.11.0 2021-06-14 20:04:09 +00:00
stvn
4d370f8a75 merge(#117): renovate/husky-6.x
commits
=======
- chore(deps): update dependency husky to v6
2021-06-11 23:22:51 -07:00
Renovate Bot
2a2be8eddb chore(deps): update dependency husky to v6 2021-06-11 20:56:20 +00:00
Renovate Bot
e7624adbfb chore(deps): update dependency @edx/frontend-build to v5.6.14 2021-06-11 20:45:14 +00:00
Renovate Bot
5d0a418e85 chore(deps): update dependency redux to v4.1.0 2021-06-09 07:17:17 +00:00
stvn
f5b18cdd54 merge(#111): renovate/actions-setup-node-2.x
commits
=======
- chore(deps): update actions/setup-node action to v2
2021-06-08 10:26:22 -07:00
Renovate Bot
d5d290bcbe chore(deps): update actions/setup-node action to v2 2021-06-08 08:45:20 +00:00
Renovate Bot
49c02c157b chore(deps): update react monorepo to v16.14.0 2021-06-08 08:35:06 +00:00
Renovate Bot
94b4aa7402 chore(deps): update dependency react-redux to v7.2.4 2021-06-08 08:16:27 +00:00
stvn
a9fe23287f merge(#19): build/renovate
commits
=======
- build(renovate): fix json syntax
2021-06-07 22:38:00 -07:00
stvn
30874b4972 build(renovate): fix json syntax 2021-06-07 22:37:21 -07:00
stvn
14d53ef514 merge(#125): build/renovate-stricter
commits
=======
- build(renovate): be more selective about automerging devDependencies
2021-06-04 13:41:14 -07:00
stvn
5c9270d88a build(renovate): be more selective about automerging devDependencies 2021-06-04 13:22:06 -07:00
Renovate Bot
f70ca27b34 chore(deps): update dependency react-router-dom to v5.2.0 2021-06-04 01:53:30 +00:00
Renovate Bot
d247e88541 fix(deps): update font awesome 2021-06-04 01:32:35 +00:00
Renovate Bot
ea257afcca chore(deps): update dependency husky to v3.1.0 2021-06-03 22:39:52 +00:00
Renovate Bot
24603cf98f chore(deps): update dependency enzyme-adapter-react-16 to v1.15.6 2021-06-03 22:14:10 +00:00
Renovate Bot
4249bbc6df chore(deps): update dependency enzyme to v3.11.0 2021-06-03 21:47:26 +00:00
Renovate Bot
611beb8294 chore(deps): pin dependencies 2021-06-03 21:20:20 +00:00
Renovate Bot
87803604b1 chore(deps): update dependency codecov to v3.8.2 2021-06-03 20:52:09 +00:00
Renovate Bot
99344d93a4 chore(deps): update commitlint monorepo 2021-06-03 20:21:45 +00:00
stvn
2a718743ea merge(#124): build/renovate
commits
=======
- build(renovate): be more liberal about what automerges
2021-06-03 11:15:55 -07:00
stvn
4fe8909ad5 build(renovate): be more liberal about what automerges
based on https://github.com/edx/frontend-app-account .
2021-06-03 10:48:02 -07:00
stvn
a0dc37dfb5 merge: stvn/own/code 2021-05-26 13:42:27 -07:00
stvn
e4917030fa build: add CODEOWNERS; edx/community-engineering
Background
==========
As part of our Squad-based ownership, we should stay on top of what
happens in these repositories. However, due to the number of
repositories (and subsequently pull requests) across the edX ecosystem,
it is challenging to stay on top of notifications, separating the
'signal' from the 'noise'. Email filters can go a long way to taming
Inbox notifications, but this is manual and requires maintenance as
Squad ownership changes. It also fails to account for Github-specific behavior.

Proposal
========
By leveraging Github support for `CODEOWNERS` files [1],
we can ensure that our team is at least CCed explicitly, here,
in the form a requested review. This request is just that, a request,
not a requirement; we are not enacting any new merge requirements
at this time.

- [1] https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners
2021-05-26 12:15:49 -07:00
David Joy
c756f42c28 docs: Updating README with repository details. (#122)
* docs: Specify component usage requirements in the README.

This includes both the component's dependency on @edx/frontend-platform, as well as its required environment variables.

* docs: fix verbatim formatting

* docs: improving footer README

Including headings and formatting consistent with frontend-component-header.  Hopefully others soon.
2021-05-14 12:57:09 -04:00
Renovate Bot
1b6a5eda0b chore(deps): update dependency @edx/frontend-platform to v1.8.4 2021-02-07 11:57:37 +00:00
David Joy
cbaf4bbb9e fix: remove unnecessary paragon peer dependency (#114)
The actual component code doesn’t use paragon.  Only the example app does, meaning this isn’t really a peer dependency.
2021-02-04 14:25:31 -05:00
Renovate Bot
c990cbbf5e fix(deps): update font awesome 2021-01-31 09:56:38 +00:00
Renovate Bot
b41af87b8e chore(deps): update dependency @edx/frontend-platform to v1.8.1 2021-01-23 11:58:46 +00:00
Carla Duarte
a7d59a874c Merge pull request #108 from edx/ciduarte/AA-465
fix: remove unnecessary aria-label
2021-01-07 09:33:22 -05:00
Carla Duarte
d66d3b7b62 fix: remove unnecessary aria-label 2021-01-06 17:23:50 -05:00
Jawayria
7095e79471 Merge pull request #103 from Jawayria/update-badge
Updated the build status badge to point to travis-ci.com
2020-12-17 13:47:00 +05:00
Renovate Bot
4a9b3f2bfb fix(deps): update font awesome 2020-12-11 09:58:08 +00:00
Jeff Chaves
e4d23d366b feat: upgrading deps, retheme with from @edx/brand, pull logo from config settings (#104)
* feat: upgrading deps, use logo from @edx/brand

* feat: upgrading peer deps

* feat: pr feedback

* update snapshots and example app

* pull config from AppContext

Co-authored-by: Adam Stankiewicz <agstanki@gmail.com>
2020-11-30 14:00:26 -05:00
Adam Stankiewicz
2e75cc95cb ci: migrate to use GH actions (#106)
* ci: migrate to use GH actions

* ci: change gh action names
2020-11-30 13:56:29 -05:00
Jawayria
f64faf9f14 Updated the build status badge to point to travis-ci.com 2020-11-20 15:01:06 +05:00
Renovate Bot
0be3098191 chore(deps): update dependency codecov to v3.7.2 2020-07-22 03:36:15 +00:00
renovate[bot]
799cdb3b3c chore(deps): update dependency codecov to v3.7.1 [security] (#95)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2020-07-21 09:26:50 -04:00
Renovate Bot
370ae52c04 fix(deps): update dependency @fortawesome/fontawesome-svg-core to v1.2.30 2020-07-15 18:20:09 +00:00
Renovate Bot
5037a5610b fix(deps): update font awesome 2020-07-04 09:56:32 +00:00
Renovate Bot
0a91f8242f fix(deps): update dependency @fortawesome/fontawesome-svg-core to v1.2.28 2020-03-23 16:19:06 +00:00
Renovate Bot
457bd843cf fix(deps): update dependency @fortawesome/react-fontawesome to v0.1.9 2020-03-05 18:10:56 +00:00
Renovate Bot
777c697c41 fix(deps): update dependency @fortawesome/fontawesome-svg-core to v1.2.27 2020-02-07 16:09:34 +00:00
Renovate Bot
b3b32613c9 chore(deps): update dependency codecov to v3.6.5 2020-02-07 15:11:57 +00:00
Renovate Bot
a6f70e895a chore(deps): update dependency codecov to v3.6.4 2020-02-01 03:12:36 +00:00
Renovate Bot
1112b426f0 chore(deps): update dependency codecov to v3.6.3 2020-01-31 14:13:51 +00:00
Renovate Bot
17278cc355 chore(deps): update dependency codecov to v3.6.2 2020-01-23 20:22:47 +00:00
Renovate Bot
65c25bfc95 fix(deps): update dependency @fortawesome/fontawesome-svg-core to v1.2.26 2019-12-11 00:12:05 +00:00
Renovate Bot
75e8962563 fix(deps): update dependency @fortawesome/react-fontawesome to v0.1.8 2019-12-06 17:14:43 +00:00
Renovate Bot
65aba84491 fix(deps): update font awesome 2019-12-04 23:19:08 +00:00
Renovate Bot
093dfa6ac2 chore(deps): update react monorepo to v16.10.2 2019-12-04 22:15:57 +00:00
Renovate Bot
4637834750 chore(deps): update dependency husky to v3.0.9 2019-12-04 21:04:01 +00:00
Renovate Bot
a021e72359 chore(deps): update dependency @edx/paragon to v7.1.5 2019-12-04 20:39:24 +00:00
Renovate Bot
925ddb7adf chore(deps): update dependency @edx/frontend-platform to v1.1.6 2019-12-04 20:21:15 +00:00
David Joy
9ebcd15623 Update renovate.json 2019-12-04 14:25:58 -05:00
Adam Butterworth
3a2e553feb fix: upgrade frontend-build for i18n extract fix (#67) 2019-12-03 16:00:43 -05:00
Adam Butterworth
eb6c253e35 fix: upgrade frontend-build to fix translation job (#65) 2019-12-03 14:13:11 -05:00
David Joy
d2315c2c21 build: dev tweaks (#64)
* build: dev tweaks

need an eslintrc file and to gitignore .vscode directories

* Update .eslintrc.js
2019-12-03 10:46:32 -05:00
Adam Butterworth
f33a972933 fix: upgrade frontend-platform (#63) 2019-12-03 10:33:28 -05:00
Adam Butterworth
d540aaa390 feat: upgrade to frontend-platform (#60)
BREAKING CHANGE: This package now relies upon frontend-platform instead of individual runway packages.
2019-11-21 17:18:26 -05:00
Adam Butterworth
c64496dd08 Update README.rst 2019-10-08 12:54:29 -04:00
edX Transifex Bot
e94cf3ac2d fix(i18n): update translations 2019-10-06 16:33:20 -04:00
David Joy
d4259ef1f6 feat: handleAllTrackEvents is no longer used (#48)
* feat: use frontend-analytics directly

BREAKING CHANGE: handleAllTrackEvents is no longer part of the Footer props API.  The footer uses frontend-analytics’s sendTrackEvent directly.

Also updating other dependencies to keep them up to date.  This part should probably be a separate PR, technically.

* fix: remove unused dependency of frontend-logging

* fix: a little PR cleanup

* fix: putting frontend logging back

It’s needed by frontend-i18n and fails if it’s not there for tests.

* fix: pinning npm at 6
2019-10-02 14:59:12 -04:00
renovate[bot]
b4f35d37c8 chore(deps): add renovate.json (#47) 2019-10-02 12:34:44 -04:00
Adam Butterworth
83bad3d47b feat: repurpose as open edx footer (#46)
* feat: simplify prop api and bake in many values

* feat: refactor build and dev server

BREAKING CHANGE: The footer is now  transpiled from es6 preserving modules. To use this package in a project it must now be transpiled by the requiring project via webpack or other configuration

* feat: make this the open edx footer

BREAKING CHANGE: This footer now serves as the Open edX footer. For the edX footer see edx/frontend-component-footer-edx on github
2019-09-30 14:33:06 -04:00
AlasdairSwan
31e255ebe9 Merge pull request #44 from edx/alasdair/remove-paragon
perf(paragon): remove paragon to reduce bundle size
2019-06-21 11:14:29 -04:00
AlasdairSwan
349f83f686 perf(paragon): remove paragon to reduce bundle size 2019-06-21 11:11:01 -04:00
David Joy
e0c205ce14 fix: non deprecated use of hyperlink (#43) 2019-06-21 09:56:05 -04:00
albemarle
81398c8cfd Merge pull request #42 from edx/albemarle/different-diff
fix(i18n): make detect_changed_source_translations work for both push and pull jobs
2019-06-11 13:51:08 -04:00
albemarle
3fcd76b455 fix(i18n): make detect_changed_source_translations work for both push and pull jobs 2019-06-11 13:34:27 -04:00
edX Transifex Bot
a8f57aa553 fix(i18n): update translations 2019-06-09 16:32:55 -04:00
David Joy
f32b0c8dcf Merge pull request #40 from edx/djoy/upgrade_i18n
fix: upgrade frontend-i18n library
2019-06-07 11:12:41 -04:00
David Joy
fb1f5c2d50 fix: delete old i18n concat file 2019-06-07 10:53:50 -04:00
David Joy
1a51d992cd Update .gitignore 2019-06-07 10:07:30 -04:00
David Joy
e9c28163d9 fix: upgrade frontend-i18n library 2019-06-07 08:58:38 -04:00
AlasdairSwan
6db2d70e97 Merge pull request #37 from edx/alasdair/update-link-sections-to-accept-arrays
fix(linkprops): update link props
2019-06-04 09:03:27 -04:00
AlasdairSwan
3ab4adf10b fix(linkprops): update link props
BREAKING CHANGE move to link arrays and remove strings from component (and thus the need for i18n)
2019-06-03 15:57:30 -04:00
edX Transifex Bot
a482325eac fix(i18n): update translations 2019-06-02 17:33:12 -04:00
Douglas Hall
d919d1a577 Merge pull request #38 from edx/douglashall/finish_i18n_refactoring
fix: modify babelrc for i18n
2019-05-31 14:17:28 -04:00
Douglas Hall
4b3a91138d fix: modify babelrc for i18n 2019-05-31 14:11:48 -04:00
David Joy
7680ad3393 Merge pull request #36 from edx/djoy/is-es5
fix: adding es check
2019-05-28 13:33:09 -04:00
David Joy
061b41bee8 fix: adding es check 2019-05-28 09:42:04 -04:00
Douglas Hall
cacae4789f fix: move to @edx/frontend-i18n dependency (#35)
fix: move to @edx/frontend-i18n dependency
2019-05-24 14:20:22 -04:00
Douglas Hall
adceca6b53 fix: move to @edx/frontend-i18n dependency
BREAKING CHANGE: consumers will now be required to supply @edx/frontend-i18n instead of react-intl
2019-05-24 12:06:17 -04:00
Douglas Hall
ab61fd35eb Merge pull request #34 from edx/douglashall/reduce_bundle_size
fix: remove paragon from bundle
2019-05-23 14:34:38 -04:00
Douglas Hall
4d739f2962 fix: remove paragon from bundle
BREAKING CHANGE: Now requires containing app to provide `@edx/paragon`.
2019-05-23 14:28:28 -04:00
albemarle
28a6c85bc0 Merge pull request #30 from edx/aehsan/prod-277/update_the_edx_icp_license
Updated ICP license in footer
2019-05-22 14:01:36 -04:00
adeelehsan
6125988bbd Updated ICP license in footer 2019-05-22 00:33:19 +05:00
edX Transifex Bot
9eeccc63cb fix(i18n): update translations 2019-05-19 17:33:41 -04:00
Robert Raposa
2f33c6718b Merge pull request #31 from edx/robrap/ARCH-748-fix-i18n-jobs
fix(i18n): fix i18n make targets
2019-05-16 13:20:46 -04:00
Adam Stankiewicz
89397fcfdb Merge pull request #32 from edx/astankiewicz/downgrade-query-string
fix(query-string): downgrade query-string to version 5 for es5
2019-05-16 12:57:21 -04:00
Adam Stankiewicz
278b4b1473 fix(query-string): downgrade query-string to version 5 for es5 2019-05-16 09:44:44 -07:00
Robert Raposa
7ff9039bb7 fix(i18n): fix i18n make targets
ARCH-748
2019-05-16 12:27:27 -04:00
Chris Pappas
0cf3164901 Merge pull request #28 from edx/cpappas/ENT-1888
fix: updating enterprise marketing link logic
2019-05-10 16:55:50 -04:00
Christopher Pappas
bf8020dfac fix: updating business marketing footer
fix: adding https:// to business marketing link

fix: fixing marketing link for business

fix: fixing marketing link for business
2019-05-10 15:49:40 -04:00
Adam Butterworth
f2a13b8c8e fix: move dependencies out of footer 2019-05-10 08:27:18 -06:00
Adam Butterworth
3dd9b25d11 fix: move peerDependencies to dependencies 2019-05-10 10:24:23 -04:00
Adam Butterworth
21d7fe04e3 fix: move dependencies out of footer 2019-05-10 10:14:37 -04:00
AlasdairSwan
46d464d515 Merge pull request #27 from edx/alasdair/add-language-selector
Alasdair/add language selector
2019-05-08 13:42:52 -04:00
AlasdairSwan
85ed8fbff4 feat(langselect): add optional language selector 2019-05-08 13:38:01 -04:00
AlasdairSwan
d6adfec189 Merge pull request #25 from edx/alasdair/update-social-media-link-approach
fix(sociallinks): update link props
2019-05-07 12:53:21 -04:00
AlasdairSwan
8b1943356e fix(sociallinks): update link props
BREAKING CHANGE will not render social links unless array is passed in
2019-05-07 12:17:42 -04:00
AlasdairSwan
5aae6e8336 Merge pull request #26 from edx/alasdair/version-bump
fix(version): trivial update to minor version bump
2019-05-07 12:12:33 -04:00
AlasdairSwan
ae18ad45b9 fix(version): trivial update to minor version bump 2019-05-07 11:56:32 -04:00
AlasdairSwan
0e15bb7e55 Merge pull request #24 from edx/alasdair/revert-social-media-links
Revert social media links PR
2019-05-07 11:30:02 -04:00
AlasdairSwan
ff664b9d3b Revert social media links PR 2019-05-07 11:24:04 -04:00
AlasdairSwan
da91fb6392 Merge pull request #23 from edx/alasdair/fontawesome-svg-and-social-link-array-prop
fix(sociallinks): array for social props BREAKING CHANGE: props change
2019-05-07 10:29:25 -04:00
AlasdairSwan
f265c7daa6 fix(sociallinks): array for social props BREAKING CHANGE: props change 2019-05-06 15:08:50 -04:00
albemarle
3037e4d8a6 Merge pull request #22 from edx/albemarle/i18n-travis
build: validate i18n
2019-05-06 10:20:20 -04:00
albemarle
b2a7696c0e build: validate i18n 2019-05-03 15:32:30 -04:00
albemarle
6dc8f64ccb Merge pull request #19 from edx/albemarle/more-i18n
fix(i18n): use up-to-date i18n-concat.js
2019-04-09 15:46:31 -04:00
albemarle
0453d7fbaa fix(i18n): use up-to-date i18n-concat.js 2019-04-09 15:38:46 -04:00
Robert Raposa
fa6d38f422 Merge pull request #18 from edx/albemarle/check-changes
fix(i18n): add detect_changed_source_translations target to stop jobs erroring
2019-04-05 16:52:44 -04:00
albemarle
9f3e945d4e fix(i18n): add detect_changed_source_translations target to stop jobs erroring 2019-04-05 16:42:50 -04:00
edX Transifex Bot
429d19291d fix(i18n): update translations 2019-04-05 16:21:24 -04:00
Matt Tuchfarber
e27bc8de39 Merge pull request #16 from edx/tuchfarber/remove_translation_fail
fix: remove incorrect translation files
2019-04-05 15:38:56 -04:00
Matt Tuchfarber
cd0b84c223 fix: remove incorrect translation files
Remove translation files that were generated by an incorrect transifex
config
2019-04-05 15:33:23 -04:00
Matt Tuchfarber
26810c99e6 Merge pull request #15 from edx/tuchfarber/make_umd_build
Generate builds so they can be used in server rendered apps
2019-04-05 15:20:44 -04:00
Matt Tuchfarber
2fb8ea2608 Generate builds so they can be used in server rendered apps
Current build uses window everywhere, thus breaking server rendered apps
2019-04-05 12:34:52 -04:00
albemarle
16c6da229b Merge pull request #14 from edx/tuchfarber/fix_i18n_quoting
Fix i18n paths
2019-04-04 15:26:50 -04:00
Matt Tuchfarber
fb8de7a59c Fix i18n paths 2019-04-04 15:13:55 -04:00
Robert Raposa
21a9e6c5e1 Merge pull request #13 from edx/robrap/ARCH-460-change-file-ext
fix: update file extension
2019-03-21 14:52:25 -04:00
Robert Raposa
9475888392 fix: update file extension 2019-03-21 14:45:35 -04:00
Robert Raposa
c069f20716 Merge pull request #12 from edx/robrap/ARCH-460-add-empty-language
ARCH-460: fix: add empty language files
2019-03-20 17:14:10 -04:00
Robert Raposa
46772ecc0e fix: add empty language files
ARCH-460
2019-03-20 17:03:47 -04:00
edX Transifex Bot
ca09a07c62 fix(i18n): update translations 2019-03-20 16:36:53 -04:00
Robert Raposa
66f6832887 Merge pull request #9 from edx/robrap/ARCH-460-i18n
ARCH-460: feat: initial localization of footer
2019-03-20 13:16:42 -04:00
Robert Raposa
8f35487558 feat: initial localization of footer
BREAKING CHANGE: Now requires containing app to use `react-intl`. See
update to README for details.

ARCH-460
2019-03-20 12:37:11 -04:00
Adam Butterworth
349a458617 Merge pull request #8 from edx/abutterworth/unique-ids
fix: add unique ids to Icon components
2019-03-08 14:00:06 -05:00
Adam Butterworth
abe3d03f58 fix: update snapshot to reflect new ids 2019-03-08 12:44:00 -05:00
Adam Butterworth
7af4b71faa fix: add unique ids to Icon components 2019-03-08 12:35:35 -05:00
Robert Raposa
7f2c5b32b1 Merge pull request #7 from edx/robrap/update-readme
Update README.rst
2019-03-08 09:44:26 -05:00
Robert Raposa
6e0f9cf30a fix(docs): update README.rst
Add a note to clarify that this component is not really
a flexible site footer at this time.
2019-03-06 09:36:43 -05:00
Robert Raposa
3dc70a890f Merge pull request #6 from edx/robrap/ARCH-378-add-test
fix(analytics): add test and fix youtube
2019-01-22 16:26:43 -05:00
Robert Raposa
a37ef7f701 fix(analytics): add test and fix youtube
Adds unit testing and fixes analytics for youtube.
2019-01-22 16:18:14 -05:00
60 changed files with 43009 additions and 20554 deletions

View File

@@ -1,44 +0,0 @@
{
"env": {
"development": {
"presets": [
["env", {
"targets": {
"browsers": ["last 2 versions", "ie 11"]
}
}],
"babel-preset-react"
],
"plugins": [
"transform-object-rest-spread"
]
},
"test": {
"presets": [
["env", {
"targets": {
"browsers": ["last 2 versions", "ie 11"]
}
}],
"babel-preset-react"
],
"plugins": [
"rewire",
"transform-object-rest-spread"
]
},
"production": {
"presets": [
["env", {
"targets": {
"browsers": ["last 2 versions", "ie 11"]
}
}],
"babel-preset-react"
],
"plugins": [
"transform-object-rest-spread"
]
}
}
}

19
.env.development Normal file
View File

@@ -0,0 +1,19 @@
ACCESS_TOKEN_COOKIE_NAME=edx-jwt-cookie-header-payload
BASE_URL=localhost:8080
CREDENTIALS_BASE_URL=http://localhost:18150
CSRF_TOKEN_API_PATH=/csrf/api/v1/token
ECOMMERCE_BASE_URL=http://localhost:18130
LANGUAGE_PREFERENCE_COOKIE_NAME=openedx-language-preference
LMS_BASE_URL=http://localhost:18000
LOGIN_URL=http://localhost:18000/login
LOGOUT_URL=http://localhost:18000/login
MARKETING_SITE_BASE_URL=http://localhost:18000
ORDER_HISTORY_URL=localhost:1996/orders
REFRESH_ACCESS_TOKEN_ENDPOINT=http://localhost:18000/login_refresh
SEGMENT_KEY=null
SITE_NAME=Open edX
USER_INFO_COOKIE_NAME=edx-user-info
LOGO_URL=https://edx-cdn.org/v3/default/logo.svg
LOGO_TRADEMARK_URL=https://edx-cdn.org/v3/default/logo-trademark.svg
LOGO_WHITE_URL=https://edx-cdn.org/v3/default/logo-white.svg
FAVICON_URL=https://edx-cdn.org/v3/default/favicon.ico

View File

@@ -1,3 +1,4 @@
coverage
dist
example
node_modules

3
.eslintrc.js Normal file
View File

@@ -0,0 +1,3 @@
const { createConfig } = require('@edx/frontend-build');
module.exports = createConfig('eslint');

View File

@@ -1,19 +0,0 @@
{
"extends": "eslint-config-edx",
"rules": {
"import/no-extraneous-dependencies": [
"error",
{
"devDependencies": [
"webpack.config.js",
"src/tests/setupTest.js",
"**/*.test.jsx",
"**/*.test.js"
]
}
]
},
"env": {
"jest": true
}
}

View File

@@ -0,0 +1,19 @@
# Run the workflow that adds new tickets that are either:
# - labelled "DEPR"
# - title starts with "[DEPR]"
# - body starts with "Proposal Date" (this is the first template field)
# to the org-wide DEPR project board
name: Add newly created DEPR issues to the DEPR project board
on:
issues:
types: [opened]
jobs:
routeissue:
uses: openedx/.github/.github/workflows/add-depr-ticket-to-depr-board.yml@master
secrets:
GITHUB_APP_ID: ${{ secrets.GRAPHQL_AUTH_APP_ID }}
GITHUB_APP_PRIVATE_KEY: ${{ secrets.GRAPHQL_AUTH_APP_PEM }}
SLACK_BOT_TOKEN: ${{ secrets.SLACK_ISSUE_BOT_TOKEN }}

35
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,35 @@
name: Default CI
on:
push:
branches:
- master
pull_request:
branches:
- '**'
jobs:
tests:
runs-on: ubuntu-latest
strategy:
matrix:
node: [16]
steps:
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Setup Nodejs
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node }}
- name: Install dependencies
run: npm ci
- name: Validate package-lock.json changes
run: make validate-no-uncommitted-package-lock-changes
- name: Lint
run: npm run lint
- name: Test
run: npm run test
- name: i18n_extract
run: npm run i18n_extract
- name: Coverage
uses: codecov/codecov-action@v2

10
.github/workflows/commitlint.yml vendored Normal file
View File

@@ -0,0 +1,10 @@
# Run commitlint on the commit messages in a pull request.
name: Lint Commit Messages
on:
- pull_request
jobs:
commitlint:
uses: edx/.github/.github/workflows/commitlint.yml@master

View File

@@ -0,0 +1,13 @@
#check package-lock file version
name: Lockfile Version check
on:
push:
branches:
- master
pull_request:
jobs:
version-check:
uses: openedx/.github/.github/workflows/lockfileversion-check.yml@master

37
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,37 @@
name: Release CI
on:
push:
branches:
- master
jobs:
release:
name: Release
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: 16
- name: Install dependencies
run: npm ci
- name: Validate package-lock.json changes
run: make validate-no-uncommitted-package-lock-changes
- name: Lint
run: npm run lint
- name: Test
run: npm run test
- name: i18n_extract
run: npm run i18n_extract
- name: Coverage
uses: codecov/codecov-action@v2
- name: Build
run: npm run build
- name: Release
env:
GITHUB_TOKEN: ${{ secrets.SEMANTIC_RELEASE_GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.SEMANTIC_RELEASE_NPM_TOKEN }}
run: npx semantic-release

7
.gitignore vendored
View File

@@ -1,5 +1,12 @@
.DS_Store
coverage
dist
node_modules
temp
.idea/
src/i18n/transifex_input.json
temp/babel-plugin-react-intl
/.vscode
module.config.js

View File

@@ -1,19 +0,0 @@
language: node_js
node_js:
- 8
cache:
directories:
- "~/.npm"
install:
- npm install
script:
- npm run lint
- npm run test
- npm run build
after_success:
- npm run travis-deploy-once "npm run semantic-release"
- npm run coveralls
env:
global:
- secure: dxQadqP6tsoJzHcqs/Hs5AjE42z45q8ZeWKP5HcjbXoJURB4gc1uIxLky0FA6ZpulaTgRVTLcWQbx9yOODc9PQuFnFEDWlCg5EP8tONzeu7BVlJvV5eakgGUhl9w2pekBKsTGhK5dDg2y2D8bGfIL55UX81uiWeytp8s/y8QNs/FNXx9ScJnfhnC+2RfW52fB7iW12F1VYdQfVe43o5PsHze+YhB3FU/ztGe3iMaQiq9QplZWpvqQMpI7pTjyUAX8ITiiPS6UvLFObgpXpfjZdgd+yveFoi3z8o8F0NkmzBphFeSYFjFZE0qJ8bnGNIZldanMeuUgHmDeTwVmKQFhH2LqqnfcdGgW6UsKcHkSN1G51zzad2dEwAHrgxj1NkMp3JfEed2C7Kvntl6KRjVDmYZqHJvt+e+AHNbpjzblOW8tYMIrdz0TeJdk4D9pP3B3tRCtP6fvQ3GLzAMnaCrSsN6hZ9YVxWku8sg8WNEDHl14sZsdgk312MlHIdiUw97FHGrqx/NCix4IkUlCBDbKYbKzbZp20FfzZcwNRNH74+k6xpOnMGSfq8gByEhm9y02MBL76HiAI2VGct2La1ExaUfoikYGoNaZpFcZyOZKo6PYTYHpiUJmqrEnDyVQEOOXUaVsxWXwnYq/mU4nOEPKCRbNpPoksZdNxf6jlmMi8s=
- secure: lrlV0WQaXTRJ2lqDkFZ+1RkRb7YM/STOViOHUNboXb5+1ReVwY0wklFDVk/Qigp3jkbqWfzkBmEjSDVGDLD61QjpGY4BsxZ/Jn3+KUdo0n82Ym6cI/je1fH2gqDLi4U8bylmnkI5oEjV/1txDxkj4hF5w/Leo/oGue3xQohpi//ihhm/PxzExj+QiDqyZPZ5RQZeqLfPEU3Wff04vLE5bRmy1nDTZrgm5Wb1n5ItGsyrUyrCGuAM9kIEun65Snb8hxCuU9pSm1w/xF73iOGLiiC8KZhLu6SxSKoC872ai1GpUXNIqA8kpVeH0Erf5opMtqJT3jTTan/VOFQEoOeAKhR0ga+5rfK2jkhhN77B98dGVndNCfBpDlgQxVv42H6riFk3payZT262QiUqDejiBDtSPTokTGxf7xFtQkQQahhxVXzC2HRKEkDTXNSP8cvk2JJ4zCcUgxJpycudLMuC/Xv0upK+Q0caItBrHxfVNnRKkjKqlDxRhA8nXTY8d2n19FNi7wahCECbyweJJ76EaJaa/Ib6remUBrbGLoQ2PkaSMBHAcn3+7+H/6x11b2s1RHj5qyfIyrvZcDDyNuxdXwpOkhtrkwZsjgtOfXL6IuxW5FExgPPr8B9nNwJJKdTxyxgfqtwBR5+m9nrMixzT6AMe95torZ6eX40gKZ/O9EU=

9
.tx/config Normal file
View File

@@ -0,0 +1,9 @@
[main]
host = https://www.transifex.com
[o:open-edx:p:edx-platform:r:frontend-component-footer]
file_filter = src/i18n/messages/<lang>.json
source_file = src/i18n/transifex_input.json
source_lang = en
type = KEYVALUEJSON

58
Makefile Executable file
View File

@@ -0,0 +1,58 @@
transifex_resource = frontend-component-footer
transifex_langs = "ar,fr,es_419,zh_CN"
transifex_utils = ./node_modules/.bin/transifex-utils.js
i18n = ./src/i18n
transifex_input = $(i18n)/transifex_input.json
tx_url1 = https://www.transifex.com/api/2/project/edx-platform/resource/$(transifex_resource)/translation/en/strings/
tx_url2 = https://www.transifex.com/api/2/project/edx-platform/resource/$(transifex_resource)/source/
# This directory must match .babelrc .
transifex_temp = ./temp/babel-plugin-react-intl
build:
rm -rf ./dist
./node_modules/.bin/fedx-scripts babel src --out-dir dist --source-maps --ignore **/*.test.jsx,**/__mocks__,**/__snapshots__,**/setupTest.js --copy-files
@# --copy-files will bring in everything else that wasn't processed by babel. Remove what we don't want.
@rm -rf dist/**/*.test.jsx
@rm -rf dist/**/__snapshots__
@rm -rf dist/__mocks__
requirements:
npm install
i18n.extract:
# Pulling display strings from .jsx files into .json files...
rm -rf $(transifex_temp)
npm run-script i18n_extract
i18n.concat:
# Gathering JSON messages into one file...
$(transifex_utils) $(transifex_temp) $(transifex_input)
extract_translations: | requirements i18n.extract i18n.concat
# Despite the name, we actually need this target to detect changes in the incoming translated message files as well.
detect_changed_source_translations:
# Checking for changed translations...
git diff --exit-code $(i18n)
# Pushes translations to Transifex. You must run make extract_translations first.
push_translations:
# Pushing strings to Transifex...
tx push -s
# Fetching hashes from Transifex...
./node_modules/reactifex/bash_scripts/get_hashed_strings.sh $(tx_url1)
# Writing out comments to file...
$(transifex_utils) $(transifex_temp) --comments
# Pushing comments to Transifex...
./node_modules/reactifex/bash_scripts/put_comments.sh $(tx_url2)
# Pulls translations from Transifex.
pull_translations:
tx pull -f --mode reviewed --languages=$(transifex_langs)
# This target is used by Travis.
validate-no-uncommitted-package-lock-changes:
# Checking for package-lock.json changes...
git diff --exit-code package-lock.json

View File

@@ -1,38 +1,96 @@
#########################
frontend-component-footer
=========================
#########################
|Build Status| |Coveralls| |npm_version| |npm_downloads| |license|
|semantic-release|
|Build Status| |Codecov| |npm_version| |npm_downloads| |license| |semantic-release|
frontend-component-footer is a library containing a site footer
component for use when building edX frontend applications.
********
Overview
********
A generic footer for Open edX micro-frontend applications. It includes a logo and an optional language selector dropdown.
************
Requirements
************
This component uses ``@edx/frontend-platform`` services such as i18n, analytics, configuration, and the ``AppContext`` React component, and expects that it has been loaded into a micro-frontend that has been properly initialized via ``@edx/frontend-platform``'s ``initialize`` function. `Please visit the frontend template application to see an example. <https://github.com/edx/frontend-template-application/blob/3355bb3a96232390e9056f35b06ffa8f105ed7ca/src/index.jsx>`_
Environment Variables
=====================
This component requires that the following environment variable be set by the consuming micro-frontend.
* ``LMS_BASE_URL`` - The URL of the LMS of your Open edX instance.
* ``LOGO_TRADEMARK_URL`` - This is a URL to a logo for use in the footer. This is a different environment variable than ``LOGO_URL`` (used in frontend-component-header) to accommodate sites that would like to have additional trademark information on a logo in the footer, such as a (tm) or (r) symbol.
************
Installation
************
To install this footer into your Open edX micro-frontend, run the following command in your MFE:
``npm i --save @edx/frontend-component-footer``
This will make the component available to be imported into your application.
*****
Usage
-----
*****
To install frontend-component-footer into your project::
This library has the following exports:
npm i --save @edx/frontend-component-footer
* ``(default)``: The footer as a React component.
* ``messages``: Internationalization messages suitable for use with `@edx/frontend-platform/i18n <https://edx.github.io/frontend-platform/module-Internationalization.html>`_
* ``dist/footer.scss``: A SASS file which contains style information for the component. It should be imported into the micro-frontend's own SCSS file.
The component expects properties specifying the various URLs that are
linked in the footer. See the sample app in src/index.jsx for an example
of how the SiteFooter component can be specified.
<Footer /> component props
==========================
* onLanguageSelected: Provides the footer with an event handler for when the user selects a
language from its dropdown.
* supportedLanguages: An array of objects representing available languages. See example below for object shape.
Examples
========
Component Usage Example::
import Footer, { messages } from '@edx/frontend-component-footer';
...
<Footer
onLanguageSelected={(languageCode) => {/* set language */}}
supportedLanguages={[
{ label: 'English', value: 'en'},
{ label: 'Español', value: 'es' },
]}
/>
* `An example of minimal component and messages usage. <https://github.com/edx/frontend-template-application/blob/3355bb3a96232390e9056f35b06ffa8f105ed7ca/src/index.jsx#L23>`_
* `An example of SCSS file usage. <https://github.com/edx/frontend-template-application/blob/3cd5485bf387b8c479baf6b02bf59e3061dc3465/src/index.scss#L9>`_
***********
Development
-----------
***********
Start the dev server::
Install dependencies::
npm i && npm start
npm i
Build the component::
Start the development server::
npm run build
npm start
.. |Build Status| image:: https://api.travis-ci.org/edx/frontend-component-footer.svg?branch=master
:target: https://travis-ci.org/edx/frontend-component-footer
.. |Coveralls| image:: https://img.shields.io/coveralls/edx/frontend-component-footer.svg?branch=master
:target: https://coveralls.io/github/edx/frontend-component-footer
Build a production distribution::
npm run build
.. |Build Status| image:: https://api.travis-ci.com/edx/frontend-component-footer.svg?branch=master
:target: https://travis-ci.com/edx/frontend-component-footer
.. |Codecov| image:: https://img.shields.io/codecov/c/github/edx/frontend-component-footer
:target: @edx/frontend-component-footer
.. |npm_version| image:: https://img.shields.io/npm/v/@edx/frontend-component-footer.svg
:target: @edx/frontend-component-footer
.. |npm_downloads| image:: https://img.shields.io/npm/dt/@edx/frontend-component-footer.svg

3
babel.config.js Normal file
View File

@@ -0,0 +1,3 @@
const { createConfig } = require('@edx/frontend-build');
module.exports = createConfig('babel-preserve-modules');

View File

@@ -1,3 +0,0 @@
module.exports = {
extends: ['@commitlint/config-angular'],
};

View File

@@ -1,15 +0,0 @@
// This is the common Webpack config. The dev and prod Webpack configs both
// inherit config defined here.
const path = require('path');
module.exports = {
entry: {
app: path.resolve(__dirname, '../src/index.jsx'),
},
output: {
path: path.resolve(__dirname, '../dist'),
},
resolve: {
extensions: ['.js', '.jsx'],
},
};

View File

@@ -1,115 +0,0 @@
// This is the dev Webpack config. All settings here should prefer a fast build
// time at the expense of creating larger, unoptimized bundles.
const Merge = require('webpack-merge');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
const commonConfig = require('./webpack.common.config.js');
module.exports = Merge.smart(commonConfig, {
mode: 'development',
entry: [
// enable react's custom hot dev client so we get errors reported in the browser
require.resolve('react-dev-utils/webpackHotDevClient'),
path.resolve(__dirname, '../src/index.jsx'),
],
module: {
// Specify file-by-file rules to Webpack. Some file-types need a particular kind of loader.
rules: [
// The babel-loader transforms newer ES2015+ syntax to older ES5 for older browsers.
// Babel is configured with the .babelrc file at the root of the project.
{
test: /\.(js|jsx)$/,
include: [
path.resolve(__dirname, '../src'),
],
loader: 'babel-loader',
options: {
// Caches result of loader to the filesystem. Future builds will attempt to read from the
// cache to avoid needing to run the expensive recompilation process on each run.
cacheDirectory: true,
},
},
// We are not extracting CSS from the javascript bundles in development because extracting
// prevents hot-reloading from working, it increases build time, and we don't care about
// flash-of-unstyled-content issues in development.
{
test: /(.scss|.css)$/,
use: [
'style-loader', // creates style nodes from JS strings
{
loader: 'css-loader', // translates CSS into CommonJS
options: {
sourceMap: true,
},
},
{
loader: 'sass-loader', // compiles Sass to CSS
options: {
sourceMap: true,
includePaths: [
path.join(__dirname, '../node_modules'),
path.join(__dirname, '../src'),
],
},
},
],
},
// Webpack, by default, uses the url-loader for images and fonts that are required/included by
// files it processes, which just base64 encodes them and inlines them in the javascript
// bundles. This makes the javascript bundles ginormous and defeats caching so we will use the
// file-loader instead to copy the files directly to the output directory.
{
test: /\.(woff2?|ttf|svg|eot)(\?v=\d+\.\d+\.\d+)?$/,
loader: 'file-loader',
},
{
test: /\.(jpe?g|png|gif|ico)(\?v=\d+\.\d+\.\d+)?$/,
use: [
'file-loader',
{
loader: 'image-webpack-loader',
options: {
optimizationlevel: 7,
mozjpeg: {
progressive: true,
},
gifsicle: {
interlaced: false,
},
pngquant: {
quality: '65-90',
speed: 4,
},
},
},
],
},
],
},
// Specify additional processing or side-effects done on the Webpack output bundles as a whole.
plugins: [
// Generates an HTML file in the output directory.
new HtmlWebpackPlugin({
inject: true, // Appends script tags linking to the webpack bundles at the end of the body
template: path.resolve(__dirname, '../public/index.html'),
}),
new webpack.EnvironmentPlugin({
NODE_ENV: 'development',
}),
// when the --hot option is not passed in as part of the command
// the HotModuleReplacementPlugin has to be specified in the Webpack configuration
// https://webpack.js.org/configuration/dev-server/#devserver-hot
new webpack.HotModuleReplacementPlugin(),
],
// This configures webpack-dev-server which serves bundles from memory and provides live
// reloading.
devServer: {
host: '0.0.0.0',
port: 3000,
historyApiFallback: true,
hot: true,
inline: true,
},
});

View File

@@ -1,58 +0,0 @@
// This is the prod Webpack config. All settings here should prefer smaller,
// optimized bundles at the expense of a longer build time.
const Merge = require('webpack-merge');
const commonConfig = require('./webpack.common.config.js');
const path = require('path');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = Merge.smart(commonConfig, {
mode: 'production',
devtool: 'source-map',
entry: './src/lib/index.js',
output: {
path: path.resolve(__dirname, '../dist'),
library: 'frontend-component-footer',
libraryTarget: 'umd',
},
resolve: {
extensions: ['.js', '.jsx'],
alias: {
react: path.resolve(__dirname, './node_modules/react'),
'react-dom': path.resolve(__dirname, './node_modules/react-dom'),
},
},
externals: {
react: {
commonjs: 'react',
commonjs2: 'react',
amd: 'React',
root: 'React',
},
'react-dom': {
commonjs: 'react-dom',
commonjs2: 'react-dom',
amd: 'ReactDOM',
root: 'ReactDOM',
},
},
plugins: [
// Cleans the dist directory before each build
new CleanWebpackPlugin(['dist'], {
root: path.join(__dirname, '../'),
}),
],
module: {
rules: [
{
test: /\.(js|jsx)$/,
include: [
path.resolve(__dirname, '../src/lib'),
],
exclude: /(node_modules)/,
use: [
{ loader: 'babel-loader' },
],
},
],
},
});

33
example/index.jsx Normal file
View File

@@ -0,0 +1,33 @@
import 'babel-polyfill';
import React from 'react';
import ReactDOM from 'react-dom';
import { initialize, getConfig, subscribe, APP_READY } from '@edx/frontend-platform';
import { AppContext, AppProvider } from '@edx/frontend-platform/react';
import Footer from '@edx/frontend-component-footer';
import './index.scss';
subscribe(APP_READY, () => {
ReactDOM.render(
<AppProvider>
<AppContext.Provider value={{
authenticatedUser: null,
config: getConfig(),
}}>
<Footer
onLanguageSelected={() => {}}
supportedLanguages={[
{ label: 'English', value: 'en' },
{ label: 'Español', value: 'es' },
]}
/>
</AppContext.Provider>
</AppProvider>,
document.getElementById('root'),
);
});
initialize({
messages: []
});

6
example/index.scss Normal file
View File

@@ -0,0 +1,6 @@
@import "@edx/brand/paragon/fonts";
@import "@edx/brand/paragon/variables";
@import "@edx/paragon/scss/core/core";
@import "@edx/brand/paragon/overrides";
@import "@edx/frontend-component-footer/footer";

7
jest.config.js Normal file
View File

@@ -0,0 +1,7 @@
const { createConfig } = require('@edx/frontend-build');
module.exports = createConfig('jest', {
setupFiles: [
'<rootDir>/src/setupTest.js',
],
});

8
openedx.yaml Normal file
View File

@@ -0,0 +1,8 @@
# openedx.yaml
---
owner: edx/fedx-team
tags:
- library
- component
- react

60546
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,26 +1,26 @@
{
"name": "@edx/frontend-component-footer",
"version": "1.0.0-semantically-released",
"description": "Site footer component for use when building edX frontend applications",
"main": "dist/main.js",
"module": "dist/main.js",
"description": "Footer component for use when building Open edX frontend applications",
"main": "dist/index.js",
"publishConfig": {
"access": "public"
},
"scripts": {
"build": "NODE_ENV=production BABEL_ENV=production webpack --config=config/webpack.prod.config.js",
"gc": "commit",
"commitmsg": "commitlint -e $GIT_PARAMS",
"coveralls": "cat ./coverage/lcov.info | coveralls",
"lint": "eslint --ext .js --ext .jsx .",
"precommit": "npm run lint",
"prepublishOnly": "npm run build",
"semantic-release": "semantic-release",
"start": "NODE_ENV=development BABEL_ENV=development node_modules/.bin/webpack-dev-server --config=config/webpack.dev.config.js --progress",
"test": "jest --coverage",
"snapshot": "jest --updateSnapshot",
"travis-deploy-once": "travis-deploy-once",
"watch": "watch 'npm run build' ./src"
"build": "make build",
"i18n_extract": "BABEL_ENV=i18n fedx-scripts babel src --quiet > /dev/null",
"lint": "fedx-scripts eslint --ext .js --ext .jsx .",
"snapshot": "fedx-scripts jest --updateSnapshot",
"start": "fedx-scripts webpack-dev-server --progress",
"test": "fedx-scripts jest --coverage"
},
"files": [
"/dist"
],
"husky": {
"hooks": {
"pre-commit": "npm run lint"
}
},
"repository": {
"type": "git",
@@ -33,73 +33,35 @@
},
"homepage": "https://github.com/edx/frontend-component-footer#readme",
"devDependencies": {
"@commitlint/cli": "^7.1.2",
"@commitlint/config-angular": "^6.0.2",
"@commitlint/prompt": "^6.0.2",
"@commitlint/prompt-cli": "^6.0.2",
"babel-cli": "^6.26.0",
"babel-core": "^6.26.3",
"babel-loader": "^7.1.5",
"babel-plugin-rewire": "^1.2.0",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
"babel-preset-env": "^1.7.0",
"babel-preset-react": "^6.24.1",
"clean-webpack-plugin": "^0.1.19",
"coveralls": "^3.0.0",
"css-loader": "^0.28.9",
"@edx/paragon": "^3.8.0",
"enzyme": "^3.3.0",
"enzyme-adapter-react-16": "^1.1.1",
"eslint": "^5.2.0",
"eslint-config-edx": "^4.0.4",
"eslint-plugin-jsx-a11y": "^6.1.2",
"file-loader": "^1.1.9",
"html-webpack-plugin": "^3.2.0",
"image-webpack-loader": "^4.2.0",
"husky": "^0.14.3",
"jest": "23.6.0",
"node-sass": "^4.7.2",
"prop-types": "^15.5.10",
"react": "^16.4.2",
"react-dom": "^16.2.0",
"react-dev-utils": "^5.0.0",
"react-test-renderer": "^16.6.0",
"sass-loader": "^6.0.6",
"semantic-release": "^15.1.7",
"source-map-loader": "^0.2.1",
"style-loader": "^0.20.2",
"travis-deploy-once": "^5.0.0",
"watch": "^1.0.2",
"webpack": "^4.19.1",
"webpack-cli": "^3.1.0",
"webpack-dev-server": "^3.1.9",
"webpack-merge": "^4.2.1"
"@edx/brand": "npm:@edx/brand-openedx@1.1.0",
"@edx/frontend-build": "9.2.2",
"@edx/frontend-platform": "^1.15.1",
"@edx/paragon": "19.22.1",
"codecov": "3.8.3",
"enzyme": "3.11.0",
"enzyme-adapter-react-16": "1.15.6",
"husky": "7.0.4",
"prop-types": "15.8.1",
"react": "16.14.0",
"react-dom": "16.14.0",
"react-redux": "7.2.8",
"react-router-dom": "5.3.1",
"react-test-renderer": "16.14.0",
"reactifex": "1.1.1",
"redux": "4.2.0",
"semantic-release": "^17.0.0"
},
"dependencies": {
"@fortawesome/fontawesome-svg-core": "1.2.36",
"@fortawesome/free-brands-svg-icons": "5.15.4",
"@fortawesome/free-regular-svg-icons": "5.15.4",
"@fortawesome/free-solid-svg-icons": "5.15.4",
"@fortawesome/react-fontawesome": "0.1.18"
},
"peerDependencies": {
"@edx/paragon": "^3.8.0",
"clean-webpack-plugin": "^0.1.19",
"copy-webpack-plugin": "^4.6.0",
"html-webpack-plugin": "^3.2.0",
"@edx/frontend-platform": "^1.8.0",
"prop-types": "^15.5.10",
"react": "^16.4.2",
"react-dom": "^16.2.0",
"webpack": "^4.19.1",
"webpack-merge": "^4.2.1"
},
"jest": {
"setupFiles": [
"./src/tests/setupTest.js"
],
"collectCoverageFrom": [
"src/lib/**/*.{js,jsx}",
"!src/tests/setupTest.js",
"!src/index.js",
"!**/node_modules/**",
"!**/tests/**"
],
"moduleNameMapper": {
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js",
"\\.(css|scss)$": "identity-obj-proxy"
}
"react": "^16.9.0",
"react-dom": "^16.9.0"
}
}

View File

@@ -1,9 +1,9 @@
<!doctype html>
<html lang="en-us">
<html lang="en-us" dir="ltr">
<head>
<title>Footer | edX</title>
<title>Footer</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<div id="root"></div>

28
renovate.json Normal file
View File

@@ -0,0 +1,28 @@
{
"extends": [
"config:base",
"schedule:weekly",
":automergeLinters",
":automergeMinor",
":automergeTesters",
":enableVulnerabilityAlerts",
":rebaseStalePrs",
":semanticCommits",
":updateNotScheduled"
],
"packageRules": [
{
"matchDepTypes": [
"devDependencies"
],
"matchUpdateTypes": [
"lockFileMaintenance",
"minor",
"patch",
"pin"
],
"automerge": true
}
],
"timezone": "America/New_York"
}

5
src/_footer.scss Normal file
View File

@@ -0,0 +1,5 @@
$gray-footer: #fcfcfc !default;
.footer {
background-color: $gray-footer;
}

103
src/components/Footer.jsx Normal file
View File

@@ -0,0 +1,103 @@
import React from 'react';
import PropTypes from 'prop-types';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { sendTrackEvent } from '@edx/frontend-platform/analytics';
import { ensureConfig } from '@edx/frontend-platform/config';
import { AppContext } from '@edx/frontend-platform/react';
import messages from './Footer.messages';
import LanguageSelector from './LanguageSelector';
ensureConfig([
'LMS_BASE_URL',
'LOGO_TRADEMARK_URL',
], 'Footer component');
const EVENT_NAMES = {
FOOTER_LINK: 'edx.bi.footer.link',
};
class SiteFooter extends React.Component {
constructor(props) {
super(props);
this.externalLinkClickHandler = this.externalLinkClickHandler.bind(this);
}
getLocalePrefix(locale) {
const twoLetterPrefix = locale.substring(0, 2).toLowerCase();
if (twoLetterPrefix === 'en') {
return '';
}
return `/${twoLetterPrefix}`;
}
externalLinkClickHandler(event) {
const label = event.currentTarget.getAttribute('href');
const eventName = EVENT_NAMES.FOOTER_LINK;
const properties = {
category: 'outbound_link',
label,
};
sendTrackEvent(eventName, properties);
}
render() {
const {
supportedLanguages,
onLanguageSelected,
logo,
intl,
} = this.props;
const showLanguageSelector = supportedLanguages.length > 0 && onLanguageSelected;
const { config } = this.context;
return (
<footer
role="contentinfo"
className="footer d-flex border-top py-3 px-4"
>
<div className="container-fluid d-flex">
<a
className="d-block"
href={config.LMS_BASE_URL}
aria-label={intl.formatMessage(messages['footer.logo.ariaLabel'])}
>
<img
style={{ maxHeight: 45 }}
src={logo || config.LOGO_TRADEMARK_URL}
alt={intl.formatMessage(messages['footer.logo.altText'])}
/>
</a>
<div className="flex-grow-1" />
{showLanguageSelector && (
<LanguageSelector
options={supportedLanguages}
onSubmit={onLanguageSelected}
/>
)}
</div>
</footer>
);
}
}
SiteFooter.contextType = AppContext;
SiteFooter.propTypes = {
intl: intlShape.isRequired,
logo: PropTypes.string,
onLanguageSelected: PropTypes.func,
supportedLanguages: PropTypes.arrayOf(PropTypes.shape({
label: PropTypes.string.isRequired,
value: PropTypes.string.isRequired,
})),
};
SiteFooter.defaultProps = {
logo: undefined,
onLanguageSelected: undefined,
supportedLanguages: [],
};
export default injectIntl(SiteFooter);
export { EVENT_NAMES };

View File

@@ -0,0 +1,156 @@
import { defineMessages } from '@edx/frontend-platform/i18n';
const messages = defineMessages({
'footer.socialLinks.srText.facebook': {
id: 'footer.socialLinks.srText.facebook',
defaultMessage: 'Like edX on Facebook',
description: 'This is screenreader text for the edX Facebook social media link in the footer.',
},
'footer.socialLinks.srText.twitter': {
id: 'footer.socialLinks.srText.twitter',
defaultMessage: 'Follow edX on Twitter',
description: 'This is screenreader text for the edX Twitter social media link in the footer.',
},
'footer.socialLinks.srText.youtube': {
id: 'footer.socialLinks.srText.youtube',
defaultMessage: 'Subscribe to the edX YouTube channel',
description: 'This is screenreader text for the edX YouTube social media link in the footer.',
},
'footer.socialLinks.srText.linkedin': {
id: 'footer.socialLinks.srText.linkedin',
defaultMessage: 'Follow edX on LinkedIn',
description: 'This is screenreader text for the edX LinkedIn social media link in the footer.',
},
'footer.socialLinks.srText.reddit': {
id: 'footer.socialLinks.srText.reddit',
defaultMessage: 'Subscribe to the edX subreddit',
description: 'This is screenreader text for the edX reddit social media link in the footer.',
},
'footer.languageForm.select.label': {
id: 'footer.languageForm.select.label',
defaultMessage: 'Choose Language',
description: 'The label for the laguage select part of the language selection form.',
},
'footer.languageForm.submit.label': {
id: 'footer.languageForm.submit.label',
defaultMessage: 'Apply',
description: 'The label for button to submit the language selection form.',
},
'footer.edxLinks.about': {
id: 'footer.edxLinks.about',
defaultMessage: 'About',
description: 'The label for the link to the about edX page.',
},
'footer.edxLinks.business': {
id: 'footer.edxLinks.business',
defaultMessage: 'edX for Business',
description: 'The label for the link to the edX for business page.',
},
'footer.edxLinks.affiliates': {
id: 'footer.edxLinks.affiliates',
defaultMessage: 'Affiliates',
description: 'The label for the link to the edX affiliates page.',
},
'footer.edxLinks.openEdx': {
id: 'footer.edxLinks.openEdx',
defaultMessage: 'Open edX',
description: 'The label for the link to the open edX site.',
},
'footer.edxLinks.careers': {
id: 'footer.edxLinks.careers',
defaultMessage: 'Careers',
description: 'The label for the link to the edX Careers page.',
},
'footer.edxLinks.news': {
id: 'footer.edxLinks.news',
defaultMessage: 'News',
description: 'The label for the link to the edX news page.',
},
'footer.legalLinks.heading': {
id: 'footer.legalLinks.heading',
defaultMessage: 'Legal',
description: 'Heading for the legal links section of the footer.',
},
'footer.legalLinks.termsOfService': {
id: 'footer.legalLinks.termsOfService',
defaultMessage: 'Terms of Service & Honor Code',
description: 'The label for the link to the edX terms of service page.',
},
'footer.legalLinks.privacyPolicy': {
id: 'footer.legalLinks.privacyPolicy',
defaultMessage: 'Privacy Policy',
description: 'The label for the link to the edX privacy policy page.',
},
'footer.legalLinks.a11yPolicy': {
id: 'footer.legalLinks.a11yPolicy',
defaultMessage: 'Accessibility Policy',
description: 'The label for the link to the edX accessibility policy page.',
},
'footer.legalLinks.trademarkPolicy': {
id: 'footer.legalLinks.trademarkPolicy',
defaultMessage: 'Trademark Policy',
description: 'The label for the link to the edX trademark policy page.',
},
'footer.legalLinks.sitemap': {
id: 'footer.legalLinks.sitemap',
defaultMessage: 'Sitemap',
description: 'The label for the link to the edX sitemap page.',
},
'footer.connectLinks.heading': {
id: 'footer.connectLinks.heading',
defaultMessage: 'Connect',
description: 'Heading for the connect links section of the footer.',
},
'footer.connectLinks.blog': {
id: 'footer.connectLinks.blog',
defaultMessage: 'Blog',
description: 'The label for the link to the edX blog.',
},
'footer.connectLinks.contact': {
id: 'footer.connectLinks.contact',
defaultMessage: 'Contact Us',
description: 'The label for the link to the contact edX page.',
},
'footer.connectLinks.help': {
id: 'footer.connectLinks.help',
defaultMessage: 'Help Center',
description: 'The label for the link to the edX help center.',
},
'footer.connectLinks.mediaKit': {
id: 'footer.connectLinks.mediaKit',
defaultMessage: 'Media Kit',
description: 'The label for the link to the edX media kit page.',
},
'footer.connectLinks.donate': {
id: 'footer.connectLinks.donate',
defaultMessage: 'Donate',
description: 'The label for the link to the edX donation page.',
},
'footer.mobileApp.apple': {
id: 'footer.mobileApp.apple',
defaultMessage: 'Download the edX mobile app from the Apple App Store',
description: 'The label for the link to download the apple version of the edX app.',
},
'footer.mobileApp.google': {
id: 'footer.mobileApp.google',
defaultMessage: 'Download the edX mobile app from Google Play',
description: 'The label for the link to download the google version of the edX app.',
},
'footer.logo.altText': {
id: 'footer.logo.altText',
defaultMessage: 'Powered by Open edX',
description: 'alt text for the footer logo.',
},
'footer.logo.ariaLabel': {
id: 'footer.logo.ariaLabel',
defaultMessage: 'edX Home',
description: 'aria-label for the footer logo.',
},
'footer.ariaLabel': {
id: 'footer.ariaLabel',
defaultMessage: 'Page Footer',
description: 'aria-label for the footer component',
},
});
export default messages;

View File

@@ -0,0 +1,117 @@
import React from 'react';
import renderer from 'react-test-renderer';
import { mount } from 'enzyme';
import { IntlProvider } from '@edx/frontend-platform/i18n';
import { AppContext } from '@edx/frontend-platform/react';
import Footer from './Footer';
describe('<Footer />', () => {
describe('renders correctly', () => {
it('renders without a language selector', () => {
const tree = renderer
.create((
<IntlProvider locale="en">
<AppContext.Provider
value={{
authenticatedUser: null,
config: {
LOGO_TRADEMARK_URL: process.env.LOGO_TRADEMARK_URL,
LMS_BASE_URL: process.env.LMS_BASE_URL,
},
}}
>
<Footer />
</AppContext.Provider>
</IntlProvider>
))
.toJSON();
expect(tree).toMatchSnapshot();
});
it('renders without a language selector in es', () => {
const tree = renderer
.create((
<IntlProvider locale="es">
<AppContext.Provider
value={{
authenticatedUser: null,
config: {
LOGO_TRADEMARK_URL: process.env.LOGO_TRADEMARK_URL,
LMS_BASE_URL: process.env.LMS_BASE_URL,
},
}}
>
<Footer />
</AppContext.Provider>
</IntlProvider>
))
.toJSON();
expect(tree).toMatchSnapshot();
});
it('renders with a language selector', () => {
const tree = renderer
.create((
<IntlProvider locale="en">
<AppContext.Provider
value={{
authenticatedUser: null,
config: {
LOGO_TRADEMARK_URL: process.env.LOGO_TRADEMARK_URL,
LMS_BASE_URL: process.env.LMS_BASE_URL,
},
}}
>
<Footer
onLanguageSelected={() => {}}
supportedLanguages={[
{ label: 'English', value: 'en' },
{ label: 'Español', value: 'es' },
]}
/>
</AppContext.Provider>
</IntlProvider>
))
.toJSON();
expect(tree).toMatchSnapshot();
});
});
describe('handles language switching', () => {
it('calls onLanguageSelected prop when a language is changed', () => {
const mockHandleLanguageSelected = jest.fn();
const wrapper = mount((
<IntlProvider locale="en">
<AppContext.Provider
value={{
authenticatedUser: null,
config: {
LOGO_TRADEMARK_URL: process.env.LOGO_TRADEMARK_URL,
LMS_BASE_URL: process.env.LMS_BASE_URL,
},
}}
>
<Footer
onLanguageSelected={mockHandleLanguageSelected}
supportedLanguages={[
{ label: 'English', value: 'en' },
{ label: 'Español', value: 'es' },
]}
/>
</AppContext.Provider>
</IntlProvider>
));
wrapper.find('form').simulate('submit', {
target: {
elements: {
'site-footer-language-select': {
value: 'es',
},
},
},
});
expect(mockHandleLanguageSelected).toHaveBeenCalledWith('es');
});
});
});

View File

@@ -0,0 +1,58 @@
import React from 'react';
import PropTypes from 'prop-types';
import { injectIntl, intlShape, FormattedMessage } from '@edx/frontend-platform/i18n';
const LanguageSelector = ({
intl, options, onSubmit, ...props
}) => {
const handleSubmit = (e) => {
e.preventDefault();
const languageCode = e.target.elements['site-footer-language-select'].value;
onSubmit(languageCode);
};
return (
<form
className="form-inline"
onSubmit={handleSubmit}
{...props}
>
<div className="form-group">
{/* eslint-disable-next-line jsx-a11y/label-has-associated-control */}
<label htmlFor="site-footer-language-select" className="d-inline-block m-0">
<FormattedMessage
id="footer.languageForm.select.label"
defaultMessage="Choose Language"
description="The label for the laguage select part of the language selection form."
/>
</label>
<select
id="site-footer-language-select"
className="form-control-sm mx-2"
name="site-footer-language-select"
defaultValue={intl.locale}
>
{options.map(({ value, label }) => <option key={value} value={value}>{label}</option>)}
</select>
<button className="btn btn-outline-primary btn-sm" type="submit">
<FormattedMessage
id="footer.languageForm.submit.label"
defaultMessage="Apply"
description="The label for button to submit the language selection form."
/>
</button>
</div>
</form>
);
};
LanguageSelector.propTypes = {
intl: intlShape.isRequired,
onSubmit: PropTypes.func.isRequired,
options: PropTypes.arrayOf(PropTypes.shape({
value: PropTypes.string,
label: PropTypes.string,
})).isRequired,
};
export default injectIntl(LanguageSelector);

View File

@@ -0,0 +1,133 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<Footer /> renders correctly renders with a language selector 1`] = `
<footer
className="footer d-flex border-top py-3 px-4"
role="contentinfo"
>
<div
className="container-fluid d-flex"
>
<a
aria-label="edX Home"
className="d-block"
href="http://localhost:18000"
>
<img
alt="Powered by Open edX"
src="https://edx-cdn.org/v3/default/logo-trademark.svg"
style={
Object {
"maxHeight": 45,
}
}
/>
</a>
<div
className="flex-grow-1"
/>
<form
className="form-inline"
onSubmit={[Function]}
>
<div
className="form-group"
>
<label
className="d-inline-block m-0"
htmlFor="site-footer-language-select"
>
<span>
Choose Language
</span>
</label>
<select
className="form-control-sm mx-2"
defaultValue="en"
id="site-footer-language-select"
name="site-footer-language-select"
>
<option
value="en"
>
English
</option>
<option
value="es"
>
Español
</option>
</select>
<button
className="btn btn-outline-primary btn-sm"
type="submit"
>
<span>
Apply
</span>
</button>
</div>
</form>
</div>
</footer>
`;
exports[`<Footer /> renders correctly renders without a language selector 1`] = `
<footer
className="footer d-flex border-top py-3 px-4"
role="contentinfo"
>
<div
className="container-fluid d-flex"
>
<a
aria-label="edX Home"
className="d-block"
href="http://localhost:18000"
>
<img
alt="Powered by Open edX"
src="https://edx-cdn.org/v3/default/logo-trademark.svg"
style={
Object {
"maxHeight": 45,
}
}
/>
</a>
<div
className="flex-grow-1"
/>
</div>
</footer>
`;
exports[`<Footer /> renders correctly renders without a language selector in es 1`] = `
<footer
className="footer d-flex border-top py-3 px-4"
role="contentinfo"
>
<div
className="container-fluid d-flex"
>
<a
aria-label="edX Home"
className="d-block"
href="http://localhost:18000"
>
<img
alt="Powered by Open edX"
src="https://edx-cdn.org/v3/default/logo-trademark.svg"
style={
Object {
"maxHeight": 45,
}
}
/>
</a>
<div
className="flex-grow-1"
/>
</div>
</footer>
`;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

32
src/i18n/index.js Normal file
View File

@@ -0,0 +1,32 @@
import arMessages from './messages/ar.json';
import caMessages from './messages/ca.json';
// no need to import en messages-- they are in the defaultMessage field
import es419Messages from './messages/es_419.json';
import frMessages from './messages/fr.json';
import zhcnMessages from './messages/zh_CN.json';
import heMessages from './messages/he.json';
import idMessages from './messages/id.json';
import kokrMessages from './messages/ko_kr.json';
import plMessages from './messages/pl.json';
import ptbrMessages from './messages/pt_br.json';
import ruMessages from './messages/ru.json';
import thMessages from './messages/th.json';
import ukMessages from './messages/uk.json';
const messages = {
ar: arMessages,
'es-419': es419Messages,
fr: frMessages,
'zh-cn': zhcnMessages,
ca: caMessages,
he: heMessages,
id: idMessages,
'ko-kr': kokrMessages,
pl: plMessages,
'pt-br': ptbrMessages,
ru: ruMessages,
th: thMessages,
uk: ukMessages,
};
export default messages;

32
src/i18n/messages/ar.json Normal file
View File

@@ -0,0 +1,32 @@
{
"footer.socialLinks.srText.facebook": "Like edX on Facebook",
"footer.socialLinks.srText.twitter": "Follow edX on Twitter",
"footer.socialLinks.srText.youtube": "Subscribe to the edX YouTube channel",
"footer.socialLinks.srText.linkedin": "Follow edX on LinkedIn",
"footer.socialLinks.srText.reddit": "Subscribe to the edX subreddit",
"footer.languageForm.select.label": "Choose Language",
"footer.languageForm.submit.label": "Apply",
"footer.edxLinks.about": "About",
"footer.edxLinks.business": "edX for Business",
"footer.edxLinks.affiliates": "Affiliates",
"footer.edxLinks.openEdx": "Open edX",
"footer.edxLinks.careers": "Careers",
"footer.edxLinks.news": "News",
"footer.legalLinks.heading": "Legal",
"footer.legalLinks.termsOfService": "Terms of Service & Honor Code",
"footer.legalLinks.privacyPolicy": "Privacy Policy",
"footer.legalLinks.a11yPolicy": "Accessibility Policy",
"footer.legalLinks.trademarkPolicy": "Trademark Policy",
"footer.legalLinks.sitemap": "Sitemap",
"footer.connectLinks.heading": "Connect",
"footer.connectLinks.blog": "Blog",
"footer.connectLinks.contact": "Contact Us",
"footer.connectLinks.help": "Help Center",
"footer.connectLinks.mediaKit": "Media Kit",
"footer.connectLinks.donate": "Donate",
"footer.mobileApp.apple": "Download the edX mobile app from the Apple App Store",
"footer.mobileApp.google": "Download the edX mobile app from Google Play",
"footer.logo.altText": "Powered by Open edX",
"footer.logo.ariaLabel": "edX Home",
"footer.ariaLabel": "Page Footer"
}

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1,32 @@
{
"footer.socialLinks.srText.facebook": "Like edX on Facebook",
"footer.socialLinks.srText.twitter": "Follow edX on Twitter",
"footer.socialLinks.srText.youtube": "Subscribe to the edX YouTube channel",
"footer.socialLinks.srText.linkedin": "Follow edX on LinkedIn",
"footer.socialLinks.srText.reddit": "Subscribe to the edX subreddit",
"footer.languageForm.select.label": "Choose Language",
"footer.languageForm.submit.label": "Apply",
"footer.edxLinks.about": "About",
"footer.edxLinks.business": "edX for Business",
"footer.edxLinks.affiliates": "Affiliates",
"footer.edxLinks.openEdx": "Open edX",
"footer.edxLinks.careers": "Careers",
"footer.edxLinks.news": "News",
"footer.legalLinks.heading": "Legal",
"footer.legalLinks.termsOfService": "Terms of Service & Honor Code",
"footer.legalLinks.privacyPolicy": "Privacy Policy",
"footer.legalLinks.a11yPolicy": "Accessibility Policy",
"footer.legalLinks.trademarkPolicy": "Trademark Policy",
"footer.legalLinks.sitemap": "Sitemap",
"footer.connectLinks.heading": "Connect",
"footer.connectLinks.blog": "Blog",
"footer.connectLinks.contact": "Contact Us",
"footer.connectLinks.help": "Help Center",
"footer.connectLinks.mediaKit": "Media Kit",
"footer.connectLinks.donate": "Donate",
"footer.mobileApp.apple": "Download the edX mobile app from the Apple App Store",
"footer.mobileApp.google": "Download the edX mobile app from Google Play",
"footer.logo.altText": "Powered by Open edX",
"footer.logo.ariaLabel": "edX Home",
"footer.ariaLabel": "Page Footer"
}

32
src/i18n/messages/fr.json Normal file
View File

@@ -0,0 +1,32 @@
{
"footer.socialLinks.srText.facebook": "Like edX on Facebook",
"footer.socialLinks.srText.twitter": "Follow edX on Twitter",
"footer.socialLinks.srText.youtube": "Subscribe to the edX YouTube channel",
"footer.socialLinks.srText.linkedin": "Follow edX on LinkedIn",
"footer.socialLinks.srText.reddit": "Subscribe to the edX subreddit",
"footer.languageForm.select.label": "Choose Language",
"footer.languageForm.submit.label": "Apply",
"footer.edxLinks.about": "About",
"footer.edxLinks.business": "edX for Business",
"footer.edxLinks.affiliates": "Affiliates",
"footer.edxLinks.openEdx": "Open edX",
"footer.edxLinks.careers": "Careers",
"footer.edxLinks.news": "News",
"footer.legalLinks.heading": "Legal",
"footer.legalLinks.termsOfService": "Terms of Service & Honor Code",
"footer.legalLinks.privacyPolicy": "Privacy Policy",
"footer.legalLinks.a11yPolicy": "Accessibility Policy",
"footer.legalLinks.trademarkPolicy": "Trademark Policy",
"footer.legalLinks.sitemap": "Sitemap",
"footer.connectLinks.heading": "Connect",
"footer.connectLinks.blog": "Blog",
"footer.connectLinks.contact": "Contact Us",
"footer.connectLinks.help": "Help Center",
"footer.connectLinks.mediaKit": "Media Kit",
"footer.connectLinks.donate": "Donate",
"footer.mobileApp.apple": "Download the edX mobile app from the Apple App Store",
"footer.mobileApp.google": "Download the edX mobile app from Google Play",
"footer.logo.altText": "Powered by Open edX",
"footer.logo.ariaLabel": "edX Home",
"footer.ariaLabel": "Page Footer"
}

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1,32 @@
{
"footer.socialLinks.srText.facebook": "Like edX on Facebook",
"footer.socialLinks.srText.twitter": "Follow edX on Twitter",
"footer.socialLinks.srText.youtube": "Subscribe to the edX YouTube channel",
"footer.socialLinks.srText.linkedin": "Follow edX on LinkedIn",
"footer.socialLinks.srText.reddit": "Subscribe to the edX subreddit",
"footer.languageForm.select.label": "Choose Language",
"footer.languageForm.submit.label": "Apply",
"footer.edxLinks.about": "About",
"footer.edxLinks.business": "edX for Business",
"footer.edxLinks.affiliates": "Affiliates",
"footer.edxLinks.openEdx": "Open edX",
"footer.edxLinks.careers": "Careers",
"footer.edxLinks.news": "News",
"footer.legalLinks.heading": "Legal",
"footer.legalLinks.termsOfService": "Terms of Service & Honor Code",
"footer.legalLinks.privacyPolicy": "Privacy Policy",
"footer.legalLinks.a11yPolicy": "Accessibility Policy",
"footer.legalLinks.trademarkPolicy": "Trademark Policy",
"footer.legalLinks.sitemap": "Sitemap",
"footer.connectLinks.heading": "Connect",
"footer.connectLinks.blog": "Blog",
"footer.connectLinks.contact": "Contact Us",
"footer.connectLinks.help": "Help Center",
"footer.connectLinks.mediaKit": "Media Kit",
"footer.connectLinks.donate": "Donate",
"footer.mobileApp.apple": "Download the edX mobile app from the Apple App Store",
"footer.mobileApp.google": "Download the edX mobile app from Google Play",
"footer.logo.altText": "Powered by Open edX",
"footer.logo.ariaLabel": "edX Home",
"footer.ariaLabel": "Page Footer"
}

5
src/index.js Normal file
View File

@@ -0,0 +1,5 @@
import Footer, { EVENT_NAMES } from './components/Footer';
import messages from './i18n/index';
export default Footer;
export { messages, EVENT_NAMES };

View File

@@ -1,29 +0,0 @@
import React from 'react';
import { render } from 'react-dom';
import SiteFooter from './lib';
import './index.scss';
import FooterLogo from './edx-footer.png';
const App = () => (
<SiteFooter
siteName="edX"
siteLogo={FooterLogo}
marketingSiteBaseUrl="https://www.example.com"
supportUrl="https://www.example.com/support"
contactUrl="https://www.example.com/contact"
openSourceUrl="https://www.example.com/open"
termsOfServiceUrl="https://www.example.com/terms-of-service"
privacyPolicyUrl="https://www.example.com/privacy-policy"
facebookUrl="https://www.facebook.com"
twitterUrl="https://www.twitter.com"
youTubeUrl="https://www.youtube.com"
linkedInUrl="https://www.linkedin.com"
googlePlusUrl="https://plus.google.com"
redditUrl="https://reddit.com"
appleAppStoreUrl="https://store.apple.com"
googlePlayUrl="https://play.google.com"
/>
);
render(<App />, document.getElementById('root'));

View File

@@ -1,4 +0,0 @@
@import "~@edx/edx-bootstrap/sass/edx/theme";
@import "~bootstrap/scss/bootstrap";
@import './lib/scss/_site-footer.scss';

View File

@@ -1,81 +0,0 @@
import React from 'react';
import renderer from 'react-test-renderer';
import FooterLogo from '../../../edx-footer.png';
import SiteFooter from '../../index';
describe('<SiteFooter />', () => {
it('renders correctly', () => {
const tree = renderer
.create(<SiteFooter
siteName="example"
siteLogo={FooterLogo}
marketingSiteBaseUrl="https://www.example.com"
supportUrl="https://www.example.com/support"
contactUrl="https://www.example.com/contact"
openSourceUrl="https://www.example.com/open"
termsOfServiceUrl="https://www.example.com/terms-of-service"
privacyPolicyUrl="https://www.example.com/privacy-policy"
facebookUrl="https://www.facebook.com"
twitterUrl="https://www.twitter.com"
youTubeUrl="https://www.youtube.com"
linkedInUrl="https://www.linkedin.com"
googlePlusUrl="https://plus.google.com"
redditUrl="https://reddit.com"
appleAppStoreUrl="https://store.apple.com"
googlePlayUrl="https://play.google.com"
/>)
.toJSON();
expect(tree).toMatchSnapshot();
});
it('does not render social links', () => {
const tree = renderer
.create(<SiteFooter
siteName="example"
siteLogo={FooterLogo}
marketingSiteBaseUrl="https://www.example.com"
supportUrl="https://www.example.com/support"
contactUrl="https://www.example.com/contact"
openSourceUrl="https://www.example.com/open"
termsOfServiceUrl="https://www.example.com/terms-of-service"
privacyPolicyUrl="https://www.example.com/privacy-policy"
facebookUrl="https://www.facebook.com"
twitterUrl="https://www.twitter.com"
youTubeUrl="https://www.youtube.com"
linkedInUrl="https://www.linkedin.com"
googlePlusUrl="https://plus.google.com"
redditUrl="https://reddit.com"
appleAppStoreUrl="https://store.apple.com"
googlePlayUrl="https://play.google.com"
showSocialLinks={false}
/>)
.toJSON();
expect(tree).toMatchSnapshot();
});
it('does not render mobile links', () => {
const tree = renderer
.create(<SiteFooter
siteName="example"
siteLogo={FooterLogo}
marketingSiteBaseUrl="https://www.example.com"
supportUrl="https://www.example.com/support"
contactUrl="https://www.example.com/contact"
openSourceUrl="https://www.example.com/open"
termsOfServiceUrl="https://www.example.com/terms-of-service"
privacyPolicyUrl="https://www.example.com/privacy-policy"
facebookUrl="https://www.facebook.com"
twitterUrl="https://www.twitter.com"
youTubeUrl="https://www.youtube.com"
linkedInUrl="https://www.linkedin.com"
googlePlusUrl="https://plus.google.com"
redditUrl="https://reddit.com"
appleAppStoreUrl="https://store.apple.com"
googlePlayUrl="https://play.google.com"
showMobileLinks={false}
/>)
.toJSON();
expect(tree).toMatchSnapshot();
});
});

View File

@@ -1,875 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<SiteFooter /> does not render mobile links 1`] = `
<footer
aria-label="Page Footer"
className="footer d-flex justify-content-center border-top py-3 px-4"
role="contentinfo"
>
<div
className="max-width-1180 d-grid"
>
<div
className="area-1"
>
<a
aria-label="example Home"
href="https://www.example.com/"
onClick={[Function]}
target="_self"
>
<img
alt="example logo"
src="test-file-stub"
/>
</a>
</div>
<div
className="area-2"
>
<h2>
example
</h2>
<ul
className="list-unstyled p-0 m-0"
>
<li>
<a
href="https://www.example.com/about-us"
>
About
</a>
</li>
<li>
<a
href="https://www.example.com/enterprise"
>
example
for Business
</a>
</li>
<li>
<a
href="https://www.example.com/affiliate-program"
>
Affiliates
</a>
</li>
<li>
<a
href="https://www.example.com/open"
>
Open
example
</a>
</li>
<li>
<a
href="https://www.example.com/careers"
>
Careers
</a>
</li>
<li>
<a
href="https://www.example.com/news-announcements"
>
News
</a>
</li>
</ul>
</div>
<div
className="area-3"
>
<h2>
Legal
</h2>
<ul
className="list-unstyled p-0 m-0"
>
<li>
<a
href="https://www.example.com/terms-of-service"
>
Terms of Service & Honor Code
</a>
</li>
<li>
<a
href="https://www.example.com/privacy-policy"
>
Privacy Policy
</a>
</li>
<li>
<a
href="https://www.example.com/accessibility"
>
Accessibility Policy
</a>
</li>
<li>
<a
href="https://www.example.com/trademarks"
>
Trademark Policy
</a>
</li>
<li>
<a
href="https://www.example.com/sitemap"
>
Sitemap
</a>
</li>
</ul>
</div>
<div
className="area-4"
>
<h2>
Connect
</h2>
<ul
className="list-unstyled p-0 m-0"
>
<li>
<a
href="https://www.example.com/blog"
>
Blog
</a>
</li>
<li>
<a
href="https://www.example.com/contact"
>
Contact Us
</a>
</li>
<li>
<a
href="https://www.example.com/support"
>
Help Center
</a>
</li>
<li>
<a
href="https://www.example.com/media-kit"
>
Media Kit
</a>
</li>
<li>
<a
href="https://www.example.com/donate"
>
Donate
</a>
</li>
</ul>
</div>
<div
className="area-5"
>
<ul
className="d-flex flex-row justify-content-between list-unstyled max-width-222 p-0 mb-4"
>
<li>
<a
href="https://www.facebook.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
title="Facebook"
>
<span
aria-hidden={true}
className="fa fa-facebook-square fa-2x"
id="Icon1"
/>
<span
className="sr-only"
>
Like example on Facebook
</span>
</a>
</li>
<li>
<a
href="https://www.twitter.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
title="Twitter"
>
<span
aria-hidden={true}
className="fa fa-twitter-square fa-2x"
id="Icon1"
/>
<span
className="sr-only"
>
Follow example on Twitter
</span>
</a>
</li>
<li>
<a
href="https://www.youtube.com"
rel="noopener noreferrer"
target="_blank"
title="Youtube"
>
<span
aria-hidden={true}
className="fa fa-youtube-square fa-2x"
id="Icon1"
/>
<span
className="sr-only"
>
Subscribe to the example YouTube channel
</span>
</a>
</li>
<li>
<a
href="https://www.linkedin.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
title="LinkedIn"
>
<span
aria-hidden={true}
className="fa fa-linkedin-square fa-2x"
id="Icon1"
/>
<span
className="sr-only"
>
Follow example on LinkedIn
</span>
</a>
</li>
<li>
<a
href="https://plus.google.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
title="Google+"
>
<span
aria-hidden={true}
className="fa fa-google-plus-square fa-2x"
id="Icon1"
/>
<span
className="sr-only"
>
Follow example on Google+
</span>
</a>
</li>
<li>
<a
href="https://reddit.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
title="Reddit"
>
<span
aria-hidden={true}
className="fa fa-reddit-square fa-2x"
id="Icon1"
/>
<span
className="sr-only"
>
Subscribe to the example subreddit
</span>
</a>
</li>
</ul>
<p>
© 2012
2019
example
Inc.
<br />
EdX, Open edX, and MicroMasters are registered trademarks of edX Inc. | 粤ICP备17044299号-2
</p>
</div>
</div>
</footer>
`;
exports[`<SiteFooter /> does not render social links 1`] = `
<footer
aria-label="Page Footer"
className="footer d-flex justify-content-center border-top py-3 px-4"
role="contentinfo"
>
<div
className="max-width-1180 d-grid"
>
<div
className="area-1"
>
<a
aria-label="example Home"
href="https://www.example.com/"
onClick={[Function]}
target="_self"
>
<img
alt="example logo"
src="test-file-stub"
/>
</a>
</div>
<div
className="area-2"
>
<h2>
example
</h2>
<ul
className="list-unstyled p-0 m-0"
>
<li>
<a
href="https://www.example.com/about-us"
>
About
</a>
</li>
<li>
<a
href="https://www.example.com/enterprise"
>
example
for Business
</a>
</li>
<li>
<a
href="https://www.example.com/affiliate-program"
>
Affiliates
</a>
</li>
<li>
<a
href="https://www.example.com/open"
>
Open
example
</a>
</li>
<li>
<a
href="https://www.example.com/careers"
>
Careers
</a>
</li>
<li>
<a
href="https://www.example.com/news-announcements"
>
News
</a>
</li>
</ul>
</div>
<div
className="area-3"
>
<h2>
Legal
</h2>
<ul
className="list-unstyled p-0 m-0"
>
<li>
<a
href="https://www.example.com/terms-of-service"
>
Terms of Service & Honor Code
</a>
</li>
<li>
<a
href="https://www.example.com/privacy-policy"
>
Privacy Policy
</a>
</li>
<li>
<a
href="https://www.example.com/accessibility"
>
Accessibility Policy
</a>
</li>
<li>
<a
href="https://www.example.com/trademarks"
>
Trademark Policy
</a>
</li>
<li>
<a
href="https://www.example.com/sitemap"
>
Sitemap
</a>
</li>
</ul>
</div>
<div
className="area-4"
>
<h2>
Connect
</h2>
<ul
className="list-unstyled p-0 m-0"
>
<li>
<a
href="https://www.example.com/blog"
>
Blog
</a>
</li>
<li>
<a
href="https://www.example.com/contact"
>
Contact Us
</a>
</li>
<li>
<a
href="https://www.example.com/support"
>
Help Center
</a>
</li>
<li>
<a
href="https://www.example.com/media-kit"
>
Media Kit
</a>
</li>
<li>
<a
href="https://www.example.com/donate"
>
Donate
</a>
</li>
</ul>
</div>
<div
className="area-5"
>
<ul
className="d-flex flex-row justify-content-between list-unstyled max-width-264 p-0 mb-5"
>
<li>
<a
href="https://store.apple.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
>
<img
alt="Download the example mobile app from the Apple App Store"
className="max-height-39"
src="https://prod-edxapp.edx-cdn.org/static/images/app/app_store_badge_135x40.d0558d910630.svg"
/>
</a>
</li>
<li>
<a
href="https://play.google.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
>
<img
alt="Download the example mobile app from Google Play"
className="max-height-39"
src="https://prod-edxapp.edx-cdn.org/static/images/app/google_play_badge_45.6ea466e328da.png"
/>
</a>
</li>
</ul>
<p>
© 2012
2019
example
Inc.
<br />
EdX, Open edX, and MicroMasters are registered trademarks of edX Inc. | 粤ICP备17044299号-2
</p>
</div>
</div>
</footer>
`;
exports[`<SiteFooter /> renders correctly 1`] = `
<footer
aria-label="Page Footer"
className="footer d-flex justify-content-center border-top py-3 px-4"
role="contentinfo"
>
<div
className="max-width-1180 d-grid"
>
<div
className="area-1"
>
<a
aria-label="example Home"
href="https://www.example.com/"
onClick={[Function]}
target="_self"
>
<img
alt="example logo"
src="test-file-stub"
/>
</a>
</div>
<div
className="area-2"
>
<h2>
example
</h2>
<ul
className="list-unstyled p-0 m-0"
>
<li>
<a
href="https://www.example.com/about-us"
>
About
</a>
</li>
<li>
<a
href="https://www.example.com/enterprise"
>
example
for Business
</a>
</li>
<li>
<a
href="https://www.example.com/affiliate-program"
>
Affiliates
</a>
</li>
<li>
<a
href="https://www.example.com/open"
>
Open
example
</a>
</li>
<li>
<a
href="https://www.example.com/careers"
>
Careers
</a>
</li>
<li>
<a
href="https://www.example.com/news-announcements"
>
News
</a>
</li>
</ul>
</div>
<div
className="area-3"
>
<h2>
Legal
</h2>
<ul
className="list-unstyled p-0 m-0"
>
<li>
<a
href="https://www.example.com/terms-of-service"
>
Terms of Service & Honor Code
</a>
</li>
<li>
<a
href="https://www.example.com/privacy-policy"
>
Privacy Policy
</a>
</li>
<li>
<a
href="https://www.example.com/accessibility"
>
Accessibility Policy
</a>
</li>
<li>
<a
href="https://www.example.com/trademarks"
>
Trademark Policy
</a>
</li>
<li>
<a
href="https://www.example.com/sitemap"
>
Sitemap
</a>
</li>
</ul>
</div>
<div
className="area-4"
>
<h2>
Connect
</h2>
<ul
className="list-unstyled p-0 m-0"
>
<li>
<a
href="https://www.example.com/blog"
>
Blog
</a>
</li>
<li>
<a
href="https://www.example.com/contact"
>
Contact Us
</a>
</li>
<li>
<a
href="https://www.example.com/support"
>
Help Center
</a>
</li>
<li>
<a
href="https://www.example.com/media-kit"
>
Media Kit
</a>
</li>
<li>
<a
href="https://www.example.com/donate"
>
Donate
</a>
</li>
</ul>
</div>
<div
className="area-5"
>
<ul
className="d-flex flex-row justify-content-between list-unstyled max-width-222 p-0 mb-4"
>
<li>
<a
href="https://www.facebook.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
title="Facebook"
>
<span
aria-hidden={true}
className="fa fa-facebook-square fa-2x"
id="Icon1"
/>
<span
className="sr-only"
>
Like example on Facebook
</span>
</a>
</li>
<li>
<a
href="https://www.twitter.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
title="Twitter"
>
<span
aria-hidden={true}
className="fa fa-twitter-square fa-2x"
id="Icon1"
/>
<span
className="sr-only"
>
Follow example on Twitter
</span>
</a>
</li>
<li>
<a
href="https://www.youtube.com"
rel="noopener noreferrer"
target="_blank"
title="Youtube"
>
<span
aria-hidden={true}
className="fa fa-youtube-square fa-2x"
id="Icon1"
/>
<span
className="sr-only"
>
Subscribe to the example YouTube channel
</span>
</a>
</li>
<li>
<a
href="https://www.linkedin.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
title="LinkedIn"
>
<span
aria-hidden={true}
className="fa fa-linkedin-square fa-2x"
id="Icon1"
/>
<span
className="sr-only"
>
Follow example on LinkedIn
</span>
</a>
</li>
<li>
<a
href="https://plus.google.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
title="Google+"
>
<span
aria-hidden={true}
className="fa fa-google-plus-square fa-2x"
id="Icon1"
/>
<span
className="sr-only"
>
Follow example on Google+
</span>
</a>
</li>
<li>
<a
href="https://reddit.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
title="Reddit"
>
<span
aria-hidden={true}
className="fa fa-reddit-square fa-2x"
id="Icon1"
/>
<span
className="sr-only"
>
Subscribe to the example subreddit
</span>
</a>
</li>
</ul>
<ul
className="d-flex flex-row justify-content-between list-unstyled max-width-264 p-0 mb-5"
>
<li>
<a
href="https://store.apple.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
>
<img
alt="Download the example mobile app from the Apple App Store"
className="max-height-39"
src="https://prod-edxapp.edx-cdn.org/static/images/app/app_store_badge_135x40.d0558d910630.svg"
/>
</a>
</li>
<li>
<a
href="https://play.google.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
>
<img
alt="Download the example mobile app from Google Play"
className="max-height-39"
src="https://prod-edxapp.edx-cdn.org/static/images/app/google_play_badge_45.6ea466e328da.png"
/>
</a>
</li>
</ul>
<p>
© 2012
2019
example
Inc.
<br />
EdX, Open edX, and MicroMasters are registered trademarks of edX Inc. | 粤ICP备17044299号-2
</p>
</div>
</div>
</footer>
`;

View File

@@ -1,272 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Hyperlink, Icon } from '@edx/paragon';
const EVENT_NAMES = {
FOOTER_LINK: 'edx.bi.footer.link',
};
class SiteFooter extends React.Component {
constructor(props) {
super(props);
this.externalLinkClickHandler = this.externalLinkClickHandler.bind(this);
}
externalLinkClickHandler(event) {
const label = event.currentTarget.getAttribute('href');
const eventName = EVENT_NAMES.FOOTER_LINK;
const properties = {
category: 'outbound_link',
label,
};
this.props.handleAllTrackEvents(eventName, properties);
}
renderSiteLogo() {
return (
<img src={this.props.siteLogo} alt={`${this.props.siteName} logo`} />
);
}
renderMarketingSiteUrl(path) {
return `${this.props.marketingSiteBaseUrl}${path}`;
}
renderSocialLinks() {
const {
siteName,
showSocialLinks,
facebookUrl,
twitterUrl,
youTubeUrl,
linkedInUrl,
googlePlusUrl,
redditUrl,
} = this.props;
let socialLinks = null;
if (showSocialLinks) {
socialLinks = (
<ul
className="d-flex flex-row justify-content-between list-unstyled max-width-222 p-0 mb-4"
>
{/* TODO: Use Paragon HyperLink with Icon. */}
{/* Would need to add rel to paragon if we still need it. */}
<li>
<a
href={facebookUrl}
title="Facebook"
rel="noopener noreferrer"
target="_blank"
onClick={this.externalLinkClickHandler}
>
<Icon className={['fa', 'fa-facebook-square', 'fa-2x']} screenReaderText={`Like ${siteName} on Facebook`} />
</a>
</li>
<li>
<a
href={twitterUrl}
title="Twitter"
rel="noopener noreferrer"
target="_blank"
onClick={this.externalLinkClickHandler}
>
<Icon className={['fa', 'fa-twitter-square', 'fa-2x']} screenReaderText={`Follow ${siteName} on Twitter`} />
</a>
</li>
<li>
<a
href={youTubeUrl}
title="Youtube"
rel="noopener noreferrer"
target="_blank"
>
<Icon className={['fa', 'fa-youtube-square', 'fa-2x']} screenReaderText={`Subscribe to the ${siteName} YouTube channel`} />
</a>
</li>
<li>
<a
href={linkedInUrl}
title="LinkedIn"
rel="noopener noreferrer"
target="_blank"
onClick={this.externalLinkClickHandler}
>
<Icon className={['fa', 'fa-linkedin-square', 'fa-2x']} screenReaderText={`Follow ${siteName} on LinkedIn`} />
</a>
</li>
<li>
<a
href={googlePlusUrl}
title="Google+"
rel="noopener noreferrer"
target="_blank"
onClick={this.externalLinkClickHandler}
>
<Icon className={['fa', 'fa-google-plus-square', 'fa-2x']} screenReaderText={`Follow ${siteName} on Google+`} />
</a>
</li>
<li>
<a
href={redditUrl}
title="Reddit"
rel="noopener noreferrer"
target="_blank"
onClick={this.externalLinkClickHandler}
>
<Icon className={['fa', 'fa-reddit-square', 'fa-2x']} screenReaderText={`Subscribe to the ${siteName} subreddit`} />
</a>
</li>
</ul>
);
}
return socialLinks;
}
renderMobileLinks() {
const {
siteName,
showMobileLinks,
appleAppStoreUrl,
googlePlayUrl,
} = this.props;
let mobileLinks = null;
if (showMobileLinks) {
mobileLinks = (
<ul className="d-flex flex-row justify-content-between list-unstyled max-width-264 p-0 mb-5">
<li>
<a href={appleAppStoreUrl} rel="noopener noreferrer" target="_blank" onClick={this.externalLinkClickHandler}>
<img
className="max-height-39"
alt={`Download the ${siteName} mobile app from the Apple App Store`}
src="https://prod-edxapp.edx-cdn.org/static/images/app/app_store_badge_135x40.d0558d910630.svg"
/>
</a>
</li>
<li>
<a href={googlePlayUrl} rel="noopener noreferrer" target="_blank" onClick={this.externalLinkClickHandler}>
<img
className="max-height-39"
alt={`Download the ${siteName} mobile app from Google Play`}
src="https://prod-edxapp.edx-cdn.org/static/images/app/google_play_badge_45.6ea466e328da.png"
/>
</a>
</li>
</ul>
);
}
return mobileLinks;
}
render() {
const {
siteName,
openSourceUrl,
termsOfServiceUrl,
privacyPolicyUrl,
contactUrl,
supportUrl,
} = this.props;
return (
<footer
role="contentinfo"
aria-label="Page Footer"
className="footer d-flex justify-content-center border-top py-3 px-4"
>
<div className="max-width-1180 d-grid">
<div className="area-1">
<Hyperlink destination={this.renderMarketingSiteUrl('/')} content={this.renderSiteLogo()} aria-label={`${siteName} Home`} />
</div>
<div className="area-2">
<h2>{siteName}</h2>
<ul className="list-unstyled p-0 m-0">
<li><a href={this.renderMarketingSiteUrl('/about-us')}>About</a></li>
<li><a href={this.renderMarketingSiteUrl('/enterprise')}>{siteName} for Business</a></li>
<li><a href={this.renderMarketingSiteUrl('/affiliate-program')}>Affiliates</a></li>
<li><a href={openSourceUrl}>Open {siteName}</a></li>
<li><a href={this.renderMarketingSiteUrl('/careers')}>Careers</a></li>
<li><a href={this.renderMarketingSiteUrl('/news-announcements')}>News</a></li>
</ul>
</div>
<div className="area-3">
<h2>Legal</h2>
<ul className="list-unstyled p-0 m-0">
<li><a href={termsOfServiceUrl}>Terms of Service & Honor Code</a></li>
<li><a href={privacyPolicyUrl}>Privacy Policy</a></li>
<li><a href={this.renderMarketingSiteUrl('/accessibility')}>Accessibility Policy</a></li>
<li><a href={this.renderMarketingSiteUrl('/trademarks')}>Trademark Policy</a></li>
<li><a href={this.renderMarketingSiteUrl('/sitemap')}>Sitemap</a></li>
</ul>
</div>
<div className="area-4">
<h2>Connect</h2>
<ul className="list-unstyled p-0 m-0">
<li><a href={this.renderMarketingSiteUrl('/blog')}>Blog</a></li>
<li><a href={contactUrl}>Contact Us</a></li>
<li><a href={supportUrl}>Help Center</a></li>
<li><a href={this.renderMarketingSiteUrl('/media-kit')}>Media Kit</a></li>
<li><a href={this.renderMarketingSiteUrl('/donate')}>Donate</a></li>
</ul>
</div>
<div className="area-5">
{this.renderSocialLinks()}
{this.renderMobileLinks()}
<p>
© 2012{(new Date().getFullYear())} {siteName} Inc.
<br />
EdX, Open edX, and MicroMasters are registered trademarks of edX Inc.
| 粤ICP备17044299号-2
</p>
</div>
</div>
</footer>
);
}
}
SiteFooter.propTypes = {
siteName: PropTypes.string,
siteLogo: PropTypes.node,
marketingSiteBaseUrl: PropTypes.string,
supportUrl: PropTypes.string,
contactUrl: PropTypes.string,
openSourceUrl: PropTypes.string,
termsOfServiceUrl: PropTypes.string,
privacyPolicyUrl: PropTypes.string,
showSocialLinks: PropTypes.bool,
facebookUrl: PropTypes.string,
twitterUrl: PropTypes.string,
youTubeUrl: PropTypes.string,
linkedInUrl: PropTypes.string,
googlePlusUrl: PropTypes.string,
redditUrl: PropTypes.string,
showMobileLinks: PropTypes.bool,
appleAppStoreUrl: PropTypes.string,
googlePlayUrl: PropTypes.string,
handleAllTrackEvents: PropTypes.func.isRequired,
};
SiteFooter.defaultProps = {
siteName: null,
siteLogo: null,
marketingSiteBaseUrl: null,
supportUrl: null,
contactUrl: null,
openSourceUrl: null,
termsOfServiceUrl: null,
privacyPolicyUrl: null,
showSocialLinks: true,
facebookUrl: null,
twitterUrl: null,
youTubeUrl: null,
linkedInUrl: null,
googlePlusUrl: null,
redditUrl: null,
showMobileLinks: true,
appleAppStoreUrl: null,
googlePlayUrl: null,
};
export default SiteFooter;
export { EVENT_NAMES };

View File

@@ -1,3 +0,0 @@
import SiteFooter from './components/SiteFooter';
export default SiteFooter;

View File

@@ -1,165 +0,0 @@
.max-width-222 {
max-width: 222px;
}
.max-width-264 {
max-width: 264px;
}
.max-width-1180 {
max-width: 1180px;
}
.max-height-39 {
max-height: 39px;
}
.d-grid {
display: grid;
}
$gray-footer: #fcfcfc;
$border-1: 1px solid $gray-200;
.footer {
background-color: $gray-footer;
.area-1 {
grid-column: 1;
grid-row: 1;
border-bottom: $border-1;
padding-bottom: 1rem;
}
.area-2 {
grid-column: 1;
grid-row: 2;
border-bottom: $border-1;
padding: 1rem 0;
}
.area-3 {
grid-column: 1;
grid-row: 3;
border-bottom: $border-1;
padding: 1rem 0;
}
.area-4 {
grid-column: 1;
grid-row: 4;
border-bottom: $border-1;
padding: 1rem 0;
}
.area-5 {
grid-column: 1;
grid-row: 5;
padding: 1rem 0;
}
@media only screen and (min-width: 717px) {
.area-1 {
grid-column: 1 / span 2;
grid-row: 1;
border-bottom: none;
padding: 1rem 0;
}
.area-2 {
grid-column: 1;
grid-row: 2;
}
.area-3 {
grid-column: 1;
grid-row: 3;
}
.area-4 {
grid-column: 1;
grid-row: 4;
border-bottom: none;
}
.area-5 {
grid-column: 2;
grid-row: 2 / span 3;
border-left: $border-1;
padding-left: 1rem;
margin-left: 1rem;
}
}
@media only screen and (min-width: 870px) {
.area-1 {
grid-column: 1;
grid-row: 1 / span 3;
border-right: $border-1;
padding-right: 1rem;
margin-right: 1rem;
}
.area-2 {
grid-column: 2;
grid-row: 1;
border-bottom: none;
border-right: $border-1;
padding-right: 1rem;
margin-right: 1rem;
}
.area-3 {
grid-column: 3;
grid-row: 1;
border-bottom: none;
border-right: $border-1;
padding-right: 1rem;
margin-right: 1rem;
}
.area-4 {
grid-column: 4;
grid-row: 1;
}
.area-5 {
grid-column: 2 / span 3;
grid-row: 2;
border: none;
margin-left: 0;
padding-left: 0;
}
}
@media only screen and (min-width: 1188px) {
.area-1 {
grid-column: 1 / span 1;
grid-row: 1;
}
.area-2 {
grid-column: 2;
grid-row: 1;
}
.area-3 {
grid-column: 3;
grid-row: 1;
}
.area-4 {
grid-column: 4;
grid-row: 1;
border-right: $border-1;
padding-right: 1rem;
margin-right: 1rem;
}
.area-5 {
grid-column: 5 / span 1;
grid-row: 1;
max-width: 372px;
}
}
}

26
src/setupTest.js Normal file
View File

@@ -0,0 +1,26 @@
import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
Enzyme.configure({ adapter: new Adapter() });
// These configuration values are usually set in webpack's EnvironmentPlugin however
// Jest does not use webpack so we need to set these so for testing
process.env.ACCESS_TOKEN_COOKIE_NAME = 'edx-jwt-cookie-header-payload';
process.env.BASE_URL = 'localhost:1995';
process.env.CREDENTIALS_BASE_URL = 'http://localhost:18150';
process.env.CSRF_TOKEN_API_PATH = '/csrf/api/v1/token';
process.env.ECOMMERCE_BASE_URL = 'http://localhost:18130';
process.env.LANGUAGE_PREFERENCE_COOKIE_NAME = 'openedx-language-preference';
process.env.LMS_BASE_URL = 'http://localhost:18000';
process.env.LOGIN_URL = 'http://localhost:18000/login';
process.env.LOGOUT_URL = 'http://localhost:18000/login';
process.env.MARKETING_SITE_BASE_URL = 'http://localhost:18000';
process.env.ORDER_HISTORY_URL = 'localhost:1996/orders';
process.env.REFRESH_ACCESS_TOKEN_ENDPOINT = 'http://localhost:18000/login_refresh';
process.env.SEGMENT_KEY = 'segment_whoa';
process.env.SITE_NAME = 'edX';
process.env.USER_INFO_COOKIE_NAME = 'edx-user-info';
process.env.LOGO_URL = 'https://edx-cdn.org/v3/default/logo.svg';
process.env.LOGO_TRADEMARK_URL = 'https://edx-cdn.org/v3/default/logo-trademark.svg';
process.env.LOGO_WHITE_URL = 'https://edx-cdn.org/v3/default/logo-white.svg';
process.env.FAVICON_URL = 'https://edx-cdn.org/v3/default/favicon.ico';

View File

@@ -1,4 +0,0 @@
import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
Enzyme.configure({ adapter: new Adapter() });

15
webpack.dev.config.js Normal file
View File

@@ -0,0 +1,15 @@
const path = require('path');
const { createConfig } = require('@edx/frontend-build');
module.exports = createConfig('webpack-dev', {
entry: path.resolve(__dirname, 'example'),
output: {
path: path.resolve(__dirname, 'example/dist'),
publicPath: '/',
},
resolve: {
alias: {
'@edx/frontend-component-footer': path.resolve(__dirname, 'src'),
},
},
});