megit-app 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -9,6 +9,19 @@ surface, and the HTTP API may change in any minor release.
9
9
 
10
10
  ## [Unreleased]
11
11
 
12
+ ## [0.10.0] - 2026-09-03
13
+
14
+ ### Added
15
+
16
+ - A **Settings** dialog in a cog button at the end of the tab bar: font, app zoom, theme,
17
+ default diff view, an author avatars toggle (stops GitHub/Gravatar lookups when off),
18
+ and a shortcut reference.
19
+
20
+ ### Changed
21
+
22
+ - The version tag moved from the right end of the tab bar to beside the logo, making room
23
+ for the new settings cog.
24
+
12
25
  ## [0.9.0] - 2026-08-28
13
26
 
14
27
  ### Changed
@@ -236,7 +249,8 @@ First public release.
236
249
  - Windows (arm64, x64): builds and runs, but untested on real hardware — recursive `fs.watch` crashes the test worker there, so auto-refresh is not covered by CI
237
250
  - Linux: everything except the terminal — node-pty is an optionalDependency with no Linux prebuild, and the terminal button is hidden when it is unavailable
238
251
 
239
- [Unreleased]: https://github.com/vuongvu1/megit/compare/v0.9.0...HEAD
252
+ [Unreleased]: https://github.com/vuongvu1/megit/compare/v0.10.0...HEAD
253
+ [0.10.0]: https://github.com/vuongvu1/megit/compare/v0.9.0...v0.10.0
240
254
  [0.9.0]: https://github.com/vuongvu1/megit/compare/v0.8.0...v0.9.0
241
255
  [0.8.0]: https://github.com/vuongvu1/megit/compare/v0.7.0...v0.8.0
242
256
  [0.7.0]: https://github.com/vuongvu1/megit/compare/v0.6.0...v0.7.0
package/README.md CHANGED
@@ -104,6 +104,13 @@ The server watches each open repository (`fs.watch`, filtered and debounced) and
104
104
 
105
105
  Auto-refresh only ever reads local git, so commits pushed by someone else stay invisible until something fetches. <kbd>r</kbd> and the ⟳ button therefore fetch from the remote first, then refresh — that is the one path that surfaces new upstream commits and refreshes the Pull/Push badges. A fetch that fails (offline, no remote) is ignored and the local refresh still happens.
106
106
 
107
+ ### Settings
108
+
109
+ The cog at the right end of the tab bar opens font (bundled Ubuntu Mono, your system
110
+ monospace, or your system UI face), text size in four steps from 80% to 140%, the theme, the default diff
111
+ view, and a toggle for author avatars — off stops the GitHub and Gravatar lookups megit
112
+ otherwise makes per commit author. The same dialog lists every keyboard shortcut below.
113
+
107
114
  ### Keyboard
108
115
 
109
116
  | Key | Action |
@@ -114,6 +121,7 @@ Auto-refresh only ever reads local git, so commits pushed by someone else stay i
114
121
  | <kbd>r</kbd> | fetch from remote, then refresh |
115
122
  | <kbd>⌘</kbd><kbd>J</kbd> | toggle terminal |
116
123
  | <kbd>⌘</kbd><kbd>K</kbd> | clear terminal |
124
+ | <kbd>⌘</kbd><kbd>D</kbd> | split terminal pane |
117
125
  | <kbd>⌘</kbd><kbd>⇧</kbd><kbd>0</kbd> | toggle theme |
118
126
  | <kbd>⌘</kbd><kbd>↵</kbd> | commit |
119
127
  | <kbd>Esc</kbd> | close search or menu / cancel edit |
@@ -1 +1 @@
1
- import{a as e,i as t,n,r}from"./index-BlIDqqEW.js";var i=e(),a=/^<<<<<<< ?(.*)$/,o=/^\|\|\|\|\|\|\| ?(.*)$/,s=/^=======$/,c=/^>>>>>>> ?(.*)$/,l=e=>e.replace(/\r?\n$/,``);function u(e){let t=e.split(/(?<=\n)/),n=[],r=[],i=null,u=`context`,d=()=>{r.length&&n.push({kind:`context`,lines:r}),r=[]};for(let e of t){let t=l(e),f=a.exec(t);if(f){if(u!==`context`)return null;d(),i={ours:[],base:null,theirs:[],oursLabel:f[1].trim(),theirsLabel:``},u=`ours`;continue}if(u===`context`){r.push(e);continue}if(o.exec(t)){if(u!==`ours`)return null;i.base=[],u=`base`;continue}if(s.test(t)){if(u!==`ours`&&u!==`base`)return null;u=`theirs`;continue}let p=c.exec(t);if(p){if(u!==`theirs`)return null;i.theirsLabel=p[1].trim(),n.push({kind:`conflict`,block:i}),i=null,u=`context`;continue}u===`ours`?i.ours.push(e):u===`base`?i.base.push(e):i.theirs.push(e)}return u===`context`?(d(),n.some(e=>e.kind===`conflict`)?n:null):null}function d(e,t){let n=[];return e.forEach((e,r)=>{if(e.kind===`context`){n.push(...e.lines);return}let i=t.get(r);if(!i)throw Error(`no pick for conflict at segment ${r}`);(i===`ours`||i===`both`)&&n.push(...e.block.ours),(i===`theirs`||i===`both`)&&n.push(...e.block.theirs)}),n.join(``)}var f=n(),p=[[`ours`,`Use ours`],[`theirs`,`Use theirs`],[`both`,`Use both`]];function m({note:e,busy:t,onPick:n,onMarkResolved:r}){return(0,f.jsxs)(`div`,{className:`cf-card`,children:[(0,f.jsx)(`div`,{className:`cf-card-note`,children:e}),(0,f.jsxs)(`div`,{className:`cf-card-actions`,children:[r&&(0,f.jsx)(`button`,{className:`primary`,disabled:t,onClick:r,children:`Mark resolved`}),(0,f.jsx)(`button`,{disabled:t,onClick:()=>n(`ours`),children:`Keep ours`}),(0,f.jsx)(`button`,{disabled:t,onClick:()=>n(`theirs`),children:`Keep theirs`}),(0,f.jsx)(`button`,{className:`danger`,disabled:t,onClick:()=>n(`delete`),children:`Delete file`})]})]})}function h({repo:e,file:n,onResolved:a}){let[o,s]=(0,i.useState)(null),[c,l]=(0,i.useState)(new Map),[h,g]=(0,i.useState)(``),[_,v]=(0,i.useState)(!1),y=`repo=${encodeURIComponent(e)}`;(0,i.useEffect)(()=>{s(null),l(new Map),g(``),r(`/api/conflict?${y}&file=${encodeURIComponent(n)}`).then(s).catch(e=>g(e.message))},[e,n]);let b=(0,i.useMemo)(()=>o?.content?u(o.content):null,[o]),x=(0,i.useMemo)(()=>b?.filter(e=>e.kind===`conflict`).length??0,[b]);(0,i.useEffect)(()=>{!b||!x||c.size<x||(v(!0),r(`/api/conflict?${y}`,t(`POST`,{action:`resolve`,file:n,content:d(b,c)})).then(a).catch(e=>{g(e.message),v(!1)}))},[c,b,x]);let S=e=>{v(!0),r(`/api/conflict?${y}`,t(`POST`,{action:e,file:n})).then(a).catch(e=>{g(e.message),v(!1)})},C=()=>{v(!0),r(`/api/conflict?${y}`,t(`POST`,{action:`resolve`,file:n,content:o?.content??``})).then(a).catch(e=>{g(e.message),v(!1)})},w=(e,t)=>l(n=>new Map(n).set(e,t)),T=e=>l(t=>{let n=new Map(t);return n.delete(e),n});return h?(0,f.jsx)(`div`,{className:`diffview error`,children:h}):o?o.tooLarge?(0,f.jsxs)(`div`,{className:`diffview empty`,children:[`File too large to resolve here (`,Math.round((o.size??0)/1024),` KB) — use the terminal`]}):o.binary?(0,f.jsx)(`div`,{className:`cf-view`,children:(0,f.jsx)(m,{note:`Binary file — there is nothing to merge line by line.`,busy:_,onPick:S})}):o.missing?(0,f.jsx)(`div`,{className:`cf-view`,children:(0,f.jsx)(m,{note:`Deleted on one side and modified on the other.`,busy:_,onPick:S})}):b?(0,f.jsxs)(`div`,{className:`cf-view`,children:[(0,f.jsxs)(`div`,{className:`cf-progress`,children:[c.size,` of `,x,` resolved`]}),b.map((e,t)=>{if(e.kind===`context`)return(0,f.jsx)(`pre`,{className:`cf-context`,children:e.lines.join(``)},t);let n=c.get(t);return(0,f.jsxs)(`div`,{className:`cf-block${n?` picked`:``}`,children:[(0,f.jsxs)(`div`,{className:`cf-bar`,children:[(0,f.jsx)(`span`,{className:`cf-side-name`,children:e.block.oursLabel||`ours`}),n?(0,f.jsxs)(f.Fragment,{children:[(0,f.jsxs)(`span`,{className:`cf-chosen`,children:[`took `,n]}),(0,f.jsx)(`button`,{disabled:_,onClick:()=>T(t),children:`Reset`})]}):p.map(([e,n])=>(0,f.jsx)(`button`,{disabled:_,onClick:()=>w(t,e),children:n},e))]}),(!n||n===`ours`||n===`both`)&&(0,f.jsx)(`pre`,{className:`cf-ours`,children:e.block.ours.join(``)}),!n&&(0,f.jsx)(`div`,{className:`cf-mid`,children:e.block.theirsLabel||`theirs`}),(!n||n===`theirs`||n===`both`)&&(0,f.jsx)(`pre`,{className:`cf-theirs`,children:e.block.theirs.join(``)})]},t)})]}):(0,f.jsx)(`div`,{className:`cf-view`,children:(0,f.jsx)(m,{note:`No conflict markers left in this file — it looks already resolved.`,busy:_,onPick:S,onMarkResolved:C})}):(0,f.jsx)(`div`,{className:`diffview empty`,children:`Loading…`})}export{h as default};
1
+ import{d as e,i as t,n,r}from"./index-l_8r494M.js";var i=e(),a=/^<<<<<<< ?(.*)$/,o=/^\|\|\|\|\|\|\| ?(.*)$/,s=/^=======$/,c=/^>>>>>>> ?(.*)$/,l=e=>e.replace(/\r?\n$/,``);function u(e){let t=e.split(/(?<=\n)/),n=[],r=[],i=null,u=`context`,d=()=>{r.length&&n.push({kind:`context`,lines:r}),r=[]};for(let e of t){let t=l(e),f=a.exec(t);if(f){if(u!==`context`)return null;d(),i={ours:[],base:null,theirs:[],oursLabel:f[1].trim(),theirsLabel:``},u=`ours`;continue}if(u===`context`){r.push(e);continue}if(o.exec(t)){if(u!==`ours`)return null;i.base=[],u=`base`;continue}if(s.test(t)){if(u!==`ours`&&u!==`base`)return null;u=`theirs`;continue}let p=c.exec(t);if(p){if(u!==`theirs`)return null;i.theirsLabel=p[1].trim(),n.push({kind:`conflict`,block:i}),i=null,u=`context`;continue}u===`ours`?i.ours.push(e):u===`base`?i.base.push(e):i.theirs.push(e)}return u===`context`?(d(),n.some(e=>e.kind===`conflict`)?n:null):null}function d(e,t){let n=[];return e.forEach((e,r)=>{if(e.kind===`context`){n.push(...e.lines);return}let i=t.get(r);if(!i)throw Error(`no pick for conflict at segment ${r}`);(i===`ours`||i===`both`)&&n.push(...e.block.ours),(i===`theirs`||i===`both`)&&n.push(...e.block.theirs)}),n.join(``)}var f=n(),p=[[`ours`,`Use ours`],[`theirs`,`Use theirs`],[`both`,`Use both`]];function m({note:e,busy:t,onPick:n,onMarkResolved:r}){return(0,f.jsxs)(`div`,{className:`cf-card`,children:[(0,f.jsx)(`div`,{className:`cf-card-note`,children:e}),(0,f.jsxs)(`div`,{className:`cf-card-actions`,children:[r&&(0,f.jsx)(`button`,{className:`primary`,disabled:t,onClick:r,children:`Mark resolved`}),(0,f.jsx)(`button`,{disabled:t,onClick:()=>n(`ours`),children:`Keep ours`}),(0,f.jsx)(`button`,{disabled:t,onClick:()=>n(`theirs`),children:`Keep theirs`}),(0,f.jsx)(`button`,{className:`danger`,disabled:t,onClick:()=>n(`delete`),children:`Delete file`})]})]})}function h({repo:e,file:n,onResolved:a}){let[o,s]=(0,i.useState)(null),[c,l]=(0,i.useState)(new Map),[h,g]=(0,i.useState)(``),[_,v]=(0,i.useState)(!1),y=`repo=${encodeURIComponent(e)}`;(0,i.useEffect)(()=>{s(null),l(new Map),g(``),r(`/api/conflict?${y}&file=${encodeURIComponent(n)}`).then(s).catch(e=>g(e.message))},[e,n]);let b=(0,i.useMemo)(()=>o?.content?u(o.content):null,[o]),x=(0,i.useMemo)(()=>b?.filter(e=>e.kind===`conflict`).length??0,[b]);(0,i.useEffect)(()=>{!b||!x||c.size<x||(v(!0),r(`/api/conflict?${y}`,t(`POST`,{action:`resolve`,file:n,content:d(b,c)})).then(a).catch(e=>{g(e.message),v(!1)}))},[c,b,x]);let S=e=>{v(!0),r(`/api/conflict?${y}`,t(`POST`,{action:e,file:n})).then(a).catch(e=>{g(e.message),v(!1)})},C=()=>{v(!0),r(`/api/conflict?${y}`,t(`POST`,{action:`resolve`,file:n,content:o?.content??``})).then(a).catch(e=>{g(e.message),v(!1)})},w=(e,t)=>l(n=>new Map(n).set(e,t)),T=e=>l(t=>{let n=new Map(t);return n.delete(e),n});return h?(0,f.jsx)(`div`,{className:`diffview error`,children:h}):o?o.tooLarge?(0,f.jsxs)(`div`,{className:`diffview empty`,children:[`File too large to resolve here (`,Math.round((o.size??0)/1024),` KB) — use the terminal`]}):o.binary?(0,f.jsx)(`div`,{className:`cf-view`,children:(0,f.jsx)(m,{note:`Binary file — there is nothing to merge line by line.`,busy:_,onPick:S})}):o.missing?(0,f.jsx)(`div`,{className:`cf-view`,children:(0,f.jsx)(m,{note:`Deleted on one side and modified on the other.`,busy:_,onPick:S})}):b?(0,f.jsxs)(`div`,{className:`cf-view`,children:[(0,f.jsxs)(`div`,{className:`cf-progress`,children:[c.size,` of `,x,` resolved`]}),b.map((e,t)=>{if(e.kind===`context`)return(0,f.jsx)(`pre`,{className:`cf-context`,children:e.lines.join(``)},t);let n=c.get(t);return(0,f.jsxs)(`div`,{className:`cf-block${n?` picked`:``}`,children:[(0,f.jsxs)(`div`,{className:`cf-bar`,children:[(0,f.jsx)(`span`,{className:`cf-side-name`,children:e.block.oursLabel||`ours`}),n?(0,f.jsxs)(f.Fragment,{children:[(0,f.jsxs)(`span`,{className:`cf-chosen`,children:[`took `,n]}),(0,f.jsx)(`button`,{disabled:_,onClick:()=>T(t),children:`Reset`})]}):p.map(([e,n])=>(0,f.jsx)(`button`,{disabled:_,onClick:()=>w(t,e),children:n},e))]}),(!n||n===`ours`||n===`both`)&&(0,f.jsx)(`pre`,{className:`cf-ours`,children:e.block.ours.join(``)}),!n&&(0,f.jsx)(`div`,{className:`cf-mid`,children:e.block.theirsLabel||`theirs`}),(!n||n===`theirs`||n===`both`)&&(0,f.jsx)(`pre`,{className:`cf-theirs`,children:e.block.theirs.join(``)})]},t)})]}):(0,f.jsx)(`div`,{className:`cf-view`,children:(0,f.jsx)(m,{note:`No conflict markers left in this file — it looks already resolved.`,busy:_,onPick:S,onMarkResolved:C})}):(0,f.jsx)(`div`,{className:`diffview empty`,children:`Loading…`})}export{h as default};